]> git.saurik.com Git - wxWidgets.git/blame - src/common/dbtable.cpp
use wx/math.h for math constants - avoids redifinition warnings
[wxWidgets.git] / src / common / dbtable.cpp
CommitLineData
108106cf 1///////////////////////////////////////////////////////////////////////////////
1fc5dd6f 2// Name: dbtable.cpp
f6bcfd97 3// Purpose: Implementation of the wxDbTable class.
108106cf 4// Author: Doug Card
67e9aaa3 5// Modified by: George Tasker
3ca6a5f0
BP
6// Bart Jourquin
7// Mark Johnson
108106cf
JS
8// Created: 9.96
9// RCS-ID: $Id$
10// Copyright: (c) 1996 Remstar International, Inc.
7e559cd8 11// Licence: wxWindows licence
108106cf
JS
12///////////////////////////////////////////////////////////////////////////////
13
14/*
15// SYNOPSIS START
16// SYNOPSIS STOP
17*/
e7c9692f 18
14f355c2 19#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
882fc8a9
GT
20 #pragma implementation "dbtable.h"
21#endif
108106cf 22
a2115c88
GT
23#include "wx/wxprec.h"
24
882fc8a9
GT
25#ifdef __BORLANDC__
26 #pragma hdrstop
108106cf 27#endif
108106cf 28
0b8410f3 29#ifdef DBDEBUG_CONSOLE
4888e623
GT
30#if wxUSE_IOSTREAMH
31 #include <iostream.h>
32#else
33 #include <iostream>
34#endif
0b8410f3
GT
35 #include "wx/ioswrap.h"
36#endif
108106cf 37
882fc8a9
GT
38#ifndef WX_PRECOMP
39 #include "wx/string.h"
40 #include "wx/object.h"
41 #include "wx/list.h"
42 #include "wx/utils.h"
882fc8a9 43 #include "wx/log.h"
a2115c88 44#endif
882fc8a9 45#include "wx/filefn.h"
f6bcfd97 46
a2115c88 47#if wxUSE_ODBC
108106cf
JS
48
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
67e9aaa3 52
882fc8a9 53#include "wx/dbtable.h"
108106cf 54
1fc5dd6f 55#ifdef __UNIX__
108106cf
JS
56// The HPUX preprocessor lines below were commented out on 8/20/97
57// because macros.h currently redefines DEBUG and is unneeded.
58// # ifdef HPUX
59// # include <macros.h>
60// # endif
1fc5dd6f 61# ifdef LINUX
108106cf
JS
62# include <sys/minmax.h>
63# endif
64#endif
65
a2115c88
GT
66ULONG lastTableID = 0;
67
68
e041ce57 69#ifdef __WXDEBUG__
89894079 70 wxList TablesInUse;
a2115c88
GT
71#endif
72
73
8a39593e 74void csstrncpyt(wxChar *target, const wxChar *source, int n)
e7c9692f
GT
75{
76 while ( (*target++ = *source++) != '\0' && --n )
77 ;
78
79 *target = '\0';
80}
81
82
83
da99271d
GT
84/********** wxDbColDef::wxDbColDef() Constructor **********/
85wxDbColDef::wxDbColDef()
86{
87 Initialize();
88} // Constructor
89
90
91bool wxDbColDef::Initialize()
92{
93 ColName[0] = 0;
94 DbDataType = DB_DATA_TYPE_INTEGER;
95 SqlCtype = SQL_C_LONG;
96 PtrDataObj = NULL;
97 SzDataObj = 0;
68379eaf
WS
98 KeyField = false;
99 Updateable = false;
100 InsertAllowed = false;
101 DerivedCol = false;
da99271d 102 CbValue = 0;
68379eaf 103 Null = false;
da99271d 104
68379eaf 105 return true;
da99271d
GT
106} // wxDbColDef::Initialize()
107
108
109/********** wxDbTable::wxDbTable() Constructor **********/
6b3f4fb8 110wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns,
4fdae997 111 const wxString &qryTblName, bool qryOnly, const wxString &tblPath)
108106cf 112{
6b3f4fb8 113 if (!initialize(pwxDb, tblName, numColumns, qryTblName, qryOnly, tblPath))
4fdae997
GT
114 cleanup();
115} // wxDbTable::wxDbTable()
116
117
118/***** DEPRECATED: use wxDbTable::wxDbTable() format above *****/
254a2129 119#if WXWIN_COMPATIBILITY_2_4
6b3f4fb8 120wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns,
4fdae997
GT
121 const wxChar *qryTblName, bool qryOnly, const wxString &tblPath)
122{
123 wxString tempQryTblName;
124 tempQryTblName = qryTblName;
6b3f4fb8 125 if (!initialize(pwxDb, tblName, numColumns, tempQryTblName, qryOnly, tblPath))
4fdae997
GT
126 cleanup();
127} // wxDbTable::wxDbTable()
254a2129 128#endif // WXWIN_COMPATIBILITY_2_4
4fdae997
GT
129
130
131/********** wxDbTable::~wxDbTable() **********/
132wxDbTable::~wxDbTable()
133{
134 this->cleanup();
135} // wxDbTable::~wxDbTable()
136
137
6b3f4fb8 138bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns,
4fdae997
GT
139 const wxString &qryTblName, bool qryOnly, const wxString &tblPath)
140{
141 // Initializing member variables
f6bcfd97 142 pDb = pwxDb; // Pointer to the wxDb object
89894079
VZ
143 henv = 0;
144 hdbc = 0;
145 hstmt = 0;
882fc8a9 146 m_hstmtGridQuery = 0;
89894079
VZ
147 hstmtDefault = 0; // Initialized below
148 hstmtCount = 0; // Initialized first time it is needed
149 hstmtInsert = 0;
150 hstmtDelete = 0;
151 hstmtUpdate = 0;
152 hstmtInternal = 0;
153 colDefs = 0;
154 tableID = 0;
b8032740 155 m_numCols = numColumns; // Number of columns in the table
4fdae997
GT
156 where.Empty(); // Where clause
157 orderBy.Empty(); // Order By clause
158 from.Empty(); // From clause
68379eaf 159 selectForUpdate = false; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase
89894079 160 queryOnly = qryOnly;
68379eaf 161 insertable = true;
4fdae997
GT
162 tablePath.Empty();
163 tableName.Empty();
164 queryTableName.Empty();
89894079 165
4fdae997
GT
166 wxASSERT(tblName.Length());
167 wxASSERT(pDb);
89894079 168
4fdae997 169 if (!pDb)
68379eaf 170 return false;
4fdae997
GT
171
172 tableName = tblName; // Table Name
215a0070
GT
173 if ((pDb->Dbms() == dbmsORACLE) ||
174 (pDb->Dbms() == dbmsFIREBIRD) ||
175 (pDb->Dbms() == dbmsINTERBASE))
176 tableName = tableName.Upper();
177
4fdae997
GT
178 if (tblPath.Length())
179 tablePath = tblPath; // Table Path - used for dBase files
f02d4a64 180 else
4fdae997 181 tablePath.Empty();
da38429d 182
4fdae997
GT
183 if (qryTblName.Length()) // Name of the table/view to query
184 queryTableName = qryTblName;
89894079 185 else
4fdae997 186 queryTableName = tblName;
da38429d 187
215a0070
GT
188 if ((pDb->Dbms() == dbmsORACLE) ||
189 (pDb->Dbms() == dbmsFIREBIRD) ||
190 (pDb->Dbms() == dbmsINTERBASE))
191 queryTableName = queryTableName.Upper();
192
f6bcfd97 193 pDb->incrementTableCount();
da38429d 194
1e92909e 195 wxString s;
89894079 196 tableID = ++lastTableID;
7d8c3dba 197 s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"), tblName.c_str(), tableID, pDb);
9082f1a9 198
e041ce57 199#ifdef __WXDEBUG__
8128349e
GT
200 wxTablesInUse *tableInUse;
201 tableInUse = new wxTablesInUse();
89894079 202 tableInUse->tableName = tblName;
1e92909e
GT
203 tableInUse->tableID = tableID;
204 tableInUse->pDb = pDb;
89894079 205 TablesInUse.Append(tableInUse);
a2115c88 206#endif
da38429d 207
4fdae997 208 pDb->WriteSqlLog(s);
da38429d 209
f6bcfd97
BP
210 // Grab the HENV and HDBC from the wxDb object
211 henv = pDb->GetHENV();
212 hdbc = pDb->GetHDBC();
da38429d 213
89894079 214 // Allocate space for column definitions
b8032740
GT
215 if (m_numCols)
216 colDefs = new wxDbColDef[m_numCols]; // Points to the first column definition
da38429d 217
89894079
VZ
218 // Allocate statement handles for the table
219 if (!queryOnly)
220 {
221 // Allocate a separate statement handle for performing inserts
222 if (SQLAllocStmt(hdbc, &hstmtInsert) != SQL_SUCCESS)
223 pDb->DispAllErrors(henv, hdbc);
224 // Allocate a separate statement handle for performing deletes
225 if (SQLAllocStmt(hdbc, &hstmtDelete) != SQL_SUCCESS)
226 pDb->DispAllErrors(henv, hdbc);
227 // Allocate a separate statement handle for performing updates
228 if (SQLAllocStmt(hdbc, &hstmtUpdate) != SQL_SUCCESS)
229 pDb->DispAllErrors(henv, hdbc);
230 }
231 // Allocate a separate statement handle for internal use
232 if (SQLAllocStmt(hdbc, &hstmtInternal) != SQL_SUCCESS)
233 pDb->DispAllErrors(henv, hdbc);
da38429d 234
89894079
VZ
235 // Set the cursor type for the statement handles
236 cursorType = SQL_CURSOR_STATIC;
da38429d 237
89894079 238 if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
da38429d 239 {
89894079
VZ
240 // Check to see if cursor type is supported
241 pDb->GetNextError(henv, hdbc, hstmtInternal);
4fdae997 242 if (! wxStrcmp(pDb->sqlState, wxT("01S02"))) // Option Value Changed
3ca6a5f0 243 {
89894079
VZ
244 // Datasource does not support static cursors. Driver
245 // will substitute a cursor type. Call SQLGetStmtOption()
246 // to determine which cursor type was selected.
247 if (SQLGetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, &cursorType) != SQL_SUCCESS)
3ca6a5f0 248 pDb->DispAllErrors(henv, hdbc, hstmtInternal);
a2115c88 249#ifdef DBDEBUG_CONSOLE
4fdae997 250 cout << wxT("Static cursor changed to: ");
89894079 251 switch(cursorType)
3ca6a5f0
BP
252 {
253 case SQL_CURSOR_FORWARD_ONLY:
4fdae997 254 cout << wxT("Forward Only");
3ca6a5f0
BP
255 break;
256 case SQL_CURSOR_STATIC:
4fdae997 257 cout << wxT("Static");
3ca6a5f0
BP
258 break;
259 case SQL_CURSOR_KEYSET_DRIVEN:
4fdae997 260 cout << wxT("Keyset Driven");
3ca6a5f0
BP
261 break;
262 case SQL_CURSOR_DYNAMIC:
4fdae997 263 cout << wxT("Dynamic");
3ca6a5f0
BP
264 break;
265 }
89894079 266 cout << endl << endl;
108106cf 267#endif
3ca6a5f0
BP
268 // BJO20000425
269 if (pDb->FwdOnlyCursors() && cursorType != SQL_CURSOR_FORWARD_ONLY)
270 {
271 // Force the use of a forward only cursor...
272 cursorType = SQL_CURSOR_FORWARD_ONLY;
273 if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
274 {
275 // Should never happen
276 pDb->GetNextError(henv, hdbc, hstmtInternal);
68379eaf 277 return false;
3ca6a5f0
BP
278 }
279 }
280 }
281 else
282 {
89894079
VZ
283 pDb->DispNextError();
284 pDb->DispAllErrors(henv, hdbc, hstmtInternal);
3ca6a5f0 285 }
89894079 286 }
a2115c88 287#ifdef DBDEBUG_CONSOLE
89894079 288 else
4fdae997 289 cout << wxT("Cursor Type set to STATIC") << endl << endl;
108106cf 290#endif
da38429d 291
89894079
VZ
292 if (!queryOnly)
293 {
294 // Set the cursor type for the INSERT statement handle
295 if (SQLSetStmtOption(hstmtInsert, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
296 pDb->DispAllErrors(henv, hdbc, hstmtInsert);
297 // Set the cursor type for the DELETE statement handle
298 if (SQLSetStmtOption(hstmtDelete, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
299 pDb->DispAllErrors(henv, hdbc, hstmtDelete);
300 // Set the cursor type for the UPDATE statement handle
301 if (SQLSetStmtOption(hstmtUpdate, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
302 pDb->DispAllErrors(henv, hdbc, hstmtUpdate);
303 }
da38429d 304
89894079 305 // Make the default cursor the active cursor
68379eaf 306 hstmtDefault = GetNewCursor(false,false);
4fdae997 307 wxASSERT(hstmtDefault);
89894079 308 hstmt = *hstmtDefault;
108106cf 309
68379eaf 310 return true;
67e9aaa3 311
4fdae997
GT
312} // wxDbTable::initialize()
313
314
315void wxDbTable::cleanup()
108106cf 316{
1e92909e 317 wxString s;
89894079
VZ
318 if (pDb)
319 {
7d8c3dba 320 s.Printf(wxT("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]"), tableName.c_str(), tableID, pDb);
4fdae997 321 pDb->WriteSqlLog(s);
89894079 322 }
a2115c88 323
e041ce57 324#ifdef __WXDEBUG__
89894079
VZ
325 if (tableID)
326 {
68379eaf 327 bool found = false;
1e92909e 328
e3f8f04d 329 wxList::compatibility_iterator pNode;
52410d54 330 pNode = TablesInUse.GetFirst();
89894079
VZ
331 while (pNode && !found)
332 {
52410d54 333 if (((wxTablesInUse *)pNode->GetData())->tableID == tableID)
89894079 334 {
68379eaf 335 found = true;
e3f8f04d
MB
336 delete (wxTablesInUse *)pNode->GetData();
337 TablesInUse.Erase(pNode);
89894079
VZ
338 }
339 else
52410d54 340 pNode = pNode->GetNext();
89894079
VZ
341 }
342 if (!found)
343 {
1e92909e 344 wxString msg;
597fadce 345 msg.Printf(wxT("Unable to find the tableID in the linked\nlist of tables in use.\n\n%s"),s.c_str());
4fdae997 346 wxLogDebug (msg,wxT("NOTICE..."));
89894079
VZ
347 }
348 }
a2115c88 349#endif
e041ce57 350
f6bcfd97 351 // Decrement the wxDb table count
89894079 352 if (pDb)
f6bcfd97 353 pDb->decrementTableCount();
89894079
VZ
354
355 // Delete memory allocated for column definitions
356 if (colDefs)
357 delete [] colDefs;
358
359 // Free statement handles
360 if (!queryOnly)
361 {
362 if (hstmtInsert)
7d8c3dba
GT
363 {
364/*
365ODBC 3.0 says to use this form
366 if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS)
367*/
89894079
VZ
368 if (SQLFreeStmt(hstmtInsert, SQL_DROP) != SQL_SUCCESS)
369 pDb->DispAllErrors(henv, hdbc);
7d8c3dba 370 }
7c5c05ae 371
89894079 372 if (hstmtDelete)
7d8c3dba
GT
373 {
374/*
375ODBC 3.0 says to use this form
376 if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS)
377*/
89894079 378 if (SQLFreeStmt(hstmtDelete, SQL_DROP) != SQL_SUCCESS)
7d8c3dba
GT
379 pDb->DispAllErrors(henv, hdbc);
380 }
7c5c05ae 381
89894079 382 if (hstmtUpdate)
7d8c3dba
GT
383 {
384/*
385ODBC 3.0 says to use this form
386 if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS)
387*/
89894079
VZ
388 if (SQLFreeStmt(hstmtUpdate, SQL_DROP) != SQL_SUCCESS)
389 pDb->DispAllErrors(henv, hdbc);
7d8c3dba 390 }
89894079 391 }
3ca6a5f0 392
89894079 393 if (hstmtInternal)
7d8c3dba 394 {
89894079
VZ
395 if (SQLFreeStmt(hstmtInternal, SQL_DROP) != SQL_SUCCESS)
396 pDb->DispAllErrors(henv, hdbc);
7d8c3dba 397 }
89894079
VZ
398
399 // Delete dynamically allocated cursors
400 if (hstmtDefault)
401 DeleteCursor(hstmtDefault);
7c5c05ae 402
89894079
VZ
403 if (hstmtCount)
404 DeleteCursor(hstmtCount);
882fc8a9
GT
405
406 if (m_hstmtGridQuery)
407 DeleteCursor(m_hstmtGridQuery);
408
4fdae997 409} // wxDbTable::cleanup()
67e9aaa3
GT
410
411
6919c53f
GT
412/***************************** PRIVATE FUNCTIONS *****************************/
413
67e9aaa3 414
0907ea9c 415void wxDbTable::setCbValueForColumn(int columnIndex)
e9ed92a2
GT
416{
417 switch(colDefs[columnIndex].DbDataType)
418 {
419 case DB_DATA_TYPE_VARCHAR:
420 if (colDefs[columnIndex].Null)
421 colDefs[columnIndex].CbValue = SQL_NULL_DATA;
422 else
423 colDefs[columnIndex].CbValue = SQL_NTS;
424 break;
425 case DB_DATA_TYPE_INTEGER:
426 if (colDefs[columnIndex].Null)
427 colDefs[columnIndex].CbValue = SQL_NULL_DATA;
428 else
429 colDefs[columnIndex].CbValue = 0;
430 break;
431 case DB_DATA_TYPE_FLOAT:
432 if (colDefs[columnIndex].Null)
433 colDefs[columnIndex].CbValue = SQL_NULL_DATA;
434 else
435 colDefs[columnIndex].CbValue = 0;
436 break;
437 case DB_DATA_TYPE_DATE:
438 if (colDefs[columnIndex].Null)
439 colDefs[columnIndex].CbValue = SQL_NULL_DATA;
440 else
441 colDefs[columnIndex].CbValue = 0;
442 break;
443 case DB_DATA_TYPE_BLOB:
444 if (colDefs[columnIndex].Null)
445 colDefs[columnIndex].CbValue = SQL_NULL_DATA;
446 else
e4e45573 447 if (colDefs[columnIndex].SqlCtype == SQL_C_WXCHAR)
fd9b9198 448 colDefs[columnIndex].CbValue = SQL_NTS;
e9ed92a2
GT
449 else
450 colDefs[columnIndex].CbValue = SQL_LEN_DATA_AT_EXEC(colDefs[columnIndex].SzDataObj);
451 break;
452 }
453}
454
2beca662 455/********** wxDbTable::bindParams() **********/
4fdae997 456bool wxDbTable::bindParams(bool forUpdate)
6919c53f 457{
4fdae997 458 wxASSERT(!queryOnly);
89894079 459 if (queryOnly)
68379eaf 460 return false;
da38429d 461
89894079 462 SWORD fSqlType = 0;
d171743e 463 SDWORD precision = 0;
89894079 464 SWORD scale = 0;
da38429d 465
4fdae997
GT
466 // Bind each column of the table that should be bound
467 // to a parameter marker
6b3f4fb8 468 int i;
b8032740 469 UWORD colNumber;
2beca662 470
b8032740 471 for (i=0, colNumber=1; i < m_numCols; i++)
89894079 472 {
4fdae997 473 if (forUpdate)
89894079 474 {
2beca662 475 if (!colDefs[i].Updateable)
4fdae997 476 continue;
89894079 477 }
4fdae997 478 else
3ca6a5f0 479 {
2beca662 480 if (!colDefs[i].InsertAllowed)
4fdae997 481 continue;
3ca6a5f0 482 }
6919c53f 483
89894079
VZ
484 switch(colDefs[i].DbDataType)
485 {
3ca6a5f0
BP
486 case DB_DATA_TYPE_VARCHAR:
487 fSqlType = pDb->GetTypeInfVarchar().FsqlType;
488 precision = colDefs[i].SzDataObj;
489 scale = 0;
3ca6a5f0
BP
490 break;
491 case DB_DATA_TYPE_INTEGER:
492 fSqlType = pDb->GetTypeInfInteger().FsqlType;
493 precision = pDb->GetTypeInfInteger().Precision;
494 scale = 0;
3ca6a5f0
BP
495 break;
496 case DB_DATA_TYPE_FLOAT:
497 fSqlType = pDb->GetTypeInfFloat().FsqlType;
498 precision = pDb->GetTypeInfFloat().Precision;
da38429d 499 scale = pDb->GetTypeInfFloat().MaximumScale;
3ca6a5f0
BP
500 // SQL Sybase Anywhere v5.5 returned a negative number for the
501 // MaxScale. This caused ODBC to kick out an error on ibscale.
502 // I check for this here and set the scale = precision.
503 //if (scale < 0)
504 // scale = (short) precision;
3ca6a5f0
BP
505 break;
506 case DB_DATA_TYPE_DATE:
507 fSqlType = pDb->GetTypeInfDate().FsqlType;
508 precision = pDb->GetTypeInfDate().Precision;
509 scale = 0;
3ca6a5f0 510 break;
bf5423ea
GT
511 case DB_DATA_TYPE_BLOB:
512 fSqlType = pDb->GetTypeInfBlob().FsqlType;
c9b6d796 513 precision = colDefs[i].SzDataObj;
bf5423ea 514 scale = 0;
bf5423ea 515 break;
3ca6a5f0 516 }
e9ed92a2
GT
517
518 setCbValueForColumn(i);
519
4fdae997
GT
520 if (forUpdate)
521 {
b8032740 522 if (SQLBindParameter(hstmtUpdate, colNumber++, SQL_PARAM_INPUT, colDefs[i].SqlCtype,
da38429d 523 fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj,
4fdae997
GT
524 precision+1, &colDefs[i].CbValue) != SQL_SUCCESS)
525 {
526 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
527 }
528 }
529 else
3ca6a5f0 530 {
b8032740 531 if (SQLBindParameter(hstmtInsert, colNumber++, SQL_PARAM_INPUT, colDefs[i].SqlCtype,
da38429d 532 fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj,
c9b6d796 533 precision+1, &colDefs[i].CbValue) != SQL_SUCCESS)
4fdae997
GT
534 {
535 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
536 }
89894079 537 }
89894079 538 }
da38429d 539
89894079 540 // Completed successfully
68379eaf 541 return true;
6919c53f 542
4fdae997
GT
543} // wxDbTable::bindParams()
544
545
546/********** wxDbTable::bindInsertParams() **********/
547bool wxDbTable::bindInsertParams(void)
548{
68379eaf 549 return bindParams(false);
4fdae997
GT
550} // wxDbTable::bindInsertParams()
551
552
553/********** wxDbTable::bindUpdateParams() **********/
554bool wxDbTable::bindUpdateParams(void)
555{
68379eaf 556 return bindParams(true);
f6bcfd97 557} // wxDbTable::bindUpdateParams()
6919c53f 558
67e9aaa3 559
f6bcfd97
BP
560/********** wxDbTable::bindCols() **********/
561bool wxDbTable::bindCols(HSTMT cursor)
6919c53f 562{
9d943681
GT
563 static SDWORD cb;
564
89894079 565 // Bind each column of the table to a memory address for fetching data
6b3f4fb8 566 UWORD i;
b8032740 567 for (i = 0; i < m_numCols; i++)
3ca6a5f0 568 {
9d943681 569 cb = colDefs[i].CbValue;
6b3f4fb8 570 if (SQLBindCol(cursor, (UWORD)(i+1), colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj,
9d943681 571 colDefs[i].SzDataObj, &cb ) != SQL_SUCCESS)
3ca6a5f0 572 return (pDb->DispAllErrors(henv, hdbc, cursor));
3ca6a5f0 573 }
89894079
VZ
574
575 // Completed successfully
68379eaf 576 return true;
6919c53f 577
f6bcfd97 578} // wxDbTable::bindCols()
6919c53f 579
67e9aaa3 580
f6bcfd97
BP
581/********** wxDbTable::getRec() **********/
582bool wxDbTable::getRec(UWORD fetchType)
6919c53f 583{
89894079
VZ
584 RETCODE retcode;
585
586 if (!pDb->FwdOnlyCursors())
587 {
588 // Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType
589 UDWORD cRowsFetched;
590 UWORD rowStatus;
591
592 retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus);
5a226de0 593 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
3ca6a5f0 594 {
89894079 595 if (retcode == SQL_NO_DATA_FOUND)
68379eaf 596 return false;
89894079
VZ
597 else
598 return(pDb->DispAllErrors(henv, hdbc, hstmt));
3ca6a5f0 599 }
f02d4a64
GT
600 else
601 {
602 // Set the Null member variable to indicate the Null state
603 // of each column just read in.
604 int i;
b8032740 605 for (i = 0; i < m_numCols; i++)
f02d4a64
GT
606 colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
607 }
89894079
VZ
608 }
609 else
610 {
611 // Fetch the next record from the record set
612 retcode = SQLFetch(hstmt);
613 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
614 {
615 if (retcode == SQL_NO_DATA_FOUND)
68379eaf 616 return false;
89894079
VZ
617 else
618 return(pDb->DispAllErrors(henv, hdbc, hstmt));
619 }
f02d4a64
GT
620 else
621 {
622 // Set the Null member variable to indicate the Null state
623 // of each column just read in.
624 int i;
b8032740 625 for (i = 0; i < m_numCols; i++)
f02d4a64
GT
626 colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
627 }
89894079
VZ
628 }
629
630 // Completed successfully
68379eaf 631 return true;
6919c53f 632
f6bcfd97 633} // wxDbTable::getRec()
6919c53f 634
67e9aaa3 635
f6bcfd97 636/********** wxDbTable::execDelete() **********/
4fdae997 637bool wxDbTable::execDelete(const wxString &pSqlStmt)
6919c53f 638{
2beca662
GT
639 RETCODE retcode;
640
89894079 641 // Execute the DELETE statement
8a39593e 642 retcode = SQLExecDirect(hstmtDelete, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
6919c53f 643
2beca662
GT
644 if (retcode == SQL_SUCCESS ||
645 retcode == SQL_NO_DATA_FOUND ||
646 retcode == SQL_SUCCESS_WITH_INFO)
647 {
648 // Record deleted successfully
68379eaf 649 return true;
2beca662
GT
650 }
651
652 // Problem deleting record
653 return(pDb->DispAllErrors(henv, hdbc, hstmtDelete));
6919c53f 654
f6bcfd97 655} // wxDbTable::execDelete()
6919c53f 656
67e9aaa3 657
f6bcfd97 658/********** wxDbTable::execUpdate() **********/
4fdae997 659bool wxDbTable::execUpdate(const wxString &pSqlStmt)
6919c53f 660{
2beca662
GT
661 RETCODE retcode;
662
89894079 663 // Execute the UPDATE statement
8a39593e 664 retcode = SQLExecDirect(hstmtUpdate, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
6919c53f 665
2beca662
GT
666 if (retcode == SQL_SUCCESS ||
667 retcode == SQL_NO_DATA_FOUND ||
668 retcode == SQL_SUCCESS_WITH_INFO)
669 {
670 // Record updated successfully
68379eaf 671 return true;
2beca662 672 }
5962bdb8
JS
673 else if (retcode == SQL_NEED_DATA)
674 {
675 PTR pParmID;
8a39593e
JS
676 retcode = SQLParamData(hstmtUpdate, &pParmID);
677 while (retcode == SQL_NEED_DATA)
5962bdb8
JS
678 {
679 // Find the parameter
680 int i;
b8032740 681 for (i=0; i < m_numCols; i++)
5962bdb8
JS
682 {
683 if (colDefs[i].PtrDataObj == pParmID)
684 {
685 // We found it. Store the parameter.
686 retcode = SQLPutData(hstmtUpdate, pParmID, colDefs[i].SzDataObj);
687 if (retcode != SQL_SUCCESS)
688 {
689 pDb->DispNextError();
690 return pDb->DispAllErrors(henv, hdbc, hstmtUpdate);
691 }
692 break;
693 }
694 }
c9b6d796 695 retcode = SQLParamData(hstmtUpdate, &pParmID);
5962bdb8
JS
696 }
697 if (retcode == SQL_SUCCESS ||
698 retcode == SQL_NO_DATA_FOUND ||
699 retcode == SQL_SUCCESS_WITH_INFO)
700 {
701 // Record updated successfully
68379eaf 702 return true;
5962bdb8
JS
703 }
704 }
2beca662
GT
705
706 // Problem updating record
707 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
6919c53f 708
f6bcfd97 709} // wxDbTable::execUpdate()
6919c53f 710
67e9aaa3 711
f6bcfd97 712/********** wxDbTable::query() **********/
4fdae997 713bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxString &pSqlStmt)
6919c53f 714{
4fdae997 715 wxString sqlStmt;
6919c53f 716
89894079
VZ
717 if (forUpdate)
718 // The user may wish to select for update, but the DBMS may not be capable
719 selectForUpdate = CanSelectForUpdate();
720 else
68379eaf 721 selectForUpdate = false;
6919c53f 722
89894079
VZ
723 // Set the SQL SELECT string
724 if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in,
3ca6a5f0 725 { // so generate a select statement.
f6bcfd97 726 BuildSelectStmt(sqlStmt, queryType, distinct);
89894079 727 pDb->WriteSqlLog(sqlStmt);
3ca6a5f0 728 }
e93a3a18 729
89894079 730 // Make sure the cursor is closed first
e93a3a18 731 if (!CloseCursor(hstmt))
68379eaf 732 return false;
6919c53f 733
89894079 734 // Execute the SQL SELECT statement
da38429d 735 int retcode;
8a39593e 736 retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt.c_str() : sqlStmt.c_str()), SQL_NTS);
89894079 737 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
3ca6a5f0 738 return(pDb->DispAllErrors(henv, hdbc, hstmt));
6919c53f 739
89894079 740 // Completed successfully
68379eaf 741 return true;
6919c53f 742
f6bcfd97 743} // wxDbTable::query()
6919c53f
GT
744
745
67e9aaa3
GT
746/***************************** PUBLIC FUNCTIONS *****************************/
747
6919c53f 748
f6bcfd97 749/********** wxDbTable::Open() **********/
1454d4e6 750bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists)
108106cf 751{
89894079 752 if (!pDb)
68379eaf 753 return false;
3ca6a5f0 754
89894079 755 int i;
1e92909e 756 wxString sqlStmt;
f02d4a64 757 wxString s;
882fc8a9
GT
758
759 // Calculate the maximum size of the concatenated
760 // keys for use with wxDbGrid
761 m_keysize = 0;
b8032740 762 for (i=0; i < m_numCols; i++)
882fc8a9
GT
763 {
764 if (colDefs[i].KeyField)
765 {
882fc8a9
GT
766 m_keysize += colDefs[i].SzDataObj;
767 }
768 }
89894079 769
4fdae997 770 s.Empty();
38ae3a10
GT
771
772 bool exists = true;
773 if (checkTableExists)
774 {
775 if (pDb->Dbms() == dbmsPOSTGRES)
776 exists = pDb->TableExists(tableName, NULL, tablePath);
777 else
778 exists = pDb->TableExists(tableName, pDb->GetUsername(), tablePath);
779 }
780
89894079 781 // Verify that the table exists in the database
38ae3a10 782 if (!exists)
89894079 783 {
4fdae997
GT
784 s = wxT("Table/view does not exist in the database");
785 if ( *(pDb->dbInf.accessibleTables) == wxT('Y'))
786 s += wxT(", or you have no permissions.\n");
e16143f6 787 else
4fdae997 788 s += wxT(".\n");
f02d4a64
GT
789 }
790 else if (checkPrivileges)
791 {
792 // Verify the user has rights to access the table.
d8d26772
WS
793 bool hasPrivs wxDUMMY_INITIALIZE(true);
794
38ae3a10
GT
795 if (pDb->Dbms() == dbmsPOSTGRES)
796 hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), NULL, tablePath);
797 else
798 hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), pDb->GetUsername(), tablePath);
799
800 if (!hasPrivs)
e4e45573 801 s = wxT("Connecting user does not have sufficient privileges to access this table.\n");
f02d4a64
GT
802 }
803
d8d26772 804 if (!s.empty())
f02d4a64
GT
805 {
806 wxString p;
807
d8d26772 808 if (!tablePath.empty())
7d8c3dba 809 p.Printf(wxT("Error opening '%s/%s'.\n"),tablePath.c_str(),tableName.c_str());
e16143f6 810 else
7d8c3dba 811 p.Printf(wxT("Error opening '%s'.\n"), tableName.c_str());
f02d4a64
GT
812
813 p += s;
814 pDb->LogError(p.GetData());
815
68379eaf 816 return false;
89894079
VZ
817 }
818
819 // Bind the member variables for field exchange between
f6bcfd97 820 // the wxDbTable object and the ODBC record.
89894079
VZ
821 if (!queryOnly)
822 {
823 if (!bindInsertParams()) // Inserts
68379eaf 824 return false;
da38429d 825
89894079 826 if (!bindUpdateParams()) // Updates
68379eaf 827 return false;
89894079 828 }
3ca6a5f0 829
89894079 830 if (!bindCols(*hstmtDefault)) // Selects
68379eaf 831 return false;
da38429d 832
89894079 833 if (!bindCols(hstmtInternal)) // Internal use only
68379eaf 834 return false;
f02d4a64
GT
835
836 /*
89894079
VZ
837 * Do NOT bind the hstmtCount cursor!!!
838 */
839
840 // Build an insert statement using parameter markers
b8032740 841 if (!queryOnly && m_numCols > 0)
89894079 842 {
68379eaf 843 bool needComma = false;
1d6f2348
VZ
844 sqlStmt.Printf(wxT("INSERT INTO %s ("),
845 pDb->SQLTableName(tableName.c_str()).c_str());
b8032740 846 for (i = 0; i < m_numCols; i++)
89894079
VZ
847 {
848 if (! colDefs[i].InsertAllowed)
849 continue;
850 if (needComma)
4fdae997 851 sqlStmt += wxT(",");
243d4b36 852 sqlStmt += pDb->SQLColumnName(colDefs[i].ColName);
68379eaf 853 needComma = true;
89894079 854 }
68379eaf 855 needComma = false;
4fdae997 856 sqlStmt += wxT(") VALUES (");
f6bcfd97 857
3ca6a5f0 858 int insertableCount = 0;
f6bcfd97 859
b8032740 860 for (i = 0; i < m_numCols; i++)
89894079
VZ
861 {
862 if (! colDefs[i].InsertAllowed)
863 continue;
864 if (needComma)
4fdae997
GT
865 sqlStmt += wxT(",");
866 sqlStmt += wxT("?");
68379eaf 867 needComma = true;
3ca6a5f0 868 insertableCount++;
89894079 869 }
4fdae997 870 sqlStmt += wxT(")");
da38429d 871
89894079 872 // Prepare the insert statement for execution
da38429d 873 if (insertableCount)
3ca6a5f0 874 {
8a39593e 875 if (SQLPrepare(hstmtInsert, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
f6bcfd97
BP
876 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
877 }
da38429d 878 else
68379eaf 879 insertable = false;
89894079 880 }
da38429d 881
89894079 882 // Completed successfully
68379eaf 883 return true;
108106cf 884
f6bcfd97 885} // wxDbTable::Open()
108106cf 886
67e9aaa3 887
f6bcfd97
BP
888/********** wxDbTable::Query() **********/
889bool wxDbTable::Query(bool forUpdate, bool distinct)
108106cf
JS
890{
891
89894079 892 return(query(DB_SELECT_WHERE, forUpdate, distinct));
108106cf 893
f6bcfd97 894} // wxDbTable::Query()
108106cf 895
67e9aaa3 896
f6bcfd97 897/********** wxDbTable::QueryBySqlStmt() **********/
4fdae997 898bool wxDbTable::QueryBySqlStmt(const wxString &pSqlStmt)
108106cf 899{
89894079 900 pDb->WriteSqlLog(pSqlStmt);
108106cf 901
68379eaf 902 return(query(DB_SELECT_STATEMENT, false, false, pSqlStmt));
108106cf 903
f6bcfd97 904} // wxDbTable::QueryBySqlStmt()
108106cf 905
67e9aaa3 906
f6bcfd97
BP
907/********** wxDbTable::QueryMatching() **********/
908bool wxDbTable::QueryMatching(bool forUpdate, bool distinct)
108106cf
JS
909{
910
89894079 911 return(query(DB_SELECT_MATCHING, forUpdate, distinct));
108106cf 912
f6bcfd97 913} // wxDbTable::QueryMatching()
108106cf 914
67e9aaa3 915
f6bcfd97
BP
916/********** wxDbTable::QueryOnKeyFields() **********/
917bool wxDbTable::QueryOnKeyFields(bool forUpdate, bool distinct)
108106cf
JS
918{
919
89894079 920 return(query(DB_SELECT_KEYFIELDS, forUpdate, distinct));
108106cf 921
f6bcfd97 922} // wxDbTable::QueryOnKeyFields()
108106cf 923
67e9aaa3 924
f6bcfd97
BP
925/********** wxDbTable::GetPrev() **********/
926bool wxDbTable::GetPrev(void)
a3439c7d 927{
89894079
VZ
928 if (pDb->FwdOnlyCursors())
929 {
f6bcfd97 930 wxFAIL_MSG(wxT("GetPrev()::Backward scrolling cursors are not enabled for this instance of wxDbTable"));
68379eaf 931 return false;
89894079
VZ
932 }
933 else
934 return(getRec(SQL_FETCH_PRIOR));
3ca6a5f0 935
f6bcfd97 936} // wxDbTable::GetPrev()
a3439c7d 937
67e9aaa3 938
f6bcfd97
BP
939/********** wxDbTable::operator-- **********/
940bool wxDbTable::operator--(int)
a3439c7d 941{
89894079
VZ
942 if (pDb->FwdOnlyCursors())
943 {
f6bcfd97 944 wxFAIL_MSG(wxT("operator--:Backward scrolling cursors are not enabled for this instance of wxDbTable"));
68379eaf 945 return false;
89894079
VZ
946 }
947 else
948 return(getRec(SQL_FETCH_PRIOR));
3ca6a5f0 949
f6bcfd97 950} // wxDbTable::operator--
a3439c7d 951
67e9aaa3 952
f6bcfd97
BP
953/********** wxDbTable::GetFirst() **********/
954bool wxDbTable::GetFirst(void)
a3439c7d 955{
89894079
VZ
956 if (pDb->FwdOnlyCursors())
957 {
f6bcfd97 958 wxFAIL_MSG(wxT("GetFirst():Backward scrolling cursors are not enabled for this instance of wxDbTable"));
68379eaf 959 return false;
89894079
VZ
960 }
961 else
962 return(getRec(SQL_FETCH_FIRST));
3ca6a5f0 963
f6bcfd97 964} // wxDbTable::GetFirst()
a3439c7d 965
67e9aaa3 966
f6bcfd97
BP
967/********** wxDbTable::GetLast() **********/
968bool wxDbTable::GetLast(void)
a3439c7d 969{
89894079
VZ
970 if (pDb->FwdOnlyCursors())
971 {
f6bcfd97 972 wxFAIL_MSG(wxT("GetLast()::Backward scrolling cursors are not enabled for this instance of wxDbTable"));
68379eaf 973 return false;
89894079 974 }
da38429d 975 else
89894079 976 return(getRec(SQL_FETCH_LAST));
3ca6a5f0 977
f6bcfd97 978} // wxDbTable::GetLast()
a3439c7d 979
67e9aaa3 980
4fdae997
GT
981/********** wxDbTable::BuildDeleteStmt() **********/
982void wxDbTable::BuildDeleteStmt(wxString &pSqlStmt, int typeOfDel, const wxString &pWhereClause)
108106cf 983{
4fdae997
GT
984 wxASSERT(!queryOnly);
985 if (queryOnly)
986 return;
987
988 wxString whereClause;
89894079 989
4fdae997
GT
990 whereClause.Empty();
991
992 // Handle the case of DeleteWhere() and the where clause is blank. It should
993 // delete all records from the database in this case.
994 if (typeOfDel == DB_DEL_WHERE && (pWhereClause.Length() == 0))
995 {
1d6f2348
VZ
996 pSqlStmt.Printf(wxT("DELETE FROM %s"),
997 pDb->SQLTableName(tableName.c_str()).c_str());
4fdae997
GT
998 return;
999 }
1000
1d6f2348
VZ
1001 pSqlStmt.Printf(wxT("DELETE FROM %s WHERE "),
1002 pDb->SQLTableName(tableName.c_str()).c_str());
4fdae997
GT
1003
1004 // Append the WHERE clause to the SQL DELETE statement
1005 switch(typeOfDel)
1006 {
1007 case DB_DEL_KEYFIELDS:
1008 // If the datasource supports the ROWID column, build
1009 // the where on ROWID for efficiency purposes.
1010 // e.g. DELETE FROM PARTS WHERE ROWID = '111.222.333'
b8032740 1011 if (CanUpdateByROWID())
4fdae997
GT
1012 {
1013 SDWORD cb;
1014 wxChar rowid[wxDB_ROWID_LEN+1];
1015
1016 // Get the ROWID value. If not successful retreiving the ROWID,
1017 // simply fall down through the code and build the WHERE clause
1018 // based on the key fields.
b8032740 1019 if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS)
4fdae997
GT
1020 {
1021 pSqlStmt += wxT("ROWID = '");
1022 pSqlStmt += rowid;
1023 pSqlStmt += wxT("'");
1024 break;
1025 }
1026 }
1027 // Unable to delete by ROWID, so build a WHERE
1028 // clause based on the keyfields.
1029 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
1030 pSqlStmt += whereClause;
1031 break;
1032 case DB_DEL_WHERE:
1033 pSqlStmt += pWhereClause;
1034 break;
1035 case DB_DEL_MATCHING:
1036 BuildWhereClause(whereClause, DB_WHERE_MATCHING);
1037 pSqlStmt += whereClause;
1038 break;
1039 }
1040
1041} // BuildDeleteStmt()
1042
1043
1044/***** DEPRECATED: use wxDbTable::BuildDeleteStmt(wxString &....) form *****/
1045void wxDbTable::BuildDeleteStmt(wxChar *pSqlStmt, int typeOfDel, const wxString &pWhereClause)
1046{
1047 wxString tempSqlStmt;
1048 BuildDeleteStmt(tempSqlStmt, typeOfDel, pWhereClause);
1049 wxStrcpy(pSqlStmt, tempSqlStmt);
1050} // wxDbTable::BuildDeleteStmt()
1051
1052
1053/********** wxDbTable::BuildSelectStmt() **********/
1054void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool distinct)
1055{
1056 wxString whereClause;
1057 whereClause.Empty();
89894079
VZ
1058
1059 // Build a select statement to query the database
4fdae997 1060 pSqlStmt = wxT("SELECT ");
89894079
VZ
1061
1062 // SELECT DISTINCT values only?
1063 if (distinct)
4fdae997 1064 pSqlStmt += wxT("DISTINCT ");
89894079
VZ
1065
1066 // Was a FROM clause specified to join tables to the base table?
1067 // Available for ::Query() only!!!
68379eaf 1068 bool appendFromClause = false;
f6bcfd97 1069#if wxODBC_BACKWARD_COMPATABILITY
89894079 1070 if (typeOfSelect == DB_SELECT_WHERE && from && wxStrlen(from))
68379eaf 1071 appendFromClause = true;
f6bcfd97
BP
1072#else
1073 if (typeOfSelect == DB_SELECT_WHERE && from.Length())
68379eaf 1074 appendFromClause = true;
f6bcfd97 1075#endif
89894079
VZ
1076
1077 // Add the column list
1078 int i;
52410d54 1079 wxString tStr;
b8032740 1080 for (i = 0; i < m_numCols; i++)
89894079 1081 {
52410d54 1082 tStr = colDefs[i].ColName;
89894079 1083 // If joining tables, the base table column names must be qualified to avoid ambiguity
d23a4aa7 1084 if ((appendFromClause || pDb->Dbms() == dbmsACCESS) && tStr.Find(wxT('.')) == wxNOT_FOUND)
89894079 1085 {
243d4b36 1086 pSqlStmt += pDb->SQLTableName(queryTableName.c_str());
4fdae997 1087 pSqlStmt += wxT(".");
89894079 1088 }
243d4b36 1089 pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName);
b8032740 1090 if (i + 1 < m_numCols)
4fdae997 1091 pSqlStmt += wxT(",");
89894079
VZ
1092 }
1093
1094 // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve
1095 // the ROWID if querying distinct records. The rowid will always be unique.
b8032740 1096 if (!distinct && CanUpdateByROWID())
89894079
VZ
1097 {
1098 // If joining tables, the base table column names must be qualified to avoid ambiguity
2beca662 1099 if (appendFromClause || pDb->Dbms() == dbmsACCESS)
89894079 1100 {
4fdae997 1101 pSqlStmt += wxT(",");
243d4b36 1102 pSqlStmt += pDb->SQLTableName(queryTableName);
4fdae997 1103 pSqlStmt += wxT(".ROWID");
89894079
VZ
1104 }
1105 else
4fdae997 1106 pSqlStmt += wxT(",ROWID");
89894079
VZ
1107 }
1108
1109 // Append the FROM tablename portion
4fdae997 1110 pSqlStmt += wxT(" FROM ");
243d4b36
GT
1111 pSqlStmt += pDb->SQLTableName(queryTableName);
1112// pSqlStmt += queryTableName;
89894079
VZ
1113
1114 // Sybase uses the HOLDLOCK keyword to lock a record during query.
1115 // The HOLDLOCK keyword follows the table name in the from clause.
1116 // Each table in the from clause must specify HOLDLOCK or
1117 // NOHOLDLOCK (the default). Note: The "FOR UPDATE" clause
1118 // is parsed but ignored in SYBASE Transact-SQL.
1119 if (selectForUpdate && (pDb->Dbms() == dbmsSYBASE_ASA || pDb->Dbms() == dbmsSYBASE_ASE))
4fdae997 1120 pSqlStmt += wxT(" HOLDLOCK");
89894079
VZ
1121
1122 if (appendFromClause)
4fdae997 1123 pSqlStmt += from;
89894079
VZ
1124
1125 // Append the WHERE clause. Either append the where clause for the class
1126 // or build a where clause. The typeOfSelect determines this.
1127 switch(typeOfSelect)
1128 {
3ca6a5f0 1129 case DB_SELECT_WHERE:
f6bcfd97 1130#if wxODBC_BACKWARD_COMPATABILITY
3ca6a5f0 1131 if (where && wxStrlen(where)) // May not want a where clause!!!
f6bcfd97 1132#else
3ca6a5f0 1133 if (where.Length()) // May not want a where clause!!!
f6bcfd97 1134#endif
3ca6a5f0 1135 {
4fdae997
GT
1136 pSqlStmt += wxT(" WHERE ");
1137 pSqlStmt += where;
3ca6a5f0
BP
1138 }
1139 break;
1140 case DB_SELECT_KEYFIELDS:
1141 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
4fdae997 1142 if (whereClause.Length())
3ca6a5f0 1143 {
4fdae997
GT
1144 pSqlStmt += wxT(" WHERE ");
1145 pSqlStmt += whereClause;
3ca6a5f0
BP
1146 }
1147 break;
1148 case DB_SELECT_MATCHING:
1149 BuildWhereClause(whereClause, DB_WHERE_MATCHING);
4fdae997 1150 if (whereClause.Length())
3ca6a5f0 1151 {
4fdae997
GT
1152 pSqlStmt += wxT(" WHERE ");
1153 pSqlStmt += whereClause;
3ca6a5f0
BP
1154 }
1155 break;
89894079
VZ
1156 }
1157
1158 // Append the ORDER BY clause
f6bcfd97 1159#if wxODBC_BACKWARD_COMPATABILITY
89894079 1160 if (orderBy && wxStrlen(orderBy))
f6bcfd97 1161#else
3ca6a5f0 1162 if (orderBy.Length())
f6bcfd97 1163#endif
89894079 1164 {
4fdae997
GT
1165 pSqlStmt += wxT(" ORDER BY ");
1166 pSqlStmt += orderBy;
89894079
VZ
1167 }
1168
1169 // SELECT FOR UPDATE if told to do so and the datasource is capable. Sybase
1170 // parses the FOR UPDATE clause but ignores it. See the comment above on the
1171 // HOLDLOCK for Sybase.
1172 if (selectForUpdate && CanSelectForUpdate())
4fdae997
GT
1173 pSqlStmt += wxT(" FOR UPDATE");
1174
1175} // wxDbTable::BuildSelectStmt()
1176
108106cf 1177
4fdae997
GT
1178/***** DEPRECATED: use wxDbTable::BuildSelectStmt(wxString &....) form *****/
1179void wxDbTable::BuildSelectStmt(wxChar *pSqlStmt, int typeOfSelect, bool distinct)
1180{
1181 wxString tempSqlStmt;
1182 BuildSelectStmt(tempSqlStmt, typeOfSelect, distinct);
1183 wxStrcpy(pSqlStmt, tempSqlStmt);
f6bcfd97 1184} // wxDbTable::BuildSelectStmt()
108106cf 1185
67e9aaa3 1186
4fdae997 1187/********** wxDbTable::BuildUpdateStmt() **********/
549c8cc2 1188void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpdate, const wxString &pWhereClause)
4fdae997
GT
1189{
1190 wxASSERT(!queryOnly);
1191 if (queryOnly)
1192 return;
1193
1194 wxString whereClause;
1195 whereClause.Empty();
1196
68379eaf 1197 bool firstColumn = true;
4fdae997 1198
1d6f2348 1199 pSqlStmt.Printf(wxT("UPDATE %s SET "),
bb064193 1200 pDb->SQLTableName(tableName.c_str()).c_str());
4fdae997
GT
1201
1202 // Append a list of columns to be updated
1203 int i;
b8032740 1204 for (i = 0; i < m_numCols; i++)
4fdae997
GT
1205 {
1206 // Only append Updateable columns
1207 if (colDefs[i].Updateable)
1208 {
9082f1a9 1209 if (!firstColumn)
4fdae997
GT
1210 pSqlStmt += wxT(",");
1211 else
68379eaf 1212 firstColumn = false;
243d4b36
GT
1213
1214 pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName);
1215// pSqlStmt += colDefs[i].ColName;
4fdae997
GT
1216 pSqlStmt += wxT(" = ?");
1217 }
1218 }
1219
1220 // Append the WHERE clause to the SQL UPDATE statement
1221 pSqlStmt += wxT(" WHERE ");
549c8cc2 1222 switch(typeOfUpdate)
4fdae997
GT
1223 {
1224 case DB_UPD_KEYFIELDS:
1225 // If the datasource supports the ROWID column, build
1226 // the where on ROWID for efficiency purposes.
1227 // e.g. UPDATE PARTS SET Col1 = ?, Col2 = ? WHERE ROWID = '111.222.333'
b8032740 1228 if (CanUpdateByROWID())
4fdae997
GT
1229 {
1230 SDWORD cb;
1231 wxChar rowid[wxDB_ROWID_LEN+1];
1232
1233 // Get the ROWID value. If not successful retreiving the ROWID,
1234 // simply fall down through the code and build the WHERE clause
1235 // based on the key fields.
b8032740 1236 if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS)
4fdae997
GT
1237 {
1238 pSqlStmt += wxT("ROWID = '");
1239 pSqlStmt += rowid;
1240 pSqlStmt += wxT("'");
1241 break;
1242 }
1243 }
1244 // Unable to delete by ROWID, so build a WHERE
1245 // clause based on the keyfields.
1246 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
1247 pSqlStmt += whereClause;
1248 break;
1249 case DB_UPD_WHERE:
1250 pSqlStmt += pWhereClause;
1251 break;
1252 }
1253} // BuildUpdateStmt()
1254
1255
1256/***** DEPRECATED: use wxDbTable::BuildUpdateStmt(wxString &....) form *****/
549c8cc2 1257void wxDbTable::BuildUpdateStmt(wxChar *pSqlStmt, int typeOfUpdate, const wxString &pWhereClause)
4fdae997
GT
1258{
1259 wxString tempSqlStmt;
549c8cc2 1260 BuildUpdateStmt(tempSqlStmt, typeOfUpdate, pWhereClause);
4fdae997
GT
1261 wxStrcpy(pSqlStmt, tempSqlStmt);
1262} // BuildUpdateStmt()
1263
1264
1265/********** wxDbTable::BuildWhereClause() **********/
1266void wxDbTable::BuildWhereClause(wxString &pWhereClause, int typeOfWhere,
1267 const wxString &qualTableName, bool useLikeComparison)
1268/*
1269 * Note: BuildWhereClause() currently ignores timestamp columns.
1270 * They are not included as part of the where clause.
1271 */
1272{
68379eaf 1273 bool moreThanOneColumn = false;
4fdae997
GT
1274 wxString colValue;
1275
1276 // Loop through the columns building a where clause as you go
b8032740
GT
1277 int colNumber;
1278 for (colNumber = 0; colNumber < m_numCols; colNumber++)
4fdae997
GT
1279 {
1280 // Determine if this column should be included in the WHERE clause
b8032740
GT
1281 if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[colNumber].KeyField) ||
1282 (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull((UWORD)colNumber))))
4fdae997
GT
1283 {
1284 // Skip over timestamp columns
b8032740 1285 if (colDefs[colNumber].SqlCtype == SQL_C_TIMESTAMP)
4fdae997
GT
1286 continue;
1287 // If there is more than 1 column, join them with the keyword "AND"
1288 if (moreThanOneColumn)
1289 pWhereClause += wxT(" AND ");
1290 else
68379eaf 1291 moreThanOneColumn = true;
e7c9692f 1292
4fdae997 1293 // Concatenate where phrase for the column
b8032740 1294 wxString tStr = colDefs[colNumber].ColName;
e7c9692f 1295
d23a4aa7 1296 if (qualTableName.Length() && tStr.Find(wxT('.')) == wxNOT_FOUND)
4fdae997 1297 {
243d4b36 1298 pWhereClause += pDb->SQLTableName(qualTableName);
4fdae997
GT
1299 pWhereClause += wxT(".");
1300 }
b8032740 1301 pWhereClause += pDb->SQLColumnName(colDefs[colNumber].ColName);
e7c9692f 1302
b8032740 1303 if (useLikeComparison && (colDefs[colNumber].SqlCtype == SQL_C_WXCHAR))
4fdae997
GT
1304 pWhereClause += wxT(" LIKE ");
1305 else
1306 pWhereClause += wxT(" = ");
e7c9692f 1307
b8032740 1308 switch(colDefs[colNumber].SqlCtype)
4fdae997
GT
1309 {
1310 case SQL_C_CHAR:
5c2cd0f6 1311#ifndef __UNIX__
e4e45573 1312 case SQL_C_WCHAR:
d8d26772 1313#endif
e4e45573 1314 //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR
b8032740 1315 colValue.Printf(wxT("'%s'"), (UCHAR FAR *) colDefs[colNumber].PtrDataObj);
4fdae997 1316 break;
e9ed92a2 1317 case SQL_C_SHORT:
4fdae997 1318 case SQL_C_SSHORT:
b8032740 1319 colValue.Printf(wxT("%hi"), *((SWORD *) colDefs[colNumber].PtrDataObj));
4fdae997
GT
1320 break;
1321 case SQL_C_USHORT:
b8032740 1322 colValue.Printf(wxT("%hu"), *((UWORD *) colDefs[colNumber].PtrDataObj));
4fdae997 1323 break;
e9ed92a2 1324 case SQL_C_LONG:
4fdae997 1325 case SQL_C_SLONG:
b8032740 1326 colValue.Printf(wxT("%li"), *((SDWORD *) colDefs[colNumber].PtrDataObj));
4fdae997
GT
1327 break;
1328 case SQL_C_ULONG:
b8032740 1329 colValue.Printf(wxT("%lu"), *((UDWORD *) colDefs[colNumber].PtrDataObj));
4fdae997
GT
1330 break;
1331 case SQL_C_FLOAT:
b8032740 1332 colValue.Printf(wxT("%.6f"), *((SFLOAT *) colDefs[colNumber].PtrDataObj));
4fdae997
GT
1333 break;
1334 case SQL_C_DOUBLE:
b8032740 1335 colValue.Printf(wxT("%.6f"), *((SDOUBLE *) colDefs[colNumber].PtrDataObj));
4fdae997 1336 break;
e9ed92a2
GT
1337 default:
1338 {
1339 wxString strMsg;
1340 strMsg.Printf(wxT("wxDbTable::bindParams(): Unknown column type for colDefs %d colName %s"),
b8032740 1341 colNumber,colDefs[colNumber].ColName);
2cb43514 1342 wxFAIL_MSG(strMsg.c_str());
e9ed92a2
GT
1343 }
1344 break;
4fdae997
GT
1345 }
1346 pWhereClause += colValue;
1347 }
1348 }
1349} // wxDbTable::BuildWhereClause()
1350
1351
1352/***** DEPRECATED: use wxDbTable::BuildWhereClause(wxString &....) form *****/
1353void wxDbTable::BuildWhereClause(wxChar *pWhereClause, int typeOfWhere,
1354 const wxString &qualTableName, bool useLikeComparison)
1355{
1356 wxString tempSqlStmt;
1357 BuildWhereClause(tempSqlStmt, typeOfWhere, qualTableName, useLikeComparison);
1358 wxStrcpy(pWhereClause, tempSqlStmt);
1359} // wxDbTable::BuildWhereClause()
1360
1361
f6bcfd97
BP
1362/********** wxDbTable::GetRowNum() **********/
1363UWORD wxDbTable::GetRowNum(void)
108106cf 1364{
89894079 1365 UDWORD rowNum;
108106cf 1366
89894079
VZ
1367 if (SQLGetStmtOption(hstmt, SQL_ROW_NUMBER, (UCHAR*) &rowNum) != SQL_SUCCESS)
1368 {
1369 pDb->DispAllErrors(henv, hdbc, hstmt);
1370 return(0);
1371 }
108106cf 1372
89894079
VZ
1373 // Completed successfully
1374 return((UWORD) rowNum);
108106cf 1375
f6bcfd97 1376} // wxDbTable::GetRowNum()
108106cf 1377
67e9aaa3 1378
f6bcfd97
BP
1379/********** wxDbTable::CloseCursor() **********/
1380bool wxDbTable::CloseCursor(HSTMT cursor)
108106cf 1381{
89894079
VZ
1382 if (SQLFreeStmt(cursor, SQL_CLOSE) != SQL_SUCCESS)
1383 return(pDb->DispAllErrors(henv, hdbc, cursor));
108106cf 1384
89894079 1385 // Completed successfully
68379eaf 1386 return true;
108106cf 1387
f6bcfd97 1388} // wxDbTable::CloseCursor()
108106cf 1389
67e9aaa3 1390
f6bcfd97
BP
1391/********** wxDbTable::CreateTable() **********/
1392bool wxDbTable::CreateTable(bool attemptDrop)
108106cf 1393{
89894079 1394 if (!pDb)
68379eaf 1395 return false;
1fc5dd6f 1396
89894079 1397 int i, j;
1e92909e 1398 wxString sqlStmt;
108106cf 1399
a2115c88 1400#ifdef DBDEBUG_CONSOLE
4fdae997 1401 cout << wxT("Creating Table ") << tableName << wxT("...") << endl;
108106cf
JS
1402#endif
1403
89894079
VZ
1404 // Drop table first
1405 if (attemptDrop && !DropTable())
68379eaf 1406 return false;
108106cf 1407
89894079 1408 // Create the table
a2115c88 1409#ifdef DBDEBUG_CONSOLE
b8032740 1410 for (i = 0; i < m_numCols; i++)
89894079
VZ
1411 {
1412 // Exclude derived columns since they are NOT part of the base table
1413 if (colDefs[i].DerivedCol)
1414 continue;
4fdae997 1415 cout << i + 1 << wxT(": ") << colDefs[i].ColName << wxT("; ");
89894079
VZ
1416 switch(colDefs[i].DbDataType)
1417 {
1418 case DB_DATA_TYPE_VARCHAR:
e4e45573 1419 cout << pDb->GetTypeInfVarchar().TypeName << wxT("(") << (int)(colDefs[i].SzDataObj / sizeof(wxChar)) << wxT(")");
89894079
VZ
1420 break;
1421 case DB_DATA_TYPE_INTEGER:
882fc8a9 1422 cout << pDb->GetTypeInfInteger().TypeName;
89894079
VZ
1423 break;
1424 case DB_DATA_TYPE_FLOAT:
882fc8a9 1425 cout << pDb->GetTypeInfFloat().TypeName;
89894079
VZ
1426 break;
1427 case DB_DATA_TYPE_DATE:
882fc8a9 1428 cout << pDb->GetTypeInfDate().TypeName;
89894079 1429 break;
bf5423ea 1430 case DB_DATA_TYPE_BLOB:
882fc8a9 1431 cout << pDb->GetTypeInfBlob().TypeName;
bf5423ea 1432 break;
89894079
VZ
1433 }
1434 cout << endl;
1435 }
108106cf
JS
1436#endif
1437
89894079 1438 // Build a CREATE TABLE string from the colDefs structure.
68379eaf 1439 bool needComma = false;
243d4b36 1440
1d6f2348
VZ
1441 sqlStmt.Printf(wxT("CREATE TABLE %s ("),
1442 pDb->SQLTableName(tableName.c_str()).c_str());
1e92909e 1443
b8032740 1444 for (i = 0; i < m_numCols; i++)
89894079
VZ
1445 {
1446 // Exclude derived columns since they are NOT part of the base table
1447 if (colDefs[i].DerivedCol)
1448 continue;
1449 // Comma Delimiter
1450 if (needComma)
4fdae997 1451 sqlStmt += wxT(",");
89894079 1452 // Column Name
243d4b36
GT
1453 sqlStmt += pDb->SQLColumnName(colDefs[i].ColName);
1454// sqlStmt += colDefs[i].ColName;
4fdae997 1455 sqlStmt += wxT(" ");
89894079
VZ
1456 // Column Type
1457 switch(colDefs[i].DbDataType)
1458 {
1459 case DB_DATA_TYPE_VARCHAR:
3ca6a5f0
BP
1460 sqlStmt += pDb->GetTypeInfVarchar().TypeName;
1461 break;
89894079 1462 case DB_DATA_TYPE_INTEGER:
3ca6a5f0
BP
1463 sqlStmt += pDb->GetTypeInfInteger().TypeName;
1464 break;
89894079 1465 case DB_DATA_TYPE_FLOAT:
3ca6a5f0
BP
1466 sqlStmt += pDb->GetTypeInfFloat().TypeName;
1467 break;
89894079 1468 case DB_DATA_TYPE_DATE:
3ca6a5f0
BP
1469 sqlStmt += pDb->GetTypeInfDate().TypeName;
1470 break;
bf5423ea
GT
1471 case DB_DATA_TYPE_BLOB:
1472 sqlStmt += pDb->GetTypeInfBlob().TypeName;
1473 break;
89894079
VZ
1474 }
1475 // For varchars, append the size of the string
e25cdb86 1476 if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR &&
8a39593e 1477 (pDb->Dbms() != dbmsMY_SQL || pDb->GetTypeInfVarchar().TypeName != _T("text")))// ||
bf5423ea 1478// colDefs[i].DbDataType == DB_DATA_TYPE_BLOB)
89894079 1479 {
1e92909e 1480 wxString s;
e4e45573 1481 s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar)));
4fdae997 1482 sqlStmt += s;
89894079
VZ
1483 }
1484
e93a3a18
GT
1485 if (pDb->Dbms() == dbmsDB2 ||
1486 pDb->Dbms() == dbmsMY_SQL ||
1487 pDb->Dbms() == dbmsSYBASE_ASE ||
9082f1a9 1488 pDb->Dbms() == dbmsINTERBASE ||
215a0070 1489 pDb->Dbms() == dbmsFIREBIRD ||
e93a3a18 1490 pDb->Dbms() == dbmsMS_SQL_SERVER)
89894079
VZ
1491 {
1492 if (colDefs[i].KeyField)
1493 {
4fdae997 1494 sqlStmt += wxT(" NOT NULL");
89894079
VZ
1495 }
1496 }
da38429d 1497
68379eaf 1498 needComma = true;
89894079
VZ
1499 }
1500 // If there is a primary key defined, include it in the create statement
b8032740 1501 for (i = j = 0; i < m_numCols; i++)
89894079
VZ
1502 {
1503 if (colDefs[i].KeyField)
1504 {
1505 j++;
1506 break;
1507 }
1508 }
52410d54
DS
1509 if ( j && (pDb->Dbms() != dbmsDBASE)
1510 && (pDb->Dbms() != dbmsXBASE_SEQUITER) ) // Found a keyfield
89894079 1511 {
87cc3456 1512 switch (pDb->Dbms())
89894079 1513 {
1dee6b39 1514 case dbmsACCESS:
597fadce 1515 case dbmsINFORMIX:
87cc3456
GT
1516 case dbmsSYBASE_ASA:
1517 case dbmsSYBASE_ASE:
1518 case dbmsMY_SQL:
215a0070 1519 case dbmsFIREBIRD:
87cc3456 1520 {
2beca662 1521 // MySQL goes out on this one. We also declare the relevant key NON NULL above
87cc3456
GT
1522 sqlStmt += wxT(",PRIMARY KEY (");
1523 break;
1524 }
1525 default:
1526 {
1527 sqlStmt += wxT(",CONSTRAINT ");
2beca662
GT
1528 // DB2 is limited to 18 characters for index names
1529 if (pDb->Dbms() == dbmsDB2)
1530 {
1531 wxASSERT_MSG((tableName && wxStrlen(tableName) <= 13), wxT("DB2 table/index names must be no longer than 13 characters in length.\n\nTruncating table name to 13 characters."));
243d4b36
GT
1532 sqlStmt += pDb->SQLTableName(tableName.substr(0, 13).c_str());
1533// sqlStmt += tableName.substr(0, 13);
2beca662
GT
1534 }
1535 else
243d4b36
GT
1536 sqlStmt += pDb->SQLTableName(tableName.c_str());
1537// sqlStmt += tableName;
2beca662 1538
87cc3456
GT
1539 sqlStmt += wxT("_PIDX PRIMARY KEY (");
1540 break;
1541 }
89894079
VZ
1542 }
1543
1544 // List column name(s) of column(s) comprising the primary key
b8032740 1545 for (i = j = 0; i < m_numCols; i++)
89894079
VZ
1546 {
1547 if (colDefs[i].KeyField)
1548 {
1549 if (j++) // Multi part key, comma separate names
4fdae997 1550 sqlStmt += wxT(",");
243d4b36 1551 sqlStmt += pDb->SQLColumnName(colDefs[i].ColName);
e25cdb86
GT
1552
1553 if (pDb->Dbms() == dbmsMY_SQL &&
1554 colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR)
1555 {
1556 wxString s;
e4e45573 1557 s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar)));
e25cdb86
GT
1558 sqlStmt += s;
1559 }
89894079
VZ
1560 }
1561 }
2beca662
GT
1562 sqlStmt += wxT(")");
1563
597fadce
GT
1564 if (pDb->Dbms() == dbmsINFORMIX ||
1565 pDb->Dbms() == dbmsSYBASE_ASA ||
2beca662
GT
1566 pDb->Dbms() == dbmsSYBASE_ASE)
1567 {
1568 sqlStmt += wxT(" CONSTRAINT ");
243d4b36
GT
1569 sqlStmt += pDb->SQLTableName(tableName);
1570// sqlStmt += tableName;
2beca662
GT
1571 sqlStmt += wxT("_PIDX");
1572 }
89894079
VZ
1573 }
1574 // Append the closing parentheses for the create table statement
4fdae997 1575 sqlStmt += wxT(")");
a2115c88 1576
4fdae997 1577 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1578
a2115c88 1579#ifdef DBDEBUG_CONSOLE
f6bcfd97 1580 cout << endl << sqlStmt.c_str() << endl;
108106cf
JS
1581#endif
1582
89894079 1583 // Execute the CREATE TABLE statement
8a39593e 1584 RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
89894079
VZ
1585 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
1586 {
1587 pDb->DispAllErrors(henv, hdbc, hstmt);
1588 pDb->RollbackTrans();
1589 CloseCursor(hstmt);
68379eaf 1590 return false;
89894079
VZ
1591 }
1592
1593 // Commit the transaction and close the cursor
3ca6a5f0 1594 if (!pDb->CommitTrans())
68379eaf 1595 return false;
3ca6a5f0 1596 if (!CloseCursor(hstmt))
68379eaf 1597 return false;
89894079
VZ
1598
1599 // Database table created successfully
68379eaf 1600 return true;
108106cf 1601
f6bcfd97 1602} // wxDbTable::CreateTable()
108106cf 1603
67e9aaa3 1604
f6bcfd97
BP
1605/********** wxDbTable::DropTable() **********/
1606bool wxDbTable::DropTable()
a2115c88 1607{
68379eaf 1608 // NOTE: This function returns true if the Table does not exist, but
89894079 1609 // only for identified databases. Code will need to be added
0b8410f3 1610 // below for any other databases when those databases are defined
89894079 1611 // to handle this situation consistently
a2115c88 1612
1e92909e 1613 wxString sqlStmt;
a2115c88 1614
1d6f2348
VZ
1615 sqlStmt.Printf(wxT("DROP TABLE %s"),
1616 pDb->SQLTableName(tableName.c_str()).c_str());
a2115c88 1617
4fdae997 1618 pDb->WriteSqlLog(sqlStmt);
a2115c88
GT
1619
1620#ifdef DBDEBUG_CONSOLE
f6bcfd97 1621 cout << endl << sqlStmt.c_str() << endl;
a2115c88
GT
1622#endif
1623
8a39593e 1624 RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
2beca662 1625 if (retcode != SQL_SUCCESS)
89894079
VZ
1626 {
1627 // Check for "Base table not found" error and ignore
da38429d 1628 pDb->GetNextError(henv, hdbc, hstmt);
2beca662 1629 if (wxStrcmp(pDb->sqlState, wxT("S0002")) /*&&
da38429d 1630 wxStrcmp(pDb->sqlState, wxT("S1000"))*/) // "Base table not found"
2beca662 1631 {
89894079 1632 // Check for product specific error codes
2beca662 1633 if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // 5.x (and lower?)
da38429d 1634 (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) ||
2beca662 1635 (pDb->Dbms() == dbmsPERVASIVE_SQL && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || // Returns an S1000 then an S0002
da38429d 1636 (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01")))))
89894079
VZ
1637 {
1638 pDb->DispNextError();
1639 pDb->DispAllErrors(henv, hdbc, hstmt);
1640 pDb->RollbackTrans();
5a226de0 1641// CloseCursor(hstmt);
68379eaf 1642 return false;
89894079
VZ
1643 }
1644 }
1645 }
1646
1647 // Commit the transaction and close the cursor
1648 if (! pDb->CommitTrans())
68379eaf 1649 return false;
89894079 1650 if (! CloseCursor(hstmt))
68379eaf 1651 return false;
89894079 1652
68379eaf 1653 return true;
f6bcfd97 1654} // wxDbTable::DropTable()
a2115c88 1655
67e9aaa3 1656
f6bcfd97 1657/********** wxDbTable::CreateIndex() **********/
549c8cc2
GT
1658bool wxDbTable::CreateIndex(const wxString &indexName, bool unique, UWORD numIndexColumns,
1659 wxDbIdxDef *pIndexDefs, bool attemptDrop)
108106cf 1660{
1e92909e 1661 wxString sqlStmt;
89894079
VZ
1662
1663 // Drop the index first
549c8cc2 1664 if (attemptDrop && !DropIndex(indexName))
68379eaf 1665 return false;
89894079 1666
3ca6a5f0
BP
1667 // MySQL (and possibly Sybase ASE?? - gt) require that any columns which are used as portions
1668 // of an index have the columns defined as "NOT NULL". During initial table creation though,
1669 // it may not be known which columns are necessarily going to be part of an index (e.g. the
1670 // table was created, then months later you determine that an additional index while
1671 // give better performance, so you want to add an index).
1672 //
1673 // The following block of code will modify the column definition to make the column be
1674 // defined with the "NOT NULL" qualifier.
1675 if (pDb->Dbms() == dbmsMY_SQL)
1676 {
1677 wxString sqlStmt;
1678 int i;
68379eaf 1679 bool ok = true;
549c8cc2 1680 for (i = 0; i < numIndexColumns && ok; i++)
3ca6a5f0
BP
1681 {
1682 int j = 0;
68379eaf 1683 bool found = false;
3ca6a5f0
BP
1684 // Find the column definition that has the ColName that matches the
1685 // index column name. We need to do this to get the DB_DATA_TYPE of
1686 // the index column, as MySQL's syntax for the ALTER column requires
1687 // this information
b8032740 1688 while (!found && (j < this->m_numCols))
3ca6a5f0 1689 {
549c8cc2 1690 if (wxStrcmp(colDefs[j].ColName,pIndexDefs[i].ColName) == 0)
68379eaf 1691 found = true;
3ca6a5f0
BP
1692 if (!found)
1693 j++;
1694 }
da38429d 1695
3ca6a5f0
BP
1696 if (found)
1697 {
549c8cc2 1698 ok = pDb->ModifyColumn(tableName, pIndexDefs[i].ColName,
e4e45573 1699 colDefs[j].DbDataType, (int)(colDefs[j].SzDataObj / sizeof(wxChar)),
4fdae997
GT
1700 wxT("NOT NULL"));
1701
3ca6a5f0
BP
1702 if (!ok)
1703 {
8a39593e
JS
1704 #if 0
1705 // retcode is not used
3ca6a5f0
BP
1706 wxODBC_ERRORS retcode;
1707 // Oracle returns a DB_ERR_GENERAL_ERROR if the column is already
1708 // defined to be NOT NULL, but reportedly MySQL doesn't mind.
1709 // This line is just here for debug checking of the value
1710 retcode = (wxODBC_ERRORS)pDb->DB_STATUS;
8a39593e 1711 #endif
3ca6a5f0
BP
1712 }
1713 }
1714 else
68379eaf 1715 ok = false;
3ca6a5f0
BP
1716 }
1717 if (ok)
1718 pDb->CommitTrans();
1719 else
1720 {
1721 pDb->RollbackTrans();
68379eaf 1722 return false;
3ca6a5f0
BP
1723 }
1724 }
da38429d 1725
89894079 1726 // Build a CREATE INDEX statement
4fdae997 1727 sqlStmt = wxT("CREATE ");
89894079 1728 if (unique)
4fdae997 1729 sqlStmt += wxT("UNIQUE ");
da38429d 1730
4fdae997 1731 sqlStmt += wxT("INDEX ");
549c8cc2 1732 sqlStmt += pDb->SQLTableName(indexName);
4fdae997 1733 sqlStmt += wxT(" ON ");
243d4b36
GT
1734
1735 sqlStmt += pDb->SQLTableName(tableName);
1736// sqlStmt += tableName;
4fdae997 1737 sqlStmt += wxT(" (");
da38429d 1738
89894079
VZ
1739 // Append list of columns making up index
1740 int i;
549c8cc2 1741 for (i = 0; i < numIndexColumns; i++)
89894079 1742 {
549c8cc2
GT
1743 sqlStmt += pDb->SQLColumnName(pIndexDefs[i].ColName);
1744// sqlStmt += pIndexDefs[i].ColName;
9082f1a9 1745
9c136858
JS
1746 // MySQL requires a key length on VARCHAR keys
1747 if ( pDb->Dbms() == dbmsMY_SQL )
1748 {
1749 // Find the details on this column
1750 int j;
b8032740 1751 for ( j = 0; j < m_numCols; ++j )
9c136858 1752 {
549c8cc2 1753 if ( wxStrcmp( pIndexDefs[i].ColName, colDefs[j].ColName ) == 0 )
9c136858
JS
1754 {
1755 break;
1756 }
1757 }
1758 if ( colDefs[j].DbDataType == DB_DATA_TYPE_VARCHAR)
1759 {
1760 wxString s;
e4e45573 1761 s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar)));
9c136858
JS
1762 sqlStmt += s;
1763 }
1764 }
68379eaf 1765
9082f1a9 1766 // Postgres and SQL Server 7 do not support the ASC/DESC keywords for index columns
8a39593e 1767 if (!((pDb->Dbms() == dbmsMS_SQL_SERVER) && (wxStrncmp(pDb->dbInf.dbmsVer,_T("07"),2)==0)) &&
215a0070 1768 !(pDb->Dbms() == dbmsFIREBIRD) &&
9082f1a9 1769 !(pDb->Dbms() == dbmsPOSTGRES))
89894079 1770 {
549c8cc2 1771 if (pIndexDefs[i].Ascending)
4fdae997 1772 sqlStmt += wxT(" ASC");
89894079 1773 else
4fdae997 1774 sqlStmt += wxT(" DESC");
89894079 1775 }
9082f1a9 1776 else
549c8cc2 1777 wxASSERT_MSG(pIndexDefs[i].Ascending, _T("Datasource does not support DESCending index columns"));
89894079 1778
549c8cc2 1779 if ((i + 1) < numIndexColumns)
4fdae997 1780 sqlStmt += wxT(",");
89894079 1781 }
da38429d 1782
89894079 1783 // Append closing parentheses
4fdae997 1784 sqlStmt += wxT(")");
89894079 1785
4fdae997 1786 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1787
a2115c88 1788#ifdef DBDEBUG_CONSOLE
f6bcfd97 1789 cout << endl << sqlStmt.c_str() << endl << endl;
108106cf
JS
1790#endif
1791
89894079 1792 // Execute the CREATE INDEX statement
215a0070
GT
1793 RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
1794 if (retcode != SQL_SUCCESS)
89894079
VZ
1795 {
1796 pDb->DispAllErrors(henv, hdbc, hstmt);
1797 pDb->RollbackTrans();
1798 CloseCursor(hstmt);
68379eaf 1799 return false;
89894079 1800 }
108106cf 1801
89894079
VZ
1802 // Commit the transaction and close the cursor
1803 if (! pDb->CommitTrans())
68379eaf 1804 return false;
89894079 1805 if (! CloseCursor(hstmt))
68379eaf 1806 return false;
108106cf 1807
89894079 1808 // Index Created Successfully
68379eaf 1809 return true;
108106cf 1810
f6bcfd97 1811} // wxDbTable::CreateIndex()
108106cf 1812
67e9aaa3 1813
f6bcfd97 1814/********** wxDbTable::DropIndex() **********/
549c8cc2 1815bool wxDbTable::DropIndex(const wxString &indexName)
a2115c88 1816{
68379eaf 1817 // NOTE: This function returns true if the Index does not exist, but
89894079 1818 // only for identified databases. Code will need to be added
5a226de0 1819 // below for any other databases when those databases are defined
89894079 1820 // to handle this situation consistently
a2115c88 1821
1e92909e 1822 wxString sqlStmt;
a2115c88 1823
5a226de0
GT
1824 if (pDb->Dbms() == dbmsACCESS || pDb->Dbms() == dbmsMY_SQL ||
1825 pDb->Dbms() == dbmsDBASE /*|| Paradox needs this syntax too when we add support*/)
1d6f2348 1826 sqlStmt.Printf(wxT("DROP INDEX %s ON %s"),
549c8cc2 1827 pDb->SQLTableName(indexName.c_str()).c_str(),
6bbff0aa 1828 pDb->SQLTableName(tableName.c_str()).c_str());
e93a3a18 1829 else if ((pDb->Dbms() == dbmsMS_SQL_SERVER) ||
9f4de2dc 1830 (pDb->Dbms() == dbmsSYBASE_ASE) ||
52410d54 1831 (pDb->Dbms() == dbmsXBASE_SEQUITER))
1d6f2348
VZ
1832 sqlStmt.Printf(wxT("DROP INDEX %s.%s"),
1833 pDb->SQLTableName(tableName.c_str()).c_str(),
549c8cc2 1834 pDb->SQLTableName(indexName.c_str()).c_str());
89894079 1835 else
1d6f2348 1836 sqlStmt.Printf(wxT("DROP INDEX %s"),
549c8cc2 1837 pDb->SQLTableName(indexName.c_str()).c_str());
a2115c88 1838
4fdae997 1839 pDb->WriteSqlLog(sqlStmt);
a2115c88
GT
1840
1841#ifdef DBDEBUG_CONSOLE
f6bcfd97 1842 cout << endl << sqlStmt.c_str() << endl;
a2115c88 1843#endif
215a0070
GT
1844 RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
1845 if (retcode != SQL_SUCCESS)
89894079
VZ
1846 {
1847 // Check for "Index not found" error and ignore
1848 pDb->GetNextError(henv, hdbc, hstmt);
4fdae997 1849 if (wxStrcmp(pDb->sqlState,wxT("S0012"))) // "Index not found"
89894079
VZ
1850 {
1851 // Check for product specific error codes
4fdae997
GT
1852 if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // v5.x (and lower?)
1853 (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) ||
1854 (pDb->Dbms() == dbmsMS_SQL_SERVER && !wxStrcmp(pDb->sqlState,wxT("S1000"))) ||
215a0070
GT
1855 (pDb->Dbms() == dbmsINTERBASE && !wxStrcmp(pDb->sqlState,wxT("S1000"))) ||
1856 (pDb->Dbms() == dbmsFIREBIRD && !wxStrcmp(pDb->sqlState,wxT("HY000"))) ||
4fdae997
GT
1857 (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("S0002"))) || // Base table not found
1858 (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,wxT("42S12"))) || // tested by Christopher Ludwik Marino-Cebulski using v3.23.21beta
1859 (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01")))
3ca6a5f0 1860 ))
89894079
VZ
1861 {
1862 pDb->DispNextError();
1863 pDb->DispAllErrors(henv, hdbc, hstmt);
1864 pDb->RollbackTrans();
1865 CloseCursor(hstmt);
68379eaf 1866 return false;
89894079
VZ
1867 }
1868 }
1869 }
1870
1871 // Commit the transaction and close the cursor
1872 if (! pDb->CommitTrans())
68379eaf 1873 return false;
89894079 1874 if (! CloseCursor(hstmt))
68379eaf 1875 return false;
89894079 1876
68379eaf 1877 return true;
f6bcfd97 1878} // wxDbTable::DropIndex()
a2115c88 1879
67e9aaa3 1880
38cfbffa 1881/********** wxDbTable::SetOrderByColNums() **********/
e938ff5e 1882bool wxDbTable::SetOrderByColNums(UWORD first, ... )
38cfbffa 1883{
b8032740 1884 int colNumber = first; // using 'int' to be able to look for wxDB_NO_MORE_COLUN_NUMBERS
38cfbffa
GT
1885 va_list argptr;
1886
68379eaf 1887 bool abort = false;
38cfbffa
GT
1888 wxString tempStr;
1889
1890 va_start(argptr, first); /* Initialize variable arguments. */
b8032740 1891 while (!abort && (colNumber != wxDB_NO_MORE_COLUMN_NUMBERS))
38cfbffa
GT
1892 {
1893 // Make sure the passed in column number
1894 // is within the valid range of columns
1895 //
b8032740
GT
1896 // Valid columns are 0 thru m_numCols-1
1897 if (colNumber >= m_numCols || colNumber < 0)
38cfbffa 1898 {
68379eaf 1899 abort = true;
38cfbffa
GT
1900 continue;
1901 }
1902
b8032740 1903 if (colNumber != first)
4fdae997 1904 tempStr += wxT(",");
38cfbffa 1905
b8032740
GT
1906 tempStr += colDefs[colNumber].ColName;
1907 colNumber = va_arg (argptr, int);
38cfbffa
GT
1908 }
1909 va_end (argptr); /* Reset variable arguments. */
1910
4fdae997 1911 SetOrderByClause(tempStr);
38cfbffa
GT
1912
1913 return (!abort);
1914} // wxDbTable::SetOrderByColNums()
1915
1916
f6bcfd97
BP
1917/********** wxDbTable::Insert() **********/
1918int wxDbTable::Insert(void)
108106cf 1919{
4fdae997 1920 wxASSERT(!queryOnly);
f6bcfd97 1921 if (queryOnly || !insertable)
89894079
VZ
1922 return(DB_FAILURE);
1923
1924 bindInsertParams();
1925
1926 // Insert the record by executing the already prepared insert statement
1927 RETCODE retcode;
215a0070 1928 retcode = SQLExecute(hstmtInsert);
5962bdb8
JS
1929 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO &&
1930 retcode != SQL_NEED_DATA)
89894079
VZ
1931 {
1932 // Check to see if integrity constraint was violated
1933 pDb->GetNextError(henv, hdbc, hstmtInsert);
4fdae997 1934 if (! wxStrcmp(pDb->sqlState, wxT("23000"))) // Integrity constraint violated
89894079
VZ
1935 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL);
1936 else
1937 {
1938 pDb->DispNextError();
1939 pDb->DispAllErrors(henv, hdbc, hstmtInsert);
1940 return(DB_FAILURE);
1941 }
1942 }
5962bdb8
JS
1943 if (retcode == SQL_NEED_DATA)
1944 {
1945 PTR pParmID;
8a39593e
JS
1946 retcode = SQLParamData(hstmtInsert, &pParmID);
1947 while (retcode == SQL_NEED_DATA)
5962bdb8
JS
1948 {
1949 // Find the parameter
1950 int i;
b8032740 1951 for (i=0; i < m_numCols; i++)
5962bdb8
JS
1952 {
1953 if (colDefs[i].PtrDataObj == pParmID)
1954 {
1955 // We found it. Store the parameter.
1956 retcode = SQLPutData(hstmtInsert, pParmID, colDefs[i].SzDataObj);
1957 if (retcode != SQL_SUCCESS)
1958 {
1959 pDb->DispNextError();
1960 pDb->DispAllErrors(henv, hdbc, hstmtInsert);
1961 return(DB_FAILURE);
1962 }
1963 break;
1964 }
1965 }
c9b6d796 1966 retcode = SQLParamData(hstmtInsert, &pParmID);
160155e6
GT
1967 if (retcode != SQL_SUCCESS &&
1968 retcode != SQL_SUCCESS_WITH_INFO)
1969 {
1970 // record was not inserted
1971 pDb->DispNextError();
1972 pDb->DispAllErrors(henv, hdbc, hstmtInsert);
1973 return(DB_FAILURE);
1974 }
5962bdb8
JS
1975 }
1976 }
89894079
VZ
1977
1978 // Record inserted into the datasource successfully
1979 return(DB_SUCCESS);
108106cf 1980
f6bcfd97 1981} // wxDbTable::Insert()
108106cf 1982
67e9aaa3 1983
f6bcfd97
BP
1984/********** wxDbTable::Update() **********/
1985bool wxDbTable::Update(void)
108106cf 1986{
4fdae997 1987 wxASSERT(!queryOnly);
89894079 1988 if (queryOnly)
68379eaf 1989 return false;
a2115c88 1990
4fdae997 1991 wxString sqlStmt;
108106cf 1992
89894079 1993 // Build the SQL UPDATE statement
f6bcfd97 1994 BuildUpdateStmt(sqlStmt, DB_UPD_KEYFIELDS);
108106cf 1995
89894079 1996 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1997
a2115c88 1998#ifdef DBDEBUG_CONSOLE
4fdae997 1999 cout << endl << sqlStmt.c_str() << endl << endl;
108106cf
JS
2000#endif
2001
89894079
VZ
2002 // Execute the SQL UPDATE statement
2003 return(execUpdate(sqlStmt));
108106cf 2004
f6bcfd97 2005} // wxDbTable::Update()
108106cf 2006
67e9aaa3 2007
f6bcfd97 2008/********** wxDbTable::Update(pSqlStmt) **********/
4fdae997 2009bool wxDbTable::Update(const wxString &pSqlStmt)
6919c53f 2010{
4fdae997 2011 wxASSERT(!queryOnly);
89894079 2012 if (queryOnly)
68379eaf 2013 return false;
6919c53f 2014
89894079 2015 pDb->WriteSqlLog(pSqlStmt);
6919c53f 2016
89894079 2017 return(execUpdate(pSqlStmt));
6919c53f 2018
f6bcfd97 2019} // wxDbTable::Update(pSqlStmt)
6919c53f 2020
67e9aaa3 2021
f6bcfd97 2022/********** wxDbTable::UpdateWhere() **********/
4fdae997 2023bool wxDbTable::UpdateWhere(const wxString &pWhereClause)
108106cf 2024{
4fdae997 2025 wxASSERT(!queryOnly);
89894079 2026 if (queryOnly)
68379eaf 2027 return false;
a2115c88 2028
4fdae997 2029 wxString sqlStmt;
108106cf 2030
89894079 2031 // Build the SQL UPDATE statement
f6bcfd97 2032 BuildUpdateStmt(sqlStmt, DB_UPD_WHERE, pWhereClause);
108106cf 2033
89894079 2034 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 2035
a2115c88 2036#ifdef DBDEBUG_CONSOLE
4fdae997 2037 cout << endl << sqlStmt.c_str() << endl << endl;
108106cf
JS
2038#endif
2039
89894079
VZ
2040 // Execute the SQL UPDATE statement
2041 return(execUpdate(sqlStmt));
108106cf 2042
f6bcfd97 2043} // wxDbTable::UpdateWhere()
108106cf 2044
67e9aaa3 2045
f6bcfd97
BP
2046/********** wxDbTable::Delete() **********/
2047bool wxDbTable::Delete(void)
108106cf 2048{
4fdae997 2049 wxASSERT(!queryOnly);
89894079 2050 if (queryOnly)
68379eaf 2051 return false;
a2115c88 2052
4fdae997
GT
2053 wxString sqlStmt;
2054 sqlStmt.Empty();
108106cf 2055
89894079 2056 // Build the SQL DELETE statement
f6bcfd97 2057 BuildDeleteStmt(sqlStmt, DB_DEL_KEYFIELDS);
108106cf 2058
89894079 2059 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 2060
89894079
VZ
2061 // Execute the SQL DELETE statement
2062 return(execDelete(sqlStmt));
108106cf 2063
f6bcfd97 2064} // wxDbTable::Delete()
108106cf 2065
67e9aaa3 2066
f6bcfd97 2067/********** wxDbTable::DeleteWhere() **********/
4fdae997 2068bool wxDbTable::DeleteWhere(const wxString &pWhereClause)
108106cf 2069{
4fdae997 2070 wxASSERT(!queryOnly);
89894079 2071 if (queryOnly)
68379eaf 2072 return false;
a2115c88 2073
4fdae997
GT
2074 wxString sqlStmt;
2075 sqlStmt.Empty();
108106cf 2076
89894079 2077 // Build the SQL DELETE statement
f6bcfd97 2078 BuildDeleteStmt(sqlStmt, DB_DEL_WHERE, pWhereClause);
108106cf 2079
89894079 2080 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 2081
89894079
VZ
2082 // Execute the SQL DELETE statement
2083 return(execDelete(sqlStmt));
108106cf 2084
f6bcfd97 2085} // wxDbTable::DeleteWhere()
108106cf 2086
67e9aaa3 2087
f6bcfd97
BP
2088/********** wxDbTable::DeleteMatching() **********/
2089bool wxDbTable::DeleteMatching(void)
108106cf 2090{
4fdae997 2091 wxASSERT(!queryOnly);
89894079 2092 if (queryOnly)
68379eaf 2093 return false;
a2115c88 2094
4fdae997
GT
2095 wxString sqlStmt;
2096 sqlStmt.Empty();
108106cf 2097
89894079 2098 // Build the SQL DELETE statement
f6bcfd97 2099 BuildDeleteStmt(sqlStmt, DB_DEL_MATCHING);
108106cf 2100
89894079 2101 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 2102
89894079
VZ
2103 // Execute the SQL DELETE statement
2104 return(execDelete(sqlStmt));
108106cf 2105
f6bcfd97 2106} // wxDbTable::DeleteMatching()
108106cf 2107
67e9aaa3 2108
f6bcfd97 2109/********** wxDbTable::IsColNull() **********/
b8032740 2110bool wxDbTable::IsColNull(UWORD colNumber) const
108106cf 2111{
f02d4a64 2112/*
68379eaf 2113 This logic is just not right. It would indicate true
f02d4a64
GT
2114 if a numeric field were set to a value of 0.
2115
b8032740 2116 switch(colDefs[colNumber].SqlCtype)
89894079 2117 {
3ca6a5f0 2118 case SQL_C_CHAR:
e4e45573
GT
2119 case SQL_C_WCHAR:
2120 //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR
b8032740 2121 return(((UCHAR FAR *) colDefs[colNumber].PtrDataObj)[0] == 0);
3ca6a5f0 2122 case SQL_C_SSHORT:
b8032740 2123 return(( *((SWORD *) colDefs[colNumber].PtrDataObj)) == 0);
3ca6a5f0 2124 case SQL_C_USHORT:
b8032740 2125 return(( *((UWORD*) colDefs[colNumber].PtrDataObj)) == 0);
3ca6a5f0 2126 case SQL_C_SLONG:
b8032740 2127 return(( *((SDWORD *) colDefs[colNumber].PtrDataObj)) == 0);
3ca6a5f0 2128 case SQL_C_ULONG:
b8032740 2129 return(( *((UDWORD *) colDefs[colNumber].PtrDataObj)) == 0);
3ca6a5f0 2130 case SQL_C_FLOAT:
b8032740 2131 return(( *((SFLOAT *) colDefs[colNumber].PtrDataObj)) == 0);
3ca6a5f0 2132 case SQL_C_DOUBLE:
b8032740 2133 return((*((SDOUBLE *) colDefs[colNumber].PtrDataObj)) == 0);
3ca6a5f0
BP
2134 case SQL_C_TIMESTAMP:
2135 TIMESTAMP_STRUCT *pDt;
b8032740 2136 pDt = (TIMESTAMP_STRUCT *) colDefs[colNumber].PtrDataObj;
3ca6a5f0 2137 if (pDt->year == 0 && pDt->month == 0 && pDt->day == 0)
68379eaf 2138 return true;
3ca6a5f0 2139 else
68379eaf 2140 return false;
3ca6a5f0 2141 default:
68379eaf 2142 return true;
89894079 2143 }
f02d4a64 2144*/
b8032740 2145 return (colDefs[colNumber].Null);
f6bcfd97 2146} // wxDbTable::IsColNull()
108106cf 2147
67e9aaa3 2148
f6bcfd97
BP
2149/********** wxDbTable::CanSelectForUpdate() **********/
2150bool wxDbTable::CanSelectForUpdate(void)
108106cf 2151{
38cfbffa 2152 if (queryOnly)
68379eaf 2153 return false;
38cfbffa 2154
89894079 2155 if (pDb->Dbms() == dbmsMY_SQL)
68379eaf 2156 return false;
a2115c88 2157
e93a3a18
GT
2158 if ((pDb->Dbms() == dbmsORACLE) ||
2159 (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE))
68379eaf 2160 return true;
89894079 2161 else
68379eaf 2162 return false;
108106cf 2163
f6bcfd97 2164} // wxDbTable::CanSelectForUpdate()
108106cf 2165
67e9aaa3 2166
b8032740
GT
2167/********** wxDbTable::CanUpdateByROWID() **********/
2168bool wxDbTable::CanUpdateByROWID(void)
108106cf 2169{
67e9aaa3 2170/*
68379eaf 2171 * NOTE: Returning false for now until this can be debugged,
89894079 2172 * as the ROWID is not getting updated correctly
67e9aaa3 2173 */
68379eaf 2174 return false;
6b3f4fb8 2175/*
89894079 2176 if (pDb->Dbms() == dbmsORACLE)
68379eaf 2177 return true;
89894079 2178 else
68379eaf 2179 return false;
6b3f4fb8 2180*/
b8032740 2181} // wxDbTable::CanUpdateByROWID()
108106cf 2182
67e9aaa3 2183
f6bcfd97
BP
2184/********** wxDbTable::IsCursorClosedOnCommit() **********/
2185bool wxDbTable::IsCursorClosedOnCommit(void)
108106cf 2186{
89894079 2187 if (pDb->dbInf.cursorCommitBehavior == SQL_CB_PRESERVE)
68379eaf 2188 return false;
89894079 2189 else
68379eaf 2190 return true;
108106cf 2191
f6bcfd97 2192} // wxDbTable::IsCursorClosedOnCommit()
108106cf 2193
67e9aaa3 2194
f02d4a64
GT
2195
2196/********** wxDbTable::ClearMemberVar() **********/
b8032740 2197void wxDbTable::ClearMemberVar(UWORD colNumber, bool setToNull)
108106cf 2198{
b8032740 2199 wxASSERT(colNumber < m_numCols);
f02d4a64 2200
b8032740 2201 switch(colDefs[colNumber].SqlCtype)
89894079 2202 {
f02d4a64 2203 case SQL_C_CHAR:
5c2cd0f6 2204#ifndef __UNIX__
e4e45573 2205 case SQL_C_WCHAR:
5c2cd0f6 2206#endif
e4e45573 2207 //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR
b8032740 2208 ((UCHAR FAR *) colDefs[colNumber].PtrDataObj)[0] = 0;
f02d4a64
GT
2209 break;
2210 case SQL_C_SSHORT:
b8032740 2211 *((SWORD *) colDefs[colNumber].PtrDataObj) = 0;
f02d4a64
GT
2212 break;
2213 case SQL_C_USHORT:
b8032740 2214 *((UWORD*) colDefs[colNumber].PtrDataObj) = 0;
f02d4a64 2215 break;
f292d0ec 2216 case SQL_C_LONG:
f02d4a64 2217 case SQL_C_SLONG:
b8032740 2218 *((SDWORD *) colDefs[colNumber].PtrDataObj) = 0;
f02d4a64
GT
2219 break;
2220 case SQL_C_ULONG:
b8032740 2221 *((UDWORD *) colDefs[colNumber].PtrDataObj) = 0;
f02d4a64
GT
2222 break;
2223 case SQL_C_FLOAT:
b8032740 2224 *((SFLOAT *) colDefs[colNumber].PtrDataObj) = 0.0f;
f02d4a64
GT
2225 break;
2226 case SQL_C_DOUBLE:
b8032740 2227 *((SDOUBLE *) colDefs[colNumber].PtrDataObj) = 0.0f;
f02d4a64
GT
2228 break;
2229 case SQL_C_TIMESTAMP:
2230 TIMESTAMP_STRUCT *pDt;
b8032740 2231 pDt = (TIMESTAMP_STRUCT *) colDefs[colNumber].PtrDataObj;
f02d4a64
GT
2232 pDt->year = 0;
2233 pDt->month = 0;
2234 pDt->day = 0;
2235 pDt->hour = 0;
2236 pDt->minute = 0;
2237 pDt->second = 0;
2238 pDt->fraction = 0;
2239 break;
89894079 2240 }
108106cf 2241
f02d4a64 2242 if (setToNull)
b8032740 2243 SetColNull(colNumber);
f02d4a64
GT
2244} // wxDbTable::ClearMemberVar()
2245
2246
2247/********** wxDbTable::ClearMemberVars() **********/
2248void wxDbTable::ClearMemberVars(bool setToNull)
2249{
2250 int i;
2251
2252 // Loop through the columns setting each member variable to zero
b8032740 2253 for (i=0; i < m_numCols; i++)
254a2129 2254 ClearMemberVar((UWORD)i,setToNull);
f02d4a64 2255
f6bcfd97 2256} // wxDbTable::ClearMemberVars()
108106cf 2257
67e9aaa3 2258
f6bcfd97
BP
2259/********** wxDbTable::SetQueryTimeout() **********/
2260bool wxDbTable::SetQueryTimeout(UDWORD nSeconds)
108106cf 2261{
89894079
VZ
2262 if (SQLSetStmtOption(hstmtInsert, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
2263 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
2264 if (SQLSetStmtOption(hstmtUpdate, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
2265 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
2266 if (SQLSetStmtOption(hstmtDelete, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
2267 return(pDb->DispAllErrors(henv, hdbc, hstmtDelete));
2268 if (SQLSetStmtOption(hstmtInternal, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
2269 return(pDb->DispAllErrors(henv, hdbc, hstmtInternal));
2270
2271 // Completed Successfully
68379eaf 2272 return true;
108106cf 2273
f6bcfd97 2274} // wxDbTable::SetQueryTimeout()
108106cf 2275
67e9aaa3 2276
f6bcfd97 2277/********** wxDbTable::SetColDefs() **********/
b8032740
GT
2278bool wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, void *pData,
2279 SWORD cType, int size, bool keyField, bool updateable,
549c8cc2 2280 bool insertAllowed, bool derivedColumn)
108106cf 2281{
b8032740
GT
2282 wxString tmpStr;
2283
2284 if (index >= m_numCols) // Columns numbers are zero based....
2285 {
2286 tmpStr.Printf(wxT("Specified column index (%d) exceeds the maximum number of columns (%d) registered for this table definition. Column definition not added."), index, m_numCols);
2287 wxFAIL_MSG(tmpStr);
2288 wxLogDebug(tmpStr);
2289 return false;
2290 }
ff294e0e 2291
89894079 2292 if (!colDefs) // May happen if the database connection fails
b8032740 2293 return false;
89894079 2294
4fdae997 2295 if (fieldName.Length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN)
89894079 2296 {
9082f1a9 2297 wxStrncpy(colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN);
b8032740 2298 colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun
da38429d 2299
b8032740 2300 tmpStr.Printf(wxT("Column name '%s' is too long. Truncated to '%s'."),
da38429d 2301 fieldName.c_str(),colDefs[index].ColName);
b8032740
GT
2302 wxFAIL_MSG(tmpStr);
2303 wxLogDebug(tmpStr);
89894079
VZ
2304 }
2305 else
2306 wxStrcpy(colDefs[index].ColName, fieldName);
2307
2308 colDefs[index].DbDataType = dataType;
2309 colDefs[index].PtrDataObj = pData;
2310 colDefs[index].SqlCtype = cType;
e4e45573 2311 colDefs[index].SzDataObj = size; //TODO: glt ??? * sizeof(wxChar) ???
89894079 2312 colDefs[index].KeyField = keyField;
549c8cc2 2313 colDefs[index].DerivedCol = derivedColumn;
89894079 2314 // Derived columns by definition would NOT be "Insertable" or "Updateable"
549c8cc2 2315 if (derivedColumn)
89894079 2316 {
68379eaf
WS
2317 colDefs[index].Updateable = false;
2318 colDefs[index].InsertAllowed = false;
89894079
VZ
2319 }
2320 else
2321 {
b8032740 2322 colDefs[index].Updateable = updateable;
549c8cc2 2323 colDefs[index].InsertAllowed = insertAllowed;
89894079
VZ
2324 }
2325
68379eaf 2326 colDefs[index].Null = false;
da38429d 2327
b8032740
GT
2328 return true;
2329
f6bcfd97 2330} // wxDbTable::SetColDefs()
108106cf 2331
67e9aaa3 2332
e93a3a18 2333/********** wxDbTable::SetColDefs() **********/
87cc3456 2334wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols)
67e9aaa3 2335{
4fdae997 2336 wxASSERT(pColInfs);
f6bcfd97 2337 wxDbColDataPtr *pColDataPtrs = NULL;
67e9aaa3 2338
89894079
VZ
2339 if (pColInfs)
2340 {
87cc3456 2341 UWORD index;
da38429d 2342
f6bcfd97 2343 pColDataPtrs = new wxDbColDataPtr[numCols+1];
67e9aaa3
GT
2344
2345 for (index = 0; index < numCols; index++)
89894079 2346 {
89894079
VZ
2347 // Process the fields
2348 switch (pColInfs[index].dbDataType)
2349 {
2350 case DB_DATA_TYPE_VARCHAR:
e4e45573
GT
2351 pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferSize+(1*sizeof(wxChar))];
2352 pColDataPtrs[index].SzDataObj = pColInfs[index].bufferSize+(1*sizeof(wxChar));
2353 pColDataPtrs[index].SqlCtype = SQL_C_WXCHAR;
0b8410f3 2354 break;
89894079 2355 case DB_DATA_TYPE_INTEGER:
67e9aaa3 2356 // Can be long or short
e4e45573 2357 if (pColInfs[index].bufferSize == sizeof(long))
89894079
VZ
2358 {
2359 pColDataPtrs[index].PtrDataObj = new long;
2360 pColDataPtrs[index].SzDataObj = sizeof(long);
2361 pColDataPtrs[index].SqlCtype = SQL_C_SLONG;
2362 }
2363 else
2364 {
2365 pColDataPtrs[index].PtrDataObj = new short;
2366 pColDataPtrs[index].SzDataObj = sizeof(short);
2367 pColDataPtrs[index].SqlCtype = SQL_C_SSHORT;
2368 }
2369 break;
89894079 2370 case DB_DATA_TYPE_FLOAT:
89894079 2371 // Can be float or double
e4e45573 2372 if (pColInfs[index].bufferSize == sizeof(float))
89894079
VZ
2373 {
2374 pColDataPtrs[index].PtrDataObj = new float;
2375 pColDataPtrs[index].SzDataObj = sizeof(float);
2376 pColDataPtrs[index].SqlCtype = SQL_C_FLOAT;
2377 }
2378 else
2379 {
2380 pColDataPtrs[index].PtrDataObj = new double;
2381 pColDataPtrs[index].SzDataObj = sizeof(double);
2382 pColDataPtrs[index].SqlCtype = SQL_C_DOUBLE;
da38429d 2383 }
89894079 2384 break;
89894079 2385 case DB_DATA_TYPE_DATE:
89894079
VZ
2386 pColDataPtrs[index].PtrDataObj = new TIMESTAMP_STRUCT;
2387 pColDataPtrs[index].SzDataObj = sizeof(TIMESTAMP_STRUCT);
2388 pColDataPtrs[index].SqlCtype = SQL_C_TIMESTAMP;
2389 break;
bf5423ea 2390 case DB_DATA_TYPE_BLOB:
da38429d 2391 wxFAIL_MSG(wxT("This form of ::SetColDefs() cannot be used with BLOB columns"));
bf5423ea
GT
2392 pColDataPtrs[index].PtrDataObj = /*BLOB ADDITION NEEDED*/NULL;
2393 pColDataPtrs[index].SzDataObj = /*BLOB ADDITION NEEDED*/sizeof(void *);
2394 pColDataPtrs[index].SqlCtype = SQL_VARBINARY;
2395 break;
2396 }
2397 if (pColDataPtrs[index].PtrDataObj != NULL)
2398 SetColDefs (index,pColInfs[index].colName,pColInfs[index].dbDataType, pColDataPtrs[index].PtrDataObj, pColDataPtrs[index].SqlCtype, pColDataPtrs[index].SzDataObj);
2399 else
2400 {
da38429d 2401 // Unable to build all the column definitions, as either one of
bf5423ea
GT
2402 // the calls to "new" failed above, or there was a BLOB field
2403 // to have a column definition for. If BLOBs are to be used,
2404 // the other form of ::SetColDefs() must be used, as it is impossible
2405 // to know the maximum size to create the PtrDataObj to be.
2406 delete [] pColDataPtrs;
2407 return NULL;
89894079 2408 }
89894079
VZ
2409 }
2410 }
3ca6a5f0 2411
89894079 2412 return (pColDataPtrs);
3ca6a5f0 2413
e93a3a18 2414} // wxDbTable::SetColDefs()
67e9aaa3
GT
2415
2416
f6bcfd97
BP
2417/********** wxDbTable::SetCursor() **********/
2418void wxDbTable::SetCursor(HSTMT *hstmtActivate)
108106cf 2419{
f6bcfd97 2420 if (hstmtActivate == wxDB_DEFAULT_CURSOR)
89894079
VZ
2421 hstmt = *hstmtDefault;
2422 else
2423 hstmt = *hstmtActivate;
108106cf 2424
f6bcfd97 2425} // wxDbTable::SetCursor()
108106cf 2426
67e9aaa3 2427
4fdae997
GT
2428/********** wxDbTable::Count(const wxString &) **********/
2429ULONG wxDbTable::Count(const wxString &args)
108106cf 2430{
3ca6a5f0 2431 ULONG count;
1e92909e 2432 wxString sqlStmt;
89894079
VZ
2433 SDWORD cb;
2434
2435 // Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement
4fdae997 2436 sqlStmt = wxT("SELECT COUNT(");
1e92909e 2437 sqlStmt += args;
4fdae997 2438 sqlStmt += wxT(") FROM ");
243d4b36
GT
2439 sqlStmt += pDb->SQLTableName(queryTableName);
2440// sqlStmt += queryTableName;
f6bcfd97 2441#if wxODBC_BACKWARD_COMPATABILITY
89894079 2442 if (from && wxStrlen(from))
f6bcfd97
BP
2443#else
2444 if (from.Length())
2445#endif
1e92909e 2446 sqlStmt += from;
89894079
VZ
2447
2448 // Add the where clause if one is provided
f6bcfd97 2449#if wxODBC_BACKWARD_COMPATABILITY
89894079 2450 if (where && wxStrlen(where))
f6bcfd97
BP
2451#else
2452 if (where.Length())
2453#endif
89894079 2454 {
4fdae997 2455 sqlStmt += wxT(" WHERE ");
1e92909e 2456 sqlStmt += where;
89894079
VZ
2457 }
2458
4fdae997 2459 pDb->WriteSqlLog(sqlStmt);
89894079
VZ
2460
2461 // Initialize the Count cursor if it's not already initialized
2462 if (!hstmtCount)
2463 {
68379eaf 2464 hstmtCount = GetNewCursor(false,false);
4fdae997 2465 wxASSERT(hstmtCount);
89894079
VZ
2466 if (!hstmtCount)
2467 return(0);
2468 }
2469
2470 // Execute the SQL statement
8a39593e 2471 if (SQLExecDirect(*hstmtCount, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
89894079
VZ
2472 {
2473 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2474 return(0);
2475 }
2476
2477 // Fetch the record
2478 if (SQLFetch(*hstmtCount) != SQL_SUCCESS)
2479 {
2480 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2481 return(0);
2482 }
2483
2484 // Obtain the result
6b3f4fb8 2485 if (SQLGetData(*hstmtCount, (UWORD)1, SQL_C_ULONG, &count, sizeof(count), &cb) != SQL_SUCCESS)
89894079
VZ
2486 {
2487 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2488 return(0);
2489 }
2490
2491 // Free the cursor
2492 if (SQLFreeStmt(*hstmtCount, SQL_CLOSE) != SQL_SUCCESS)
2493 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2494
2495 // Return the record count
3ca6a5f0 2496 return(count);
108106cf 2497
f6bcfd97 2498} // wxDbTable::Count()
108106cf 2499
67e9aaa3 2500
f6bcfd97
BP
2501/********** wxDbTable::Refresh() **********/
2502bool wxDbTable::Refresh(void)
108106cf 2503{
68379eaf 2504 bool result = true;
89894079
VZ
2505
2506 // Switch to the internal cursor so any active cursors are not corrupted
2507 HSTMT currCursor = GetCursor();
2508 hstmt = hstmtInternal;
f6bcfd97 2509#if wxODBC_BACKWARD_COMPATABILITY
89894079 2510 // Save the where and order by clauses
8a39593e
JS
2511 wxChar *saveWhere = where;
2512 wxChar *saveOrderBy = orderBy;
f6bcfd97
BP
2513#else
2514 wxString saveWhere = where;
2515 wxString saveOrderBy = orderBy;
2516#endif
89894079
VZ
2517 // Build a where clause to refetch the record with. Try and use the
2518 // ROWID if it's available, ow use the key fields.
4fdae997
GT
2519 wxString whereClause;
2520 whereClause.Empty();
2521
b8032740 2522 if (CanUpdateByROWID())
89894079
VZ
2523 {
2524 SDWORD cb;
e4e45573 2525 wxChar rowid[wxDB_ROWID_LEN+1];
89894079
VZ
2526
2527 // Get the ROWID value. If not successful retreiving the ROWID,
2528 // simply fall down through the code and build the WHERE clause
2529 // based on the key fields.
b8032740 2530 if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS)
89894079 2531 {
243d4b36
GT
2532 whereClause += pDb->SQLTableName(queryTableName);
2533// whereClause += queryTableName;
4fdae997
GT
2534 whereClause += wxT(".ROWID = '");
2535 whereClause += rowid;
2536 whereClause += wxT("'");
89894079
VZ
2537 }
2538 }
2539
2540 // If unable to use the ROWID, build a where clause from the keyfields
2541 if (wxStrlen(whereClause) == 0)
f6bcfd97 2542 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS, queryTableName);
89894079
VZ
2543
2544 // Requery the record
2545 where = whereClause;
4fdae997 2546 orderBy.Empty();
89894079 2547 if (!Query())
68379eaf 2548 result = false;
89894079
VZ
2549
2550 if (result && !GetNext())
68379eaf 2551 result = false;
89894079
VZ
2552
2553 // Switch back to original cursor
2554 SetCursor(&currCursor);
2555
2556 // Free the internal cursor
2557 if (SQLFreeStmt(hstmtInternal, SQL_CLOSE) != SQL_SUCCESS)
2558 pDb->DispAllErrors(henv, hdbc, hstmtInternal);
2559
2560 // Restore the original where and order by clauses
1e92909e 2561 where = saveWhere;
89894079
VZ
2562 orderBy = saveOrderBy;
2563
2564 return(result);
108106cf 2565
f6bcfd97 2566} // wxDbTable::Refresh()
108106cf 2567
67e9aaa3 2568
e938ff5e 2569/********** wxDbTable::SetColNull() **********/
b8032740 2570bool wxDbTable::SetColNull(UWORD colNumber, bool set)
a2115c88 2571{
b8032740 2572 if (colNumber < m_numCols)
f02d4a64 2573 {
b8032740 2574 colDefs[colNumber].Null = set;
f02d4a64 2575 if (set) // Blank out the values in the member variable
b8032740 2576 ClearMemberVar(colNumber, false); // Must call with false here, or infinite recursion will happen
e9ed92a2 2577
b8032740 2578 setCbValueForColumn(colNumber);
e9ed92a2 2579
68379eaf 2580 return true;
f02d4a64 2581 }
89894079 2582 else
68379eaf 2583 return false;
a2115c88 2584
4fdae997 2585} // wxDbTable::SetColNull()
67e9aaa3 2586
a2115c88 2587
e938ff5e 2588/********** wxDbTable::SetColNull() **********/
4fdae997 2589bool wxDbTable::SetColNull(const wxString &colName, bool set)
a2115c88 2590{
b8032740
GT
2591 int colNumber;
2592 for (colNumber = 0; colNumber < m_numCols; colNumber++)
89894079 2593 {
b8032740 2594 if (!wxStricmp(colName, colDefs[colNumber].ColName))
89894079
VZ
2595 break;
2596 }
2597
b8032740 2598 if (colNumber < m_numCols)
f02d4a64 2599 {
b8032740 2600 colDefs[colNumber].Null = set;
f02d4a64 2601 if (set) // Blank out the values in the member variable
b8032740 2602 ClearMemberVar((UWORD)colNumber,false); // Must call with false here, or infinite recursion will happen
e9ed92a2 2603
b8032740 2604 setCbValueForColumn(colNumber);
e9ed92a2 2605
68379eaf 2606 return true;
f02d4a64 2607 }
89894079 2608 else
68379eaf 2609 return false;
a2115c88 2610
4fdae997 2611} // wxDbTable::SetColNull()
a2115c88 2612
67e9aaa3 2613
f6bcfd97
BP
2614/********** wxDbTable::GetNewCursor() **********/
2615HSTMT *wxDbTable::GetNewCursor(bool setCursor, bool bindColumns)
a2115c88 2616{
89894079 2617 HSTMT *newHSTMT = new HSTMT;
4fdae997 2618 wxASSERT(newHSTMT);
89894079
VZ
2619 if (!newHSTMT)
2620 return(0);
2621
2622 if (SQLAllocStmt(hdbc, newHSTMT) != SQL_SUCCESS)
2623 {
2624 pDb->DispAllErrors(henv, hdbc);
2625 delete newHSTMT;
2626 return(0);
2627 }
2628
2629 if (SQLSetStmtOption(*newHSTMT, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
2630 {
2631 pDb->DispAllErrors(henv, hdbc, *newHSTMT);
2632 delete newHSTMT;
2633 return(0);
2634 }
2635
2636 if (bindColumns)
2637 {
882fc8a9 2638 if (!bindCols(*newHSTMT))
89894079
VZ
2639 {
2640 delete newHSTMT;
2641 return(0);
2642 }
2643 }
2644
2645 if (setCursor)
2646 SetCursor(newHSTMT);
2647
2648 return(newHSTMT);
2649
f6bcfd97 2650} // wxDbTable::GetNewCursor()
67e9aaa3 2651
a2115c88 2652
f6bcfd97
BP
2653/********** wxDbTable::DeleteCursor() **********/
2654bool wxDbTable::DeleteCursor(HSTMT *hstmtDel)
a2115c88 2655{
68379eaf 2656 bool result = true;
a2115c88 2657
89894079
VZ
2658 if (!hstmtDel) // Cursor already deleted
2659 return(result);
a2115c88 2660
7d8c3dba
GT
2661/*
2662ODBC 3.0 says to use this form
2663 if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS)
da38429d 2664
7d8c3dba 2665*/
89894079
VZ
2666 if (SQLFreeStmt(*hstmtDel, SQL_DROP) != SQL_SUCCESS)
2667 {
2668 pDb->DispAllErrors(henv, hdbc);
68379eaf 2669 result = false;
89894079 2670 }
a2115c88 2671
89894079 2672 delete hstmtDel;
a2115c88 2673
89894079 2674 return(result);
a2115c88 2675
f6bcfd97 2676} // wxDbTable::DeleteCursor()
a2115c88 2677
882fc8a9
GT
2678//////////////////////////////////////////////////////////////
2679// wxDbGrid support functions
2680//////////////////////////////////////////////////////////////
2681
2682void wxDbTable::SetRowMode(const rowmode_t rowmode)
2683{
2684 if (!m_hstmtGridQuery)
2685 {
68379eaf 2686 m_hstmtGridQuery = GetNewCursor(false,false);
882fc8a9
GT
2687 if (!bindCols(*m_hstmtGridQuery))
2688 return;
2689 }
2690
2691 m_rowmode = rowmode;
2692 switch (m_rowmode)
2693 {
2694 case WX_ROW_MODE_QUERY:
2695 SetCursor(m_hstmtGridQuery);
2696 break;
2697 case WX_ROW_MODE_INDIVIDUAL:
2698 SetCursor(hstmtDefault);
2699 break;
2700 default:
e7c9692f 2701 wxASSERT(0);
882fc8a9
GT
2702 }
2703} // wxDbTable::SetRowMode()
2704
2705
b8032740 2706wxVariant wxDbTable::GetColumn(const int colNumber) const
882fc8a9
GT
2707{
2708 wxVariant val;
b8032740 2709 if ((colNumber < m_numCols) && (!IsColNull((UWORD)colNumber)))
882fc8a9 2710 {
b8032740 2711 switch (colDefs[colNumber].SqlCtype)
882fc8a9 2712 {
81b89785
GT
2713#if wxUSE_UNICODE
2714 #if defined(SQL_WCHAR)
38ae3a10 2715 case SQL_WCHAR:
81b89785
GT
2716 #endif
2717 #if defined(SQL_WVARCHAR)
38ae3a10 2718 case SQL_WVARCHAR:
81b89785
GT
2719 #endif
2720#endif
882fc8a9
GT
2721 case SQL_CHAR:
2722 case SQL_VARCHAR:
b8032740 2723 val = (wxChar *)(colDefs[colNumber].PtrDataObj);
882fc8a9
GT
2724 break;
2725 case SQL_C_LONG:
2726 case SQL_C_SLONG:
b8032740 2727 val = *(long *)(colDefs[colNumber].PtrDataObj);
882fc8a9
GT
2728 break;
2729 case SQL_C_SHORT:
2730 case SQL_C_SSHORT:
b8032740 2731 val = (long int )(*(short *)(colDefs[colNumber].PtrDataObj));
882fc8a9
GT
2732 break;
2733 case SQL_C_ULONG:
b8032740 2734 val = (long)(*(unsigned long *)(colDefs[colNumber].PtrDataObj));
882fc8a9
GT
2735 break;
2736 case SQL_C_TINYINT:
b8032740 2737 val = (long)(*(wxChar *)(colDefs[colNumber].PtrDataObj));
882fc8a9
GT
2738 break;
2739 case SQL_C_UTINYINT:
b8032740 2740 val = (long)(*(wxChar *)(colDefs[colNumber].PtrDataObj));
882fc8a9
GT
2741 break;
2742 case SQL_C_USHORT:
b8032740 2743 val = (long)(*(UWORD *)(colDefs[colNumber].PtrDataObj));
882fc8a9
GT
2744 break;
2745 case SQL_C_DATE:
b8032740 2746 val = (DATE_STRUCT *)(colDefs[colNumber].PtrDataObj);
882fc8a9
GT
2747 break;
2748 case SQL_C_TIME:
b8032740 2749 val = (TIME_STRUCT *)(colDefs[colNumber].PtrDataObj);
882fc8a9
GT
2750 break;
2751 case SQL_C_TIMESTAMP:
b8032740 2752 val = (TIMESTAMP_STRUCT *)(colDefs[colNumber].PtrDataObj);
882fc8a9
GT
2753 break;
2754 case SQL_C_DOUBLE:
b8032740 2755 val = *(double *)(colDefs[colNumber].PtrDataObj);
882fc8a9
GT
2756 break;
2757 default:
2758 assert(0);
2759 }
2760 }
2761 return val;
2762} // wxDbTable::GetCol()
2763
2764
b8032740 2765void wxDbTable::SetColumn(const int colNumber, const wxVariant val)
882fc8a9
GT
2766{
2767 //FIXME: Add proper wxDateTime support to wxVariant..
2768 wxDateTime dateval;
2769
b8032740 2770 SetColNull((UWORD)colNumber, val.IsNull());
882fc8a9
GT
2771
2772 if (!val.IsNull())
2773 {
b8032740
GT
2774 if ((colDefs[colNumber].SqlCtype == SQL_C_DATE)
2775 || (colDefs[colNumber].SqlCtype == SQL_C_TIME)
2776 || (colDefs[colNumber].SqlCtype == SQL_C_TIMESTAMP))
882fc8a9
GT
2777 {
2778 //Returns null if invalid!
2779 if (!dateval.ParseDate(val.GetString()))
b8032740 2780 SetColNull((UWORD)colNumber, true);
da38429d 2781 }
882fc8a9 2782
b8032740 2783 switch (colDefs[colNumber].SqlCtype)
882fc8a9 2784 {
81b89785
GT
2785#if wxUSE_UNICODE
2786 #if defined(SQL_WCHAR)
38ae3a10 2787 case SQL_WCHAR:
81b89785
GT
2788 #endif
2789 #if defined(SQL_WVARCHAR)
38ae3a10 2790 case SQL_WVARCHAR:
81b89785
GT
2791 #endif
2792#endif
882fc8a9
GT
2793 case SQL_CHAR:
2794 case SQL_VARCHAR:
b8032740 2795 csstrncpyt((wxChar *)(colDefs[colNumber].PtrDataObj),
da38429d 2796 val.GetString().c_str(),
b8032740 2797 colDefs[colNumber].SzDataObj-1); //TODO: glt ??? * sizeof(wxChar) ???
882fc8a9
GT
2798 break;
2799 case SQL_C_LONG:
2800 case SQL_C_SLONG:
b8032740 2801 *(long *)(colDefs[colNumber].PtrDataObj) = val;
882fc8a9
GT
2802 break;
2803 case SQL_C_SHORT:
2804 case SQL_C_SSHORT:
b8032740 2805 *(short *)(colDefs[colNumber].PtrDataObj) = (short)val.GetLong();
882fc8a9
GT
2806 break;
2807 case SQL_C_ULONG:
b8032740 2808 *(unsigned long *)(colDefs[colNumber].PtrDataObj) = val.GetLong();
882fc8a9
GT
2809 break;
2810 case SQL_C_TINYINT:
b8032740 2811 *(wxChar *)(colDefs[colNumber].PtrDataObj) = val.GetChar();
882fc8a9
GT
2812 break;
2813 case SQL_C_UTINYINT:
b8032740 2814 *(wxChar *)(colDefs[colNumber].PtrDataObj) = val.GetChar();
882fc8a9
GT
2815 break;
2816 case SQL_C_USHORT:
b8032740 2817 *(unsigned short *)(colDefs[colNumber].PtrDataObj) = (unsigned short)val.GetLong();
882fc8a9
GT
2818 break;
2819 //FIXME: Add proper wxDateTime support to wxVariant..
2820 case SQL_C_DATE:
2821 {
2822 DATE_STRUCT *dataptr =
b8032740 2823 (DATE_STRUCT *)colDefs[colNumber].PtrDataObj;
da38429d 2824
39d350d6
WS
2825 dataptr->year = (SWORD)dateval.GetYear();
2826 dataptr->month = (UWORD)(dateval.GetMonth()+1);
2827 dataptr->day = (UWORD)dateval.GetDay();
882fc8a9
GT
2828 }
2829 break;
2830 case SQL_C_TIME:
2831 {
2832 TIME_STRUCT *dataptr =
b8032740 2833 (TIME_STRUCT *)colDefs[colNumber].PtrDataObj;
da38429d 2834
882fc8a9
GT
2835 dataptr->hour = dateval.GetHour();
2836 dataptr->minute = dateval.GetMinute();
2837 dataptr->second = dateval.GetSecond();
2838 }
2839 break;
2840 case SQL_C_TIMESTAMP:
2841 {
2842 TIMESTAMP_STRUCT *dataptr =
b8032740 2843 (TIMESTAMP_STRUCT *)colDefs[colNumber].PtrDataObj;
39d350d6
WS
2844 dataptr->year = (SWORD)dateval.GetYear();
2845 dataptr->month = (UWORD)(dateval.GetMonth()+1);
2846 dataptr->day = (UWORD)dateval.GetDay();
da38429d 2847
882fc8a9
GT
2848 dataptr->hour = dateval.GetHour();
2849 dataptr->minute = dateval.GetMinute();
2850 dataptr->second = dateval.GetSecond();
2851 }
2852 break;
2853 case SQL_C_DOUBLE:
b8032740 2854 *(double *)(colDefs[colNumber].PtrDataObj) = val;
882fc8a9
GT
2855 break;
2856 default:
2857 assert(0);
2858 } // switch
2859 } // if (!val.IsNull())
2860} // wxDbTable::SetCol()
2861
2862
2863GenericKey wxDbTable::GetKey()
2864{
2865 void *blk;
1dee6b39 2866 wxChar *blkptr;
da38429d 2867
882fc8a9 2868 blk = malloc(m_keysize);
1dee6b39 2869 blkptr = (wxChar *) blk;
da38429d 2870
882fc8a9 2871 int i;
b8032740 2872 for (i=0; i < m_numCols; i++)
882fc8a9
GT
2873 {
2874 if (colDefs[i].KeyField)
2875 {
2876 memcpy(blkptr,colDefs[i].PtrDataObj, colDefs[i].SzDataObj);
2877 blkptr += colDefs[i].SzDataObj;
2878 }
2879 }
2880
2881 GenericKey k = GenericKey(blk, m_keysize);
2882 free(blk);
2883
2884 return k;
2885} // wxDbTable::GetKey()
2886
2887
2888void wxDbTable::SetKey(const GenericKey& k)
2889{
1dee6b39
GT
2890 void *blk;
2891 wxChar *blkptr;
da38429d 2892
882fc8a9 2893 blk = k.GetBlk();
1dee6b39 2894 blkptr = (wxChar *)blk;
882fc8a9
GT
2895
2896 int i;
b8032740 2897 for (i=0; i < m_numCols; i++)
882fc8a9
GT
2898 {
2899 if (colDefs[i].KeyField)
2900 {
254a2129 2901 SetColNull((UWORD)i, false);
882fc8a9
GT
2902 memcpy(colDefs[i].PtrDataObj, blkptr, colDefs[i].SzDataObj);
2903 blkptr += colDefs[i].SzDataObj;
2904 }
2905 }
2906} // wxDbTable::SetKey()
2907
2908
a2115c88 2909#endif // wxUSE_ODBC
1fc5dd6f 2910