]> git.saurik.com Git - wxWidgets.git/blame - src/common/dbtable.cpp
matrix compile fix
[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
f6bcfd97
BP
1444/********** wxDbTable::Insert() **********/
1445int wxDbTable::Insert(void)
108106cf 1446{
89894079 1447 assert(!queryOnly);
f6bcfd97 1448 if (queryOnly || !insertable)
89894079
VZ
1449 return(DB_FAILURE);
1450
1451 bindInsertParams();
1452
1453 // Insert the record by executing the already prepared insert statement
1454 RETCODE retcode;
1455 retcode=SQLExecute(hstmtInsert);
1456 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
1457 {
1458 // Check to see if integrity constraint was violated
1459 pDb->GetNextError(henv, hdbc, hstmtInsert);
1460 if (! wxStrcmp(pDb->sqlState, "23000")) // Integrity constraint violated
1461 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL);
1462 else
1463 {
1464 pDb->DispNextError();
1465 pDb->DispAllErrors(henv, hdbc, hstmtInsert);
1466 return(DB_FAILURE);
1467 }
1468 }
1469
1470 // Record inserted into the datasource successfully
1471 return(DB_SUCCESS);
108106cf 1472
f6bcfd97 1473} // wxDbTable::Insert()
108106cf 1474
67e9aaa3 1475
f6bcfd97
BP
1476/********** wxDbTable::Update() **********/
1477bool wxDbTable::Update(void)
108106cf 1478{
89894079
VZ
1479 assert(!queryOnly);
1480 if (queryOnly)
1481 return(FALSE);
a2115c88 1482
89894079 1483 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1484
89894079 1485 // Build the SQL UPDATE statement
f6bcfd97 1486 BuildUpdateStmt(sqlStmt, DB_UPD_KEYFIELDS);
108106cf 1487
89894079 1488 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1489
a2115c88 1490#ifdef DBDEBUG_CONSOLE
0b8410f3 1491 cout << endl << sqlStmt << endl << endl;
108106cf
JS
1492#endif
1493
89894079
VZ
1494 // Execute the SQL UPDATE statement
1495 return(execUpdate(sqlStmt));
108106cf 1496
f6bcfd97 1497} // wxDbTable::Update()
108106cf 1498
67e9aaa3 1499
f6bcfd97
BP
1500/********** wxDbTable::Update(pSqlStmt) **********/
1501bool wxDbTable::Update(const char *pSqlStmt)
6919c53f 1502{
89894079
VZ
1503 assert(!queryOnly);
1504 if (queryOnly)
1505 return(FALSE);
6919c53f 1506
89894079 1507 pDb->WriteSqlLog(pSqlStmt);
6919c53f 1508
89894079 1509 return(execUpdate(pSqlStmt));
6919c53f 1510
f6bcfd97 1511} // wxDbTable::Update(pSqlStmt)
6919c53f 1512
67e9aaa3 1513
f6bcfd97
BP
1514/********** wxDbTable::UpdateWhere() **********/
1515bool wxDbTable::UpdateWhere(const char *pWhereClause)
108106cf 1516{
89894079
VZ
1517 assert(!queryOnly);
1518 if (queryOnly)
1519 return(FALSE);
a2115c88 1520
89894079 1521 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1522
89894079 1523 // Build the SQL UPDATE statement
f6bcfd97 1524 BuildUpdateStmt(sqlStmt, DB_UPD_WHERE, pWhereClause);
108106cf 1525
89894079 1526 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1527
a2115c88 1528#ifdef DBDEBUG_CONSOLE
0b8410f3 1529 cout << endl << sqlStmt << endl << endl;
108106cf
JS
1530#endif
1531
89894079
VZ
1532 // Execute the SQL UPDATE statement
1533 return(execUpdate(sqlStmt));
108106cf 1534
f6bcfd97 1535} // wxDbTable::UpdateWhere()
108106cf 1536
67e9aaa3 1537
f6bcfd97
BP
1538/********** wxDbTable::Delete() **********/
1539bool wxDbTable::Delete(void)
108106cf 1540{
89894079
VZ
1541 assert(!queryOnly);
1542 if (queryOnly)
1543 return(FALSE);
a2115c88 1544
89894079 1545 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1546
89894079 1547 // Build the SQL DELETE statement
f6bcfd97 1548 BuildDeleteStmt(sqlStmt, DB_DEL_KEYFIELDS);
108106cf 1549
89894079 1550 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1551
89894079
VZ
1552 // Execute the SQL DELETE statement
1553 return(execDelete(sqlStmt));
108106cf 1554
f6bcfd97 1555} // wxDbTable::Delete()
108106cf 1556
67e9aaa3 1557
f6bcfd97
BP
1558/********** wxDbTable::DeleteWhere() **********/
1559bool wxDbTable::DeleteWhere(const char *pWhereClause)
108106cf 1560{
89894079
VZ
1561 assert(!queryOnly);
1562 if (queryOnly)
1563 return(FALSE);
a2115c88 1564
89894079 1565 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1566
89894079 1567 // Build the SQL DELETE statement
f6bcfd97 1568 BuildDeleteStmt(sqlStmt, DB_DEL_WHERE, pWhereClause);
108106cf 1569
89894079 1570 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1571
89894079
VZ
1572 // Execute the SQL DELETE statement
1573 return(execDelete(sqlStmt));
108106cf 1574
f6bcfd97 1575} // wxDbTable::DeleteWhere()
108106cf 1576
67e9aaa3 1577
f6bcfd97
BP
1578/********** wxDbTable::DeleteMatching() **********/
1579bool wxDbTable::DeleteMatching(void)
108106cf 1580{
89894079
VZ
1581 assert(!queryOnly);
1582 if (queryOnly)
1583 return(FALSE);
a2115c88 1584
89894079 1585 char sqlStmt[DB_MAX_STATEMENT_LEN];
108106cf 1586
89894079 1587 // Build the SQL DELETE statement
f6bcfd97 1588 BuildDeleteStmt(sqlStmt, DB_DEL_MATCHING);
108106cf 1589
89894079 1590 pDb->WriteSqlLog(sqlStmt);
1fc5dd6f 1591
89894079
VZ
1592 // Execute the SQL DELETE statement
1593 return(execDelete(sqlStmt));
108106cf 1594
f6bcfd97 1595} // wxDbTable::DeleteMatching()
108106cf 1596
67e9aaa3 1597
f6bcfd97
BP
1598/********** wxDbTable::BuildUpdateStmt() **********/
1599void wxDbTable::BuildUpdateStmt(char *pSqlStmt, int typeOfUpd, const char *pWhereClause)
108106cf 1600{
89894079
VZ
1601 assert(!queryOnly);
1602 if (queryOnly)
1603 return;
1604
1605 char whereClause[DB_MAX_WHERE_CLAUSE_LEN];
1606 bool firstColumn = TRUE;
1607
1608 whereClause[0] = 0;
1609 sprintf(pSqlStmt, "UPDATE %s SET ", tableName);
1610
1611 // Append a list of columns to be updated
1612 int i;
1613 for (i = 0; i < noCols; i++)
1614 {
1615 // Only append Updateable columns
1616 if (colDefs[i].Updateable)
1617 {
1618 if (! firstColumn)
1619 wxStrcat(pSqlStmt, ",");
1620 else
1621 firstColumn = FALSE;
1622 wxStrcat(pSqlStmt, colDefs[i].ColName);
1623 wxStrcat(pSqlStmt, " = ?");
1624 }
1625 }
1626
1627 // Append the WHERE clause to the SQL UPDATE statement
1628 wxStrcat(pSqlStmt, " WHERE ");
1629 switch(typeOfUpd)
1630 {
3ca6a5f0
BP
1631 case DB_UPD_KEYFIELDS:
1632 // If the datasource supports the ROWID column, build
1633 // the where on ROWID for efficiency purposes.
1634 // e.g. UPDATE PARTS SET Col1 = ?, Col2 = ? WHERE ROWID = '111.222.333'
1635 if (CanUpdByROWID())
89894079 1636 {
3ca6a5f0
BP
1637 SDWORD cb;
1638 char rowid[wxDB_ROWID_LEN];
1639
1640 // Get the ROWID value. If not successful retreiving the ROWID,
1641 // simply fall down through the code and build the WHERE clause
1642 // based on the key fields.
1643 if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS)
1644 {
1645 wxStrcat(pSqlStmt, "ROWID = '");
1646 wxStrcat(pSqlStmt, rowid);
1647 wxStrcat(pSqlStmt, "'");
1648 break;
1649 }
89894079 1650 }
3ca6a5f0
BP
1651 // Unable to delete by ROWID, so build a WHERE
1652 // clause based on the keyfields.
1653 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
1654 wxStrcat(pSqlStmt, whereClause);
1655 break;
1656 case DB_UPD_WHERE:
1657 wxStrcat(pSqlStmt, pWhereClause);
1658 break;
89894079 1659 }
f6bcfd97 1660} // BuildUpdateStmt()
108106cf 1661
67e9aaa3 1662
f6bcfd97
BP
1663/********** wxDbTable::BuildDeleteStmt() **********/
1664void wxDbTable::BuildDeleteStmt(char *pSqlStmt, int typeOfDel, const char *pWhereClause)
108106cf 1665{
89894079
VZ
1666 assert(!queryOnly);
1667 if (queryOnly)
1668 return;
1669
1670 char whereClause[DB_MAX_WHERE_CLAUSE_LEN];
1671
1672 whereClause[0] = 0;
1673
1674 // Handle the case of DeleteWhere() and the where clause is blank. It should
1675 // delete all records from the database in this case.
1676 if (typeOfDel == DB_DEL_WHERE && (pWhereClause == 0 || wxStrlen(pWhereClause) == 0))
1677 {
1678 sprintf(pSqlStmt, "DELETE FROM %s", tableName);
1679 return;
1680 }
1681
1682 sprintf(pSqlStmt, "DELETE FROM %s WHERE ", tableName);
1683
1684 // Append the WHERE clause to the SQL DELETE statement
1685 switch(typeOfDel)
1686 {
3ca6a5f0
BP
1687 case DB_DEL_KEYFIELDS:
1688 // If the datasource supports the ROWID column, build
1689 // the where on ROWID for efficiency purposes.
1690 // e.g. DELETE FROM PARTS WHERE ROWID = '111.222.333'
1691 if (CanUpdByROWID())
89894079 1692 {
3ca6a5f0
BP
1693 SDWORD cb;
1694 char rowid[wxDB_ROWID_LEN];
1695
1696 // Get the ROWID value. If not successful retreiving the ROWID,
1697 // simply fall down through the code and build the WHERE clause
1698 // based on the key fields.
1699 if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS)
1700 {
1701 wxStrcat(pSqlStmt, "ROWID = '");
1702 wxStrcat(pSqlStmt, rowid);
1703 wxStrcat(pSqlStmt, "'");
1704 break;
1705 }
89894079 1706 }
3ca6a5f0
BP
1707 // Unable to delete by ROWID, so build a WHERE
1708 // clause based on the keyfields.
1709 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS);
1710 wxStrcat(pSqlStmt, whereClause);
1711 break;
1712 case DB_DEL_WHERE:
1713 wxStrcat(pSqlStmt, pWhereClause);
1714 break;
1715 case DB_DEL_MATCHING:
1716 BuildWhereClause(whereClause, DB_WHERE_MATCHING);
1717 wxStrcat(pSqlStmt, whereClause);
1718 break;
89894079 1719 }
108106cf 1720
f6bcfd97 1721} // BuildDeleteStmt()
108106cf 1722
67e9aaa3 1723
f6bcfd97
BP
1724/********** wxDbTable::BuildWhereClause() **********/
1725void wxDbTable::BuildWhereClause(char *pWhereClause, int typeOfWhere,
1726 const char *qualTableName, bool useLikeComparison)
108106cf 1727/*
f6bcfd97 1728 * Note: BuildWhereClause() currently ignores timestamp columns.
108106cf
JS
1729 * They are not included as part of the where clause.
1730 */
108106cf 1731{
89894079
VZ
1732 bool moreThanOneColumn = FALSE;
1733 char colValue[255];
1734
1735 // Loop through the columns building a where clause as you go
1736 int i;
1737 for (i = 0; i < noCols; i++)
1738 {
1739 // Determine if this column should be included in the WHERE clause
1740 if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[i].KeyField) ||
f02d4a64 1741 (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull(i))))
89894079
VZ
1742 {
1743 // Skip over timestamp columns
1744 if (colDefs[i].SqlCtype == SQL_C_TIMESTAMP)
1745 continue;
1746 // If there is more than 1 column, join them with the keyword "AND"
1747 if (moreThanOneColumn)
1748 wxStrcat(pWhereClause, " AND ");
1749 else
1750 moreThanOneColumn = TRUE;
1751 // Concatenate where phrase for the column
1752 if (qualTableName && wxStrlen(qualTableName))
1753 {
1754 wxStrcat(pWhereClause, qualTableName);
1755 wxStrcat(pWhereClause, ".");
1756 }
1757 wxStrcat(pWhereClause, colDefs[i].ColName);
8128349e
GT
1758 if (useLikeComparison && (colDefs[i].SqlCtype == SQL_C_CHAR))
1759 wxStrcat(pWhereClause, " LIKE ");
1760 else
1761 wxStrcat(pWhereClause, " = ");
89894079
VZ
1762 switch(colDefs[i].SqlCtype)
1763 {
3ca6a5f0
BP
1764 case SQL_C_CHAR:
1765 sprintf(colValue, "'%s'", (UCHAR FAR *) colDefs[i].PtrDataObj);
1766 break;
1767 case SQL_C_SSHORT:
1768 sprintf(colValue, "%hi", *((SWORD *) colDefs[i].PtrDataObj));
1769 break;
1770 case SQL_C_USHORT:
1771 sprintf(colValue, "%hu", *((UWORD *) colDefs[i].PtrDataObj));
1772 break;
1773 case SQL_C_SLONG:
1774 sprintf(colValue, "%li", *((SDWORD *) colDefs[i].PtrDataObj));
1775 break;
1776 case SQL_C_ULONG:
1777 sprintf(colValue, "%lu", *((UDWORD *) colDefs[i].PtrDataObj));
1778 break;
1779 case SQL_C_FLOAT:
1780 sprintf(colValue, "%.6f", *((SFLOAT *) colDefs[i].PtrDataObj));
1781 break;
1782 case SQL_C_DOUBLE:
1783 sprintf(colValue, "%.6f", *((SDOUBLE *) colDefs[i].PtrDataObj));
1784 break;
89894079
VZ
1785 }
1786 wxStrcat(pWhereClause, colValue);
1787 }
1788 }
f6bcfd97 1789} // wxDbTable::BuildWhereClause()
108106cf 1790
67e9aaa3 1791
f6bcfd97
BP
1792/********** wxDbTable::IsColNull() **********/
1793bool wxDbTable::IsColNull(int colNo)
108106cf 1794{
f02d4a64
GT
1795/*
1796 This logic is just not right. It would indicate TRUE
1797 if a numeric field were set to a value of 0.
1798
89894079
VZ
1799 switch(colDefs[colNo].SqlCtype)
1800 {
3ca6a5f0
BP
1801 case SQL_C_CHAR:
1802 return(((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] == 0);
1803 case SQL_C_SSHORT:
1804 return(( *((SWORD *) colDefs[colNo].PtrDataObj)) == 0);
1805 case SQL_C_USHORT:
1806 return(( *((UWORD*) colDefs[colNo].PtrDataObj)) == 0);
1807 case SQL_C_SLONG:
1808 return(( *((SDWORD *) colDefs[colNo].PtrDataObj)) == 0);
1809 case SQL_C_ULONG:
1810 return(( *((UDWORD *) colDefs[colNo].PtrDataObj)) == 0);
1811 case SQL_C_FLOAT:
1812 return(( *((SFLOAT *) colDefs[colNo].PtrDataObj)) == 0);
1813 case SQL_C_DOUBLE:
1814 return((*((SDOUBLE *) colDefs[colNo].PtrDataObj)) == 0);
1815 case SQL_C_TIMESTAMP:
1816 TIMESTAMP_STRUCT *pDt;
1817 pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj;
1818 if (pDt->year == 0 && pDt->month == 0 && pDt->day == 0)
1819 return(TRUE);
1820 else
1821 return(FALSE);
1822 default:
89894079 1823 return(TRUE);
89894079 1824 }
f02d4a64
GT
1825*/
1826 return (colDefs[colNo].Null);
f6bcfd97 1827} // wxDbTable::IsColNull()
108106cf 1828
67e9aaa3 1829
f6bcfd97
BP
1830/********** wxDbTable::CanSelectForUpdate() **********/
1831bool wxDbTable::CanSelectForUpdate(void)
108106cf 1832{
89894079
VZ
1833 if (pDb->Dbms() == dbmsMY_SQL)
1834 return FALSE;
a2115c88 1835
e93a3a18
GT
1836 if ((pDb->Dbms() == dbmsORACLE) ||
1837 (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE))
89894079
VZ
1838 return(TRUE);
1839 else
1840 return(FALSE);
108106cf 1841
f6bcfd97 1842} // wxDbTable::CanSelectForUpdate()
108106cf 1843
67e9aaa3 1844
f6bcfd97
BP
1845/********** wxDbTable::CanUpdByROWID() **********/
1846bool wxDbTable::CanUpdByROWID(void)
108106cf 1847{
67e9aaa3
GT
1848/*
1849 * NOTE: Returning FALSE for now until this can be debugged,
89894079 1850 * as the ROWID is not getting updated correctly
67e9aaa3 1851 */
89894079 1852 return FALSE;
108106cf 1853
89894079
VZ
1854 if (pDb->Dbms() == dbmsORACLE)
1855 return(TRUE);
1856 else
1857 return(FALSE);
108106cf 1858
f6bcfd97 1859} // wxDbTable::CanUpdByROWID()
108106cf 1860
67e9aaa3 1861
f6bcfd97
BP
1862/********** wxDbTable::IsCursorClosedOnCommit() **********/
1863bool wxDbTable::IsCursorClosedOnCommit(void)
108106cf 1864{
89894079
VZ
1865 if (pDb->dbInf.cursorCommitBehavior == SQL_CB_PRESERVE)
1866 return(FALSE);
1867 else
1868 return(TRUE);
108106cf 1869
f6bcfd97 1870} // wxDbTable::IsCursorClosedOnCommit()
108106cf 1871
67e9aaa3 1872
f02d4a64
GT
1873
1874/********** wxDbTable::ClearMemberVar() **********/
1875void wxDbTable::ClearMemberVar(int colNo, bool setToNull)
108106cf 1876{
f02d4a64
GT
1877 assert(colNo < noCols);
1878
1879 switch(colDefs[colNo].SqlCtype)
89894079 1880 {
f02d4a64
GT
1881 case SQL_C_CHAR:
1882 ((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] = 0;
1883 break;
1884 case SQL_C_SSHORT:
1885 *((SWORD *) colDefs[colNo].PtrDataObj) = 0;
1886 break;
1887 case SQL_C_USHORT:
1888 *((UWORD*) colDefs[colNo].PtrDataObj) = 0;
1889 break;
1890 case SQL_C_SLONG:
1891 *((SDWORD *) colDefs[colNo].PtrDataObj) = 0;
1892 break;
1893 case SQL_C_ULONG:
1894 *((UDWORD *) colDefs[colNo].PtrDataObj) = 0;
1895 break;
1896 case SQL_C_FLOAT:
1897 *((SFLOAT *) colDefs[colNo].PtrDataObj) = 0.0f;
1898 break;
1899 case SQL_C_DOUBLE:
1900 *((SDOUBLE *) colDefs[colNo].PtrDataObj) = 0.0f;
1901 break;
1902 case SQL_C_TIMESTAMP:
1903 TIMESTAMP_STRUCT *pDt;
1904 pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj;
1905 pDt->year = 0;
1906 pDt->month = 0;
1907 pDt->day = 0;
1908 pDt->hour = 0;
1909 pDt->minute = 0;
1910 pDt->second = 0;
1911 pDt->fraction = 0;
1912 break;
89894079 1913 }
108106cf 1914
f02d4a64
GT
1915 if (setToNull)
1916 SetColNull(colNo);
1917} // wxDbTable::ClearMemberVar()
1918
1919
1920/********** wxDbTable::ClearMemberVars() **********/
1921void wxDbTable::ClearMemberVars(bool setToNull)
1922{
1923 int i;
1924
1925 // Loop through the columns setting each member variable to zero
1926 for (i=0; i < noCols; i++)
1927 ClearMemberVar(i,setToNull);
1928
f6bcfd97 1929} // wxDbTable::ClearMemberVars()
108106cf 1930
67e9aaa3 1931
f6bcfd97
BP
1932/********** wxDbTable::SetQueryTimeout() **********/
1933bool wxDbTable::SetQueryTimeout(UDWORD nSeconds)
108106cf 1934{
89894079
VZ
1935 if (SQLSetStmtOption(hstmtInsert, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1936 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
1937 if (SQLSetStmtOption(hstmtUpdate, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1938 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
1939 if (SQLSetStmtOption(hstmtDelete, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1940 return(pDb->DispAllErrors(henv, hdbc, hstmtDelete));
1941 if (SQLSetStmtOption(hstmtInternal, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1942 return(pDb->DispAllErrors(henv, hdbc, hstmtInternal));
1943
1944 // Completed Successfully
1945 return(TRUE);
108106cf 1946
f6bcfd97 1947} // wxDbTable::SetQueryTimeout()
108106cf 1948
67e9aaa3 1949
f6bcfd97 1950/********** wxDbTable::SetColDefs() **********/
e93a3a18
GT
1951void wxDbTable::SetColDefs(int index, const char *fieldName, int dataType, void *pData,
1952 int cType, int size, bool keyField, bool upd,
1953 bool insAllow, bool derivedCol)
108106cf 1954{
89894079
VZ
1955 if (!colDefs) // May happen if the database connection fails
1956 return;
1957
1958 if (wxStrlen(fieldName) > (unsigned int) DB_MAX_COLUMN_NAME_LEN)
1959 {
1960 wxStrncpy (colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN);
1961 colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0;
1962 }
1963 else
1964 wxStrcpy(colDefs[index].ColName, fieldName);
1965
1966 colDefs[index].DbDataType = dataType;
1967 colDefs[index].PtrDataObj = pData;
1968 colDefs[index].SqlCtype = cType;
1969 colDefs[index].SzDataObj = size;
1970 colDefs[index].KeyField = keyField;
1971 colDefs[index].DerivedCol = derivedCol;
1972 // Derived columns by definition would NOT be "Insertable" or "Updateable"
1973 if (derivedCol)
1974 {
1975 colDefs[index].Updateable = FALSE;
1976 colDefs[index].InsertAllowed = FALSE;
1977 }
1978 else
1979 {
1980 colDefs[index].Updateable = upd;
1981 colDefs[index].InsertAllowed = insAllow;
1982 }
1983
1984 colDefs[index].Null = FALSE;
1985
f6bcfd97 1986} // wxDbTable::SetColDefs()
108106cf 1987
67e9aaa3 1988
e93a3a18
GT
1989/********** wxDbTable::SetColDefs() **********/
1990wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, ULONG numCols)
67e9aaa3 1991{
89894079 1992 assert(pColInfs);
f6bcfd97 1993 wxDbColDataPtr *pColDataPtrs = NULL;
67e9aaa3 1994
89894079
VZ
1995 if (pColInfs)
1996 {
1997 ULONG index;
1b7274a8 1998
f6bcfd97 1999 pColDataPtrs = new wxDbColDataPtr[numCols+1];
67e9aaa3
GT
2000
2001 for (index = 0; index < numCols; index++)
89894079 2002 {
89894079
VZ
2003 // Process the fields
2004 switch (pColInfs[index].dbDataType)
2005 {
2006 case DB_DATA_TYPE_VARCHAR:
0b8410f3
GT
2007 pColDataPtrs[index].PtrDataObj = new char[pColInfs[index].bufferLength+1];
2008 pColDataPtrs[index].SzDataObj = pColInfs[index].columnSize;
2009 pColDataPtrs[index].SqlCtype = SQL_C_CHAR;
2010 break;
89894079 2011 case DB_DATA_TYPE_INTEGER:
67e9aaa3 2012 // Can be long or short
89894079
VZ
2013 if (pColInfs[index].bufferLength == sizeof(long))
2014 {
2015 pColDataPtrs[index].PtrDataObj = new long;
2016 pColDataPtrs[index].SzDataObj = sizeof(long);
2017 pColDataPtrs[index].SqlCtype = SQL_C_SLONG;
2018 }
2019 else
2020 {
2021 pColDataPtrs[index].PtrDataObj = new short;
2022 pColDataPtrs[index].SzDataObj = sizeof(short);
2023 pColDataPtrs[index].SqlCtype = SQL_C_SSHORT;
2024 }
2025 break;
89894079 2026 case DB_DATA_TYPE_FLOAT:
89894079
VZ
2027 // Can be float or double
2028 if (pColInfs[index].bufferLength == sizeof(float))
2029 {
2030 pColDataPtrs[index].PtrDataObj = new float;
2031 pColDataPtrs[index].SzDataObj = sizeof(float);
2032 pColDataPtrs[index].SqlCtype = SQL_C_FLOAT;
2033 }
2034 else
2035 {
2036 pColDataPtrs[index].PtrDataObj = new double;
2037 pColDataPtrs[index].SzDataObj = sizeof(double);
2038 pColDataPtrs[index].SqlCtype = SQL_C_DOUBLE;
2039 }
2040 break;
89894079 2041 case DB_DATA_TYPE_DATE:
89894079
VZ
2042 pColDataPtrs[index].PtrDataObj = new TIMESTAMP_STRUCT;
2043 pColDataPtrs[index].SzDataObj = sizeof(TIMESTAMP_STRUCT);
2044 pColDataPtrs[index].SqlCtype = SQL_C_TIMESTAMP;
2045 break;
89894079 2046 }
3ca6a5f0 2047 SetColDefs (index,pColInfs[index].colName,pColInfs[index].dbDataType, pColDataPtrs[index].PtrDataObj, pColDataPtrs[index].SqlCtype, pColDataPtrs[index].SzDataObj);
89894079
VZ
2048 }
2049 }
3ca6a5f0 2050
89894079 2051 return (pColDataPtrs);
3ca6a5f0 2052
e93a3a18 2053} // wxDbTable::SetColDefs()
67e9aaa3
GT
2054
2055
f6bcfd97
BP
2056/********** wxDbTable::SetCursor() **********/
2057void wxDbTable::SetCursor(HSTMT *hstmtActivate)
108106cf 2058{
f6bcfd97 2059 if (hstmtActivate == wxDB_DEFAULT_CURSOR)
89894079
VZ
2060 hstmt = *hstmtDefault;
2061 else
2062 hstmt = *hstmtActivate;
108106cf 2063
f6bcfd97 2064} // wxDbTable::SetCursor()
108106cf 2065
67e9aaa3 2066
f6bcfd97
BP
2067/********** wxDbTable::Count(const char *) **********/
2068ULONG wxDbTable::Count(const char *args)
108106cf 2069{
3ca6a5f0 2070 ULONG count;
1e92909e 2071 wxString sqlStmt;
89894079
VZ
2072 SDWORD cb;
2073
2074 // Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement
1e92909e
GT
2075 sqlStmt = "SELECT COUNT(";
2076 sqlStmt += args;
2077 sqlStmt += ") FROM ";
2078 sqlStmt += queryTableName;
f6bcfd97 2079#if wxODBC_BACKWARD_COMPATABILITY
89894079 2080 if (from && wxStrlen(from))
f6bcfd97
BP
2081#else
2082 if (from.Length())
2083#endif
1e92909e 2084 sqlStmt += from;
89894079
VZ
2085
2086 // Add the where clause if one is provided
f6bcfd97 2087#if wxODBC_BACKWARD_COMPATABILITY
89894079 2088 if (where && wxStrlen(where))
f6bcfd97
BP
2089#else
2090 if (where.Length())
2091#endif
89894079 2092 {
1e92909e
GT
2093 sqlStmt += " WHERE ";
2094 sqlStmt += where;
89894079
VZ
2095 }
2096
f6bcfd97 2097 pDb->WriteSqlLog(sqlStmt.c_str());
89894079
VZ
2098
2099 // Initialize the Count cursor if it's not already initialized
2100 if (!hstmtCount)
2101 {
f6bcfd97 2102 hstmtCount = GetNewCursor(FALSE,FALSE);
89894079
VZ
2103 assert(hstmtCount);
2104 if (!hstmtCount)
2105 return(0);
2106 }
2107
2108 // Execute the SQL statement
f6bcfd97 2109 if (SQLExecDirect(*hstmtCount, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
89894079
VZ
2110 {
2111 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2112 return(0);
2113 }
2114
2115 // Fetch the record
2116 if (SQLFetch(*hstmtCount) != SQL_SUCCESS)
2117 {
2118 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2119 return(0);
2120 }
2121
2122 // Obtain the result
3ca6a5f0 2123 if (SQLGetData(*hstmtCount, 1, SQL_C_ULONG, &count, sizeof(count), &cb) != SQL_SUCCESS)
89894079
VZ
2124 {
2125 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2126 return(0);
2127 }
2128
2129 // Free the cursor
2130 if (SQLFreeStmt(*hstmtCount, SQL_CLOSE) != SQL_SUCCESS)
2131 pDb->DispAllErrors(henv, hdbc, *hstmtCount);
2132
2133 // Return the record count
3ca6a5f0 2134 return(count);
108106cf 2135
f6bcfd97 2136} // wxDbTable::Count()
108106cf 2137
67e9aaa3 2138
f6bcfd97
BP
2139/********** wxDbTable::Refresh() **********/
2140bool wxDbTable::Refresh(void)
108106cf 2141{
89894079
VZ
2142 bool result = TRUE;
2143
2144 // Switch to the internal cursor so any active cursors are not corrupted
2145 HSTMT currCursor = GetCursor();
2146 hstmt = hstmtInternal;
f6bcfd97 2147#if wxODBC_BACKWARD_COMPATABILITY
89894079
VZ
2148 // Save the where and order by clauses
2149 char *saveWhere = where;
2150 char *saveOrderBy = orderBy;
f6bcfd97
BP
2151#else
2152 wxString saveWhere = where;
2153 wxString saveOrderBy = orderBy;
2154#endif
89894079
VZ
2155 // Build a where clause to refetch the record with. Try and use the
2156 // ROWID if it's available, ow use the key fields.
2157 char whereClause[DB_MAX_WHERE_CLAUSE_LEN+1];
2158 wxStrcpy(whereClause, "");
2159 if (CanUpdByROWID())
2160 {
2161 SDWORD cb;
f6bcfd97 2162 char rowid[wxDB_ROWID_LEN+1];
89894079
VZ
2163
2164 // Get the ROWID value. If not successful retreiving the ROWID,
2165 // simply fall down through the code and build the WHERE clause
2166 // based on the key fields.
f6bcfd97 2167 if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, (UCHAR*) rowid, wxDB_ROWID_LEN, &cb) == SQL_SUCCESS)
89894079
VZ
2168 {
2169 wxStrcat(whereClause, queryTableName);
2170 wxStrcat(whereClause, ".ROWID = '");
2171 wxStrcat(whereClause, rowid);
2172 wxStrcat(whereClause, "'");
2173 }
2174 }
2175
2176 // If unable to use the ROWID, build a where clause from the keyfields
2177 if (wxStrlen(whereClause) == 0)
f6bcfd97 2178 BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS, queryTableName);
89894079
VZ
2179
2180 // Requery the record
2181 where = whereClause;
f6bcfd97 2182 orderBy = "";
89894079
VZ
2183 if (!Query())
2184 result = FALSE;
2185
2186 if (result && !GetNext())
2187 result = FALSE;
2188
2189 // Switch back to original cursor
2190 SetCursor(&currCursor);
2191
2192 // Free the internal cursor
2193 if (SQLFreeStmt(hstmtInternal, SQL_CLOSE) != SQL_SUCCESS)
2194 pDb->DispAllErrors(henv, hdbc, hstmtInternal);
2195
2196 // Restore the original where and order by clauses
1e92909e 2197 where = saveWhere;
89894079
VZ
2198 orderBy = saveOrderBy;
2199
2200 return(result);
108106cf 2201
f6bcfd97 2202} // wxDbTable::Refresh()
108106cf 2203
67e9aaa3 2204
f02d4a64
GT
2205/********** wxDbTable::SetColNull(int colNo, bool set) **********/
2206bool wxDbTable::SetColNull(int colNo, bool set)
a2115c88 2207{
89894079 2208 if (colNo < noCols)
f02d4a64
GT
2209 {
2210 colDefs[colNo].Null = set;
2211 if (set) // Blank out the values in the member variable
2212 ClearMemberVar(colNo,FALSE); // Must call with FALSE, or infinite recursion will happen
2213 return(TRUE);
2214 }
89894079
VZ
2215 else
2216 return(FALSE);
a2115c88 2217
f02d4a64 2218} // wxDbTable::SetColNull(int colNo)
67e9aaa3 2219
a2115c88 2220
f02d4a64
GT
2221/********** wxDbTable::SetColNull(char *colName, bool set) **********/
2222bool wxDbTable::SetColNull(const char *colName, bool set)
a2115c88 2223{
89894079
VZ
2224 int i;
2225 for (i = 0; i < noCols; i++)
2226 {
2227 if (!wxStricmp(colName, colDefs[i].ColName))
2228 break;
2229 }
2230
2231 if (i < noCols)
f02d4a64
GT
2232 {
2233 colDefs[i].Null = set;
2234 if (set) // Blank out the values in the member variable
2235 ClearMemberVar(i,FALSE); // Must call with FALSE, or infinite recursion will happen
2236 return(TRUE);
2237 }
89894079
VZ
2238 else
2239 return(FALSE);
a2115c88 2240
f02d4a64 2241} // wxDbTable::SetColNull(char *colName)
a2115c88 2242
67e9aaa3 2243
f6bcfd97
BP
2244/********** wxDbTable::GetNewCursor() **********/
2245HSTMT *wxDbTable::GetNewCursor(bool setCursor, bool bindColumns)
a2115c88 2246{
89894079
VZ
2247 HSTMT *newHSTMT = new HSTMT;
2248 assert(newHSTMT);
2249 if (!newHSTMT)
2250 return(0);
2251
2252 if (SQLAllocStmt(hdbc, newHSTMT) != SQL_SUCCESS)
2253 {
2254 pDb->DispAllErrors(henv, hdbc);
2255 delete newHSTMT;
2256 return(0);
2257 }
2258
2259 if (SQLSetStmtOption(*newHSTMT, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
2260 {
2261 pDb->DispAllErrors(henv, hdbc, *newHSTMT);
2262 delete newHSTMT;
2263 return(0);
2264 }
2265
2266 if (bindColumns)
2267 {
2268 if(!bindCols(*newHSTMT))
2269 {
2270 delete newHSTMT;
2271 return(0);
2272 }
2273 }
2274
2275 if (setCursor)
2276 SetCursor(newHSTMT);
2277
2278 return(newHSTMT);
2279
f6bcfd97 2280} // wxDbTable::GetNewCursor()
67e9aaa3 2281
a2115c88 2282
f6bcfd97
BP
2283/********** wxDbTable::DeleteCursor() **********/
2284bool wxDbTable::DeleteCursor(HSTMT *hstmtDel)
a2115c88 2285{
89894079 2286 bool result = TRUE;
a2115c88 2287
89894079
VZ
2288 if (!hstmtDel) // Cursor already deleted
2289 return(result);
a2115c88 2290
89894079
VZ
2291 if (SQLFreeStmt(*hstmtDel, SQL_DROP) != SQL_SUCCESS)
2292 {
2293 pDb->DispAllErrors(henv, hdbc);
2294 result = FALSE;
2295 }
a2115c88 2296
89894079 2297 delete hstmtDel;
a2115c88 2298
89894079 2299 return(result);
a2115c88 2300
f6bcfd97 2301} // wxDbTable::DeleteCursor()
a2115c88
GT
2302
2303#endif // wxUSE_ODBC
1fc5dd6f 2304