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