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