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