]> git.saurik.com Git - wxWidgets.git/blame - src/common/dbtable.cpp
Introduced wxSOCKET_INT to socket.cpp. The previous code wouldn't compile on Windows.
[wxWidgets.git] / src / common / dbtable.cpp
CommitLineData
108106cf 1///////////////////////////////////////////////////////////////////////////////
1fc5dd6f 2// Name: dbtable.cpp
108106cf
JS
3// Purpose: Implementation of the wxTable class.
4// Author: Doug Card
5// Modified by:
6// Created: 9.96
7// RCS-ID: $Id$
8// Copyright: (c) 1996 Remstar International, Inc.
9// Licence: wxWindows licence, plus:
10// Notice: This class library and its intellectual design are free of charge for use,
11// modification, enhancement, debugging under the following conditions:
12// 1) These classes may only be used as part of the implementation of a
13// wxWindows-based application
14// 2) All enhancements and bug fixes are to be submitted back to the wxWindows
15// user groups free of all charges for use with the wxWindows library.
16// 3) These classes may not be distributed as part of any other class library,
17// DLL, text (written or electronic), other than a complete distribution of
18// the wxWindows GUI development toolkit.
19///////////////////////////////////////////////////////////////////////////////
20
1fc5dd6f
JS
21#ifdef __GNUG__
22#pragma implementation "dbtable.h"
23#endif
24
108106cf
JS
25/*
26// SYNOPSIS START
27// SYNOPSIS STOP
28*/
29
30/*
31#ifdef _CONSOLE
32 #include <iostream.h>
33#endif
34*/
35
36#include "wx/wxprec.h"
37
38#ifdef __BORLANDC__
39 #pragma hdrstop
40#endif //__BORLANDC__
41
42#ifndef WX_PRECOMP
43 #include <wx/wx.h>
44#endif //WX_PRECOMP
45
47d67540 46#if wxUSE_ODBC
108106cf
JS
47
48#include <wx/dbtable.h>
49
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
1fc5dd6f 53#include <assert.h>
108106cf 54
1fc5dd6f 55#ifdef __UNIX__
108106cf
JS
56// The HPUX preprocessor lines below were commented out on 8/20/97
57// because macros.h currently redefines DEBUG and is unneeded.
58// # ifdef HPUX
59// # include <macros.h>
60// # endif
1fc5dd6f 61# ifdef LINUX
108106cf
JS
62# include <sys/minmax.h>
63# endif
64#endif
65
66/********** wxTable::wxTable() **********/
67wxTable::wxTable(wxDB *pwxDB, const char *tblName, const int nCols, const char *qryTblName)
68{
69 // Assign member variables
70 pDb = pwxDB; // Pointer to the wxDB object
1fc5dd6f 71
108106cf
JS
72 strcpy(tableName, tblName); // Table Name
73 if (qryTblName) // Name of the table/view to query
74 strcpy(queryTableName, qryTblName);
75 else
76 strcpy(queryTableName, tblName);
77
1fc5dd6f
JS
78 assert(pDb); // Assert is placed after table name is assigned for error reporting reasons
79 if (!pDb)
80 return;
81
82 noCols = nCols; // No. of cols in the table
83 where = 0; // Where clause
84 orderBy = 0; // Order By clause
85 from = 0; // From clause
86 selectForUpdate = FALSE; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase
108106cf
JS
87
88 // Grab the HENV and HDBC from the wxDB object
89 henv = pDb->henv;
90 hdbc = pDb->hdbc;
91
92 // Allocate space for column definitions
93 if (noCols)
94 colDefs = new CcolDef[noCols]; // Points to the first column defintion
95 else
96 colDefs = 0;
97
98 // Allocate statement handles for the table
99 if (SQLAllocStmt(hdbc, &c0) != SQL_SUCCESS)
100 pDb->DispAllErrors(henv, hdbc);
101 if (SQLAllocStmt(hdbc, &c1) != SQL_SUCCESS)
102 pDb->DispAllErrors(henv, hdbc);
103 if (SQLAllocStmt(hdbc, &c2) != SQL_SUCCESS)
104 pDb->DispAllErrors(henv, hdbc);
105// if (SQLAllocStmt(hdbc, &c3) != SQL_SUCCESS)
106// pDb->DispAllErrors(henv, hdbc);
107// if (SQLAllocStmt(hdbc, &c4) != SQL_SUCCESS)
108// pDb->DispAllErrors(henv, hdbc);
109// if (SQLAllocStmt(hdbc, &c5) != SQL_SUCCESS)
110// pDb->DispAllErrors(henv, hdbc);
111 // Allocate a separate statement handle for performing inserts
112 if (SQLAllocStmt(hdbc, &hstmtInsert) != SQL_SUCCESS)
113 pDb->DispAllErrors(henv, hdbc);
114 // Allocate a separate statement handle for performing deletes
115 if (SQLAllocStmt(hdbc, &hstmtDelete) != SQL_SUCCESS)
116 pDb->DispAllErrors(henv, hdbc);
117 // Allocate a separate statement handle for performing updates
118 if (SQLAllocStmt(hdbc, &hstmtUpdate) != SQL_SUCCESS)
119 pDb->DispAllErrors(henv, hdbc);
120 // Allocate a separate statement handle for performing count(*) function
121 if (SQLAllocStmt(hdbc, &hstmtCount) != SQL_SUCCESS)
122 pDb->DispAllErrors(henv, hdbc);
123
124 // Set the cursor type for the statement handles
125 UDWORD cursorType = SQL_CURSOR_STATIC;
126 if (SQLSetStmtOption(c1, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
127 {
128 // Check to see if cursor type is supported
129 pDb->GetNextError(henv, hdbc, c1);
130 if (! strcmp(pDb->sqlState, "01S02")) // Option Value Changed
131 {
132 // Datasource does not support static cursors. Driver
133 // will substitute a cursor type. Call SQLGetStmtOption()
134 // to determine which cursor type was selected.
135 if (SQLGetStmtOption(c1, SQL_CURSOR_TYPE, &cursorType) != SQL_SUCCESS)
136 pDb->DispAllErrors(henv, hdbc, c1);
137#ifdef _CONSOLE
138 cout << "Static cursor changed to: ";
139 switch(cursorType)
140 {
141 case SQL_CURSOR_FORWARD_ONLY:
142 cout << "Forward Only"; break;
143 case SQL_CURSOR_STATIC:
144 cout << "Static"; break;
145 case SQL_CURSOR_KEYSET_DRIVEN:
146 cout << "Keyset Driven"; break;
147 case SQL_CURSOR_DYNAMIC:
148 cout << "Dynamic"; break;
149 }
150 cout << endl << endl;
151#endif
152 }
153 else
154 {
155 pDb->DispNextError();
156 pDb->DispAllErrors(henv, hdbc, c1);
157 }
158 }
159#ifdef _CONSOLE
160 else
161 cout << "Cursor Type set to STATIC" << endl << endl;
162#endif
163
164 if (SQLSetStmtOption(c0, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
165 pDb->DispAllErrors(henv, hdbc, c0);
166 if (SQLSetStmtOption(c2, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
167 pDb->DispAllErrors(henv, hdbc, c2);
168// if (SQLSetStmtOption(c3, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
169// pDb->DispAllErrors(henv, hdbc, c3);
170// if (SQLSetStmtOption(c4, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
171// pDb->DispAllErrors(henv, hdbc, c4);
172// if (SQLSetStmtOption(c5, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS)
173// pDb->DispAllErrors(henv, hdbc, c5);
174
175 // Set the cursor type for the INSERT statement handle
176 if (SQLSetStmtOption(hstmtInsert, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
177 pDb->DispAllErrors(henv, hdbc, hstmtInsert);
178 // Set the cursor type for the DELETE statement handle
179 if (SQLSetStmtOption(hstmtDelete, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
180 pDb->DispAllErrors(henv, hdbc, hstmtDelete);
181 // Set the cursor type for the UPDATE statement handle
182 if (SQLSetStmtOption(hstmtUpdate, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
183 pDb->DispAllErrors(henv, hdbc, hstmtUpdate);
184 // Set the cursor type for the COUNT(*) statement handle
185 if (SQLSetStmtOption(hstmtCount, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS)
186 pDb->DispAllErrors(henv, hdbc, hstmtCount);
187
188 // Copy cursor 1 to the default cursor
189 hstmt = c1;
190 currCursorNo = DB_CURSOR1;
191
192} // wxTable::wxTable()
193
194/********** wxTable::~wxTable() **********/
195wxTable::~wxTable()
196{
197 // Delete memory allocated for column definitions
198 if (colDefs)
199 delete [] colDefs;
200
201 // Free statement handles
202 if (SQLFreeStmt(c0, SQL_DROP) != SQL_SUCCESS)
203 pDb->DispAllErrors(henv, hdbc);
204 if (SQLFreeStmt(c1, SQL_DROP) != SQL_SUCCESS)
205 pDb->DispAllErrors(henv, hdbc);
206 if (SQLFreeStmt(c2, SQL_DROP) != SQL_SUCCESS)
207 pDb->DispAllErrors(henv, hdbc);
208// if (SQLFreeStmt(c3, SQL_DROP) != SQL_SUCCESS)
209// pDb->DispAllErrors(henv, hdbc);
210// if (SQLFreeStmt(c4, SQL_DROP) != SQL_SUCCESS)
211// pDb->DispAllErrors(henv, hdbc);
212// if (SQLFreeStmt(c5, SQL_DROP) != SQL_SUCCESS)
213// pDb->DispAllErrors(henv, hdbc);
214 if (SQLFreeStmt(hstmtInsert, SQL_DROP) != SQL_SUCCESS)
215 pDb->DispAllErrors(henv, hdbc);
216 if (SQLFreeStmt(hstmtDelete, SQL_DROP) != SQL_SUCCESS)
217 pDb->DispAllErrors(henv, hdbc);
218 if (SQLFreeStmt(hstmtUpdate, SQL_DROP) != SQL_SUCCESS)
219 pDb->DispAllErrors(henv, hdbc);
220 if (SQLFreeStmt(hstmtCount, SQL_DROP) != SQL_SUCCESS)
221 pDb->DispAllErrors(henv, hdbc);
222
223} // wxTable::~wxTable()
224
225/********** wxTable::Open() **********/
226bool wxTable::Open(void)
227{
1fc5dd6f
JS
228 if (!pDb)
229 return FALSE;
230
108106cf
JS
231 int i;
232 char sqlStmt[DB_MAX_STATEMENT_LEN];
233
234 // Verify that the table exists in the database
235 if (!pDb->TableExists(tableName))
236 {
1fc5dd6f
JS
237 char s[128];
238 sprintf(s, "Error opening '%s', table/view does not exist in the database.", tableName);
239 pDb->LogError(s);
108106cf
JS
240 return(FALSE);
241 }
242
243 // Bind the member variables for field exchange between
244 // the wxTable object and the ODBC record.
245 if(! bindInsertParams()) // Inserts
246 return(FALSE);
247 if(! bindUpdateParams()) // Updates
248 return(FALSE);
249 if(! bindCols(c0)) // Selects
250 return(FALSE);
251 if(! bindCols(c1))
252 return(FALSE);
253 if(! bindCols(c2))
254 return(FALSE);
255// if(! bindCols(c3))
256// return(FALSE);
257// if(! bindCols(c4))
258// return(FALSE);
259// if(! bindCols(c5))
260// return(FALSE);
261
262 // Build an insert statement using parameter markers
263 if (noCols > 0)
264 {
265 bool needComma = FALSE;
266 sprintf(sqlStmt, "INSERT INTO %s (", tableName);
267 for (i = 0; i < noCols; i++)
268 {
269 if (! colDefs[i].InsertAllowed)
270 continue;
271 if (needComma)
272 strcat(sqlStmt, ",");
273 strcat(sqlStmt, colDefs[i].ColName);
274 needComma = TRUE;
275 }
276 needComma = FALSE;
277 strcat(sqlStmt, ") VALUES (");
278 for (i = 0; i < noCols; i++)
279 {
280 if (! colDefs[i].InsertAllowed)
281 continue;
282 if (needComma)
283 strcat(sqlStmt, ",");
284 strcat(sqlStmt, "?");
285 needComma = TRUE;
286 }
287 strcat(sqlStmt, ")");
288
1fc5dd6f
JS
289 pDb->WriteSqlLog(sqlStmt);
290
108106cf
JS
291 // Prepare the insert statement for execution
292 if (SQLPrepare(hstmtInsert, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS)
293 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
294 }
295
296 // Completed successfully
297 return(TRUE);
298
299} // wxTable::Open()
300
301/********** wxTable::Query() **********/
302bool wxTable::Query(bool forUpdate, bool distinct)
303{
304
305 return(query(DB_SELECT_WHERE, forUpdate, distinct));
306
307} // wxTable::Query()
308
309/********** wxTable::QueryBySqlStmt() **********/
310bool wxTable::QueryBySqlStmt(char *pSqlStmt)
311{
1fc5dd6f 312 pDb->WriteSqlLog(pSqlStmt);
108106cf
JS
313
314 return(query(DB_SELECT_STATEMENT, FALSE, FALSE, pSqlStmt));
315
316} // wxTable::QueryBySqlStmt()
317
318/********** wxTable::QueryMatching() **********/
319bool wxTable::QueryMatching(bool forUpdate, bool distinct)
320{
321
322 return(query(DB_SELECT_MATCHING, forUpdate, distinct));
323
324} // wxTable::QueryMatching()
325
326/********** wxTable::QueryOnKeyFields() **********/
327bool wxTable::QueryOnKeyFields(bool forUpdate, bool distinct)
328{
329
330 return(query(DB_SELECT_KEYFIELDS, forUpdate, distinct));
331
332} // wxTable::QueryOnKeyFields()
333
334/********** wxTable::query() **********/
335bool wxTable::query(int queryType, bool forUpdate, bool distinct, char *pSqlStmt)
336{
337 char sqlStmt[DB_MAX_STATEMENT_LEN];
338
339 // Set the selectForUpdate member variable
340 if (forUpdate)
341 // The user may wish to select for update, but the DBMS may not be capable
342 selectForUpdate = CanSelectForUpdate();
343 else
344 selectForUpdate = FALSE;
345
346 // Set the SQL SELECT string
347 if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in,
1fc5dd6f
JS
348 { // so generate a select statement.
349 GetSelectStmt(sqlStmt, queryType, distinct);
350 pDb->WriteSqlLog(sqlStmt);
351 }
108106cf
JS
352
353 // Make sure the cursor is closed first
354 if (! CloseCursor(hstmt))
355 return(FALSE);
356
357 // Execute the SQL SELECT statement
358 if (SQLExecDirect(hstmt, (UCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt : sqlStmt),
359 SQL_NTS) != SQL_SUCCESS)
360 return(pDb->DispAllErrors(henv, hdbc, hstmt));
361
362 // Completed successfully
363 return(TRUE);
364
365} // wxTable::query()
366
367/********** wxTable::GetSelectStmt() **********/
368void wxTable::GetSelectStmt(char *pSqlStmt, int typeOfSelect, bool distinct)
369{
370 char whereClause[DB_MAX_WHERE_CLAUSE_LEN];
371
372 whereClause[0] = 0;
373
374 // Build a select statement to query the database
375 strcpy(pSqlStmt, "SELECT ");
376
377 // SELECT DISTINCT values only?
378 if (distinct)
379 strcat(pSqlStmt, "DISTINCT ");
380
1fc5dd6f
JS
381 // Was a FROM clause specified to join tables to the base table?
382 // Available for ::Query() only!!!
383 bool appendFromClause = FALSE;
384 if (typeOfSelect == DB_SELECT_WHERE && from && strlen(from))
385 appendFromClause = TRUE;
386
108106cf
JS
387 // Add the column list
388 for (int i = 0; i < noCols; i++)
389 {
1fc5dd6f
JS
390 // If joining tables, the base table column names must be qualified to avoid ambiguity
391 if (appendFromClause)
392 {
393 strcat(pSqlStmt, queryTableName);
394 strcat(pSqlStmt, ".");
395 }
108106cf
JS
396 strcat(pSqlStmt, colDefs[i].ColName);
397 if (i + 1 < noCols)
398 strcat(pSqlStmt, ",");
399 }
400
401 // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve
402 // the ROWID if querying distinct records. The rowid will always be unique.
403 if (!distinct && CanUpdByROWID())
1fc5dd6f
JS
404 {
405 // If joining tables, the base table column names must be qualified to avoid ambiguity
406 if (appendFromClause)
407 {
408 strcat(pSqlStmt, ",");
409 strcat(pSqlStmt, queryTableName);
410 strcat(pSqlStmt, ".ROWID");
411 }
412 else
413 strcat(pSqlStmt, ",ROWID");
414 }
108106cf
JS
415
416 // Append the FROM tablename portion
417 strcat(pSqlStmt, " FROM ");
418 strcat(pSqlStmt, queryTableName);
1fc5dd6f
JS
419 if (appendFromClause)
420 strcat(pSqlStmt, from);
108106cf
JS
421
422 // Append the WHERE clause. Either append the where clause for the class
423 // or build a where clause. The typeOfSelect determines this.
424 switch(typeOfSelect)
425 {
426 case DB_SELECT_WHERE:
427 if (where && strlen(where)) // May not want a where clause!!!
428 {
429 strcat(pSqlStmt, " WHERE ");
430 strcat(pSqlStmt, where);
431 }
432 break;
433 case DB_SELECT_KEYFIELDS:
434 GetWhereClause(whereClause, DB_WHERE_KEYFIELDS);
435 if (strlen(whereClause))
436 {
437 strcat(pSqlStmt, " WHERE ");
438 strcat(pSqlStmt, whereClause);
439 }
440 break;
441 case DB_SELECT_MATCHING:
442 GetWhereClause(whereClause, DB_WHERE_MATCHING);
443 if (strlen(whereClause))
444 {
445 strcat(pSqlStmt, " WHERE ");
446 strcat(pSqlStmt, whereClause);
447 }
448 break;
449 }
450
451 // Append the ORDER BY clause
452 if (orderBy && strlen(orderBy))
453 {
454 strcat(pSqlStmt, " ORDER BY ");
455 strcat(pSqlStmt, orderBy);
456 }
457
458 // SELECT FOR UPDATE if told to do so and the datasource is capable
459 if (selectForUpdate && CanSelectForUpdate())
460 strcat(pSqlStmt, " FOR UPDATE");
461
462} // wxTable::GetSelectStmt()
463
464/********** wxTable::getRec() **********/
465bool wxTable::getRec(UWORD fetchType)
466{
467 RETCODE retcode;
468
469#ifndef FWD_ONLY_CURSORS
470 // Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType
471 UDWORD cRowsFetched;
472 UWORD rowStatus;
473 if ((retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus)) != SQL_SUCCESS)
474 if (retcode == SQL_NO_DATA_FOUND)
475 return(FALSE);
476 else
477 return(pDb->DispAllErrors(henv, hdbc, hstmt));
478#else
479 // Fetch the next record from the record set
480 if ((retcode = SQLFetch(hstmt)) != SQL_SUCCESS)
481 if (retcode == SQL_NO_DATA_FOUND)
482 return(FALSE);
483 else
484 return(pDb->DispAllErrors(henv, hdbc, hstmt));
485#endif
486
487 // Completed successfully
488 return(TRUE);
489
490} // wxTable::getRec()
491
492/********** wxTable::GetRowNum() **********/
493UWORD wxTable::GetRowNum(void)
494{
495 UDWORD rowNum;
496
497 if (SQLGetStmtOption(hstmt, SQL_ROW_NUMBER, &rowNum) != SQL_SUCCESS)
498 {
499 pDb->DispAllErrors(henv, hdbc, hstmt);
500 return(0);
501 }
502
503 // Completed successfully
504 return((UWORD) rowNum);
505
506} // wxTable::GetRowNum()
507
508/********** wxTable::bindInsertParams() **********/
509bool wxTable::bindInsertParams(void)
510{
511 SWORD fSqlType;
512 UDWORD precision;
513 SWORD scale;
514
108106cf
JS
515 // Bind each column (that can be inserted) of the table to a parameter marker
516 for (int i = 0; i < noCols; i++)
517 {
108106cf
JS
518 if (! colDefs[i].InsertAllowed)
519 continue;
520 switch(colDefs[i].DbDataType)
521 {
522 case DB_DATA_TYPE_VARCHAR:
523 fSqlType = pDb->typeInfVarchar.FsqlType;
524 precision = colDefs[i].SzDataObj;
525 scale = 0;
526 colDefs[i].CbValue = SQL_NTS;
527 break;
528 case DB_DATA_TYPE_INTEGER:
529 fSqlType = pDb->typeInfInteger.FsqlType;
530 precision = pDb->typeInfInteger.Precision;
531 scale = 0;
532 colDefs[i].CbValue = 0;
533 break;
534 case DB_DATA_TYPE_FLOAT:
535 fSqlType = pDb->typeInfFloat.FsqlType;
536 precision = pDb->typeInfFloat.Precision;
537 scale = pDb->typeInfFloat.MaximumScale;
538 // SQL Sybase Anywhere v5.5 returned a negative number for the
539 // MaxScale. This caused ODBC to kick out an error on ibscale.
540 // I check for this here and set the scale = precision.
541 //if (scale < 0)
542 // scale = (short) precision;
543 colDefs[i].CbValue = 0;
544 break;
545 case DB_DATA_TYPE_DATE:
546 fSqlType = pDb->typeInfDate.FsqlType;
547 precision = pDb->typeInfDate.Precision;
548 scale = 0;
549 colDefs[i].CbValue = 0;
550 break;
551 }
552 if (SQLBindParameter(hstmtInsert, i+1, SQL_PARAM_INPUT, colDefs[i].SqlCtype,
553 fSqlType, precision, scale, colDefs[i].PtrDataObj,
554 precision+1,&colDefs[i].CbValue) != SQL_SUCCESS)
555 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
556 }
557
558 // Completed successfully
559 return(TRUE);
560
561} // wxTable::bindInsertParams()
562
563/********** wxTable::bindUpdateParams() **********/
564bool wxTable::bindUpdateParams(void)
565{
566 SWORD fSqlType;
567 UDWORD precision;
568 SWORD scale;
569
570 // Bind each UPDATEABLE column of the table to a parameter marker
571 for (int i = 0, colNo = 1; i < noCols; i++)
572 {
573 if (! colDefs[i].Updateable)
574 continue;
575 switch(colDefs[i].DbDataType)
576 {
577 case DB_DATA_TYPE_VARCHAR:
578 fSqlType = pDb->typeInfVarchar.FsqlType;
579 precision = colDefs[i].SzDataObj;
580 scale = 0;
581 colDefs[i].CbValue = SQL_NTS;
582 break;
583 case DB_DATA_TYPE_INTEGER:
584 fSqlType = pDb->typeInfInteger.FsqlType;
585 precision = pDb->typeInfInteger.Precision;
586 scale = 0;
587 colDefs[i].CbValue = 0;
588 break;
589 case DB_DATA_TYPE_FLOAT:
590 fSqlType = pDb->typeInfFloat.FsqlType;
591 precision = pDb->typeInfFloat.Precision;
592 scale = pDb->typeInfFloat.MaximumScale;
593 // SQL Sybase Anywhere v5.5 returned a negative number for the
594 // MaxScale. This caused ODBC to kick out an error on ibscale.
595 // I check for this here and set the scale = precision.
596 //if (scale < 0)
597 // scale = (short) precision;
598 colDefs[i].CbValue = 0;
599 break;
600 case DB_DATA_TYPE_DATE:
601 fSqlType = pDb->typeInfDate.FsqlType;
602 precision = pDb->typeInfDate.Precision;
603 scale = 0;
604 colDefs[i].CbValue = 0;
605 break;
606 }
607 if (SQLBindParameter(hstmtUpdate, colNo++, SQL_PARAM_INPUT, colDefs[i].SqlCtype,
608 fSqlType, precision, scale, colDefs[i].PtrDataObj,
609 precision+1, &colDefs[i].CbValue) != SQL_SUCCESS)
610 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
611 }
612
613 // Completed successfully
614 return(TRUE);
615
616} // wxTable::bindUpdateParams()
617
618/********** wxTable::bindCols() **********/
619bool wxTable::bindCols(HSTMT cursor)
620{
621 static SDWORD cb;
622
623 // Bind each column of the table to a memory address for fetching data
624 for (int i = 0; i < noCols; i++)
625 {
626 if (SQLBindCol(cursor, i+1, colDefs[i].SqlCtype, colDefs[i].PtrDataObj,
627 colDefs[i].SzDataObj, &cb) != SQL_SUCCESS)
628 return(pDb->DispAllErrors(henv, hdbc, cursor));
629 }
630
631 // Completed successfully
632 return(TRUE);
633
634} // wxTable::bindCols()
635
636/********** wxTable::CloseCursor() **********/
637bool wxTable::CloseCursor(HSTMT cursor)
638{
639 if (SQLFreeStmt(cursor, SQL_CLOSE) != SQL_SUCCESS)
640 return(pDb->DispAllErrors(henv, hdbc, cursor));
641
642 // Completed successfully
643 return(TRUE);
644
645} // wxTable::CloseCursor()
646
647/********** wxTable::CreateTable() **********/
648bool wxTable::CreateTable(void)
649{
1fc5dd6f
JS
650 if (!pDb)
651 return FALSE;
652
108106cf
JS
653 int i, j;
654 char sqlStmt[DB_MAX_STATEMENT_LEN];
655
656#ifdef _CONSOLE
657 cout << "Creating Table " << tableName << "..." << endl;
658#endif
659
660 // Drop the table first
661 sprintf(sqlStmt, "DROP TABLE %s", tableName);
662 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS)
663 {
664 // Check for sqlState = S0002, "Table or view not found".
665 // Ignore this error, bomb out on any other error.
666 // SQL Sybase Anwhere v5.5 returns an access violation error here
667 // (sqlstate = 42000) rather than an S0002.
668 pDb->GetNextError(henv, hdbc, hstmt);
669 if (strcmp(pDb->sqlState, "S0002") && strcmp(pDb->sqlState, "42000"))
670 {
671 pDb->DispNextError();
672 pDb->DispAllErrors(henv, hdbc, hstmt);
673 pDb->RollbackTrans();
674 CloseCursor(hstmt);
675 return(FALSE);
676 }
677 }
678
1fc5dd6f
JS
679 pDb->WriteSqlLog(sqlStmt);
680
108106cf
JS
681 // Commit the transaction and close the cursor
682 if (! pDb->CommitTrans())
683 return(FALSE);
684 if (! CloseCursor(hstmt))
685 return(FALSE);
686
687 // Create the table
688#ifdef _CONSOLE
689 for (i = 0; i < noCols; i++)
690 {
691 // Exclude derived columns since they are NOT part of the base table
692 if (colDefs[i].DerivedCol)
693 continue;
694 cout << i + 1 << ": " << colDefs[i].ColName << "; ";
695 switch(colDefs[i].DbDataType)
696 {
697 case DB_DATA_TYPE_VARCHAR:
698 cout << pDb->typeInfVarchar.TypeName << "(" << colDefs[i].SzDataObj << ")";
699 break;
700 case DB_DATA_TYPE_INTEGER:
701 cout << pDb->typeInfInteger.TypeName;
702 break;
703 case DB_DATA_TYPE_FLOAT:
704 cout << pDb->typeInfFloat.TypeName;
705 break;
706 case DB_DATA_TYPE_DATE:
707 cout << pDb->typeInfDate.TypeName;
708 break;
709 }
710 cout << endl;
711 }
712#endif
713
714 // Build a CREATE TABLE string from the colDefs structure.
715 bool needComma = FALSE;
716 sprintf(sqlStmt, "CREATE TABLE %s (", tableName);
717 for (i = 0; i < noCols; i++)
718 {
719 // Exclude derived columns since they are NOT part of the base table
720 if (colDefs[i].DerivedCol)
721 continue;
722 // Comma Delimiter
723 if (needComma)
724 strcat(sqlStmt, ",");
725 // Column Name
726 strcat(sqlStmt, colDefs[i].ColName);
727 strcat(sqlStmt, " ");
728 // Column Type
729 switch(colDefs[i].DbDataType)
730 {
731 case DB_DATA_TYPE_VARCHAR:
732 strcat(sqlStmt, pDb->typeInfVarchar.TypeName); break;
733 case DB_DATA_TYPE_INTEGER:
734 strcat(sqlStmt, pDb->typeInfInteger.TypeName); break;
735 case DB_DATA_TYPE_FLOAT:
736 strcat(sqlStmt, pDb->typeInfFloat.TypeName); break;
737 case DB_DATA_TYPE_DATE:
738 strcat(sqlStmt, pDb->typeInfDate.TypeName); break;
739 }
740 // For varchars, append the size of the string
741 if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR)
742 {
1fc5dd6f 743 char s[10];
108106cf
JS
744 // strcat(sqlStmt, "(");
745 // strcat(sqlStmt, itoa(colDefs[i].SzDataObj, s, 10));
746 // strcat(sqlStmt, ")");
1fc5dd6f 747 sprintf(s, "(%d)", colDefs[i].SzDataObj);
108106cf
JS
748 strcat(sqlStmt, s);
749 }
750 needComma = TRUE;
751 }
752 // If there is a primary key defined, include it in the create statement
753 for (i = j = 0; i < noCols; i++)
754 {
755 if (colDefs[i].KeyField)
756 {
757 j++;
758 break;
759 }
760 }
761 if (j) // Found a keyfield
762 {
763 strcat(sqlStmt, ",CONSTRAINT ");
764 strcat(sqlStmt, tableName);
765 strcat(sqlStmt, "_PIDX PRIMARY KEY (");
766 // List column name(s) of column(s) comprising the primary key
767 for (i = j = 0; i < noCols; i++)
768 {
769 if (colDefs[i].KeyField)
770 {
771 if (j++) // Multi part key, comma separate names
772 strcat(sqlStmt, ",");
773 strcat(sqlStmt, colDefs[i].ColName);
774 }
775 }
776 strcat(sqlStmt, ")");
777 }
778 // Append the closing parentheses for the create table statement
779 strcat(sqlStmt, ")");
780
1fc5dd6f
JS
781 pDb->WriteSqlLog(sqlStmt);
782
108106cf
JS
783#ifdef _CONSOLE
784 cout << endl << sqlStmt << endl;
785#endif
786
787 // Execute the CREATE TABLE statement
788 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS)
789 {
790 pDb->DispAllErrors(henv, hdbc, hstmt);
791 pDb->RollbackTrans();
792 CloseCursor(hstmt);
793 return(FALSE);
794 }
795
796 // Commit the transaction and close the cursor
797 if (! pDb->CommitTrans())
798 return(FALSE);
799 if (! CloseCursor(hstmt))
800 return(FALSE);
801
802 // Database table created successfully
803 return(TRUE);
804
805} // wxTable::CreateTable()
806
807/********** wxTable::CreateIndex() **********/
808bool wxTable::CreateIndex(char * idxName, bool unique, int noIdxCols, CidxDef *pIdxDefs)
809{
810 char sqlStmt[DB_MAX_STATEMENT_LEN];
811
812 // Build a CREATE INDEX statement
813 strcpy(sqlStmt, "CREATE ");
814 if (unique)
815 strcat(sqlStmt, "UNIQUE ");
816
817 strcat(sqlStmt, "INDEX ");
818 strcat(sqlStmt, idxName);
819 strcat(sqlStmt, " ON ");
820 strcat(sqlStmt, tableName);
821 strcat(sqlStmt, " (");
822
823 // Append list of columns making up index
824 for (int i = 0; i < noIdxCols; i++)
825 {
826 strcat(sqlStmt, pIdxDefs[i].ColName);
827 if (pIdxDefs[i].Ascending)
828 strcat(sqlStmt, " ASC");
829 else
830 strcat(sqlStmt, " DESC");
831 if ((i + 1) < noIdxCols)
832 strcat(sqlStmt, ",");
833 }
834
835 // Append closing parentheses
836 strcat(sqlStmt, ")");
837
1fc5dd6f
JS
838 pDb->WriteSqlLog(sqlStmt);
839
108106cf
JS
840#ifdef _CONSOLE
841 cout << endl << sqlStmt << endl << endl;
842#endif
843
844 // Execute the CREATE INDEX statement
845 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS)
846 {
847 pDb->DispAllErrors(henv, hdbc, hstmt);
848 pDb->RollbackTrans();
849 CloseCursor(hstmt);
850 return(FALSE);
851 }
852
853 // Commit the transaction and close the cursor
854 if (! pDb->CommitTrans())
855 return(FALSE);
856 if (! CloseCursor(hstmt))
857 return(FALSE);
858
859 // Index Created Successfully
860 return(TRUE);
861
862} // wxTable::CreateIndex()
863
864/********** wxTable::Insert() **********/
865int wxTable::Insert(void)
866{
867 // Insert the record by executing the already prepared insert statement
868 if (SQLExecute(hstmtInsert) != SQL_SUCCESS)
869 {
870 // Check to see if integrity constraint was violated
871 pDb->GetNextError(henv, hdbc, hstmtInsert);
872 if (! strcmp(pDb->sqlState, "23000")) // Integrity constraint violated
873 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL);
874 else
875 {
876 pDb->DispNextError();
877 pDb->DispAllErrors(henv, hdbc, hstmtInsert);
878 return(DB_FAILURE);
879 }
880 }
881
882 // Record inserted into the datasource successfully
883 return(DB_SUCCESS);
884
885} // wxTable::Insert()
886
887/********** wxTable::Update(pSqlStmt) **********/
888bool wxTable::Update(char *pSqlStmt)
889{
1fc5dd6f 890 pDb->WriteSqlLog(pSqlStmt);
108106cf
JS
891
892 return(execUpdate(pSqlStmt));
893
894} // wxTable::Update(pSqlStmt)
895
896/********** wxTable::Update() **********/
897bool wxTable::Update(void)
898{
899 char sqlStmt[DB_MAX_STATEMENT_LEN];
900
901 // Build the SQL UPDATE statement
902 GetUpdateStmt(sqlStmt, DB_UPD_KEYFIELDS);
903
1fc5dd6f
JS
904 pDb->WriteSqlLog(sqlStmt);
905
108106cf
JS
906#ifdef _CONSOLE
907 cout << endl << sqlStmt << endl << endl;
908#endif
909
910 // Execute the SQL UPDATE statement
911 return(execUpdate(sqlStmt));
912
913} // wxTable::Update()
914
915/********** wxTable::UpdateWhere() **********/
916bool wxTable::UpdateWhere(char *pWhereClause)
917{
918 char sqlStmt[DB_MAX_STATEMENT_LEN];
919
920 // Build the SQL UPDATE statement
921 GetUpdateStmt(sqlStmt, DB_UPD_WHERE, pWhereClause);
922
1fc5dd6f
JS
923 pDb->WriteSqlLog(sqlStmt);
924
108106cf
JS
925#ifdef _CONSOLE
926 cout << endl << sqlStmt << endl << endl;
927#endif
928
929 // Execute the SQL UPDATE statement
930 return(execUpdate(sqlStmt));
931
932} // wxTable::UpdateWhere()
933
934/********** wxTable::Delete() **********/
935bool wxTable::Delete(void)
936{
937 char sqlStmt[DB_MAX_STATEMENT_LEN];
938
939 // Build the SQL DELETE statement
940 GetDeleteStmt(sqlStmt, DB_DEL_KEYFIELDS);
941
1fc5dd6f
JS
942 pDb->WriteSqlLog(sqlStmt);
943
108106cf
JS
944 // Execute the SQL DELETE statement
945 return(execDelete(sqlStmt));
946
947} // wxTable::Delete()
948
949/********** wxTable::DeleteWhere() **********/
950bool wxTable::DeleteWhere(char *pWhereClause)
951{
952 char sqlStmt[DB_MAX_STATEMENT_LEN];
953
954 // Build the SQL DELETE statement
955 GetDeleteStmt(sqlStmt, DB_DEL_WHERE, pWhereClause);
956
1fc5dd6f
JS
957 pDb->WriteSqlLog(sqlStmt);
958
108106cf
JS
959 // Execute the SQL DELETE statement
960 return(execDelete(sqlStmt));
961
962} // wxTable::DeleteWhere()
963
964/********** wxTable::DeleteMatching() **********/
965bool wxTable::DeleteMatching(void)
966{
967 char sqlStmt[DB_MAX_STATEMENT_LEN];
968
969 // Build the SQL DELETE statement
970 GetDeleteStmt(sqlStmt, DB_DEL_MATCHING);
971
1fc5dd6f
JS
972 pDb->WriteSqlLog(sqlStmt);
973
108106cf
JS
974 // Execute the SQL DELETE statement
975 return(execDelete(sqlStmt));
976
977} // wxTable::DeleteMatching()
978
979/********** wxTable::execDelete() **********/
980bool wxTable::execDelete(char *pSqlStmt)
981{
982 // Execute the DELETE statement
983 if (SQLExecDirect(hstmtDelete, (UCHAR FAR *) pSqlStmt, SQL_NTS) != SQL_SUCCESS)
984 return(pDb->DispAllErrors(henv, hdbc, hstmtDelete));
985
986 // Record deleted successfully
987 return(TRUE);
988
989} // wxTable::execDelete()
990
991/********** wxTable::execUpdate() **********/
992bool wxTable::execUpdate(char *pSqlStmt)
993{
994 // Execute the UPDATE statement
995 if (SQLExecDirect(hstmtUpdate, (UCHAR FAR *) pSqlStmt, SQL_NTS) != SQL_SUCCESS)
996 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
997
998 // Record deleted successfully
999 return(TRUE);
1000
1001} // wxTable::execUpdate()
1002
1003/********** wxTable::GetUpdateStmt() **********/
1004void wxTable::GetUpdateStmt(char *pSqlStmt, int typeOfUpd, char *pWhereClause)
1005{
1006 char whereClause[DB_MAX_WHERE_CLAUSE_LEN];
1007 bool firstColumn = TRUE;
1008
1009 whereClause[0] = 0;
1010 sprintf(pSqlStmt, "UPDATE %s SET ", tableName);
1011
1012 // Append a list of columns to be updated
1013 for (int i = 0; i < noCols; i++)
1014 {
1015 // Only append Updateable columns
1016 if (colDefs[i].Updateable)
1017 {
1018 if (! firstColumn)
1019 strcat(pSqlStmt, ",");
1020 else
1021 firstColumn = FALSE;
1022 strcat(pSqlStmt, colDefs[i].ColName);
1023 strcat(pSqlStmt, " = ?");
1024 }
1025 }
1026
1027 // Append the WHERE clause to the SQL UPDATE statement
1028 strcat(pSqlStmt, " WHERE ");
1029 switch(typeOfUpd)
1030 {
1031 case DB_UPD_KEYFIELDS:
1032 // If the datasource supports the ROWID column, build
1033 // the where on ROWID for efficiency purposes.
1034 // e.g. UPDATE PARTS SET C1 = ?, C2 = ? WHERE ROWID = '111.222.333'
1035 if (CanUpdByROWID())
1036 {
1037 SDWORD cb;
1038 char rowid[ROWID_LEN];
1039
1040 // Get the ROWID value. If not successful retreiving the ROWID,
1041 // simply fall down through the code and build the WHERE clause
1042 // based on the key fields.
1043 if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, rowid, ROWID_LEN, &cb) == SQL_SUCCESS)
1044 {
1045 strcat(pSqlStmt, "ROWID = '");
1046 strcat(pSqlStmt, rowid);
1047 strcat(pSqlStmt, "'");
1048 break;
1049 }
1050 }
1051 // Unable to delete by ROWID, so build a WHERE
1052 // clause based on the keyfields.
1053 GetWhereClause(whereClause, DB_WHERE_KEYFIELDS);
1054 strcat(pSqlStmt, whereClause);
1055 break;
1056 case DB_UPD_WHERE:
1057 strcat(pSqlStmt, pWhereClause);
1058 break;
1059 }
1060
1061} // GetUpdateStmt()
1062
1063/********** wxTable::GetDeleteStmt() **********/
1064void wxTable::GetDeleteStmt(char *pSqlStmt, int typeOfDel, char *pWhereClause)
1065{
1066 char whereClause[DB_MAX_WHERE_CLAUSE_LEN];
1067
1068 whereClause[0] = 0;
1069
1070 // Handle the case of DeleteWhere() and the where clause is blank. It should
1071 // delete all records from the database in this case.
1072 if (typeOfDel == DB_DEL_WHERE && (pWhereClause == 0 || strlen(pWhereClause) == 0))
1073 {
1074 sprintf(pSqlStmt, "DELETE FROM %s", tableName);
1075 return;
1076 }
1077
1078 sprintf(pSqlStmt, "DELETE FROM %s WHERE ", tableName);
1079
1080 // Append the WHERE clause to the SQL DELETE statement
1081 switch(typeOfDel)
1082 {
1083 case DB_DEL_KEYFIELDS:
1084 // If the datasource supports the ROWID column, build
1085 // the where on ROWID for efficiency purposes.
1086 // e.g. DELETE FROM PARTS WHERE ROWID = '111.222.333'
1087 if (CanUpdByROWID())
1088 {
1089 SDWORD cb;
1090 char rowid[ROWID_LEN];
1091
1092 // Get the ROWID value. If not successful retreiving the ROWID,
1093 // simply fall down through the code and build the WHERE clause
1094 // based on the key fields.
1095 if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, rowid, ROWID_LEN, &cb) == SQL_SUCCESS)
1096 {
1097 strcat(pSqlStmt, "ROWID = '");
1098 strcat(pSqlStmt, rowid);
1099 strcat(pSqlStmt, "'");
1100 break;
1101 }
1102 }
1103 // Unable to delete by ROWID, so build a WHERE
1104 // clause based on the keyfields.
1105 GetWhereClause(whereClause, DB_WHERE_KEYFIELDS);
1106 strcat(pSqlStmt, whereClause);
1107 break;
1108 case DB_DEL_WHERE:
1109 strcat(pSqlStmt, pWhereClause);
1110 break;
1111 case DB_DEL_MATCHING:
1112 GetWhereClause(whereClause, DB_WHERE_MATCHING);
1113 strcat(pSqlStmt, whereClause);
1114 break;
1115 }
1116
1117} // GetDeleteStmt()
1118
1119/********** wxTable::GetWhereClause() **********/
1120/*
1121 * Note: GetWhereClause() currently ignores timestamp columns.
1122 * They are not included as part of the where clause.
1123 */
1124
1fc5dd6f 1125void wxTable::GetWhereClause(char *pWhereClause, int typeOfWhere, char *qualTableName)
108106cf
JS
1126{
1127 bool moreThanOneColumn = FALSE;
1fc5dd6f 1128 char colValue[255];
108106cf
JS
1129
1130 // Loop through the columns building a where clause as you go
1131 for (int i = 0; i < noCols; i++)
1132 {
1133 // Determine if this column should be included in the WHERE clause
1134 if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[i].KeyField) ||
1135 (typeOfWhere == DB_WHERE_MATCHING && (! IsColNull(i))))
1136 {
1137 // Skip over timestamp columns
1138 if (colDefs[i].SqlCtype == SQL_C_TIMESTAMP)
1139 continue;
1140 // If there is more than 1 column, join them with the keyword "AND"
1141 if (moreThanOneColumn)
1142 strcat(pWhereClause, " AND ");
1143 else
1144 moreThanOneColumn = TRUE;
1145 // Concatenate where phrase for the column
1fc5dd6f
JS
1146 if (qualTableName && strlen(qualTableName))
1147 {
1148 strcat(pWhereClause, qualTableName);
1149 strcat(pWhereClause, ".");
1150 }
108106cf
JS
1151 strcat(pWhereClause, colDefs[i].ColName);
1152 strcat(pWhereClause, " = ");
1153 switch(colDefs[i].SqlCtype)
1154 {
1155 case SQL_C_CHAR:
1fc5dd6f 1156 sprintf(colValue, "'%s'", (UCHAR FAR *) colDefs[i].PtrDataObj);
108106cf
JS
1157 break;
1158 case SQL_C_SSHORT:
1fc5dd6f 1159 sprintf(colValue, "%hi", *((SWORD *) colDefs[i].PtrDataObj));
108106cf
JS
1160 break;
1161 case SQL_C_USHORT:
1fc5dd6f 1162 sprintf(colValue, "%hu", *((UWORD *) colDefs[i].PtrDataObj));
108106cf
JS
1163 break;
1164 case SQL_C_SLONG:
1fc5dd6f 1165 sprintf(colValue, "%li", *((SDWORD *) colDefs[i].PtrDataObj));
108106cf
JS
1166 break;
1167 case SQL_C_ULONG:
1fc5dd6f 1168 sprintf(colValue, "%lu", *((UDWORD *) colDefs[i].PtrDataObj));
108106cf
JS
1169 break;
1170 case SQL_C_FLOAT:
1fc5dd6f 1171 sprintf(colValue, "%.6f", *((SFLOAT *) colDefs[i].PtrDataObj));
108106cf
JS
1172 break;
1173 case SQL_C_DOUBLE:
1fc5dd6f 1174 sprintf(colValue, "%.6f", *((SDOUBLE *) colDefs[i].PtrDataObj));
108106cf
JS
1175 break;
1176 }
1177 strcat(pWhereClause, colValue);
1178 }
1179 }
1180
1181} // wxTable::GetWhereClause()
1182
1183/********** wxTable::IsColNull() **********/
1184bool wxTable::IsColNull(int colNo)
1185{
1186 switch(colDefs[colNo].SqlCtype)
1187 {
1188 case SQL_C_CHAR:
1189 return(((UCHAR FAR *) colDefs[colNo].PtrDataObj)[0] == 0);
1190 case SQL_C_SSHORT:
1191 return(( *((SWORD *) colDefs[colNo].PtrDataObj)) == 0);
1192 case SQL_C_USHORT:
1193 return(( *((UWORD*) colDefs[colNo].PtrDataObj)) == 0);
1194 case SQL_C_SLONG:
1195 return(( *((SDWORD *) colDefs[colNo].PtrDataObj)) == 0);
1196 case SQL_C_ULONG:
1197 return(( *((UDWORD *) colDefs[colNo].PtrDataObj)) == 0);
1198 case SQL_C_FLOAT:
1199 return(( *((SFLOAT *) colDefs[colNo].PtrDataObj)) == 0);
1200 case SQL_C_DOUBLE:
1201 return((*((SDOUBLE *) colDefs[colNo].PtrDataObj)) == 0);
1202 case SQL_C_TIMESTAMP:
1203 TIMESTAMP_STRUCT *pDt;
1204 pDt = (TIMESTAMP_STRUCT *) colDefs[colNo].PtrDataObj;
1205 if (pDt->year == 0 && pDt->month == 0 && pDt->day == 0)
1206 return(TRUE);
1207 else
1208 return(FALSE);
1209 default:
1210 return(TRUE);
1211 }
1212
1213} // wxTable::IsColNull()
1214
1215/********** wxTable::CanSelectForUpdate() **********/
1216
1217bool wxTable::CanSelectForUpdate(void)
1218{
1219 if (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)
1220 return(TRUE);
1221 else
1222 return(FALSE);
1223
1224} // wxTable::CanSelectForUpdate()
1225
1226/********** wxTable::CanUpdByROWID() **********/
1227bool wxTable::CanUpdByROWID(void)
1228{
1229
1fc5dd6f
JS
1230//NOTE: Returning FALSE for now until this can be debugged,
1231// as the ROWID is not getting updated correctly
108106cf
JS
1232 return FALSE;
1233
1234 if ((! strcmp(pDb->dbInf.dbmsName, "Oracle")) || (! strcmp(pDb->dbInf.dbmsName, "ORACLE")))
1235 return(TRUE);
1236 else
1237 return(FALSE);
1238
1239} // wxTable::CanUpdByROWID()
1240
1241/********** wxTable::IsCursorClosedOnCommit() **********/
1242bool wxTable::IsCursorClosedOnCommit(void)
1243{
1244 if (pDb->dbInf.cursorCommitBehavior == SQL_CB_PRESERVE)
1245 return(FALSE);
1246 else
1247 return(TRUE);
1248
1249} // wxTable::IsCursorClosedOnCommit()
1250
1251/********** wxTable::ClearMemberVars() **********/
1252void wxTable::ClearMemberVars(void)
1253{
1254 // Loop through the columns setting each member variable to zero
1255 for (int i = 0; i < noCols; i++)
1256 {
1257 switch(colDefs[i].SqlCtype)
1258 {
1259 case SQL_C_CHAR:
1260 ((UCHAR FAR *) colDefs[i].PtrDataObj)[0] = 0;
1261 break;
1262 case SQL_C_SSHORT:
1263 *((SWORD *) colDefs[i].PtrDataObj) = 0;
1264 break;
1265 case SQL_C_USHORT:
1266 *((UWORD*) colDefs[i].PtrDataObj) = 0;
1267 break;
1268 case SQL_C_SLONG:
1269 *((SDWORD *) colDefs[i].PtrDataObj) = 0;
1270 break;
1271 case SQL_C_ULONG:
1272 *((UDWORD *) colDefs[i].PtrDataObj) = 0;
1273 break;
1274 case SQL_C_FLOAT:
1275 *((SFLOAT *) colDefs[i].PtrDataObj) = 0.0f;
1276 break;
1277 case SQL_C_DOUBLE:
1278 *((SDOUBLE *) colDefs[i].PtrDataObj) = 0.0f;
1279 break;
1280 case SQL_C_TIMESTAMP:
1281 TIMESTAMP_STRUCT *pDt;
1282 pDt = (TIMESTAMP_STRUCT *) colDefs[i].PtrDataObj;
1283 pDt->year = 0;
1284 pDt->month = 0;
1285 pDt->day = 0;
1286 pDt->hour = 0;
1287 pDt->minute = 0;
1288 pDt->second = 0;
1289 pDt->fraction = 0;
1290 break;
1291 }
1292 }
1293
1294} // wxTable::ClearMemberVars()
1295
1296/********** wxTable::SetQueryTimeout() **********/
1297bool wxTable::SetQueryTimeout(UDWORD nSeconds)
1298{
1299 if (SQLSetStmtOption(c0, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1300 return(pDb->DispAllErrors(henv, hdbc, c0));
1301 if (SQLSetStmtOption(c1, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1302 return(pDb->DispAllErrors(henv, hdbc, c1));
1303 if (SQLSetStmtOption(c2, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1304 return(pDb->DispAllErrors(henv, hdbc, c2));
1305// if (SQLSetStmtOption(c3, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1306// return(pDb->DispAllErrors(henv, hdbc, c3));
1307// if (SQLSetStmtOption(c4, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1308// return(pDb->DispAllErrors(henv, hdbc, c4));
1309// if (SQLSetStmtOption(c5, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1310// return(pDb->DispAllErrors(henv, hdbc, c5));
1311 if (SQLSetStmtOption(hstmtInsert, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1312 return(pDb->DispAllErrors(henv, hdbc, hstmtInsert));
1313 if (SQLSetStmtOption(hstmtUpdate, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1314 return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate));
1315 if (SQLSetStmtOption(hstmtDelete, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1316 return(pDb->DispAllErrors(henv, hdbc, hstmtDelete));
1317 if (SQLSetStmtOption(hstmtCount, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS)
1318 return(pDb->DispAllErrors(henv, hdbc, hstmtCount));
1319
1320 // Completed Successfully
1321 return(TRUE);
1322
1323} // wxTable::SetQueryTimeout()
1324
1325/********** wxTable::SetColDefs() **********/
1326void wxTable::SetColDefs (int index, char *fieldName, int dataType, void *pData,
1327 int cType, int size, bool keyField, bool upd,
1328 bool insAllow, bool derivedCol)
1329{
1330 if (strlen(fieldName) > DB_MAX_COLUMN_NAME_LEN) // glt 4/21/97
1331 {
1332 strncpy (colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN);
1333 colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0; // glt 10/23/97
1334 }
1335 else
1336 strcpy(colDefs[index].ColName, fieldName);
1337
1338 colDefs[index].DbDataType = dataType;
1339 colDefs[index].PtrDataObj = pData;
1340 colDefs[index].SqlCtype = cType;
1341 colDefs[index].SzDataObj = size;
1342 colDefs[index].KeyField = keyField;
1343 colDefs[index].DerivedCol = derivedCol;
1344 // Derived columns by definition would NOT be "Insertable" or "Updateable"
1345 if (derivedCol)
1346 {
1347 colDefs[index].Updateable = FALSE;
1348 colDefs[index].InsertAllowed = FALSE;
1349 }
1350 else
1351 {
1352 colDefs[index].Updateable = upd;
1353 colDefs[index].InsertAllowed = insAllow;
1354 }
1355
1356} // wxTable::SetColDefs()
1357
1358/********** wxTable::SetCursor() **********/
1359bool wxTable::SetCursor(int cursorNo)
1360{
1361 switch(cursorNo)
1362 {
1363 case DB_CURSOR0:
1364 hstmt = c0;
1365 // currCursorNo doesn't change since Cursor0 is a temp cursor
1366 break;
1367 case DB_CURSOR1:
1368 hstmt = c1;
1369 currCursorNo = DB_CURSOR1;
1370 break;
1371 case DB_CURSOR2:
1372 hstmt = c2;
1373 currCursorNo = DB_CURSOR2;
1374 break;
1375// case DB_CURSOR3:
1376// hstmt = c3;
1377// currCursorNo = DB_CURSOR3;
1378// break;
1379// case DB_CURSOR4:
1380// hstmt = c4;
1381// currCursorNo = DB_CURSOR4;
1382// break;
1383// case DB_CURSOR5:
1384// hstmt = c5;
1385// currCursorNo = DB_CURSOR5;
1386// break;
1387 default:
1388 return(FALSE);
1389 }
1390
1391 // Refresh the current record
1392#ifndef FWD_ONLY_CURSORS
1393 UDWORD cRowsFetched;
1394 UWORD rowStatus;
1395 SQLExtendedFetch(hstmt, SQL_FETCH_NEXT, 0, &cRowsFetched, &rowStatus);
1396 SQLExtendedFetch(hstmt, SQL_FETCH_PRIOR, 0, &cRowsFetched, &rowStatus);
1397#endif
1398
1399 // Completed successfully
1400 return(TRUE);
1401
1402} // wxTable::SetCursor()
1403
1404/********** wxTable::Count() **********/
1405ULONG wxTable::Count(void)
1406{
1407 ULONG l;
1408 char sqlStmt[DB_MAX_STATEMENT_LEN];
1409 SDWORD cb;
1410
1411 // Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement
1412 strcpy(sqlStmt, "SELECT COUNT(*) FROM ");
1413 strcat(sqlStmt, queryTableName);
1414
1fc5dd6f
JS
1415 if (from && strlen(from))
1416 strcat(sqlStmt, from);
1417
108106cf
JS
1418 // Add the where clause if one is provided
1419 if (where && strlen(where))
1420 {
1421 strcat(sqlStmt, " WHERE ");
1422 strcat(sqlStmt, where);
1423 }
1424
1fc5dd6f
JS
1425 pDb->WriteSqlLog(sqlStmt);
1426
108106cf
JS
1427 // Execute the SQL statement
1428 if (SQLExecDirect(hstmtCount, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS)
1429 {
1430 pDb->DispAllErrors(henv, hdbc, hstmtCount);
1431 return(0);
1432 }
1433
1434 // Fetch the record
1435 if (SQLFetch(hstmtCount) != SQL_SUCCESS)
1436 {
1437 pDb->DispAllErrors(henv, hdbc, hstmtCount);
1438 return(0);
1439 }
1440
1441 // Obtain the result
1442 if (SQLGetData(hstmtCount, 1, SQL_C_ULONG, &l, sizeof(l), &cb) != SQL_SUCCESS)
1443 {
1444 pDb->DispAllErrors(henv, hdbc, hstmtCount);
1445 return(0);
1446 }
1447
1448 // Free the cursor
1449 if (SQLFreeStmt(hstmtCount, SQL_CLOSE) != SQL_SUCCESS)
1450 pDb->DispAllErrors(henv, hdbc, hstmtCount);
1451
1452 // Return the record count
1453 return(l);
1454
1455} // wxTable::Count()
1456
1457/********** wxTable::Refresh() **********/
1458bool wxTable::Refresh(void)
1459{
1460 bool result = TRUE;
1461
1462 // Switch to cursor 0
1463 int cursorNo = GetCursor();
1464 if (!SetCursor())
1465 return(FALSE);
1466
1467 // Save the where and order by clauses
1468 char *saveWhere = where;
1469 char *saveOrderBy = orderBy;
1470
1471 // Build a where clause to refetch the record with. Try and use the
1472 // ROWID if it's available, ow use the key fields.
1473 char whereClause[DB_MAX_WHERE_CLAUSE_LEN+1];
1474 strcpy(whereClause, "");
1475 if (CanUpdByROWID())
1476 {
1477 SDWORD cb;
1478 char rowid[ROWID_LEN+1];
1479
1480 // Get the ROWID value. If not successful retreiving the ROWID,
1481 // simply fall down through the code and build the WHERE clause
1482 // based on the key fields.
1483 if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, rowid, ROWID_LEN, &cb) == SQL_SUCCESS)
1484 {
1fc5dd6f
JS
1485 strcat(whereClause, queryTableName);
1486 strcat(whereClause, ".ROWID = '");
108106cf
JS
1487 strcat(whereClause, rowid);
1488 strcat(whereClause, "'");
1489 }
1490 }
1491
1492 // If unable to use the ROWID, build a where clause from the keyfields
1493 if (strlen(whereClause) == 0)
1fc5dd6f 1494 GetWhereClause(whereClause, DB_WHERE_KEYFIELDS, queryTableName);
108106cf
JS
1495
1496 // Requery the record
1497 where = whereClause;
1498 orderBy = 0;
1499 if (!Query())
1500 result = FALSE;
1501
1502 if (result && !GetNext())
1503 result = FALSE;
1504
1505 // Switch back to original cursor
1506 if (!SetCursor(cursorNo))
1507 result = FALSE;
1508
1509 // Restore the original where and order by clauses
1510 where = saveWhere;
1511 orderBy = saveOrderBy;
1512
1513 return(result);
1514
1515} // wxTable::Refresh()
1516
1517#endif
1fc5dd6f
JS
1518 // wxUSE_ODBC
1519