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