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