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