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