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