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