]> git.saurik.com Git - wxWidgets.git/blame - src/common/dbtable.cpp
Added m_destroybuf initialisation
[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.
11// Licence: wxWindows licence, plus:
1e92909e 12// Notice: This class library and its intellectual design are free of charge for use,
108106cf
JS
13// modification, enhancement, debugging under the following conditions:
14// 1) These classes may only be used as part of the implementation of a
15// wxWindows-based application
16// 2) All enhancements and bug fixes are to be submitted back to the wxWindows
17// user groups free of all charges for use with the wxWindows library.
18// 3) These classes may not be distributed as part of any other class library,
19// DLL, text (written or electronic), other than a complete distribution of
20// the wxWindows GUI development toolkit.
21///////////////////////////////////////////////////////////////////////////////
22
23/*
24// SYNOPSIS START
25// SYNOPSIS STOP
26*/
27
a2115c88
GT
28// Use this line for wxWindows v1.x
29//#include "wx_ver.h"
30// Use this line for wxWindows v2.x
a2115c88 31#include "wx/wxprec.h"
f6bcfd97 32#include "wx/version.h"
a2115c88
GT
33
34#if wxMAJOR_VERSION == 2
3ca6a5f0
BP
35 #ifdef __GNUG__
36 #pragma implementation "dbtable.h"
37 #endif
108106cf 38#endif
108106cf 39
0b8410f3
GT
40#ifdef DBDEBUG_CONSOLE
41 #include "wx/ioswrap.h"
42#endif
108106cf 43
f6bcfd97 44
108106cf 45#ifdef __BORLANDC__
1e92909e 46 #pragma hdrstop
108106cf
JS
47#endif //__BORLANDC__
48
a2115c88 49#if wxMAJOR_VERSION == 2
1e92909e
GT
50 #ifndef WX_PRECOMP
51 #include "wx/string.h"
52 #include "wx/object.h"
53 #include "wx/list.h"
54 #include "wx/utils.h"
55 #include "wx/msgdlg.h"
0efe4a98 56 #include "wx/log.h"
89894079
VZ
57 #endif
58 #include "wx/filefn.h"
a2115c88 59#endif
108106cf 60
a2115c88 61#if wxMAJOR_VERSION == 1
89894079
VZ
62# if defined(wx_msw) || defined(wx_x)
63# ifdef WX_PRECOMP
64# include "wx_prec.h"
65# else
66# include "wx.h"
67# endif
68# endif
69# define wxUSE_ODBC 1
a2115c88 70#endif
108106cf 71
f6bcfd97 72
a2115c88 73#if wxUSE_ODBC
108106cf
JS
74
75#include <stdio.h>
76#include <stdlib.h>
77#include <string.h>
1fc5dd6f 78#include <assert.h>
67e9aaa3 79
a2115c88 80#if wxMAJOR_VERSION == 1
89894079 81 #include "table.h"
a2115c88 82#elif wxMAJOR_VERSION == 2
89894079 83 #include "wx/dbtable.h"
a2115c88 84#endif
108106cf 85
1fc5dd6f 86#ifdef __UNIX__
108106cf
JS
87// The HPUX preprocessor lines below were commented out on 8/20/97
88// because macros.h currently redefines DEBUG and is unneeded.
89// # ifdef HPUX
90// # include <macros.h>
91// # endif
1fc5dd6f 92# ifdef LINUX
108106cf
JS
93# include <sys/minmax.h>
94# endif
95#endif
96
a2115c88
GT
97ULONG lastTableID = 0;
98
99
e041ce57 100#ifdef __WXDEBUG__
89894079 101 wxList TablesInUse;
a2115c88
GT
102#endif
103
104
f6bcfd97
BP
105/********** wxDbTable::wxDbTable() **********/
106wxDbTable::wxDbTable(wxDb *pwxDb, const char *tblName, const int nCols,
89894079 107 const char *qryTblName, bool qryOnly, const char *tblPath)
108106cf 108{
f6bcfd97 109 pDb = pwxDb; // Pointer to the wxDb object
89894079
VZ
110 henv = 0;
111 hdbc = 0;
112 hstmt = 0;
113 hstmtDefault = 0; // Initialized below
114 hstmtCount = 0; // Initialized first time it is needed
115 hstmtInsert = 0;
116 hstmtDelete = 0;
117 hstmtUpdate = 0;
118 hstmtInternal = 0;
119 colDefs = 0;
120 tableID = 0;
121 noCols = nCols; // No. of cols in the table
f6bcfd97
BP
122 where = ""; // Where clause
123 orderBy = ""; // Order By clause
124 from = ""; // From clause
89894079
VZ
125 selectForUpdate = FALSE; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase
126 queryOnly = qryOnly;
f6bcfd97 127 insertable = TRUE;
e93a3a18
GT
128 wxStrcpy(tablePath,"");
129 wxStrcpy(tableName,"");
130 wxStrcpy(queryTableName,"");
89894079
VZ
131
132 assert (tblName);
133
134 wxStrcpy(tableName, tblName); // Table Name
135 if (tblPath)
136 wxStrcpy(tablePath, tblPath); // Table Path - used for dBase files
f02d4a64
GT
137 else
138 tablePath[0] = 0;
3ca6a5f0 139
89894079
VZ
140 if (qryTblName) // Name of the table/view to query
141 wxStrcpy(queryTableName, qryTblName);
142 else
143 wxStrcpy(queryTableName, tblName);
3ca6a5f0 144
89894079
VZ
145 if (!pDb)
146 return;
3ca6a5f0 147
f6bcfd97 148 pDb->incrementTableCount();
3ca6a5f0 149
1e92909e 150 wxString s;
89894079 151 tableID = ++lastTableID;
f6bcfd97 152 s.sprintf("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]", tblName,tableID,pDb);
3ca6a5f0 153
e041ce57 154#ifdef __WXDEBUG__
8128349e
GT
155 wxTablesInUse *tableInUse;
156 tableInUse = new wxTablesInUse();
89894079 157 tableInUse->tableName = tblName;
1e92909e
GT
158 tableInUse->tableID = tableID;
159 tableInUse->pDb = pDb;
89894079 160 TablesInUse.Append(tableInUse);
a2115c88 161#endif
3ca6a5f0 162
f6bcfd97 163 pDb->WriteSqlLog(s.c_str());
3ca6a5f0 164
f6bcfd97
BP
165 // Grab the HENV and HDBC from the wxDb object
166 henv = pDb->GetHENV();
167 hdbc = pDb->GetHDBC();
3ca6a5f0 168
89894079
VZ
169 // Allocate space for column definitions
170 if (noCols)
f6bcfd97 171 colDefs = new wxDbColDef[noCols]; // Points to the first column defintion
3ca6a5f0 172
89894079
VZ
173 // Allocate statement handles for the table
174 if (!queryOnly)
175 {
176 // Allocate a separate statement handle for performing inserts
177 if (SQLAllocStmt(hdbc, &hstmtInsert) != SQL_SUCCESS)
178 pDb->DispAllErrors(henv, hdbc);
179 // Allocate a separate statement handle for performing deletes
180 if (SQLAllocStmt(hdbc, &hstmtDelete) != SQL_SUCCESS)
181 pDb->DispAllErrors(henv, hdbc);
182 // Allocate a separate statement handle for performing updates
183 if (SQLAllocStmt(hdbc, &hstmtUpdate) != SQL_SUCCESS)
184 pDb->DispAllErrors(henv, hdbc);
185 }
186 // Allocate a separate statement handle for internal use
187 if (SQLAllocStmt(hdbc, &hstmtInternal) != SQL_SUCCESS)
188 pDb->DispAllErrors(henv, hdbc);
3ca6a5f0 189
89894079
VZ
190 // Set the cursor type for the statement handles
191 cursorType = SQL_CURSOR_STATIC;
3ca6a5f0 192
89894079 193 if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
3ca6a5f0 194 {
89894079
VZ
195 // Check to see if cursor type is supported
196 pDb->GetNextError(henv, hdbc, hstmtInternal);
197 if (! wxStrcmp(pDb->sqlState, "01S02")) // Option Value Changed
3ca6a5f0 198 {
89894079
VZ
199 // Datasource does not support static cursors. Driver
200 // will substitute a cursor type. Call SQLGetStmtOption()
201 // to determine which cursor type was selected.
202 if (SQLGetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, &cursorType) != SQL_SUCCESS)
3ca6a5f0 203 pDb->DispAllErrors(henv, hdbc, hstmtInternal);
a2115c88 204#ifdef DBDEBUG_CONSOLE
89894079
VZ
205 cout << "Static cursor changed to: ";
206 switch(cursorType)
3ca6a5f0
BP
207 {
208 case SQL_CURSOR_FORWARD_ONLY:
209 cout << "Forward Only";
210 break;
211 case SQL_CURSOR_STATIC:
212 cout << "Static";
213 break;
214 case SQL_CURSOR_KEYSET_DRIVEN:
215 cout << "Keyset Driven";
216 break;
217 case SQL_CURSOR_DYNAMIC:
218 cout << "Dynamic";
219 break;
220 }
89894079 221 cout << endl << endl;
108106cf 222#endif
3ca6a5f0
BP
223 // BJO20000425
224 if (pDb->FwdOnlyCursors() && cursorType != SQL_CURSOR_FORWARD_ONLY)
225 {
226 // Force the use of a forward only cursor...
227 cursorType = SQL_CURSOR_FORWARD_ONLY;
228 if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
229 {
230 // Should never happen
231 pDb->GetNextError(henv, hdbc, hstmtInternal);
232 return;
233 }
234 }
235 }
236 else
237 {
89894079
VZ
238 pDb->DispNextError();
239 pDb->DispAllErrors(henv, hdbc, hstmtInternal);
3ca6a5f0 240 }
89894079 241 }
a2115c88 242#ifdef DBDEBUG_CONSOLE
89894079
VZ
243 else
244 cout << "Cursor Type set to STATIC" << endl << endl;
108106cf 245#endif
3ca6a5f0 246
89894079
VZ
247 if (!queryOnly)
248 {
249 // Set the cursor type for the INSERT statement handle
250 if (SQLSetStmtOption(hstmtInsert, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
251 pDb->DispAllErrors(henv, hdbc, hstmtInsert);
252 // Set the cursor type for the DELETE statement handle
253 if (SQLSetStmtOption(hstmtDelete, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
254 pDb->DispAllErrors(henv, hdbc, hstmtDelete);
255 // Set the cursor type for the UPDATE statement handle
256 if (SQLSetStmtOption(hstmtUpdate, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
257 pDb->DispAllErrors(henv, hdbc, hstmtUpdate);
258 }
3ca6a5f0 259
89894079 260 // Make the default cursor the active cursor
f6bcfd97 261 hstmtDefault = GetNewCursor(FALSE,FALSE);
89894079
VZ
262 assert(hstmtDefault);
263 hstmt = *hstmtDefault;
3ca6a5f0 264
f6bcfd97 265} // wxDbTable::wxDbTable()
108106cf 266
67e9aaa3 267
f6bcfd97
BP
268/********** wxDbTable::~wxDbTable() **********/
269wxDbTable::~wxDbTable()
108106cf 270{
1e92909e 271 wxString s;
89894079
VZ
272 if (pDb)
273 {
f6bcfd97
BP
274 s.sprintf("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]", tableName,tableID,pDb);
275 pDb->WriteSqlLog(s.c_str());
89894079 276 }
a2115c88 277
e041ce57 278#ifdef __WXDEBUG__
89894079
VZ
279 if (tableID)
280 {
a4086039 281 TablesInUse.DeleteContents(TRUE);
89894079 282 bool found = FALSE;
1e92909e 283
0b8410f3 284 wxNode *pNode;
89894079
VZ
285 pNode = TablesInUse.First();
286 while (pNode && !found)
287 {
8128349e 288 if (((wxTablesInUse *)pNode->Data())->tableID == tableID)
89894079
VZ
289 {
290 found = TRUE;
291 if (!TablesInUse.DeleteNode(pNode))
f6bcfd97 292 wxLogDebug (s.c_str(),wxT("Unable to delete node!"));
89894079
VZ
293 }
294 else
295 pNode = pNode->Next();
296 }
297 if (!found)
298 {
1e92909e 299 wxString msg;
f6bcfd97
BP
300 msg.sprintf(wxT("Unable to find the tableID in the linked\nlist of tables in use.\n\n%s"),s.c_str());
301 wxLogDebug (msg.c_str(),wxT("NOTICE..."));
89894079
VZ
302 }
303 }
a2115c88 304#endif
e041ce57 305
f6bcfd97 306 // Decrement the wxDb table count
89894079 307 if (pDb)
f6bcfd97 308 pDb->decrementTableCount();
89894079
VZ
309
310 // Delete memory allocated for column definitions
311 if (colDefs)
312 delete [] colDefs;
313
314 // Free statement handles
315 if (!queryOnly)
316 {
317 if (hstmtInsert)
318 if (SQLFreeStmt(hstmtInsert, SQL_DROP) != SQL_SUCCESS)
319 pDb->DispAllErrors(henv, hdbc);
7c5c05ae 320
89894079
VZ
321 if (hstmtDelete)
322 if (SQLFreeStmt(hstmtDelete, SQL_DROP) != SQL_SUCCESS)
7c5c05ae 323
89894079
VZ
324 if (hstmtUpdate)
325 if (SQLFreeStmt(hstmtUpdate, SQL_DROP) != SQL_SUCCESS)
326 pDb->DispAllErrors(henv, hdbc);
327 }
3ca6a5f0 328
89894079
VZ
329 if (hstmtInternal)
330 if (SQLFreeStmt(hstmtInternal, SQL_DROP) != SQL_SUCCESS)
331 pDb->DispAllErrors(henv, hdbc);
332
333 // Delete dynamically allocated cursors
334 if (hstmtDefault)
335 DeleteCursor(hstmtDefault);
7c5c05ae 336
89894079
VZ
337 if (hstmtCount)
338 DeleteCursor(hstmtCount);
108106cf 339
f6bcfd97 340} // wxDbTable::~wxDbTable()
108106cf 341
67e9aaa3
GT
342
343
6919c53f
GT
344/***************************** PRIVATE FUNCTIONS *****************************/
345
67e9aaa3
GT
346
347
f6bcfd97
BP
348/********** wxDbTable::bindInsertParams() **********/
349bool wxDbTable::bindInsertParams(void)
6919c53f 350{
89894079
VZ
351 assert(!queryOnly);
352 if (queryOnly)
353 return(FALSE);
354
355 SWORD fSqlType = 0;
356 UDWORD precision = 0;
357 SWORD scale = 0;
358
359 // Bind each column (that can be inserted) of the table to a parameter marker
360 int i,colNo;
361 for (i = 0, colNo = 1; i < noCols; i++)
362 {
363 if (! colDefs[i].InsertAllowed)
364 continue;
365 switch(colDefs[i].DbDataType)
366 {
3ca6a5f0
BP
367 case DB_DATA_TYPE_VARCHAR:
368 fSqlType = pDb->GetTypeInfVarchar().FsqlType;
369 precision = colDefs[i].SzDataObj;
370 scale = 0;
f02d4a64
GT
371 if (colDefs[i].Null)
372 colDefs[i].CbValue = SQL_NULL_DATA;
373 else
374 colDefs[i].CbValue = SQL_NTS;
3ca6a5f0
BP
375 break;
376 case DB_DATA_TYPE_INTEGER:
377 fSqlType = pDb->GetTypeInfInteger().FsqlType;
378 precision = pDb->GetTypeInfInteger().Precision;
379 scale = 0;
f02d4a64
GT
380 if (colDefs[i].Null)
381 colDefs[i].CbValue = SQL_NULL_DATA;
382 else
383 colDefs[i].CbValue = 0;
3ca6a5f0
BP
384 break;
385 case DB_DATA_TYPE_FLOAT:
386 fSqlType = pDb->GetTypeInfFloat().FsqlType;
387 precision = pDb->GetTypeInfFloat().Precision;
388 scale = pDb->GetTypeInfFloat().MaximumScale;
389 // SQL Sybase Anywhere v5.5 returned a negative number for the
390 // MaxScale. This caused ODBC to kick out an error on ibscale.
391 // I check for this here and set the scale = precision.
392 //if (scale < 0)
393 // scale = (short) precision;
f02d4a64
GT
394 if (colDefs[i].Null)
395 colDefs[i].CbValue = SQL_NULL_DATA;
396 else
397 colDefs[i].CbValue = 0;
3ca6a5f0
BP
398 break;
399 case DB_DATA_TYPE_DATE:
400 fSqlType = pDb->GetTypeInfDate().FsqlType;
401 precision = pDb->GetTypeInfDate().Precision;
402 scale = 0;
f02d4a64
GT
403 if (colDefs[i].Null)
404 colDefs[i].CbValue = SQL_NULL_DATA;
405 else
406 colDefs[i].CbValue = 0;
3ca6a5f0 407 break;
89894079
VZ
408 }
409 // Null values
f02d4a64
GT
410//RG-NULL
411//RG-NULL if (colDefs[i].Null)
412//RG-NULL {
413//RG-NULL colDefs[i].CbValue = SQL_NULL_DATA;
414//RG-NULL colDefs[i].Null = FALSE;
415//RG-NULL }
f6bcfd97 416
3ca6a5f0
BP
417 if (SQLBindParameter(hstmtInsert, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype,
418 fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj,
419 precision+1,&colDefs[i].CbValue) != SQL_SUCCESS)
420 {
421 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
422 }
89894079
VZ
423 }
424
425 // Completed successfully
426 return(TRUE);
6919c53f 427
f6bcfd97 428} // wxDbTable::bindInsertParams()
6919c53f 429
67e9aaa3 430
f6bcfd97
BP
431/********** wxDbTable::bindUpdateParams() **********/
432bool wxDbTable::bindUpdateParams(void)
6919c53f 433{
89894079
VZ
434 assert(!queryOnly);
435 if (queryOnly)
436 return(FALSE);
3ca6a5f0 437
89894079
VZ
438 SWORD fSqlType = 0;
439 UDWORD precision = 0;
440 SWORD scale = 0;
441
442 // Bind each UPDATEABLE column of the table to a parameter marker
443 int i,colNo;
444 for (i = 0, colNo = 1; i < noCols; i++)
445 {
446 if (! colDefs[i].Updateable)
447 continue;
448 switch(colDefs[i].DbDataType)
449 {
3ca6a5f0
BP
450 case DB_DATA_TYPE_VARCHAR:
451 fSqlType = pDb->GetTypeInfVarchar().FsqlType;
452 precision = colDefs[i].SzDataObj;
453 scale = 0;
f02d4a64
GT
454 if (colDefs[i].Null)
455 colDefs[i].CbValue = SQL_NULL_DATA;
456 else
457 colDefs[i].CbValue = SQL_NTS;
3ca6a5f0
BP
458 break;
459 case DB_DATA_TYPE_INTEGER:
460 fSqlType = pDb->GetTypeInfInteger().FsqlType;
461 precision = pDb->GetTypeInfInteger().Precision;
462 scale = 0;
f02d4a64
GT
463 if (colDefs[i].Null)
464 colDefs[i].CbValue = SQL_NULL_DATA;
465 else
466 colDefs[i].CbValue = 0;
3ca6a5f0
BP
467 break;
468 case DB_DATA_TYPE_FLOAT:
469 fSqlType = pDb->GetTypeInfFloat().FsqlType;
470 precision = pDb->GetTypeInfFloat().Precision;
471 scale = pDb->GetTypeInfFloat().MaximumScale;
472 // SQL Sybase Anywhere v5.5 returned a negative number for the
473 // MaxScale. This caused ODBC to kick out an error on ibscale.
474 // I check for this here and set the scale = precision.
475 //if (scale < 0)
476 // scale = (short) precision;
f02d4a64
GT
477 if (colDefs[i].Null)
478 colDefs[i].CbValue = SQL_NULL_DATA;
479 else
480 colDefs[i].CbValue = 0;
3ca6a5f0
BP
481 break;
482 case DB_DATA_TYPE_DATE:
483 fSqlType = pDb->GetTypeInfDate().FsqlType;
484 precision = pDb->GetTypeInfDate().Precision;
485 scale = 0;
f02d4a64
GT
486 if (colDefs[i].Null)
487 colDefs[i].CbValue = SQL_NULL_DATA;
488 else
489 colDefs[i].CbValue = 0;
3ca6a5f0
BP
490 break;
491 }
492
493 if (SQLBindParameter(hstmtUpdate, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype,
494 fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj,
495 precision+1, &colDefs[i].CbValue) != SQL_SUCCESS)
496 {
497 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
89894079 498 }
89894079 499 }
3ca6a5f0 500
89894079
VZ
501 // Completed successfully
502 return(TRUE);
6919c53f 503
f6bcfd97 504} // wxDbTable::bindUpdateParams()
6919c53f 505
67e9aaa3 506
f6bcfd97
BP
507/********** wxDbTable::bindCols() **********/
508bool wxDbTable::bindCols(HSTMT cursor)
6919c53f 509{
f02d4a64 510//RG-NULL static SDWORD cb;
89894079
VZ
511
512 // Bind each column of the table to a memory address for fetching data
513 int i;
514 for (i = 0; i < noCols; i++)
3ca6a5f0
BP
515 {
516 if (SQLBindCol(cursor, i+1, colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj,
f02d4a64
GT
517//RG-NULL colDefs[i].SzDataObj, &cb) != SQL_SUCCESS)
518 colDefs[i].SzDataObj, &colDefs[i].CbValue ) != SQL_SUCCESS)
3ca6a5f0
BP
519 {
520 return (pDb->DispAllErrors(henv, hdbc, cursor));
521 }
522 }
89894079
VZ
523
524 // Completed successfully
525 return(TRUE);
6919c53f 526
f6bcfd97 527} // wxDbTable::bindCols()
6919c53f 528
67e9aaa3 529
f6bcfd97
BP
530/********** wxDbTable::getRec() **********/
531bool wxDbTable::getRec(UWORD fetchType)
6919c53f 532{
89894079
VZ
533 RETCODE retcode;
534
535 if (!pDb->FwdOnlyCursors())
536 {
537 // Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType
538 UDWORD cRowsFetched;
539 UWORD rowStatus;
540
541 retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus);
542 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
3ca6a5f0 543 {
89894079
VZ
544 if (retcode == SQL_NO_DATA_FOUND)
545 return(FALSE);
546 else
547 return(pDb->DispAllErrors(henv, hdbc, hstmt));
3ca6a5f0 548 }
f02d4a64
GT
549 else
550 {
551 // Set the Null member variable to indicate the Null state
552 // of each column just read in.
553 int i;
554 for (i = 0; i < noCols; i++)
555 colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
556 }
89894079
VZ
557 }
558 else
559 {
560 // Fetch the next record from the record set
561 retcode = SQLFetch(hstmt);
562 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
563 {
564 if (retcode == SQL_NO_DATA_FOUND)
565 return(FALSE);
566 else
567 return(pDb->DispAllErrors(henv, hdbc, hstmt));
568 }
f02d4a64
GT
569 else
570 {
571 // Set the Null member variable to indicate the Null state
572 // of each column just read in.
573 int i;
574 for (i = 0; i < noCols; i++)
575 colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA);
576 }
89894079
VZ
577 }
578
579 // Completed successfully
580 return(TRUE);
6919c53f 581
f6bcfd97 582} // wxDbTable::getRec()
6919c53f 583
67e9aaa3 584
f6bcfd97
BP
585/********** wxDbTable::execDelete() **********/
586bool wxDbTable::execDelete(const char *pSqlStmt)
6919c53f 587{
89894079
VZ
588 // Execute the DELETE statement
589 if (SQLExecDirect(hstmtDelete, (UCHAR FAR *) pSqlStmt, SQL_NTS) != SQL_SUCCESS)
590 return(pDb->DispAllErrors(henv, hdbc, hstmtDelete));
6919c53f 591
89894079
VZ
592 // Record deleted successfully
593 return(TRUE);
6919c53f 594
f6bcfd97 595} // wxDbTable::execDelete()
6919c53f 596
67e9aaa3 597
f6bcfd97
BP
598/********** wxDbTable::execUpdate() **********/
599bool wxDbTable::execUpdate(const char *pSqlStmt)
6919c53f 600{
89894079
VZ
601 // Execute the UPDATE statement
602 if (SQLExecDirect(hstmtUpdate, (UCHAR FAR *) pSqlStmt, SQL_NTS) != SQL_SUCCESS)
603 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
6919c53f 604
89894079
VZ
605 // Record deleted successfully
606 return(TRUE);
6919c53f 607
f6bcfd97 608} // wxDbTable::execUpdate()
6919c53f 609
67e9aaa3 610
f6bcfd97
BP
611/********** wxDbTable::query() **********/
612bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const char *pSqlStmt)
6919c53f 613{
89894079 614 char sqlStmt[DB_MAX_STATEMENT_LEN];
6919c53f 615
89894079
VZ
616 if (forUpdate)
617 // The user may wish to select for update, but the DBMS may not be capable
618 selectForUpdate = CanSelectForUpdate();
619 else
620 selectForUpdate = FALSE;
6919c53f 621
89894079
VZ
622 // Set the SQL SELECT string
623 if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in,
3ca6a5f0 624 { // so generate a select statement.
f6bcfd97 625 BuildSelectStmt(sqlStmt, queryType, distinct);
89894079 626 pDb->WriteSqlLog(sqlStmt);
3ca6a5f0 627 }
e93a3a18
GT
628/*
629 This is the block of code that got added during the 2.2.1 merge with
630 the 2.2 main branch that somehow got added here when it should not have. - gt
631
3ca6a5f0
BP
632 else
633 wxStrcpy(sqlStmt, pSqlStmt);
f6bcfd97
BP
634
635 SQLFreeStmt(hstmt, SQL_CLOSE);
636 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) == SQL_SUCCESS)
3ca6a5f0 637 return(TRUE);
f6bcfd97 638 else
3ca6a5f0 639 {
f6bcfd97
BP
640 pDb->DispAllErrors(henv, hdbc, hstmt);
641 return(FALSE);
3ca6a5f0 642 }
e93a3a18 643*/
89894079 644 // Make sure the cursor is closed first
e93a3a18 645 if (!CloseCursor(hstmt))
3ca6a5f0 646 return(FALSE);
6919c53f 647
89894079 648 // Execute the SQL SELECT statement
f6bcfd97
BP
649 int retcode;
650 retcode = SQLExecDirect(hstmt, (UCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt : sqlStmt), SQL_NTS);
89894079 651 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
3ca6a5f0 652 return(pDb->DispAllErrors(henv, hdbc, hstmt));
6919c53f 653
89894079
VZ
654 // Completed successfully
655 return(TRUE);
6919c53f 656
f6bcfd97 657} // wxDbTable::query()
6919c53f
GT
658
659
67e9aaa3
GT
660/***************************** PUBLIC FUNCTIONS *****************************/
661
6919c53f 662
f6bcfd97 663/********** wxDbTable::Open() **********/
f02d4a64 664bool wxDbTable::Open(bool checkPrivileges)
108106cf 665{
89894079 666 if (!pDb)
f6bcfd97 667 return FALSE;
3ca6a5f0 668
89894079 669 int i;
1e92909e 670 wxString sqlStmt;
f02d4a64 671 wxString s;
89894079 672
f02d4a64 673 s = "";
89894079 674 // Verify that the table exists in the database
f02d4a64 675 if (!pDb->TableExists(tableName,/*pDb->GetUsername()*/NULL,tablePath))
89894079 676 {
f02d4a64
GT
677 s = "Table/view does not exist in the database";
678 if ( *(pDb->dbInf.accessibleTables) == 'Y')
679 s += ", or you have no permissions.\n";
e16143f6 680 else
f02d4a64
GT
681 s += ".\n";
682 }
683 else if (checkPrivileges)
684 {
685 // Verify the user has rights to access the table.
686 // Shortcut boolean evaluation to optimize out call to
687 // TablePrivileges
688 //
689 // Unfortunately this optimization doesn't seem to be
690 // reliable!
691 if (// *(pDb->dbInf.accessibleTables) == 'N' &&
692 !pDb->TablePrivileges(tableName,"SELECT",NULL,pDb->GetUsername(),tablePath))
693 s = "Current logged in user does not have sufficient privileges to access this table.\n";
694 }
695
696 if (!s.IsEmpty())
697 {
698 wxString p;
699
700 if (wxStrcmp(tablePath,""))
701 p.sprintf("Error opening '%s/%s'.\n",tablePath,tableName);
e16143f6 702 else
f02d4a64
GT
703 p.sprintf("Error opening '%s'.\n", tableName);
704
705 p += s;
706 pDb->LogError(p.GetData());
707
89894079
VZ
708 return(FALSE);
709 }
710
711 // Bind the member variables for field exchange between
f6bcfd97 712 // the wxDbTable object and the ODBC record.
89894079
VZ
713 if (!queryOnly)
714 {
715 if (!bindInsertParams()) // Inserts
716 return(FALSE);
f6bcfd97 717
89894079
VZ
718 if (!bindUpdateParams()) // Updates
719 return(FALSE);
720 }
3ca6a5f0 721
89894079
VZ
722 if (!bindCols(*hstmtDefault)) // Selects
723 return(FALSE);
3ca6a5f0 724
89894079
VZ
725 if (!bindCols(hstmtInternal)) // Internal use only
726 return(FALSE);
f02d4a64
GT
727
728 /*
89894079
VZ
729 * Do NOT bind the hstmtCount cursor!!!
730 */
731
732 // Build an insert statement using parameter markers
733 if (!queryOnly && noCols > 0)
734 {
735 bool needComma = FALSE;
1e92909e 736 sqlStmt.sprintf("INSERT INTO %s (", tableName);
89894079
VZ
737 for (i = 0; i < noCols; i++)
738 {
739 if (! colDefs[i].InsertAllowed)
740 continue;
741 if (needComma)
1e92909e
GT
742 sqlStmt += ",";
743 sqlStmt += colDefs[i].ColName;
89894079
VZ
744 needComma = TRUE;
745 }
746 needComma = FALSE;
1e92909e 747 sqlStmt += ") VALUES (";
f6bcfd97 748
3ca6a5f0 749 int insertableCount = 0;
f6bcfd97 750
89894079
VZ
751 for (i = 0; i < noCols; i++)
752 {
753 if (! colDefs[i].InsertAllowed)
754 continue;
755 if (needComma)
1e92909e
GT
756 sqlStmt += ",";
757 sqlStmt += "?";
89894079 758 needComma = TRUE;
3ca6a5f0 759 insertableCount++;
89894079 760 }
1e92909e 761 sqlStmt += ")";
3ca6a5f0 762
89894079 763 // Prepare the insert statement for execution
f6bcfd97 764 if (insertableCount)
3ca6a5f0 765 {
f6bcfd97
BP
766 if (SQLPrepare(hstmtInsert, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
767 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
768 }
3ca6a5f0 769 else
f6bcfd97 770 insertable= FALSE;
89894079
VZ
771 }
772
773 // Completed successfully
774 return(TRUE);
108106cf 775
f6bcfd97 776} // wxDbTable::Open()
108106cf 777
67e9aaa3 778
f6bcfd97
BP
779/********** wxDbTable::Query() **********/
780bool wxDbTable::Query(bool forUpdate, bool distinct)
108106cf
JS
781{
782
89894079 783 return(query(DB_SELECT_WHERE, forUpdate, distinct));
108106cf 784
f6bcfd97 785} // wxDbTable::Query()
108106cf 786
67e9aaa3 787
f6bcfd97
BP
788/********** wxDbTable::QueryBySqlStmt() **********/
789bool wxDbTable::QueryBySqlStmt(const char *pSqlStmt)
108106cf 790{
89894079 791 pDb->WriteSqlLog(pSqlStmt);
108106cf 792
89894079 793 return(query(DB_SELECT_STATEMENT, FALSE, FALSE, pSqlStmt));
108106cf 794
f6bcfd97 795} // wxDbTable::QueryBySqlStmt()
108106cf 796
67e9aaa3 797
f6bcfd97
BP
798/********** wxDbTable::QueryMatching() **********/
799bool wxDbTable::QueryMatching(bool forUpdate, bool distinct)
108106cf
JS
800{
801
89894079 802 return(query(DB_SELECT_MATCHING, forUpdate, distinct));
108106cf 803
f6bcfd97 804} // wxDbTable::QueryMatching()
108106cf 805
67e9aaa3 806
f6bcfd97
BP
807/********** wxDbTable::QueryOnKeyFields() **********/
808bool wxDbTable::QueryOnKeyFields(bool forUpdate, bool distinct)
108106cf
JS
809{
810
89894079 811 return(query(DB_SELECT_KEYFIELDS, forUpdate, distinct));
108106cf 812
f6bcfd97 813} // wxDbTable::QueryOnKeyFields()
108106cf 814
67e9aaa3 815
f6bcfd97
BP
816/********** wxDbTable::GetPrev() **********/
817bool wxDbTable::GetPrev(void)
a3439c7d 818{
89894079
VZ
819 if (pDb->FwdOnlyCursors())
820 {
f6bcfd97 821 wxFAIL_MSG(wxT("GetPrev()::Backward scrolling cursors are not enabled for this instance of wxDbTable"));
89894079
VZ
822 return FALSE;
823 }
824 else
825 return(getRec(SQL_FETCH_PRIOR));
3ca6a5f0 826
f6bcfd97 827} // wxDbTable::GetPrev()
a3439c7d 828
67e9aaa3 829
f6bcfd97
BP
830/********** wxDbTable::operator-- **********/
831bool wxDbTable::operator--(int)
a3439c7d 832{
89894079
VZ
833 if (pDb->FwdOnlyCursors())
834 {
f6bcfd97 835 wxFAIL_MSG(wxT("operator--:Backward scrolling cursors are not enabled for this instance of wxDbTable"));
89894079
VZ
836 return FALSE;
837 }
838 else
839 return(getRec(SQL_FETCH_PRIOR));
3ca6a5f0 840
f6bcfd97 841} // wxDbTable::operator--
a3439c7d 842
67e9aaa3 843
f6bcfd97
BP
844/********** wxDbTable::GetFirst() **********/
845bool wxDbTable::GetFirst(void)
a3439c7d 846{
89894079
VZ
847 if (pDb->FwdOnlyCursors())
848 {
f6bcfd97 849 wxFAIL_MSG(wxT("GetFirst():Backward scrolling cursors are not enabled for this instance of wxDbTable"));
89894079
VZ
850 return FALSE;
851 }
852 else
853 return(getRec(SQL_FETCH_FIRST));
3ca6a5f0 854
f6bcfd97 855} // wxDbTable::GetFirst()
a3439c7d 856
67e9aaa3 857
f6bcfd97
BP
858/********** wxDbTable::GetLast() **********/
859bool wxDbTable::GetLast(void)
a3439c7d 860{
89894079
VZ
861 if (pDb->FwdOnlyCursors())
862 {
f6bcfd97 863 wxFAIL_MSG(wxT("GetLast()::Backward scrolling cursors are not enabled for this instance of wxDbTable"));
89894079
VZ
864 return FALSE;
865 }
866 else
867 return(getRec(SQL_FETCH_LAST));
3ca6a5f0 868
f6bcfd97 869} // wxDbTable::GetLast()
a3439c7d 870
67e9aaa3 871
f6bcfd97
BP
872/********** wxDbTable::BuildSelectStmt() **********/
873void wxDbTable::BuildSelectStmt(char *pSqlStmt, int typeOfSelect, bool distinct)
108106cf 874{
89894079
VZ
875 char whereClause[DB_MAX_WHERE_CLAUSE_LEN];
876
877 whereClause[0] = 0;
878
879 // Build a select statement to query the database
880 wxStrcpy(pSqlStmt, "SELECT ");
881
882 // SELECT DISTINCT values only?
883 if (distinct)
884 wxStrcat(pSqlStmt, "DISTINCT ");
885
886 // Was a FROM clause specified to join tables to the base table?
887 // Available for ::Query() only!!!
888 bool appendFromClause = FALSE;
f6bcfd97 889#if wxODBC_BACKWARD_COMPATABILITY
89894079
VZ
890 if (typeOfSelect == DB_SELECT_WHERE && from && wxStrlen(from))
891 appendFromClause = TRUE;
f6bcfd97
BP
892#else
893 if (typeOfSelect == DB_SELECT_WHERE && from.Length())
894 appendFromClause = TRUE;
895#endif
89894079
VZ
896
897 // Add the column list
898 int i;
899 for (i = 0; i < noCols; i++)
900 {
901 // If joining tables, the base table column names must be qualified to avoid ambiguity
902 if (appendFromClause)
903 {
904 wxStrcat(pSqlStmt, queryTableName);
905 wxStrcat(pSqlStmt, ".");
906 }
907 wxStrcat(pSqlStmt, colDefs[i].ColName);
908 if (i + 1 < noCols)
909 wxStrcat(pSqlStmt, ",");
910 }
911
912 // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve
913 // the ROWID if querying distinct records. The rowid will always be unique.
914 if (!distinct && CanUpdByROWID())
915 {
916 // If joining tables, the base table column names must be qualified to avoid ambiguity
917 if (appendFromClause)
918 {
919 wxStrcat(pSqlStmt, ",");
920 wxStrcat(pSqlStmt, queryTableName);
921 wxStrcat(pSqlStmt, ".ROWID");
922 }
923 else
924 wxStrcat(pSqlStmt, ",ROWID");
925 }
926
927 // Append the FROM tablename portion
928 wxStrcat(pSqlStmt, " FROM ");
929 wxStrcat(pSqlStmt, queryTableName);
930
931 // Sybase uses the HOLDLOCK keyword to lock a record during query.
932 // The HOLDLOCK keyword follows the table name in the from clause.
933 // Each table in the from clause must specify HOLDLOCK or
934 // NOHOLDLOCK (the default). Note: The "FOR UPDATE" clause
935 // is parsed but ignored in SYBASE Transact-SQL.
936 if (selectForUpdate && (pDb->Dbms() == dbmsSYBASE_ASA || pDb->Dbms() == dbmsSYBASE_ASE))
937 wxStrcat(pSqlStmt, " HOLDLOCK");
938
939 if (appendFromClause)
940 wxStrcat(pSqlStmt, from);
941
942 // Append the WHERE clause. Either append the where clause for the class
943 // or build a where clause. The typeOfSelect determines this.
944 switch(typeOfSelect)
945 {
3ca6a5f0 946 case DB_SELECT_WHERE:
f6bcfd97 947#if wxODBC_BACKWARD_COMPATABILITY
3ca6a5f0 948 if (where && wxStrlen(where)) // May not want a where clause!!!
f6bcfd97 949#else
3ca6a5f0 950 if (where.Length()) // May not want a where clause!!!
f6bcfd97 951#endif
3ca6a5f0
BP
952 {
953 wxStrcat(pSqlStmt, " WHERE ");
954 wxStrcat(pSqlStmt, where);
955 }
956 break;
957 case DB_SELECT_KEYFIELDS:
958 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
959 if (wxStrlen(whereClause))
960 {
961 wxStrcat(pSqlStmt, " WHERE ");
962 wxStrcat(pSqlStmt, whereClause);
963 }
964 break;
965 case DB_SELECT_MATCHING:
966 BuildWhereClause(whereClause, DB_WHERE_MATCHING);
967 if (wxStrlen(whereClause))
968 {
969 wxStrcat(pSqlStmt, " WHERE ");
970 wxStrcat(pSqlStmt, whereClause);
971 }
972 break;
89894079
VZ
973 }
974
975 // Append the ORDER BY clause
f6bcfd97 976#if wxODBC_BACKWARD_COMPATABILITY
89894079 977 if (orderBy && wxStrlen(orderBy))
f6bcfd97 978#else
3ca6a5f0 979 if (orderBy.Length())
f6bcfd97 980#endif
89894079
VZ
981 {
982 wxStrcat(pSqlStmt, " ORDER BY ");
983 wxStrcat(pSqlStmt, orderBy);
984 }
985
986 // SELECT FOR UPDATE if told to do so and the datasource is capable. Sybase
987 // parses the FOR UPDATE clause but ignores it. See the comment above on the
988 // HOLDLOCK for Sybase.
989 if (selectForUpdate && CanSelectForUpdate())
990 wxStrcat(pSqlStmt, " FOR UPDATE");
108106cf 991
f6bcfd97 992} // wxDbTable::BuildSelectStmt()
108106cf 993
67e9aaa3 994
f6bcfd97
BP
995/********** wxDbTable::GetRowNum() **********/
996UWORD wxDbTable::GetRowNum(void)
108106cf 997{
89894079 998 UDWORD rowNum;
108106cf 999
89894079
VZ
1000 if (SQLGetStmtOption(hstmt, SQL_ROW_NUMBER, (UCHAR*) &rowNum) != SQL_SUCCESS)
1001 {
1002 pDb->DispAllErrors(henv, hdbc, hstmt);
1003 return(0);
1004 }
108106cf 1005
89894079
VZ
1006 // Completed successfully
1007 return((UWORD) rowNum);
108106cf 1008
f6bcfd97 1009} // wxDbTable::GetRowNum()
108106cf 1010
67e9aaa3 1011
f6bcfd97
BP
1012/********** wxDbTable::CloseCursor() **********/
1013bool wxDbTable::CloseCursor(HSTMT cursor)
108106cf 1014{
89894079
VZ
1015 if (SQLFreeStmt(cursor, SQL_CLOSE) != SQL_SUCCESS)
1016 return(pDb->DispAllErrors(henv, hdbc, cursor));
108106cf 1017
89894079
VZ
1018 // Completed successfully
1019 return(TRUE);
108106cf 1020
f6bcfd97 1021} // wxDbTable::CloseCursor()
108106cf 1022
67e9aaa3 1023
f6bcfd97
BP
1024/********** wxDbTable::CreateTable() **********/
1025bool wxDbTable::CreateTable(bool attemptDrop)
108106cf 1026{
89894079
VZ
1027 if (!pDb)
1028 return FALSE;
1fc5dd6f 1029
89894079 1030 int i, j;
1e92909e 1031 wxString sqlStmt;
108106cf 1032
a2115c88 1033#ifdef DBDEBUG_CONSOLE
89894079 1034 cout << "Creating Table " << tableName << "..." << endl;
108106cf
JS
1035#endif
1036
89894079
VZ
1037 // Drop table first
1038 if (attemptDrop && !DropTable())
1039 return FALSE;
108106cf 1040
89894079 1041 // Create the table
a2115c88 1042#ifdef DBDEBUG_CONSOLE
89894079
VZ
1043 for (i = 0; i < noCols; i++)
1044 {
1045 // Exclude derived columns since they are NOT part of the base table
1046 if (colDefs[i].DerivedCol)
1047 continue;
1048 cout << i + 1 << ": " << colDefs[i].ColName << "; ";
1049 switch(colDefs[i].DbDataType)
1050 {
1051 case DB_DATA_TYPE_VARCHAR:
1052 cout << pDb->typeInfVarchar.TypeName << "(" << colDefs[i].SzDataObj << ")";
1053 break;
1054 case DB_DATA_TYPE_INTEGER:
1055 cout << pDb->typeInfInteger.TypeName;
1056 break;
1057 case DB_DATA_TYPE_FLOAT:
1058 cout << pDb->typeInfFloat.TypeName;
1059 break;
1060 case DB_DATA_TYPE_DATE:
1061 cout << pDb->typeInfDate.TypeName;
1062 break;
1063 }
1064 cout << endl;
1065 }
108106cf
JS
1066#endif
1067
89894079
VZ
1068 // Build a CREATE TABLE string from the colDefs structure.
1069 bool needComma = FALSE;
1e92909e
GT
1070 sqlStmt.sprintf("CREATE TABLE %s (", tableName);
1071
89894079
VZ
1072 for (i = 0; i < noCols; i++)
1073 {
1074 // Exclude derived columns since they are NOT part of the base table
1075 if (colDefs[i].DerivedCol)
1076 continue;
1077 // Comma Delimiter
1078 if (needComma)
3ca6a5f0 1079 sqlStmt += ",";
89894079 1080 // Column Name
1e92909e
GT
1081 sqlStmt += colDefs[i].ColName;
1082 sqlStmt += " ";
89894079
VZ
1083 // Column Type
1084 switch(colDefs[i].DbDataType)
1085 {
1086 case DB_DATA_TYPE_VARCHAR:
3ca6a5f0
BP
1087 sqlStmt += pDb->GetTypeInfVarchar().TypeName;
1088 break;
89894079 1089 case DB_DATA_TYPE_INTEGER:
3ca6a5f0
BP
1090 sqlStmt += pDb->GetTypeInfInteger().TypeName;
1091 break;
89894079 1092 case DB_DATA_TYPE_FLOAT:
3ca6a5f0
BP
1093 sqlStmt += pDb->GetTypeInfFloat().TypeName;
1094 break;
89894079 1095 case DB_DATA_TYPE_DATE:
3ca6a5f0
BP
1096 sqlStmt += pDb->GetTypeInfDate().TypeName;
1097 break;
89894079
VZ
1098 }
1099 // For varchars, append the size of the string
1100 if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR)
1101 {
1e92909e 1102 wxString s;
89894079
VZ
1103 // wxStrcat(sqlStmt, "(");
1104 // wxStrcat(sqlStmt, itoa(colDefs[i].SzDataObj, s, 10));
1105 // wxStrcat(sqlStmt, ")");
1e92909e 1106 s.sprintf("(%d)", colDefs[i].SzDataObj);
f6bcfd97 1107 sqlStmt += s.c_str();
89894079
VZ
1108 }
1109
e93a3a18
GT
1110 if (pDb->Dbms() == dbmsDB2 ||
1111 pDb->Dbms() == dbmsMY_SQL ||
1112 pDb->Dbms() == dbmsSYBASE_ASE ||
1113 pDb->Dbms() == dbmsMS_SQL_SERVER)
89894079
VZ
1114 {
1115 if (colDefs[i].KeyField)
1116 {
1e92909e 1117 sqlStmt += " NOT NULL";
89894079
VZ
1118 }
1119 }
1120
1121 needComma = TRUE;
1122 }
1123 // If there is a primary key defined, include it in the create statement
1124 for (i = j = 0; i < noCols; i++)
1125 {
1126 if (colDefs[i].KeyField)
1127 {
1128 j++;
1129 break;
1130 }
1131 }
1132 if (j && pDb->Dbms() != dbmsDBASE) // Found a keyfield
1133 {
1134 if (pDb->Dbms() != dbmsMY_SQL)
1135 {
1e92909e
GT
1136 sqlStmt += ",CONSTRAINT ";
1137 sqlStmt += tableName;
1138 sqlStmt += "_PIDX PRIMARY KEY (";
89894079
VZ
1139 }
1140 else
1141 {
1142 /* MySQL goes out on this one. We also declare the relevant key NON NULL above */
1e92909e 1143 sqlStmt += ", PRIMARY KEY (";
89894079
VZ
1144 }
1145
1146 // List column name(s) of column(s) comprising the primary key
1147 for (i = j = 0; i < noCols; i++)
1148 {
1149 if (colDefs[i].KeyField)
1150 {
1151 if (j++) // Multi part key, comma separate names
1e92909e
GT
1152 sqlStmt += ",";
1153 sqlStmt += colDefs[i].ColName;
89894079
VZ
1154 }
1155 }
1e92909e 1156 sqlStmt += ")";
89894079
VZ
1157 }
1158 // Append the closing parentheses for the create table statement
1e92909e 1159 sqlStmt += ")";
a2115c88 1160
f6bcfd97 1161 pDb->WriteSqlLog(sqlStmt.c_str());
1fc5dd6f 1162
a2115c88 1163#ifdef DBDEBUG_CONSOLE
f6bcfd97 1164 cout << endl << sqlStmt.c_str() << endl;
108106cf
JS
1165#endif
1166
89894079 1167 // Execute the CREATE TABLE statement
f6bcfd97 1168 RETCODE retcode = SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS);
89894079
VZ
1169 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
1170 {
1171 pDb->DispAllErrors(henv, hdbc, hstmt);
1172 pDb->RollbackTrans();
1173 CloseCursor(hstmt);
1174 return(FALSE);
1175 }
1176
1177 // Commit the transaction and close the cursor
3ca6a5f0 1178 if (!pDb->CommitTrans())
89894079 1179 return(FALSE);
3ca6a5f0 1180 if (!CloseCursor(hstmt))
89894079
VZ
1181 return(FALSE);
1182
1183 // Database table created successfully
1184 return(TRUE);
108106cf 1185
f6bcfd97 1186} // wxDbTable::CreateTable()
108106cf 1187
67e9aaa3 1188
f6bcfd97
BP
1189/********** wxDbTable::DropTable() **********/
1190bool wxDbTable::DropTable()
a2115c88 1191{
89894079
VZ
1192 // NOTE: This function returns TRUE if the Table does not exist, but
1193 // only for identified databases. Code will need to be added
0b8410f3 1194 // below for any other databases when those databases are defined
89894079 1195 // to handle this situation consistently
a2115c88 1196
1e92909e 1197 wxString sqlStmt;
a2115c88 1198
1e92909e 1199 sqlStmt.sprintf("DROP TABLE %s", tableName);
a2115c88 1200
f6bcfd97 1201 pDb->WriteSqlLog(sqlStmt.c_str());
a2115c88
GT
1202
1203#ifdef DBDEBUG_CONSOLE
f6bcfd97 1204 cout << endl << sqlStmt.c_str() << endl;
a2115c88
GT
1205#endif
1206
f6bcfd97 1207 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
89894079
VZ
1208 {
1209 // Check for "Base table not found" error and ignore
3ca6a5f0 1210 pDb->GetNextError(henv, hdbc, hstmt);
f6bcfd97 1211 if (wxStrcmp(pDb->sqlState,"S0002") && wxStrcmp(pDb->sqlState, "S1000")) // "Base table not found"
3ca6a5f0 1212 {
89894079 1213 // Check for product specific error codes
3ca6a5f0
BP
1214 if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,"42000")) || // 5.x (and lower?)
1215 (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"37000")) ||
1216 (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,"08S01"))))
89894079
VZ
1217 {
1218 pDb->DispNextError();
1219 pDb->DispAllErrors(henv, hdbc, hstmt);
1220 pDb->RollbackTrans();
1221 CloseCursor(hstmt);
1222 return(FALSE);
1223 }
1224 }
1225 }
1226
1227 // Commit the transaction and close the cursor
1228 if (! pDb->CommitTrans())
1229 return(FALSE);
1230 if (! CloseCursor(hstmt))
1231 return(FALSE);
1232
1233 return(TRUE);
f6bcfd97 1234} // wxDbTable::DropTable()
a2115c88 1235
67e9aaa3 1236
f6bcfd97
BP
1237/********** wxDbTable::CreateIndex() **********/
1238bool wxDbTable::CreateIndex(const char * idxName, bool unique, int noIdxCols, wxDbIdxDef *pIdxDefs, bool attemptDrop)
108106cf 1239{
1e92909e 1240 wxString sqlStmt;
89894079
VZ
1241
1242 // Drop the index first
1243 if (attemptDrop && !DropIndex(idxName))
1244 return (FALSE);
1245
3ca6a5f0
BP
1246 // MySQL (and possibly Sybase ASE?? - gt) require that any columns which are used as portions
1247 // of an index have the columns defined as "NOT NULL". During initial table creation though,
1248 // it may not be known which columns are necessarily going to be part of an index (e.g. the
1249 // table was created, then months later you determine that an additional index while
1250 // give better performance, so you want to add an index).
1251 //
1252 // The following block of code will modify the column definition to make the column be
1253 // defined with the "NOT NULL" qualifier.
1254 if (pDb->Dbms() == dbmsMY_SQL)
1255 {
1256 wxString sqlStmt;
1257 int i;
1258 bool ok = TRUE;
1259 for (i = 0; i < noIdxCols && ok; i++)
1260 {
1261 int j = 0;
1262 bool found = FALSE;
1263 // Find the column definition that has the ColName that matches the
1264 // index column name. We need to do this to get the DB_DATA_TYPE of
1265 // the index column, as MySQL's syntax for the ALTER column requires
1266 // this information
1267 while (!found && (j < this->noCols))
1268 {
1269 if (wxStrcmp(colDefs[j].ColName,pIdxDefs[i].ColName) == 0)
1270 found = TRUE;
1271 if (!found)
1272 j++;
1273 }
1274
1275 if (found)
1276 {
1277 wxString typeNameAndSize;
1278
1279 switch(colDefs[j].DbDataType)
1280 {
1281 case DB_DATA_TYPE_VARCHAR:
1282 typeNameAndSize = pDb->GetTypeInfVarchar().TypeName;
1283 break;
1284 case DB_DATA_TYPE_INTEGER:
1285 typeNameAndSize = pDb->GetTypeInfInteger().TypeName;
1286 break;
1287 case DB_DATA_TYPE_FLOAT:
1288 typeNameAndSize = pDb->GetTypeInfFloat().TypeName;
1289 break;
1290 case DB_DATA_TYPE_DATE:
1291 typeNameAndSize = pDb->GetTypeInfDate().TypeName;
1292 break;
1293 }
1294
1295 // For varchars, append the size of the string
1296 if (colDefs[j].DbDataType == DB_DATA_TYPE_VARCHAR)
1297 {
1298 wxString s;
1299 s.sprintf("(%d)", colDefs[i].SzDataObj);
1300 typeNameAndSize += s.c_str();
1301 }
1302
1303 sqlStmt.sprintf("ALTER TABLE %s MODIFY %s %s NOT NULL",tableName,pIdxDefs[i].ColName,typeNameAndSize.c_str());
1304 ok = pDb->ExecSql(sqlStmt.c_str());
1305
1306 if (!ok)
1307 {
1308 wxODBC_ERRORS retcode;
1309 // Oracle returns a DB_ERR_GENERAL_ERROR if the column is already
1310 // defined to be NOT NULL, but reportedly MySQL doesn't mind.
1311 // This line is just here for debug checking of the value
1312 retcode = (wxODBC_ERRORS)pDb->DB_STATUS;
1313 }
1314 }
1315 else
1316 ok = FALSE;
1317 }
1318 if (ok)
1319 pDb->CommitTrans();
1320 else
1321 {
1322 pDb->RollbackTrans();
1323 return(FALSE);
1324 }
1325 }
1326
89894079 1327 // Build a CREATE INDEX statement
1e92909e 1328 sqlStmt = "CREATE ";
89894079 1329 if (unique)
1e92909e 1330 sqlStmt += "UNIQUE ";
3ca6a5f0 1331
1e92909e
GT
1332 sqlStmt += "INDEX ";
1333 sqlStmt += idxName;
1334 sqlStmt += " ON ";
1335 sqlStmt += tableName;
1336 sqlStmt += " (";
3ca6a5f0 1337
89894079
VZ
1338 // Append list of columns making up index
1339 int i;
1340 for (i = 0; i < noIdxCols; i++)
1341 {
1e92909e
GT
1342 sqlStmt += pIdxDefs[i].ColName;
1343 /* Postgres doesn't cope with ASC */
89894079
VZ
1344 if (pDb->Dbms() != dbmsPOSTGRES)
1345 {
1346 if (pIdxDefs[i].Ascending)
1e92909e 1347 sqlStmt += " ASC";
89894079 1348 else
1e92909e 1349 sqlStmt += " DESC";
89894079
VZ
1350 }
1351
1352 if ((i + 1) < noIdxCols)
1e92909e 1353 sqlStmt += ",";
89894079
VZ
1354 }
1355
1356 // Append closing parentheses
1e92909e 1357 sqlStmt += ")";
89894079 1358
f6bcfd97 1359 pDb->WriteSqlLog(sqlStmt.c_str());
1fc5dd6f 1360
a2115c88 1361#ifdef DBDEBUG_CONSOLE
f6bcfd97 1362 cout << endl << sqlStmt.c_str() << endl << endl;
108106cf
JS
1363#endif
1364
89894079 1365 // Execute the CREATE INDEX statement
f6bcfd97 1366 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
89894079
VZ
1367 {
1368 pDb->DispAllErrors(henv, hdbc, hstmt);
1369 pDb->RollbackTrans();
1370 CloseCursor(hstmt);
1371 return(FALSE);
1372 }
108106cf 1373
89894079
VZ
1374 // Commit the transaction and close the cursor
1375 if (! pDb->CommitTrans())
1376 return(FALSE);
1377 if (! CloseCursor(hstmt))
1378 return(FALSE);
108106cf 1379
89894079
VZ
1380 // Index Created Successfully
1381 return(TRUE);
108106cf 1382
f6bcfd97 1383} // wxDbTable::CreateIndex()
108106cf 1384
67e9aaa3 1385
f6bcfd97
BP
1386/********** wxDbTable::DropIndex() **********/
1387bool wxDbTable::DropIndex(const char * idxName)
a2115c88 1388{
89894079
VZ
1389 // NOTE: This function returns TRUE if the Index does not exist, but
1390 // only for identified databases. Code will need to be added
1391 // below for any other databases when those databases are defined
1392 // to handle this situation consistently
a2115c88 1393
1e92909e 1394 wxString sqlStmt;
a2115c88 1395
3ca6a5f0 1396 if (pDb->Dbms() == dbmsACCESS || pDb->Dbms() == dbmsMY_SQL)
1e92909e 1397 sqlStmt.sprintf("DROP INDEX %s ON %s",idxName,tableName);
e93a3a18
GT
1398 else if ((pDb->Dbms() == dbmsMS_SQL_SERVER) ||
1399 (pDb->Dbms() == dbmsSYBASE_ASE))
1e92909e 1400 sqlStmt.sprintf("DROP INDEX %s.%s",tableName,idxName);
89894079 1401 else
1e92909e 1402 sqlStmt.sprintf("DROP INDEX %s",idxName);
a2115c88 1403
f6bcfd97 1404 pDb->WriteSqlLog(sqlStmt.c_str());
a2115c88
GT
1405
1406#ifdef DBDEBUG_CONSOLE
f6bcfd97 1407 cout << endl << sqlStmt.c_str() << endl;
a2115c88
GT
1408#endif
1409
f6bcfd97 1410 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
89894079
VZ
1411 {
1412 // Check for "Index not found" error and ignore
1413 pDb->GetNextError(henv, hdbc, hstmt);
1414 if (wxStrcmp(pDb->sqlState,"S0012")) // "Index not found"
1415 {
1416 // Check for product specific error codes
3ca6a5f0
BP
1417 if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,"42000")) || // v5.x (and lower?)
1418 (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"37000")) ||
1419 (pDb->Dbms() == dbmsMS_SQL_SERVER && !wxStrcmp(pDb->sqlState,"S1000")) ||
1420 (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,"S0002")) || // Base table not found
1421 (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,"42S12")) || // tested by Christopher Ludwik Marino-Cebulski using v3.23.21beta
1422 (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,"08S01"))
1423 ))
89894079
VZ
1424 {
1425 pDb->DispNextError();
1426 pDb->DispAllErrors(henv, hdbc, hstmt);
1427 pDb->RollbackTrans();
1428 CloseCursor(hstmt);
1429 return(FALSE);
1430 }
1431 }
1432 }
1433
1434 // Commit the transaction and close the cursor
1435 if (! pDb->CommitTrans())
1436 return(FALSE);
1437 if (! CloseCursor(hstmt))
1438 return(FALSE);
1439
1440 return(TRUE);
f6bcfd97 1441} // wxDbTable::DropIndex()
a2115c88 1442
67e9aaa3 1443
38cfbffa
GT
1444/********** wxDbTable::SetOrderByColNums() **********/
1445bool wxDbTable::SetOrderByColNums(int first, ... )
1446{
1447 int colNo = first;
1448 va_list argptr;
1449
1450 bool abort = FALSE;
1451 wxString tempStr;
1452
1453 va_start(argptr, first); /* Initialize variable arguments. */
1454 while (!abort && (colNo != wxDB_NO_MORE_COLUMN_NUMBERS))
1455 {
1456 // Make sure the passed in column number
1457 // is within the valid range of columns
1458 //
1459 // Valid columns are 0 thru noCols-1
1460 if (colNo >= noCols || colNo < 0)
1461 {
1462 abort = TRUE;
1463 continue;
1464 }
1465
1466 if (colNo != first)
1467 tempStr += ",";
1468
1469 tempStr += colDefs[colNo].ColName;
1470 colNo = va_arg (argptr, int);
1471 }
1472 va_end (argptr); /* Reset variable arguments. */
1473
1474 SetOrderByClause(tempStr.c_str());
1475
1476 return (!abort);
1477} // wxDbTable::SetOrderByColNums()
1478
1479
f6bcfd97
BP
1480/********** wxDbTable::Insert() **********/
1481int wxDbTable::Insert(void)
108106cf 1482{
89894079 1483 assert(!queryOnly);
f6bcfd97 1484 if (queryOnly || !insertable)
89894079
VZ
1485 return(DB_FAILURE);
1486
1487 bindInsertParams();
1488
1489 // Insert the record by executing the already prepared insert statement
1490 RETCODE retcode;
1491 retcode=SQLExecute(hstmtInsert);
1492 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
1493 {
1494 // Check to see if integrity constraint was violated
1495 pDb->GetNextError(henv, hdbc, hstmtInsert);
1496 if (! wxStrcmp(pDb->sqlState, "23000")) // Integrity constraint violated
1497 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL);
1498 else
1499 {
1500 pDb->DispNextError();
1501 pDb->DispAllErrors(henv, hdbc, hstmtInsert);
1502 return(DB_FAILURE);
1503 }
1504 }
1505
1506 // Record inserted into the datasource successfully
1507 return(DB_SUCCESS);
108106cf 1508
f6bcfd97 1509} // wxDbTable::Insert()
108106cf 1510
67e9aaa3 1511
f6bcfd97
BP
1512/********** wxDbTable::Update() **********/
1513bool wxDbTable::Update(void)
108106cf 1514{
89894079
VZ
1515 assert(!queryOnly);
1516 if (queryOnly)
1517 return(FALSE);
a2115c88 1518
89894079 1519 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1520
89894079 1521 // Build the SQL UPDATE statement
f6bcfd97 1522 BuildUpdateStmt(sqlStmt, DB_UPD_KEYFIELDS);
108106cf 1523
89894079 1524 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1525
a2115c88 1526#ifdef DBDEBUG_CONSOLE
0b8410f3 1527 cout << endl << sqlStmt << endl << endl;
108106cf
JS
1528#endif
1529
89894079
VZ
1530 // Execute the SQL UPDATE statement
1531 return(execUpdate(sqlStmt));
108106cf 1532
f6bcfd97 1533} // wxDbTable::Update()
108106cf 1534
67e9aaa3 1535
f6bcfd97
BP
1536/********** wxDbTable::Update(pSqlStmt) **********/
1537bool wxDbTable::Update(const char *pSqlStmt)
6919c53f 1538{
89894079
VZ
1539 assert(!queryOnly);
1540 if (queryOnly)
1541 return(FALSE);
6919c53f 1542
89894079 1543 pDb->WriteSqlLog(pSqlStmt);
6919c53f 1544
89894079 1545 return(execUpdate(pSqlStmt));
6919c53f 1546
f6bcfd97 1547} // wxDbTable::Update(pSqlStmt)
6919c53f 1548
67e9aaa3 1549
f6bcfd97
BP
1550/********** wxDbTable::UpdateWhere() **********/
1551bool wxDbTable::UpdateWhere(const char *pWhereClause)
108106cf 1552{
89894079
VZ
1553 assert(!queryOnly);
1554 if (queryOnly)
1555 return(FALSE);
a2115c88 1556
89894079 1557 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1558
89894079 1559 // Build the SQL UPDATE statement
f6bcfd97 1560 BuildUpdateStmt(sqlStmt, DB_UPD_WHERE, pWhereClause);
108106cf 1561
89894079 1562 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1563
a2115c88 1564#ifdef DBDEBUG_CONSOLE
0b8410f3 1565 cout << endl << sqlStmt << endl << endl;
108106cf
JS
1566#endif
1567
89894079
VZ
1568 // Execute the SQL UPDATE statement
1569 return(execUpdate(sqlStmt));
108106cf 1570
f6bcfd97 1571} // wxDbTable::UpdateWhere()
108106cf 1572
67e9aaa3 1573
f6bcfd97
BP
1574/********** wxDbTable::Delete() **********/
1575bool wxDbTable::Delete(void)
108106cf 1576{
89894079
VZ
1577 assert(!queryOnly);
1578 if (queryOnly)
1579 return(FALSE);
a2115c88 1580
89894079 1581 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1582
89894079 1583 // Build the SQL DELETE statement
f6bcfd97 1584 BuildDeleteStmt(sqlStmt, DB_DEL_KEYFIELDS);
108106cf 1585
89894079 1586 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1587
89894079
VZ
1588 // Execute the SQL DELETE statement
1589 return(execDelete(sqlStmt));
108106cf 1590
f6bcfd97 1591} // wxDbTable::Delete()
108106cf 1592
67e9aaa3 1593
f6bcfd97
BP
1594/********** wxDbTable::DeleteWhere() **********/
1595bool wxDbTable::DeleteWhere(const char *pWhereClause)
108106cf 1596{
89894079
VZ
1597 assert(!queryOnly);
1598 if (queryOnly)
1599 return(FALSE);
a2115c88 1600
89894079 1601 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1602
89894079 1603 // Build the SQL DELETE statement
f6bcfd97 1604 BuildDeleteStmt(sqlStmt, DB_DEL_WHERE, pWhereClause);
108106cf 1605
89894079 1606 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1607
89894079
VZ
1608 // Execute the SQL DELETE statement
1609 return(execDelete(sqlStmt));
108106cf 1610
f6bcfd97 1611} // wxDbTable::DeleteWhere()
108106cf 1612
67e9aaa3 1613
f6bcfd97
BP
1614/********** wxDbTable::DeleteMatching() **********/
1615bool wxDbTable::DeleteMatching(void)
108106cf 1616{
89894079
VZ
1617 assert(!queryOnly);
1618 if (queryOnly)
1619 return(FALSE);
a2115c88 1620
89894079 1621 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1622
89894079 1623 // Build the SQL DELETE statement
f6bcfd97 1624 BuildDeleteStmt(sqlStmt, DB_DEL_MATCHING);
108106cf 1625
89894079 1626 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1627
89894079
VZ
1628 // Execute the SQL DELETE statement
1629 return(execDelete(sqlStmt));
108106cf 1630
f6bcfd97 1631} // wxDbTable::DeleteMatching()
108106cf 1632
67e9aaa3 1633
f6bcfd97
BP
1634/********** wxDbTable::BuildUpdateStmt() **********/
1635void wxDbTable::BuildUpdateStmt(char *pSqlStmt, int typeOfUpd, const char *pWhereClause)
108106cf 1636{
89894079
VZ
1637 assert(!queryOnly);
1638 if (queryOnly)
1639 return;
1640
1641 char whereClause[DB_MAX_WHERE_CLAUSE_LEN];
1642 bool firstColumn = TRUE;
1643
1644 whereClause[0] = 0;
1645 sprintf(pSqlStmt, "UPDATE %s SET ", tableName);
1646
1647 // Append a list of columns to be updated
1648 int i;
1649 for (i = 0; i < noCols; i++)
1650 {
1651 // Only append Updateable columns
1652 if (colDefs[i].Updateable)
1653 {
1654 if (! firstColumn)
1655 wxStrcat(pSqlStmt, ",");
1656 else
1657 firstColumn = FALSE;
1658 wxStrcat(pSqlStmt, colDefs[i].ColName);
1659 wxStrcat(pSqlStmt, " = ?");
1660 }
1661 }
1662
1663 // Append the WHERE clause to the SQL UPDATE statement
1664 wxStrcat(pSqlStmt, " WHERE ");
1665 switch(typeOfUpd)
1666 {
3ca6a5f0
BP
1667 case DB_UPD_KEYFIELDS:
1668 // If the datasource supports the ROWID column, build
1669 // the where on ROWID for efficiency purposes.
1670 // e.g. UPDATE PARTS SET Col1 = ?, Col2 = ? WHERE ROWID = '111.222.333'
1671 if (CanUpdByROWID())
89894079 1672 {
3ca6a5f0
BP
1673 SDWORD cb;
1674 char rowid[wxDB_ROWID_LEN];
1675
1676 // Get the ROWID value. If not successful retreiving the ROWID,
1677 // simply fall down through the code and build the WHERE clause
1678 // based on the key fields.
1679 if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS)
1680 {
1681 wxStrcat(pSqlStmt, "ROWID = '");
1682 wxStrcat(pSqlStmt, rowid);
1683 wxStrcat(pSqlStmt, "'");
1684 break;
1685 }
89894079 1686 }
3ca6a5f0
BP
1687 // Unable to delete by ROWID, so build a WHERE
1688 // clause based on the keyfields.
1689 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
1690 wxStrcat(pSqlStmt, whereClause);
1691 break;
1692 case DB_UPD_WHERE:
1693 wxStrcat(pSqlStmt, pWhereClause);
1694 break;
89894079 1695 }
f6bcfd97 1696} // BuildUpdateStmt()
108106cf 1697
67e9aaa3 1698
f6bcfd97
BP
1699/********** wxDbTable::BuildDeleteStmt() **********/
1700void wxDbTable::BuildDeleteStmt(char *pSqlStmt, int typeOfDel, const char *pWhereClause)
108106cf 1701{
89894079
VZ
1702 assert(!queryOnly);
1703 if (queryOnly)
1704 return;
1705
1706 char whereClause[DB_MAX_WHERE_CLAUSE_LEN];
1707
1708 whereClause[0] = 0;
1709
1710 // Handle the case of DeleteWhere() and the where clause is blank. It should
1711 // delete all records from the database in this case.
1712 if (typeOfDel == DB_DEL_WHERE && (pWhereClause == 0 || wxStrlen(pWhereClause) == 0))
1713 {
1714 sprintf(pSqlStmt, "DELETE FROM %s", tableName);
1715 return;
1716 }
1717
1718 sprintf(pSqlStmt, "DELETE FROM %s WHERE ", tableName);
1719
1720 // Append the WHERE clause to the SQL DELETE statement
1721 switch(typeOfDel)
1722 {
3ca6a5f0
BP
1723 case DB_DEL_KEYFIELDS:
1724 // If the datasource supports the ROWID column, build
1725 // the where on ROWID for efficiency purposes.
1726 // e.g. DELETE FROM PARTS WHERE ROWID = '111.222.333'
1727 if (CanUpdByROWID())
89894079 1728 {
3ca6a5f0
BP
1729 SDWORD cb;
1730 char rowid[wxDB_ROWID_LEN];
1731
1732 // Get the ROWID value. If not successful retreiving the ROWID,
1733 // simply fall down through the code and build the WHERE clause
1734 // based on the key fields.
1735 if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS)
1736 {
1737 wxStrcat(pSqlStmt, "ROWID = '");
1738 wxStrcat(pSqlStmt, rowid);
1739 wxStrcat(pSqlStmt, "'");
1740 break;
1741 }
89894079 1742 }
3ca6a5f0
BP
1743 // Unable to delete by ROWID, so build a WHERE
1744 // clause based on the keyfields.
1745 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
1746 wxStrcat(pSqlStmt, whereClause);
1747 break;
1748 case DB_DEL_WHERE:
1749 wxStrcat(pSqlStmt, pWhereClause);
1750 break;
1751 case DB_DEL_MATCHING:
1752 BuildWhereClause(whereClause, DB_WHERE_MATCHING);
1753 wxStrcat(pSqlStmt, whereClause);
1754 break;
89894079 1755 }
108106cf 1756
f6bcfd97 1757} // BuildDeleteStmt()
108106cf 1758
67e9aaa3 1759
f6bcfd97
BP
1760/********** wxDbTable::BuildWhereClause() **********/
1761void wxDbTable::BuildWhereClause(char *pWhereClause, int typeOfWhere,
1762 const char *qualTableName, bool useLikeComparison)
108106cf 1763/*
f6bcfd97 1764 * Note: BuildWhereClause() currently ignores timestamp columns.
108106cf
JS
1765 * They are not included as part of the where clause.
1766 */
108106cf 1767{
89894079
VZ
1768 bool moreThanOneColumn = FALSE;
1769 char colValue[255];
1770
1771 // Loop through the columns building a where clause as you go
1772 int i;
1773 for (i = 0; i < noCols; i++)
1774 {
1775 // Determine if this column should be included in the WHERE clause
1776 if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[i].KeyField) ||
f02d4a64 1777 (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull(i))))
89894079
VZ
1778 {
1779 // Skip over timestamp columns
1780 if (colDefs[i].SqlCtype == SQL_C_TIMESTAMP)
1781 continue;
1782 // If there is more than 1 column, join them with the keyword "AND"
1783 if (moreThanOneColumn)
1784 wxStrcat(pWhereClause, " AND ");
1785 else
1786 moreThanOneColumn = TRUE;
1787 // Concatenate where phrase for the column
1788 if (qualTableName && wxStrlen(qualTableName))
1789 {
1790 wxStrcat(pWhereClause, qualTableName);
1791 wxStrcat(pWhereClause, ".");
1792 }
1793 wxStrcat(pWhereClause, colDefs[i].ColName);
8128349e
GT
1794 if (useLikeComparison && (colDefs[i].SqlCtype == SQL_C_CHAR))
1795 wxStrcat(pWhereClause, " LIKE ");
1796 else
1797 wxStrcat(pWhereClause, " = ");
89894079
VZ
1798 switch(colDefs[i].SqlCtype)
1799 {
3ca6a5f0
BP
1800 case SQL_C_CHAR:
1801 sprintf(colValue, "'%s'", (UCHAR FAR *) colDefs[i].PtrDataObj);
1802 break;
1803 case SQL_C_SSHORT:
1804 sprintf(colValue, "%hi", *((SWORD *) colDefs[i].PtrDataObj));
1805 break;
1806 case SQL_C_USHORT:
1807 sprintf(colValue, "%hu", *((UWORD *) colDefs[i].PtrDataObj));
1808 break;
1809 case SQL_C_SLONG:
1810 sprintf(colValue, "%li", *((SDWORD *) colDefs[i].PtrDataObj));
1811 break;
1812 case SQL_C_ULONG:
1813 sprintf(colValue, "%lu", *((UDWORD *) colDefs[i].PtrDataObj));
1814 break;
1815 case SQL_C_FLOAT:
1816 sprintf(colValue, "%.6f", *((SFLOAT *) colDefs[i].PtrDataObj));
1817 break;
1818 case SQL_C_DOUBLE:
1819 sprintf(colValue, "%.6f", *((SDOUBLE *) colDefs[i].PtrDataObj));
1820 break;
89894079
VZ
1821 }
1822 wxStrcat(pWhereClause, colValue);
1823 }
1824 }
f6bcfd97 1825} // wxDbTable::BuildWhereClause()
108106cf 1826
67e9aaa3 1827
f6bcfd97
BP
1828/********** wxDbTable::IsColNull() **********/
1829bool wxDbTable::IsColNull(int colNo)
108106cf 1830{
f02d4a64
GT
1831/*
1832 This logic is just not right. It would indicate TRUE
1833 if a numeric field were set to a value of 0.
1834
89894079
VZ
1835 switch(colDefs[colNo].SqlCtype)
1836 {
3ca6a5f0
BP
1837 case SQL_C_CHAR:
1838 return(((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] == 0);
1839 case SQL_C_SSHORT:
1840 return(( *((SWORD *) colDefs[colNo].PtrDataObj)) == 0);
1841 case SQL_C_USHORT:
1842 return(( *((UWORD*) colDefs[colNo].PtrDataObj)) == 0);
1843 case SQL_C_SLONG:
1844 return(( *((SDWORD *) colDefs[colNo].PtrDataObj)) == 0);
1845 case SQL_C_ULONG:
1846 return(( *((UDWORD *) colDefs[colNo].PtrDataObj)) == 0);
1847 case SQL_C_FLOAT:
1848 return(( *((SFLOAT *) colDefs[colNo].PtrDataObj)) == 0);
1849 case SQL_C_DOUBLE:
1850 return((*((SDOUBLE *) colDefs[colNo].PtrDataObj)) == 0);
1851 case SQL_C_TIMESTAMP:
1852 TIMESTAMP_STRUCT *pDt;
1853 pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj;
1854 if (pDt->year == 0 && pDt->month == 0 && pDt->day == 0)
1855 return(TRUE);
1856 else
1857 return(FALSE);
1858 default:
89894079 1859 return(TRUE);
89894079 1860 }
f02d4a64
GT
1861*/
1862 return (colDefs[colNo].Null);
f6bcfd97 1863} // wxDbTable::IsColNull()
108106cf 1864
67e9aaa3 1865
f6bcfd97
BP
1866/********** wxDbTable::CanSelectForUpdate() **********/
1867bool wxDbTable::CanSelectForUpdate(void)
108106cf 1868{
38cfbffa
GT
1869 if (queryOnly)
1870 return FALSE;
1871
89894079
VZ
1872 if (pDb->Dbms() == dbmsMY_SQL)
1873 return FALSE;
a2115c88 1874
e93a3a18
GT
1875 if ((pDb->Dbms() == dbmsORACLE) ||
1876 (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE))
89894079
VZ
1877 return(TRUE);
1878 else
1879 return(FALSE);
108106cf 1880
f6bcfd97 1881} // wxDbTable::CanSelectForUpdate()
108106cf 1882
67e9aaa3 1883
f6bcfd97
BP
1884/********** wxDbTable::CanUpdByROWID() **********/
1885bool wxDbTable::CanUpdByROWID(void)
108106cf 1886{
67e9aaa3
GT
1887/*
1888 * NOTE: Returning FALSE for now until this can be debugged,
89894079 1889 * as the ROWID is not getting updated correctly
67e9aaa3 1890 */
89894079 1891 return FALSE;
108106cf 1892
89894079
VZ
1893 if (pDb->Dbms() == dbmsORACLE)
1894 return(TRUE);
1895 else
1896 return(FALSE);
108106cf 1897
f6bcfd97 1898} // wxDbTable::CanUpdByROWID()
108106cf 1899
67e9aaa3 1900
f6bcfd97
BP
1901/********** wxDbTable::IsCursorClosedOnCommit() **********/
1902bool wxDbTable::IsCursorClosedOnCommit(void)
108106cf 1903{
89894079
VZ
1904 if (pDb->dbInf.cursorCommitBehavior == SQL_CB_PRESERVE)
1905 return(FALSE);
1906 else
1907 return(TRUE);
108106cf 1908
f6bcfd97 1909} // wxDbTable::IsCursorClosedOnCommit()
108106cf 1910
67e9aaa3 1911
f02d4a64
GT
1912
1913/********** wxDbTable::ClearMemberVar() **********/
1914void wxDbTable::ClearMemberVar(int colNo, bool setToNull)
108106cf 1915{
f02d4a64
GT
1916 assert(colNo < noCols);
1917
1918 switch(colDefs[colNo].SqlCtype)
89894079 1919 {
f02d4a64
GT
1920 case SQL_C_CHAR:
1921 ((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] = 0;
1922 break;
1923 case SQL_C_SSHORT:
1924 *((SWORD *) colDefs[colNo].PtrDataObj) = 0;
1925 break;
1926 case SQL_C_USHORT:
1927 *((UWORD*) colDefs[colNo].PtrDataObj) = 0;
1928 break;
1929 case SQL_C_SLONG:
1930 *((SDWORD *) colDefs[colNo].PtrDataObj) = 0;
1931 break;
1932 case SQL_C_ULONG:
1933 *((UDWORD *) colDefs[colNo].PtrDataObj) = 0;
1934 break;
1935 case SQL_C_FLOAT:
1936 *((SFLOAT *) colDefs[colNo].PtrDataObj) = 0.0f;
1937 break;
1938 case SQL_C_DOUBLE:
1939 *((SDOUBLE *) colDefs[colNo].PtrDataObj) = 0.0f;
1940 break;
1941 case SQL_C_TIMESTAMP:
1942 TIMESTAMP_STRUCT *pDt;
1943 pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj;
1944 pDt->year = 0;
1945 pDt->month = 0;
1946 pDt->day = 0;
1947 pDt->hour = 0;
1948 pDt->minute = 0;
1949 pDt->second = 0;
1950 pDt->fraction = 0;
1951 break;
89894079 1952 }
108106cf 1953
f02d4a64
GT
1954 if (setToNull)
1955 SetColNull(colNo);
1956} // wxDbTable::ClearMemberVar()
1957
1958
1959/********** wxDbTable::ClearMemberVars() **********/
1960void wxDbTable::ClearMemberVars(bool setToNull)
1961{
1962 int i;
1963
1964 // Loop through the columns setting each member variable to zero
1965 for (i=0; i < noCols; i++)
1966 ClearMemberVar(i,setToNull);
1967
f6bcfd97 1968} // wxDbTable::ClearMemberVars()
108106cf 1969
67e9aaa3 1970
f6bcfd97
BP
1971/********** wxDbTable::SetQueryTimeout() **********/
1972bool wxDbTable::SetQueryTimeout(UDWORD nSeconds)
108106cf 1973{
89894079
VZ
1974 if (SQLSetStmtOption(hstmtInsert, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1975 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
1976 if (SQLSetStmtOption(hstmtUpdate, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1977 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
1978 if (SQLSetStmtOption(hstmtDelete, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1979 return(pDb->DispAllErrors(henv, hdbc, hstmtDelete));
1980 if (SQLSetStmtOption(hstmtInternal, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1981 return(pDb->DispAllErrors(henv, hdbc, hstmtInternal));
1982
1983 // Completed Successfully
1984 return(TRUE);
108106cf 1985
f6bcfd97 1986} // wxDbTable::SetQueryTimeout()
108106cf 1987
67e9aaa3 1988
f6bcfd97 1989/********** wxDbTable::SetColDefs() **********/
e93a3a18
GT
1990void wxDbTable::SetColDefs(int index, const char *fieldName, int dataType, void *pData,
1991 int cType, int size, bool keyField, bool upd,
1992 bool insAllow, bool derivedCol)
108106cf 1993{
89894079
VZ
1994 if (!colDefs) // May happen if the database connection fails
1995 return;
1996
1997 if (wxStrlen(fieldName) > (unsigned int) DB_MAX_COLUMN_NAME_LEN)
1998 {
1999 wxStrncpy (colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN);
2000 colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0;
2001 }
2002 else
2003 wxStrcpy(colDefs[index].ColName, fieldName);
2004
2005 colDefs[index].DbDataType = dataType;
2006 colDefs[index].PtrDataObj = pData;
2007 colDefs[index].SqlCtype = cType;
2008 colDefs[index].SzDataObj = size;
2009 colDefs[index].KeyField = keyField;
2010 colDefs[index].DerivedCol = derivedCol;
2011 // Derived columns by definition would NOT be "Insertable" or "Updateable"
2012 if (derivedCol)
2013 {
2014 colDefs[index].Updateable = FALSE;
2015 colDefs[index].InsertAllowed = FALSE;
2016 }
2017 else
2018 {
2019 colDefs[index].Updateable = upd;
2020 colDefs[index].InsertAllowed = insAllow;
2021 }
2022
2023 colDefs[index].Null = FALSE;
2024
f6bcfd97 2025} // wxDbTable::SetColDefs()
108106cf 2026
67e9aaa3 2027
e93a3a18
GT
2028/********** wxDbTable::SetColDefs() **********/
2029wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, ULONG numCols)
67e9aaa3 2030{
89894079 2031 assert(pColInfs);
f6bcfd97 2032 wxDbColDataPtr *pColDataPtrs = NULL;
67e9aaa3 2033
89894079
VZ
2034 if (pColInfs)
2035 {
2036 ULONG index;
1b7274a8 2037
f6bcfd97 2038 pColDataPtrs = new wxDbColDataPtr[numCols+1];
67e9aaa3
GT
2039
2040 for (index = 0; index < numCols; index++)
89894079 2041 {
89894079
VZ
2042 // Process the fields
2043 switch (pColInfs[index].dbDataType)
2044 {
2045 case DB_DATA_TYPE_VARCHAR:
0b8410f3
GT
2046 pColDataPtrs[index].PtrDataObj = new char[pColInfs[index].bufferLength+1];
2047 pColDataPtrs[index].SzDataObj = pColInfs[index].columnSize;
2048 pColDataPtrs[index].SqlCtype = SQL_C_CHAR;
2049 break;
89894079 2050 case DB_DATA_TYPE_INTEGER:
67e9aaa3 2051 // Can be long or short
89894079
VZ
2052 if (pColInfs[index].bufferLength == sizeof(long))
2053 {
2054 pColDataPtrs[index].PtrDataObj = new long;
2055 pColDataPtrs[index].SzDataObj = sizeof(long);
2056 pColDataPtrs[index].SqlCtype = SQL_C_SLONG;
2057 }
2058 else
2059 {
2060 pColDataPtrs[index].PtrDataObj = new short;
2061 pColDataPtrs[index].SzDataObj = sizeof(short);
2062 pColDataPtrs[index].SqlCtype = SQL_C_SSHORT;
2063 }
2064 break;
89894079 2065 case DB_DATA_TYPE_FLOAT:
89894079
VZ
2066 // Can be float or double
2067 if (pColInfs[index].bufferLength == sizeof(float))
2068 {
2069 pColDataPtrs[index].PtrDataObj = new float;
2070 pColDataPtrs[index].SzDataObj = sizeof(float);
2071 pColDataPtrs[index].SqlCtype = SQL_C_FLOAT;
2072 }
2073 else
2074 {
2075 pColDataPtrs[index].PtrDataObj = new double;
2076 pColDataPtrs[index].SzDataObj = sizeof(double);
2077 pColDataPtrs[index].SqlCtype = SQL_C_DOUBLE;
2078 }
2079 break;
89894079 2080 case DB_DATA_TYPE_DATE:
89894079
VZ
2081 pColDataPtrs[index].PtrDataObj = new TIMESTAMP_STRUCT;
2082 pColDataPtrs[index].SzDataObj = sizeof(TIMESTAMP_STRUCT);
2083 pColDataPtrs[index].SqlCtype = SQL_C_TIMESTAMP;
2084 break;
89894079 2085 }
3ca6a5f0 2086 SetColDefs (index,pColInfs[index].colName,pColInfs[index].dbDataType, pColDataPtrs[index].PtrDataObj, pColDataPtrs[index].SqlCtype, pColDataPtrs[index].SzDataObj);
89894079
VZ
2087 }
2088 }
3ca6a5f0 2089
89894079 2090 return (pColDataPtrs);
3ca6a5f0 2091
e93a3a18 2092} // wxDbTable::SetColDefs()
67e9aaa3
GT
2093
2094
f6bcfd97
BP
2095/********** wxDbTable::SetCursor() **********/
2096void wxDbTable::SetCursor(HSTMT *hstmtActivate)
108106cf 2097{
f6bcfd97 2098 if (hstmtActivate == wxDB_DEFAULT_CURSOR)
89894079
VZ
2099 hstmt = *hstmtDefault;
2100 else
2101 hstmt = *hstmtActivate;
108106cf 2102
f6bcfd97 2103} // wxDbTable::SetCursor()
108106cf 2104
67e9aaa3 2105
f6bcfd97
BP
2106/********** wxDbTable::Count(const char *) **********/
2107ULONG wxDbTable::Count(const char *args)
108106cf 2108{
3ca6a5f0 2109 ULONG count;
1e92909e 2110 wxString sqlStmt;
89894079
VZ
2111 SDWORD cb;
2112
2113 // Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement
1e92909e
GT
2114 sqlStmt = "SELECT COUNT(";
2115 sqlStmt += args;
2116 sqlStmt += ") FROM ";
2117 sqlStmt += queryTableName;
f6bcfd97 2118#if wxODBC_BACKWARD_COMPATABILITY
89894079 2119 if (from && wxStrlen(from))
f6bcfd97
BP
2120#else
2121 if (from.Length())
2122#endif
1e92909e 2123 sqlStmt += from;
89894079
VZ
2124
2125 // Add the where clause if one is provided
f6bcfd97 2126#if wxODBC_BACKWARD_COMPATABILITY
89894079 2127 if (where && wxStrlen(where))
f6bcfd97
BP
2128#else
2129 if (where.Length())
2130#endif
89894079 2131 {
1e92909e
GT
2132 sqlStmt += " WHERE ";
2133 sqlStmt += where;
89894079
VZ
2134 }
2135
f6bcfd97 2136 pDb->WriteSqlLog(sqlStmt.c_str());
89894079
VZ
2137
2138 // Initialize the Count cursor if it's not already initialized
2139 if (!hstmtCount)
2140 {
f6bcfd97 2141 hstmtCount = GetNewCursor(FALSE,FALSE);
89894079
VZ
2142 assert(hstmtCount);
2143 if (!hstmtCount)
2144 return(0);
2145 }
2146
2147 // Execute the SQL statement
f6bcfd97 2148 if (SQLExecDirect(*hstmtCount, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
89894079
VZ
2149 {
2150 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2151 return(0);
2152 }
2153
2154 // Fetch the record
2155 if (SQLFetch(*hstmtCount) != SQL_SUCCESS)
2156 {
2157 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2158 return(0);
2159 }
2160
2161 // Obtain the result
3ca6a5f0 2162 if (SQLGetData(*hstmtCount, 1, SQL_C_ULONG, &count, sizeof(count), &cb) != SQL_SUCCESS)
89894079
VZ
2163 {
2164 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2165 return(0);
2166 }
2167
2168 // Free the cursor
2169 if (SQLFreeStmt(*hstmtCount, SQL_CLOSE) != SQL_SUCCESS)
2170 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2171
2172 // Return the record count
3ca6a5f0 2173 return(count);
108106cf 2174
f6bcfd97 2175} // wxDbTable::Count()
108106cf 2176
67e9aaa3 2177
f6bcfd97
BP
2178/********** wxDbTable::Refresh() **********/
2179bool wxDbTable::Refresh(void)
108106cf 2180{
89894079
VZ
2181 bool result = TRUE;
2182
2183 // Switch to the internal cursor so any active cursors are not corrupted
2184 HSTMT currCursor = GetCursor();
2185 hstmt = hstmtInternal;
f6bcfd97 2186#if wxODBC_BACKWARD_COMPATABILITY
89894079
VZ
2187 // Save the where and order by clauses
2188 char *saveWhere = where;
2189 char *saveOrderBy = orderBy;
f6bcfd97
BP
2190#else
2191 wxString saveWhere = where;
2192 wxString saveOrderBy = orderBy;
2193#endif
89894079
VZ
2194 // Build a where clause to refetch the record with. Try and use the
2195 // ROWID if it's available, ow use the key fields.
2196 char whereClause[DB_MAX_WHERE_CLAUSE_LEN+1];
2197 wxStrcpy(whereClause, "");
2198 if (CanUpdByROWID())
2199 {
2200 SDWORD cb;
f6bcfd97 2201 char rowid[wxDB_ROWID_LEN+1];
89894079
VZ
2202
2203 // Get the ROWID value. If not successful retreiving the ROWID,
2204 // simply fall down through the code and build the WHERE clause
2205 // based on the key fields.
f6bcfd97 2206 if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS)
89894079
VZ
2207 {
2208 wxStrcat(whereClause, queryTableName);
2209 wxStrcat(whereClause, ".ROWID = '");
2210 wxStrcat(whereClause, rowid);
2211 wxStrcat(whereClause, "'");
2212 }
2213 }
2214
2215 // If unable to use the ROWID, build a where clause from the keyfields
2216 if (wxStrlen(whereClause) == 0)
f6bcfd97 2217 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS, queryTableName);
89894079
VZ
2218
2219 // Requery the record
2220 where = whereClause;
f6bcfd97 2221 orderBy = "";
89894079
VZ
2222 if (!Query())
2223 result = FALSE;
2224
2225 if (result && !GetNext())
2226 result = FALSE;
2227
2228 // Switch back to original cursor
2229 SetCursor(&currCursor);
2230
2231 // Free the internal cursor
2232 if (SQLFreeStmt(hstmtInternal, SQL_CLOSE) != SQL_SUCCESS)
2233 pDb->DispAllErrors(henv, hdbc, hstmtInternal);
2234
2235 // Restore the original where and order by clauses
1e92909e 2236 where = saveWhere;
89894079
VZ
2237 orderBy = saveOrderBy;
2238
2239 return(result);
108106cf 2240
f6bcfd97 2241} // wxDbTable::Refresh()
108106cf 2242
67e9aaa3 2243
f02d4a64
GT
2244/********** wxDbTable::SetColNull(int colNo, bool set) **********/
2245bool wxDbTable::SetColNull(int colNo, bool set)
a2115c88 2246{
89894079 2247 if (colNo < noCols)
f02d4a64
GT
2248 {
2249 colDefs[colNo].Null = set;
2250 if (set) // Blank out the values in the member variable
2251 ClearMemberVar(colNo,FALSE); // Must call with FALSE, or infinite recursion will happen
2252 return(TRUE);
2253 }
89894079
VZ
2254 else
2255 return(FALSE);
a2115c88 2256
f02d4a64 2257} // wxDbTable::SetColNull(int colNo)
67e9aaa3 2258
a2115c88 2259
f02d4a64
GT
2260/********** wxDbTable::SetColNull(char *colName, bool set) **********/
2261bool wxDbTable::SetColNull(const char *colName, bool set)
a2115c88 2262{
89894079
VZ
2263 int i;
2264 for (i = 0; i < noCols; i++)
2265 {
2266 if (!wxStricmp(colName, colDefs[i].ColName))
2267 break;
2268 }
2269
2270 if (i < noCols)
f02d4a64
GT
2271 {
2272 colDefs[i].Null = set;
2273 if (set) // Blank out the values in the member variable
2274 ClearMemberVar(i,FALSE); // Must call with FALSE, or infinite recursion will happen
2275 return(TRUE);
2276 }
89894079
VZ
2277 else
2278 return(FALSE);
a2115c88 2279
f02d4a64 2280} // wxDbTable::SetColNull(char *colName)
a2115c88 2281
67e9aaa3 2282
f6bcfd97
BP
2283/********** wxDbTable::GetNewCursor() **********/
2284HSTMT *wxDbTable::GetNewCursor(bool setCursor, bool bindColumns)
a2115c88 2285{
89894079
VZ
2286 HSTMT *newHSTMT = new HSTMT;
2287 assert(newHSTMT);
2288 if (!newHSTMT)
2289 return(0);
2290
2291 if (SQLAllocStmt(hdbc, newHSTMT) != SQL_SUCCESS)
2292 {
2293 pDb->DispAllErrors(henv, hdbc);
2294 delete newHSTMT;
2295 return(0);
2296 }
2297
2298 if (SQLSetStmtOption(*newHSTMT, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
2299 {
2300 pDb->DispAllErrors(henv, hdbc, *newHSTMT);
2301 delete newHSTMT;
2302 return(0);
2303 }
2304
2305 if (bindColumns)
2306 {
2307 if(!bindCols(*newHSTMT))
2308 {
2309 delete newHSTMT;
2310 return(0);
2311 }
2312 }
2313
2314 if (setCursor)
2315 SetCursor(newHSTMT);
2316
2317 return(newHSTMT);
2318
f6bcfd97 2319} // wxDbTable::GetNewCursor()
67e9aaa3 2320
a2115c88 2321
f6bcfd97
BP
2322/********** wxDbTable::DeleteCursor() **********/
2323bool wxDbTable::DeleteCursor(HSTMT *hstmtDel)
a2115c88 2324{
89894079 2325 bool result = TRUE;
a2115c88 2326
89894079
VZ
2327 if (!hstmtDel) // Cursor already deleted
2328 return(result);
a2115c88 2329
89894079
VZ
2330 if (SQLFreeStmt(*hstmtDel, SQL_DROP) != SQL_SUCCESS)
2331 {
2332 pDb->DispAllErrors(henv, hdbc);
2333 result = FALSE;
2334 }
a2115c88 2335
89894079 2336 delete hstmtDel;
a2115c88 2337
89894079 2338 return(result);
a2115c88 2339
f6bcfd97 2340} // wxDbTable::DeleteCursor()
a2115c88
GT
2341
2342#endif // wxUSE_ODBC
1fc5dd6f 2343