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