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