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