1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: Implementation of the wxTable class.
6 // -Dynamic cursor support - Only one predefined cursor, as many others as
7 // you need may be created on demand
8 // -Reduced number of active cursors significantly
9 // -Query-Only wxTable objects
12 // Copyright: (c) 1996 Remstar International, Inc.
13 // Licence: wxWindows licence, plus:
14 // Notice: This class library and its intellectual design are free of charge for use,
15 // modification, enhancement, debugging under the following conditions:
16 // 1) These classes may only be used as part of the implementation of a
17 // wxWindows-based application
18 // 2) All enhancements and bug fixes are to be submitted back to the wxWindows
19 // user groups free of all charges for use with the wxWindows library.
20 // 3) These classes may not be distributed as part of any other class library,
21 // DLL, text (written or electronic), other than a complete distribution of
22 // the wxWindows GUI development toolkit.
23 ///////////////////////////////////////////////////////////////////////////////
30 // Use this line for wxWindows v1.x
32 // Use this line for wxWindows v2.x
33 #include "wx/version.h"
34 #include "wx/wxprec.h"
36 #if wxMAJOR_VERSION == 2
38 # pragma implementation "dbtable.h"
42 #ifdef DBDEBUG_CONSOLE
50 #if wxMAJOR_VERSION == 2
52 #include "wx/string.h"
53 #include "wx/object.h"
56 #include "wx/msgdlg.h"
58 #include "wx/filefn.h"
61 #if wxMAJOR_VERSION == 1
62 # if defined(wx_msw) || defined(wx_x)
78 #if wxMAJOR_VERSION == 1
80 #elif wxMAJOR_VERSION == 2
81 #include "wx/dbtable.h"
85 // The HPUX preprocessor lines below were commented out on 8/20/97
86 // because macros.h currently redefines DEBUG and is unneeded.
88 // # include <macros.h>
91 # include <sys/minmax.h>
95 ULONG lastTableID
= 0;
103 /********** wxTable::wxTable() **********/
104 wxTable::wxTable(wxDB
*pwxDB
, const char *tblName
, const int nCols
,
105 const char *qryTblName
, bool qryOnly
, char *tblPath
)
107 pDb
= pwxDB
; // Pointer to the wxDB object
111 hstmtDefault
= 0; // Initialized below
112 hstmtCount
= 0; // Initialized first time it is needed
119 noCols
= nCols
; // No. of cols in the table
120 where
= 0; // Where clause
121 orderBy
= 0; // Order By clause
122 from
= 0; // From clause
123 selectForUpdate
= FALSE
; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase
128 strcpy(tableName
, tblName
); // Table Name
130 strcpy(tablePath
, tblPath
); // Table Path - used for dBase files
132 if (qryTblName
) // Name of the table/view to query
133 strcpy(queryTableName
, qryTblName
);
135 strcpy(queryTableName
, tblName
);
137 // assert(pDb); // Assert is placed after table name is assigned for error reporting reasons
144 tableID
= ++lastTableID
;
145 sprintf(s
, "wxTable constructor (%-20s) tableID:[%6lu] pDb:[%p]", tblName
,tableID
,pDb
);
148 CstructTablesInUse
*tableInUse
;
149 tableInUse
= new CstructTablesInUse();
150 tableInUse
->tableName
= tblName
;
151 tableInUse
->tableID
= tableID
;
152 tableInUse
->pDb
= pDb
;
153 TablesInUse
.Append(tableInUse
);
158 // Grab the HENV and HDBC from the wxDB object
162 // Allocate space for column definitions
164 colDefs
= new CcolDef
[noCols
]; // Points to the first column defintion
166 // Allocate statement handles for the table
169 // Allocate a separate statement handle for performing inserts
170 if (SQLAllocStmt(hdbc
, &hstmtInsert
) != SQL_SUCCESS
)
171 pDb
->DispAllErrors(henv
, hdbc
);
172 // Allocate a separate statement handle for performing deletes
173 if (SQLAllocStmt(hdbc
, &hstmtDelete
) != SQL_SUCCESS
)
174 pDb
->DispAllErrors(henv
, hdbc
);
175 // Allocate a separate statement handle for performing updates
176 if (SQLAllocStmt(hdbc
, &hstmtUpdate
) != SQL_SUCCESS
)
177 pDb
->DispAllErrors(henv
, hdbc
);
179 // Allocate a separate statement handle for internal use
180 if (SQLAllocStmt(hdbc
, &hstmtInternal
) != SQL_SUCCESS
)
181 pDb
->DispAllErrors(henv
, hdbc
);
183 // Set the cursor type for the statement handles
184 cursorType
= SQL_CURSOR_STATIC
;
185 if (SQLSetStmtOption(hstmtInternal
, SQL_CURSOR_TYPE
, cursorType
) != SQL_SUCCESS
)
187 // Check to see if cursor type is supported
188 pDb
->GetNextError(henv
, hdbc
, hstmtInternal
);
189 if (! wxStrcmp(pDb
->sqlState
, "01S02")) // Option Value Changed
191 // Datasource does not support static cursors. Driver
192 // will substitute a cursor type. Call SQLGetStmtOption()
193 // to determine which cursor type was selected.
194 if (SQLGetStmtOption(hstmtInternal
, SQL_CURSOR_TYPE
, &cursorType
) != SQL_SUCCESS
)
195 pDb
->DispAllErrors(henv
, hdbc
, hstmtInternal
);
196 #ifdef DBDEBUG_CONSOLE
197 cout
<< "Static cursor changed to: ";
200 case SQL_CURSOR_FORWARD_ONLY
:
201 cout
<< "Forward Only"; break;
202 case SQL_CURSOR_STATIC
:
203 cout
<< "Static"; break;
204 case SQL_CURSOR_KEYSET_DRIVEN
:
205 cout
<< "Keyset Driven"; break;
206 case SQL_CURSOR_DYNAMIC
:
207 cout
<< "Dynamic"; break;
209 cout
<< endl
<< endl
;
214 pDb
->DispNextError();
215 pDb
->DispAllErrors(henv
, hdbc
, hstmtInternal
);
218 #ifdef DBDEBUG_CONSOLE
220 cout
<< "Cursor Type set to STATIC" << endl
<< endl
;
225 // Set the cursor type for the INSERT statement handle
226 if (SQLSetStmtOption(hstmtInsert
, SQL_CURSOR_TYPE
, SQL_CURSOR_FORWARD_ONLY
) != SQL_SUCCESS
)
227 pDb
->DispAllErrors(henv
, hdbc
, hstmtInsert
);
228 // Set the cursor type for the DELETE statement handle
229 if (SQLSetStmtOption(hstmtDelete
, SQL_CURSOR_TYPE
, SQL_CURSOR_FORWARD_ONLY
) != SQL_SUCCESS
)
230 pDb
->DispAllErrors(henv
, hdbc
, hstmtDelete
);
231 // Set the cursor type for the UPDATE statement handle
232 if (SQLSetStmtOption(hstmtUpdate
, SQL_CURSOR_TYPE
, SQL_CURSOR_FORWARD_ONLY
) != SQL_SUCCESS
)
233 pDb
->DispAllErrors(henv
, hdbc
, hstmtUpdate
);
236 // Make the default cursor the active cursor
237 hstmtDefault
= NewCursor(FALSE
,FALSE
);
238 assert(hstmtDefault
);
239 hstmt
= *hstmtDefault
;
241 } // wxTable::wxTable()
243 /********** wxTable::~wxTable() **********/
249 sprintf(s
, "wxTable destructor (%-20s) tableID:[%6lu] pDb:[%p]", tableName
,tableID
,pDb
);
253 #ifndef PROGRAM_FP4UPG
259 pNode
= TablesInUse
.First();
260 while (pNode
&& !found
)
262 if (((CstructTablesInUse
*)pNode
->Data())->tableID
== tableID
)
265 if (!TablesInUse
.DeleteNode(pNode
))
266 wxMessageBox (s
,"Unable to delete node!");
269 pNode
= pNode
->Next();
274 sprintf(msg
,"Unable to find the tableID in the linked\nlist of tables in use.\n\n%s",s
);
275 wxMessageBox (msg
,"NOTICE...");
280 // Decrement the wxDB table count
284 // Delete memory allocated for column definitions
288 // Free statement handles
292 if (SQLFreeStmt(hstmtInsert
, SQL_DROP
) != SQL_SUCCESS
)
293 pDb
->DispAllErrors(henv
, hdbc
);
295 if (SQLFreeStmt(hstmtDelete
, SQL_DROP
) != SQL_SUCCESS
)
296 pDb
->DispAllErrors(henv
, hdbc
);
298 if (SQLFreeStmt(hstmtUpdate
, SQL_DROP
) != SQL_SUCCESS
)
299 pDb
->DispAllErrors(henv
, hdbc
);
302 if (SQLFreeStmt(hstmtInternal
, SQL_DROP
) != SQL_SUCCESS
)
303 pDb
->DispAllErrors(henv
, hdbc
);
305 // Delete dynamically allocated cursors
307 DeleteCursor(hstmtDefault
);
309 DeleteCursor(hstmtCount
);
311 } // wxTable::~wxTable()
313 /********** wxTable::Open() **********/
314 bool wxTable::Open(void)
320 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
322 // Verify that the table exists in the database
323 if (!pDb
->TableExists(tableName
,NULL
,tablePath
))
326 sprintf(s
, "Error opening '%s', table/view does not exist in the database.", tableName
);
331 // Bind the member variables for field exchange between
332 // the wxTable object and the ODBC record.
335 if (!bindInsertParams()) // Inserts
337 if (!bindUpdateParams()) // Updates
340 if (!bindCols(*hstmtDefault
)) // Selects
342 if (!bindCols(hstmtInternal
)) // Internal use only
345 * Do NOT bind the hstmtCount cursor!!!
348 // Build an insert statement using parameter markers
349 if (!queryOnly
&& noCols
> 0)
351 bool needComma
= FALSE
;
352 sprintf(sqlStmt
, "INSERT INTO %s (", tableName
);
353 for (i
= 0; i
< noCols
; i
++)
355 if (! colDefs
[i
].InsertAllowed
)
358 strcat(sqlStmt
, ",");
359 strcat(sqlStmt
, colDefs
[i
].ColName
);
363 strcat(sqlStmt
, ") VALUES (");
364 for (i
= 0; i
< noCols
; i
++)
366 if (! colDefs
[i
].InsertAllowed
)
369 strcat(sqlStmt
, ",");
370 strcat(sqlStmt
, "?");
373 strcat(sqlStmt
, ")");
375 // pDb->WriteSqlLog(sqlStmt);
377 // Prepare the insert statement for execution
378 if (SQLPrepare(hstmtInsert
, (UCHAR FAR
*) sqlStmt
, SQL_NTS
) != SQL_SUCCESS
)
379 return(pDb
->DispAllErrors(henv
, hdbc
, hstmtInsert
));
382 // Completed successfully
387 /********** wxTable::Query() **********/
388 bool wxTable::Query(bool forUpdate
, bool distinct
)
391 return(query(DB_SELECT_WHERE
, forUpdate
, distinct
));
393 } // wxTable::Query()
395 /********** wxTable::QueryBySqlStmt() **********/
396 bool wxTable::QueryBySqlStmt(char *pSqlStmt
)
398 pDb
->WriteSqlLog(pSqlStmt
);
400 return(query(DB_SELECT_STATEMENT
, FALSE
, FALSE
, pSqlStmt
));
402 } // wxTable::QueryBySqlStmt()
404 /********** wxTable::QueryMatching() **********/
405 bool wxTable::QueryMatching(bool forUpdate
, bool distinct
)
408 return(query(DB_SELECT_MATCHING
, forUpdate
, distinct
));
410 } // wxTable::QueryMatching()
412 /********** wxTable::QueryOnKeyFields() **********/
413 bool wxTable::QueryOnKeyFields(bool forUpdate
, bool distinct
)
416 return(query(DB_SELECT_KEYFIELDS
, forUpdate
, distinct
));
418 } // wxTable::QueryOnKeyFields()
420 /********** wxTable::query() **********/
421 bool wxTable::query(int queryType
, bool forUpdate
, bool distinct
, char *pSqlStmt
)
423 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
425 // Set the selectForUpdate member variable
427 // The user may wish to select for update, but the DBMS may not be capable
428 selectForUpdate
= CanSelectForUpdate();
430 selectForUpdate
= FALSE
;
432 // Set the SQL SELECT string
433 if (queryType
!= DB_SELECT_STATEMENT
) // A select statement was not passed in,
434 { // so generate a select statement.
435 GetSelectStmt(sqlStmt
, queryType
, distinct
);
436 pDb
->WriteSqlLog(sqlStmt
);
439 // Make sure the cursor is closed first
440 if (! CloseCursor(hstmt
))
443 // Execute the SQL SELECT statement
446 retcode
= SQLExecDirect(hstmt
, (UCHAR FAR
*) (queryType
== DB_SELECT_STATEMENT
? pSqlStmt
: sqlStmt
), SQL_NTS
);
447 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
448 return(pDb
->DispAllErrors(henv
, hdbc
, hstmt
));
450 // Completed successfully
453 } // wxTable::query()
455 /********** wxTable::GetSelectStmt() **********/
456 void wxTable::GetSelectStmt(char *pSqlStmt
, int typeOfSelect
, bool distinct
)
458 char whereClause
[DB_MAX_WHERE_CLAUSE_LEN
];
462 // Build a select statement to query the database
463 strcpy(pSqlStmt
, "SELECT ");
465 // SELECT DISTINCT values only?
467 strcat(pSqlStmt
, "DISTINCT ");
469 // Was a FROM clause specified to join tables to the base table?
470 // Available for ::Query() only!!!
471 bool appendFromClause
= FALSE
;
472 if (typeOfSelect
== DB_SELECT_WHERE
&& from
&& strlen(from
))
473 appendFromClause
= TRUE
;
475 // Add the column list
477 for (i
= 0; i
< noCols
; i
++)
479 // If joining tables, the base table column names must be qualified to avoid ambiguity
480 if (appendFromClause
)
482 strcat(pSqlStmt
, queryTableName
);
483 strcat(pSqlStmt
, ".");
485 strcat(pSqlStmt
, colDefs
[i
].ColName
);
487 strcat(pSqlStmt
, ",");
490 // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve
491 // the ROWID if querying distinct records. The rowid will always be unique.
492 if (!distinct
&& CanUpdByROWID())
494 // If joining tables, the base table column names must be qualified to avoid ambiguity
495 if (appendFromClause
)
497 strcat(pSqlStmt
, ",");
498 strcat(pSqlStmt
, queryTableName
);
499 strcat(pSqlStmt
, ".ROWID");
502 strcat(pSqlStmt
, ",ROWID");
505 // Append the FROM tablename portion
506 strcat(pSqlStmt
, " FROM ");
507 strcat(pSqlStmt
, queryTableName
);
509 // Sybase uses the HOLDLOCK keyword to lock a record during query.
510 // The HOLDLOCK keyword follows the table name in the from clause.
511 // Each table in the from clause must specify HOLDLOCK or
512 // NOHOLDLOCK (the default). Note: The "FOR UPDATE" clause
513 // is parsed but ignored in SYBASE Transact-SQL.
514 if (selectForUpdate
&& (pDb
->Dbms() == dbmsSYBASE_ASA
|| pDb
->Dbms() == dbmsSYBASE_ASE
))
515 strcat(pSqlStmt
, " HOLDLOCK");
517 if (appendFromClause
)
518 strcat(pSqlStmt
, from
);
520 // Append the WHERE clause. Either append the where clause for the class
521 // or build a where clause. The typeOfSelect determines this.
524 case DB_SELECT_WHERE
:
525 if (where
&& strlen(where
)) // May not want a where clause!!!
527 strcat(pSqlStmt
, " WHERE ");
528 strcat(pSqlStmt
, where
);
531 case DB_SELECT_KEYFIELDS
:
532 GetWhereClause(whereClause
, DB_WHERE_KEYFIELDS
);
533 if (strlen(whereClause
))
535 strcat(pSqlStmt
, " WHERE ");
536 strcat(pSqlStmt
, whereClause
);
539 case DB_SELECT_MATCHING
:
540 GetWhereClause(whereClause
, DB_WHERE_MATCHING
);
541 if (strlen(whereClause
))
543 strcat(pSqlStmt
, " WHERE ");
544 strcat(pSqlStmt
, whereClause
);
549 // Append the ORDER BY clause
550 if (orderBy
&& strlen(orderBy
))
552 strcat(pSqlStmt
, " ORDER BY ");
553 strcat(pSqlStmt
, orderBy
);
556 // SELECT FOR UPDATE if told to do so and the datasource is capable. Sybase
557 // parses the FOR UPDATE clause but ignores it. See the comment above on the
558 // HOLDLOCK for Sybase.
559 if (selectForUpdate
&& CanSelectForUpdate())
560 strcat(pSqlStmt
, " FOR UPDATE");
562 } // wxTable::GetSelectStmt()
564 /********** wxTable::getRec() **********/
565 bool wxTable::getRec(UWORD fetchType
)
569 #if wxODBC_FWD_ONLY_CURSORS
571 // Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType
574 if ((retcode
= SQLExtendedFetch(hstmt
, fetchType
, 0, &cRowsFetched
, &rowStatus
)) != SQL_SUCCESS
)
575 if (retcode
== SQL_NO_DATA_FOUND
)
578 return(pDb
->DispAllErrors(henv
, hdbc
, hstmt
));
581 // Fetch the next record from the record set
582 retcode
= SQLFetch(hstmt
);
583 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
585 if (retcode
== SQL_NO_DATA_FOUND
)
588 return(pDb
->DispAllErrors(henv
, hdbc
, hstmt
));
592 // Completed successfully
595 } // wxTable::getRec()
597 /********** wxTable::GetRowNum() **********/
598 UWORD
wxTable::GetRowNum(void)
602 if (SQLGetStmtOption(hstmt
, SQL_ROW_NUMBER
, (UCHAR
*) &rowNum
) != SQL_SUCCESS
)
604 pDb
->DispAllErrors(henv
, hdbc
, hstmt
);
608 // Completed successfully
609 return((UWORD
) rowNum
);
611 } // wxTable::GetRowNum()
613 /********** wxTable::bindInsertParams() **********/
614 bool wxTable::bindInsertParams(void)
621 UDWORD precision
= 0;
624 // Bind each column (that can be inserted) of the table to a parameter marker
626 for (i
= 0; i
< noCols
; i
++)
628 if (! colDefs
[i
].InsertAllowed
)
630 switch(colDefs
[i
].DbDataType
)
632 case DB_DATA_TYPE_VARCHAR
:
633 fSqlType
= pDb
->typeInfVarchar
.FsqlType
;
634 precision
= colDefs
[i
].SzDataObj
;
636 colDefs
[i
].CbValue
= SQL_NTS
;
638 case DB_DATA_TYPE_INTEGER
:
639 fSqlType
= pDb
->typeInfInteger
.FsqlType
;
640 precision
= pDb
->typeInfInteger
.Precision
;
642 colDefs
[i
].CbValue
= 0;
644 case DB_DATA_TYPE_FLOAT
:
645 fSqlType
= pDb
->typeInfFloat
.FsqlType
;
646 precision
= pDb
->typeInfFloat
.Precision
;
647 scale
= pDb
->typeInfFloat
.MaximumScale
;
648 // SQL Sybase Anywhere v5.5 returned a negative number for the
649 // MaxScale. This caused ODBC to kick out an error on ibscale.
650 // I check for this here and set the scale = precision.
652 // scale = (short) precision;
653 colDefs
[i
].CbValue
= 0;
655 case DB_DATA_TYPE_DATE
:
656 fSqlType
= pDb
->typeInfDate
.FsqlType
;
657 precision
= pDb
->typeInfDate
.Precision
;
659 colDefs
[i
].CbValue
= 0;
665 colDefs
[i
].CbValue
= SQL_NULL_DATA
;
666 colDefs
[i
].Null
= FALSE
;
668 if (SQLBindParameter(hstmtInsert
, i
+1, SQL_PARAM_INPUT
, colDefs
[i
].SqlCtype
,
669 fSqlType
, precision
, scale
, (UCHAR
*) colDefs
[i
].PtrDataObj
,
670 precision
+1,&colDefs
[i
].CbValue
) != SQL_SUCCESS
)
671 return(pDb
->DispAllErrors(henv
, hdbc
, hstmtInsert
));
674 // Completed successfully
677 } // wxTable::bindInsertParams()
679 /********** wxTable::bindUpdateParams() **********/
680 bool wxTable::bindUpdateParams(void)
687 UDWORD precision
= 0;
690 // Bind each UPDATEABLE column of the table to a parameter marker
692 for (i
= 0, colNo
= 1; i
< noCols
; i
++)
694 if (! colDefs
[i
].Updateable
)
696 switch(colDefs
[i
].DbDataType
)
698 case DB_DATA_TYPE_VARCHAR
:
699 fSqlType
= pDb
->typeInfVarchar
.FsqlType
;
700 precision
= colDefs
[i
].SzDataObj
;
702 colDefs
[i
].CbValue
= SQL_NTS
;
704 case DB_DATA_TYPE_INTEGER
:
705 fSqlType
= pDb
->typeInfInteger
.FsqlType
;
706 precision
= pDb
->typeInfInteger
.Precision
;
708 colDefs
[i
].CbValue
= 0;
710 case DB_DATA_TYPE_FLOAT
:
711 fSqlType
= pDb
->typeInfFloat
.FsqlType
;
712 precision
= pDb
->typeInfFloat
.Precision
;
713 scale
= pDb
->typeInfFloat
.MaximumScale
;
714 // SQL Sybase Anywhere v5.5 returned a negative number for the
715 // MaxScale. This caused ODBC to kick out an error on ibscale.
716 // I check for this here and set the scale = precision.
718 // scale = (short) precision;
719 colDefs
[i
].CbValue
= 0;
721 case DB_DATA_TYPE_DATE
:
722 fSqlType
= pDb
->typeInfDate
.FsqlType
;
723 precision
= pDb
->typeInfDate
.Precision
;
725 colDefs
[i
].CbValue
= 0;
728 if (SQLBindParameter(hstmtUpdate
, colNo
++, SQL_PARAM_INPUT
, colDefs
[i
].SqlCtype
,
729 fSqlType
, precision
, scale
, (UCHAR
*) colDefs
[i
].PtrDataObj
,
730 precision
+1, &colDefs
[i
].CbValue
) != SQL_SUCCESS
)
731 return(pDb
->DispAllErrors(henv
, hdbc
, hstmtUpdate
));
734 // Completed successfully
737 } // wxTable::bindUpdateParams()
739 /********** wxTable::bindCols() **********/
740 bool wxTable::bindCols(HSTMT cursor
)
744 // Bind each column of the table to a memory address for fetching data
746 for (i
= 0; i
< noCols
; i
++)
748 if (SQLBindCol(cursor
, i
+1, colDefs
[i
].SqlCtype
, (UCHAR
*) colDefs
[i
].PtrDataObj
,
749 colDefs
[i
].SzDataObj
, &cb
) != SQL_SUCCESS
)
750 return(pDb
->DispAllErrors(henv
, hdbc
, cursor
));
753 // Completed successfully
756 } // wxTable::bindCols()
758 /********** wxTable::CloseCursor() **********/
759 bool wxTable::CloseCursor(HSTMT cursor
)
761 if (SQLFreeStmt(cursor
, SQL_CLOSE
) != SQL_SUCCESS
)
762 return(pDb
->DispAllErrors(henv
, hdbc
, cursor
));
764 // Completed successfully
767 } // wxTable::CloseCursor()
769 /********** wxTable::CreateTable() **********/
770 bool wxTable::CreateTable(bool attemptDrop
)
776 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
778 #ifdef DBDEBUG_CONSOLE
779 cout
<< "Creating Table " << tableName
<< "..." << endl
;
783 if (attemptDrop
&& !DropTable())
787 #ifdef DBDEBUG_CONSOLE
788 for (i
= 0; i
< noCols
; i
++)
790 // Exclude derived columns since they are NOT part of the base table
791 if (colDefs
[i
].DerivedCol
)
793 cout
<< i
+ 1 << ": " << colDefs
[i
].ColName
<< "; ";
794 switch(colDefs
[i
].DbDataType
)
796 case DB_DATA_TYPE_VARCHAR
:
797 cout
<< pDb
->typeInfVarchar
.TypeName
<< "(" << colDefs
[i
].SzDataObj
<< ")";
799 case DB_DATA_TYPE_INTEGER
:
800 cout
<< pDb
->typeInfInteger
.TypeName
;
802 case DB_DATA_TYPE_FLOAT
:
803 cout
<< pDb
->typeInfFloat
.TypeName
;
805 case DB_DATA_TYPE_DATE
:
806 cout
<< pDb
->typeInfDate
.TypeName
;
813 // Build a CREATE TABLE string from the colDefs structure.
814 bool needComma
= FALSE
;
815 sprintf(sqlStmt
, "CREATE TABLE %s (", tableName
);
816 for (i
= 0; i
< noCols
; i
++)
818 // Exclude derived columns since they are NOT part of the base table
819 if (colDefs
[i
].DerivedCol
)
823 strcat(sqlStmt
, ",");
825 strcat(sqlStmt
, colDefs
[i
].ColName
);
826 strcat(sqlStmt
, " ");
828 switch(colDefs
[i
].DbDataType
)
830 case DB_DATA_TYPE_VARCHAR
:
831 strcat(sqlStmt
, pDb
->typeInfVarchar
.TypeName
); break;
832 case DB_DATA_TYPE_INTEGER
:
833 strcat(sqlStmt
, pDb
->typeInfInteger
.TypeName
); break;
834 case DB_DATA_TYPE_FLOAT
:
835 strcat(sqlStmt
, pDb
->typeInfFloat
.TypeName
); break;
836 case DB_DATA_TYPE_DATE
:
837 strcat(sqlStmt
, pDb
->typeInfDate
.TypeName
); break;
839 // For varchars, append the size of the string
840 if (colDefs
[i
].DbDataType
== DB_DATA_TYPE_VARCHAR
)
843 // strcat(sqlStmt, "(");
844 // strcat(sqlStmt, itoa(colDefs[i].SzDataObj, s, 10));
845 // strcat(sqlStmt, ")");
846 sprintf(s
, "(%d)", colDefs
[i
].SzDataObj
);
850 if (pDb
->Dbms() == dbmsSYBASE_ASE
|| pDb
->Dbms() == dbmsMY_SQL
)
852 if (colDefs
[i
].KeyField
)
854 strcat(sqlStmt
, " NOT NULL");
860 // If there is a primary key defined, include it in the create statement
861 for (i
= j
= 0; i
< noCols
; i
++)
863 if (colDefs
[i
].KeyField
)
869 if (j
&& pDb
->Dbms() != dbmsDBASE
) // Found a keyfield
871 if (pDb
->Dbms() != dbmsMY_SQL
)
873 strcat(sqlStmt
, ",CONSTRAINT ");
874 strcat(sqlStmt
, tableName
);
875 strcat(sqlStmt
, "_PIDX PRIMARY KEY (");
879 /* MySQL goes out on this one. We also declare the relevant key NON NULL above */
880 strcat(sqlStmt
, ", PRIMARY KEY (");
883 // List column name(s) of column(s) comprising the primary key
884 for (i
= j
= 0; i
< noCols
; i
++)
886 if (colDefs
[i
].KeyField
)
888 if (j
++) // Multi part key, comma separate names
889 strcat(sqlStmt
, ",");
890 strcat(sqlStmt
, colDefs
[i
].ColName
);
893 strcat(sqlStmt
, ")");
895 // Append the closing parentheses for the create table statement
896 strcat(sqlStmt
, ")");
898 pDb
->WriteSqlLog(sqlStmt
);
900 #ifdef DBDEBUG_CONSOLE
901 cout
<< endl
<< sqlStmt
<< endl
;
904 // Execute the CREATE TABLE statement
905 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
, SQL_NTS
) != SQL_SUCCESS
)
907 pDb
->DispAllErrors(henv
, hdbc
, hstmt
);
908 pDb
->RollbackTrans();
913 // Commit the transaction and close the cursor
914 if (! pDb
->CommitTrans())
916 if (! CloseCursor(hstmt
))
919 // Database table created successfully
922 } // wxTable::CreateTable()
924 /********** wxTable::DropTable() **********/
925 bool wxTable::DropTable()
927 // NOTE: This function returns TRUE if the Table does not exist, but
928 // only for identified databases. Code will need to be added
929 // below for any other databases when those databases are defined
930 // to handle this situation consistently
932 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
934 sprintf(sqlStmt
, "DROP TABLE %s", tableName
);
936 pDb
->WriteSqlLog(sqlStmt
);
938 #ifdef DBDEBUG_CONSOLE
939 cout
<< endl
<< sqlStmt
<< endl
;
942 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
, SQL_NTS
) != SQL_SUCCESS
)
944 // Check for "Base table not found" error and ignore
945 pDb
->GetNextError(henv
, hdbc
, hstmt
);
946 if (wxStrcmp(pDb
->sqlState
,"S0002")) // "Base table not found"
948 // Check for product specific error codes
949 if (!((pDb
->Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(pDb
->sqlState
,"42000")) || // 5.x (and lower?)
950 (pDb
->Dbms() == dbmsMY_SQL
&& !wxStrcmp(pDb
->sqlState
,"S1000")) || // untested
951 (pDb
->Dbms() == dbmsPOSTGRES
&& !wxStrcmp(pDb
->sqlState
,"08S01")))) // untested
953 pDb
->DispNextError();
954 pDb
->DispAllErrors(henv
, hdbc
, hstmt
);
955 pDb
->RollbackTrans();
962 // Commit the transaction and close the cursor
963 if (! pDb
->CommitTrans())
965 if (! CloseCursor(hstmt
))
969 } // wxTable::DropTable()
971 /********** wxTable::CreateIndex() **********/
972 bool wxTable::CreateIndex(char * idxName
, bool unique
, int noIdxCols
, CidxDef
*pIdxDefs
, bool attemptDrop
)
974 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
976 // Drop the index first
977 if (attemptDrop
&& !DropIndex(idxName
))
980 // Build a CREATE INDEX statement
981 strcpy(sqlStmt
, "CREATE ");
983 strcat(sqlStmt
, "UNIQUE ");
985 strcat(sqlStmt
, "INDEX ");
986 strcat(sqlStmt
, idxName
);
987 strcat(sqlStmt
, " ON ");
988 strcat(sqlStmt
, tableName
);
989 strcat(sqlStmt
, " (");
991 // Append list of columns making up index
993 for (i
= 0; i
< noIdxCols
; i
++)
995 strcat(sqlStmt
, pIdxDefs
[i
].ColName
);
996 /* Postgres doesn't cope with ASC */
997 if (pDb
->Dbms() != dbmsPOSTGRES
)
999 if (pIdxDefs
[i
].Ascending
)
1000 strcat(sqlStmt
, " ASC");
1002 strcat(sqlStmt
, " DESC");
1005 if ((i
+ 1) < noIdxCols
)
1006 strcat(sqlStmt
, ",");
1009 // Append closing parentheses
1010 strcat(sqlStmt
, ")");
1012 pDb
->WriteSqlLog(sqlStmt
);
1014 #ifdef DBDEBUG_CONSOLE
1015 cout
<< endl
<< sqlStmt
<< endl
<< endl
;
1018 // Execute the CREATE INDEX statement
1019 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
, SQL_NTS
) != SQL_SUCCESS
)
1021 pDb
->DispAllErrors(henv
, hdbc
, hstmt
);
1022 pDb
->RollbackTrans();
1027 // Commit the transaction and close the cursor
1028 if (! pDb
->CommitTrans())
1030 if (! CloseCursor(hstmt
))
1033 // Index Created Successfully
1036 } // wxTable::CreateIndex()
1038 /********** wxTable::DropIndex() **********/
1039 bool wxTable::DropIndex(char * idxName
)
1041 // NOTE: This function returns TRUE if the Index does not exist, but
1042 // only for identified databases. Code will need to be added
1043 // below for any other databases when those databases are defined
1044 // to handle this situation consistently
1046 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
1048 if (pDb
->Dbms() == dbmsACCESS
)
1049 sprintf(sqlStmt
, "DROP INDEX %s ON %s",idxName
,tableName
);
1050 else if (pDb
->Dbms() == dbmsSYBASE_ASE
)
1051 sprintf(sqlStmt
, "DROP INDEX %s.%s",tableName
,idxName
);
1053 sprintf(sqlStmt
, "DROP INDEX %s",idxName
);
1055 pDb
->WriteSqlLog(sqlStmt
);
1057 #ifdef DBDEBUG_CONSOLE
1058 cout
<< endl
<< sqlStmt
<< endl
;
1061 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
, SQL_NTS
) != SQL_SUCCESS
)
1063 // Check for "Index not found" error and ignore
1064 pDb
->GetNextError(henv
, hdbc
, hstmt
);
1065 if (wxStrcmp(pDb
->sqlState
,"S0012")) // "Index not found"
1067 // Check for product specific error codes
1068 if (!((pDb
->Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(pDb
->sqlState
,"42000")) || // v5.x (and lower?)
1069 (pDb
->Dbms() == dbmsSYBASE_ASE
&& !wxStrcmp(pDb
->sqlState
,"S0002")) || // Base table not found
1070 (pDb
->Dbms() == dbmsMY_SQL
&& !wxStrcmp(pDb
->sqlState
,"42S02")) // untested
1073 pDb
->DispNextError();
1074 pDb
->DispAllErrors(henv
, hdbc
, hstmt
);
1075 pDb
->RollbackTrans();
1082 // Commit the transaction and close the cursor
1083 if (! pDb
->CommitTrans())
1085 if (! CloseCursor(hstmt
))
1089 } // wxTable::DropIndex()
1091 /********** wxTable::Insert() **********/
1092 int wxTable::Insert(void)
1100 // Insert the record by executing the already prepared insert statement
1102 retcode
=SQLExecute(hstmtInsert
);
1103 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1105 // Check to see if integrity constraint was violated
1106 pDb
->GetNextError(henv
, hdbc
, hstmtInsert
);
1107 if (! wxStrcmp(pDb
->sqlState
, "23000")) // Integrity constraint violated
1108 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL
);
1111 pDb
->DispNextError();
1112 pDb
->DispAllErrors(henv
, hdbc
, hstmtInsert
);
1117 // Record inserted into the datasource successfully
1120 } // wxTable::Insert()
1122 /********** wxTable::Update(pSqlStmt) **********/
1123 bool wxTable::Update(char *pSqlStmt
)
1129 pDb
->WriteSqlLog(pSqlStmt
);
1131 return(execUpdate(pSqlStmt
));
1133 } // wxTable::Update(pSqlStmt)
1135 /********** wxTable::Update() **********/
1136 bool wxTable::Update(void)
1142 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
1144 // Build the SQL UPDATE statement
1145 GetUpdateStmt(sqlStmt
, DB_UPD_KEYFIELDS
);
1147 pDb
->WriteSqlLog(sqlStmt
);
1149 #ifdef DBDEBUG_CONSOLE
1150 cout
<< endl
<< sqlStmt
<< endl
<< endl
;
1153 // Execute the SQL UPDATE statement
1154 return(execUpdate(sqlStmt
));
1156 } // wxTable::Update()
1158 /********** wxTable::UpdateWhere() **********/
1159 bool wxTable::UpdateWhere(char *pWhereClause
)
1165 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
1167 // Build the SQL UPDATE statement
1168 GetUpdateStmt(sqlStmt
, DB_UPD_WHERE
, pWhereClause
);
1170 pDb
->WriteSqlLog(sqlStmt
);
1172 #ifdef DBDEBUG_CONSOLE
1173 cout
<< endl
<< sqlStmt
<< endl
<< endl
;
1176 // Execute the SQL UPDATE statement
1177 return(execUpdate(sqlStmt
));
1179 } // wxTable::UpdateWhere()
1181 /********** wxTable::Delete() **********/
1182 bool wxTable::Delete(void)
1188 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
1190 // Build the SQL DELETE statement
1191 GetDeleteStmt(sqlStmt
, DB_DEL_KEYFIELDS
);
1193 pDb
->WriteSqlLog(sqlStmt
);
1195 // Execute the SQL DELETE statement
1196 return(execDelete(sqlStmt
));
1198 } // wxTable::Delete()
1200 /********** wxTable::DeleteWhere() **********/
1201 bool wxTable::DeleteWhere(char *pWhereClause
)
1207 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
1209 // Build the SQL DELETE statement
1210 GetDeleteStmt(sqlStmt
, DB_DEL_WHERE
, pWhereClause
);
1212 pDb
->WriteSqlLog(sqlStmt
);
1214 // Execute the SQL DELETE statement
1215 return(execDelete(sqlStmt
));
1217 } // wxTable::DeleteWhere()
1219 /********** wxTable::DeleteMatching() **********/
1220 bool wxTable::DeleteMatching(void)
1226 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
1228 // Build the SQL DELETE statement
1229 GetDeleteStmt(sqlStmt
, DB_DEL_MATCHING
);
1231 pDb
->WriteSqlLog(sqlStmt
);
1233 // Execute the SQL DELETE statement
1234 return(execDelete(sqlStmt
));
1236 } // wxTable::DeleteMatching()
1238 /********** wxTable::execDelete() **********/
1239 bool wxTable::execDelete(char *pSqlStmt
)
1241 // Execute the DELETE statement
1242 if (SQLExecDirect(hstmtDelete
, (UCHAR FAR
*) pSqlStmt
, SQL_NTS
) != SQL_SUCCESS
)
1243 return(pDb
->DispAllErrors(henv
, hdbc
, hstmtDelete
));
1245 // Record deleted successfully
1248 } // wxTable::execDelete()
1250 /********** wxTable::execUpdate() **********/
1251 bool wxTable::execUpdate(char *pSqlStmt
)
1253 // Execute the UPDATE statement
1254 if (SQLExecDirect(hstmtUpdate
, (UCHAR FAR
*) pSqlStmt
, SQL_NTS
) != SQL_SUCCESS
)
1255 return(pDb
->DispAllErrors(henv
, hdbc
, hstmtUpdate
));
1257 // Record deleted successfully
1260 } // wxTable::execUpdate()
1262 /********** wxTable::GetUpdateStmt() **********/
1263 void wxTable::GetUpdateStmt(char *pSqlStmt
, int typeOfUpd
, char *pWhereClause
)
1269 char whereClause
[DB_MAX_WHERE_CLAUSE_LEN
];
1270 bool firstColumn
= TRUE
;
1273 sprintf(pSqlStmt
, "UPDATE %s SET ", tableName
);
1275 // Append a list of columns to be updated
1277 for (i
= 0; i
< noCols
; i
++)
1279 // Only append Updateable columns
1280 if (colDefs
[i
].Updateable
)
1283 strcat(pSqlStmt
, ",");
1285 firstColumn
= FALSE
;
1286 strcat(pSqlStmt
, colDefs
[i
].ColName
);
1287 strcat(pSqlStmt
, " = ?");
1291 // Append the WHERE clause to the SQL UPDATE statement
1292 strcat(pSqlStmt
, " WHERE ");
1295 case DB_UPD_KEYFIELDS
:
1296 // If the datasource supports the ROWID column, build
1297 // the where on ROWID for efficiency purposes.
1298 // e.g. UPDATE PARTS SET Col1 = ?, Col2 = ? WHERE ROWID = '111.222.333'
1299 if (CanUpdByROWID())
1302 char rowid
[ROWID_LEN
];
1304 // Get the ROWID value. If not successful retreiving the ROWID,
1305 // simply fall down through the code and build the WHERE clause
1306 // based on the key fields.
1307 if (SQLGetData(hstmt
, noCols
+1, SQL_C_CHAR
, (UCHAR
*) rowid
, ROWID_LEN
, &cb
) == SQL_SUCCESS
)
1309 strcat(pSqlStmt
, "ROWID = '");
1310 strcat(pSqlStmt
, rowid
);
1311 strcat(pSqlStmt
, "'");
1315 // Unable to delete by ROWID, so build a WHERE
1316 // clause based on the keyfields.
1317 GetWhereClause(whereClause
, DB_WHERE_KEYFIELDS
);
1318 strcat(pSqlStmt
, whereClause
);
1321 strcat(pSqlStmt
, pWhereClause
);
1325 } // GetUpdateStmt()
1327 /********** wxTable::GetDeleteStmt() **********/
1328 void wxTable::GetDeleteStmt(char *pSqlStmt
, int typeOfDel
, char *pWhereClause
)
1334 char whereClause
[DB_MAX_WHERE_CLAUSE_LEN
];
1338 // Handle the case of DeleteWhere() and the where clause is blank. It should
1339 // delete all records from the database in this case.
1340 if (typeOfDel
== DB_DEL_WHERE
&& (pWhereClause
== 0 || strlen(pWhereClause
) == 0))
1342 sprintf(pSqlStmt
, "DELETE FROM %s", tableName
);
1346 sprintf(pSqlStmt
, "DELETE FROM %s WHERE ", tableName
);
1348 // Append the WHERE clause to the SQL DELETE statement
1351 case DB_DEL_KEYFIELDS
:
1352 // If the datasource supports the ROWID column, build
1353 // the where on ROWID for efficiency purposes.
1354 // e.g. DELETE FROM PARTS WHERE ROWID = '111.222.333'
1355 if (CanUpdByROWID())
1358 char rowid
[ROWID_LEN
];
1360 // Get the ROWID value. If not successful retreiving the ROWID,
1361 // simply fall down through the code and build the WHERE clause
1362 // based on the key fields.
1363 if (SQLGetData(hstmt
, noCols
+1, SQL_C_CHAR
, (UCHAR
*) rowid
, ROWID_LEN
, &cb
) == SQL_SUCCESS
)
1365 strcat(pSqlStmt
, "ROWID = '");
1366 strcat(pSqlStmt
, rowid
);
1367 strcat(pSqlStmt
, "'");
1371 // Unable to delete by ROWID, so build a WHERE
1372 // clause based on the keyfields.
1373 GetWhereClause(whereClause
, DB_WHERE_KEYFIELDS
);
1374 strcat(pSqlStmt
, whereClause
);
1377 strcat(pSqlStmt
, pWhereClause
);
1379 case DB_DEL_MATCHING
:
1380 GetWhereClause(whereClause
, DB_WHERE_MATCHING
);
1381 strcat(pSqlStmt
, whereClause
);
1385 } // GetDeleteStmt()
1387 /********** wxTable::GetWhereClause() **********/
1389 * Note: GetWhereClause() currently ignores timestamp columns.
1390 * They are not included as part of the where clause.
1393 void wxTable::GetWhereClause(char *pWhereClause
, int typeOfWhere
, char *qualTableName
)
1395 bool moreThanOneColumn
= FALSE
;
1398 // Loop through the columns building a where clause as you go
1400 for (i
= 0; i
< noCols
; i
++)
1402 // Determine if this column should be included in the WHERE clause
1403 if ((typeOfWhere
== DB_WHERE_KEYFIELDS
&& colDefs
[i
].KeyField
) ||
1404 (typeOfWhere
== DB_WHERE_MATCHING
&& (! IsColNull(i
))))
1406 // Skip over timestamp columns
1407 if (colDefs
[i
].SqlCtype
== SQL_C_TIMESTAMP
)
1409 // If there is more than 1 column, join them with the keyword "AND"
1410 if (moreThanOneColumn
)
1411 strcat(pWhereClause
, " AND ");
1413 moreThanOneColumn
= TRUE
;
1414 // Concatenate where phrase for the column
1415 if (qualTableName
&& strlen(qualTableName
))
1417 strcat(pWhereClause
, qualTableName
);
1418 strcat(pWhereClause
, ".");
1420 strcat(pWhereClause
, colDefs
[i
].ColName
);
1421 strcat(pWhereClause
, " = ");
1422 switch(colDefs
[i
].SqlCtype
)
1425 sprintf(colValue
, "'%s'", (UCHAR FAR
*) colDefs
[i
].PtrDataObj
);
1428 sprintf(colValue
, "%hi", *((SWORD
*) colDefs
[i
].PtrDataObj
));
1431 sprintf(colValue
, "%hu", *((UWORD
*) colDefs
[i
].PtrDataObj
));
1434 sprintf(colValue
, "%li", *((SDWORD
*) colDefs
[i
].PtrDataObj
));
1437 sprintf(colValue
, "%lu", *((UDWORD
*) colDefs
[i
].PtrDataObj
));
1440 sprintf(colValue
, "%.6f", *((SFLOAT
*) colDefs
[i
].PtrDataObj
));
1443 sprintf(colValue
, "%.6f", *((SDOUBLE
*) colDefs
[i
].PtrDataObj
));
1446 strcat(pWhereClause
, colValue
);
1450 } // wxTable::GetWhereClause()
1452 /********** wxTable::IsColNull() **********/
1453 bool wxTable::IsColNull(int colNo
)
1455 switch(colDefs
[colNo
].SqlCtype
)
1458 return(((UCHAR FAR
*) colDefs
[colNo
].PtrDataObj
)[0] == 0);
1460 return(( *((SWORD
*) colDefs
[colNo
].PtrDataObj
)) == 0);
1462 return(( *((UWORD
*) colDefs
[colNo
].PtrDataObj
)) == 0);
1464 return(( *((SDWORD
*) colDefs
[colNo
].PtrDataObj
)) == 0);
1466 return(( *((UDWORD
*) colDefs
[colNo
].PtrDataObj
)) == 0);
1468 return(( *((SFLOAT
*) colDefs
[colNo
].PtrDataObj
)) == 0);
1470 return((*((SDOUBLE
*) colDefs
[colNo
].PtrDataObj
)) == 0);
1471 case SQL_C_TIMESTAMP
:
1472 TIMESTAMP_STRUCT
*pDt
;
1473 pDt
= (TIMESTAMP_STRUCT
*) colDefs
[colNo
].PtrDataObj
;
1474 if (pDt
->year
== 0 && pDt
->month
== 0 && pDt
->day
== 0)
1482 } // wxTable::IsColNull()
1484 /********** wxTable::CanSelectForUpdate() **********/
1485 bool wxTable::CanSelectForUpdate(void)
1487 if (pDb
->Dbms() == dbmsMY_SQL
)
1490 if (pDb
->dbInf
.posStmts
& SQL_PS_SELECT_FOR_UPDATE
)
1495 } // wxTable::CanSelectForUpdate()
1497 /********** wxTable::CanUpdByROWID() **********/
1498 bool wxTable::CanUpdByROWID(void)
1501 //NOTE: Returning FALSE for now until this can be debugged,
1502 // as the ROWID is not getting updated correctly
1505 if (pDb
->Dbms() == dbmsORACLE
)
1510 } // wxTable::CanUpdByROWID()
1512 /********** wxTable::IsCursorClosedOnCommit() **********/
1513 bool wxTable::IsCursorClosedOnCommit(void)
1515 if (pDb
->dbInf
.cursorCommitBehavior
== SQL_CB_PRESERVE
)
1520 } // wxTable::IsCursorClosedOnCommit()
1522 /********** wxTable::ClearMemberVars() **********/
1523 void wxTable::ClearMemberVars(void)
1525 // Loop through the columns setting each member variable to zero
1527 for (i
= 0; i
< noCols
; i
++)
1529 switch(colDefs
[i
].SqlCtype
)
1532 ((UCHAR FAR
*) colDefs
[i
].PtrDataObj
)[0] = 0;
1535 *((SWORD
*) colDefs
[i
].PtrDataObj
) = 0;
1538 *((UWORD
*) colDefs
[i
].PtrDataObj
) = 0;
1541 *((SDWORD
*) colDefs
[i
].PtrDataObj
) = 0;
1544 *((UDWORD
*) colDefs
[i
].PtrDataObj
) = 0;
1547 *((SFLOAT
*) colDefs
[i
].PtrDataObj
) = 0.0f
;
1550 *((SDOUBLE
*) colDefs
[i
].PtrDataObj
) = 0.0f
;
1552 case SQL_C_TIMESTAMP
:
1553 TIMESTAMP_STRUCT
*pDt
;
1554 pDt
= (TIMESTAMP_STRUCT
*) colDefs
[i
].PtrDataObj
;
1566 } // wxTable::ClearMemberVars()
1568 /********** wxTable::SetQueryTimeout() **********/
1569 bool wxTable::SetQueryTimeout(UDWORD nSeconds
)
1571 if (SQLSetStmtOption(hstmtInsert
, SQL_QUERY_TIMEOUT
, nSeconds
) != SQL_SUCCESS
)
1572 return(pDb
->DispAllErrors(henv
, hdbc
, hstmtInsert
));
1573 if (SQLSetStmtOption(hstmtUpdate
, SQL_QUERY_TIMEOUT
, nSeconds
) != SQL_SUCCESS
)
1574 return(pDb
->DispAllErrors(henv
, hdbc
, hstmtUpdate
));
1575 if (SQLSetStmtOption(hstmtDelete
, SQL_QUERY_TIMEOUT
, nSeconds
) != SQL_SUCCESS
)
1576 return(pDb
->DispAllErrors(henv
, hdbc
, hstmtDelete
));
1577 if (SQLSetStmtOption(hstmtInternal
, SQL_QUERY_TIMEOUT
, nSeconds
) != SQL_SUCCESS
)
1578 return(pDb
->DispAllErrors(henv
, hdbc
, hstmtInternal
));
1580 // Completed Successfully
1583 } // wxTable::SetQueryTimeout()
1585 /********** wxTable::SetColDefs() **********/
1586 void wxTable::SetColDefs (int index
, char *fieldName
, int dataType
, void *pData
,
1587 int cType
, int size
, bool keyField
, bool upd
,
1588 bool insAllow
, bool derivedCol
)
1590 if (!colDefs
) // May happen if the database connection fails
1593 if (strlen(fieldName
) > (unsigned int) DB_MAX_COLUMN_NAME_LEN
)
1595 strncpy (colDefs
[index
].ColName
, fieldName
, DB_MAX_COLUMN_NAME_LEN
);
1596 colDefs
[index
].ColName
[DB_MAX_COLUMN_NAME_LEN
] = 0;
1599 strcpy(colDefs
[index
].ColName
, fieldName
);
1601 colDefs
[index
].DbDataType
= dataType
;
1602 colDefs
[index
].PtrDataObj
= pData
;
1603 colDefs
[index
].SqlCtype
= cType
;
1604 colDefs
[index
].SzDataObj
= size
;
1605 colDefs
[index
].KeyField
= keyField
;
1606 colDefs
[index
].DerivedCol
= derivedCol
;
1607 // Derived columns by definition would NOT be "Insertable" or "Updateable"
1610 colDefs
[index
].Updateable
= FALSE
;
1611 colDefs
[index
].InsertAllowed
= FALSE
;
1615 colDefs
[index
].Updateable
= upd
;
1616 colDefs
[index
].InsertAllowed
= insAllow
;
1619 colDefs
[index
].Null
= FALSE
;
1621 } // wxTable::SetColDefs()
1623 /********** wxTable::SetCursor() **********/
1624 void wxTable::SetCursor(HSTMT
*hstmtActivate
)
1626 if (hstmtActivate
== DEFAULT_CURSOR
)
1627 hstmt
= *hstmtDefault
;
1629 hstmt
= *hstmtActivate
;
1631 } // wxTable::SetCursor()
1633 /********** wxTable::Count() **********/
1634 ULONG
wxTable::Count(void)
1637 char sqlStmt
[DB_MAX_STATEMENT_LEN
];
1640 // Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement
1641 strcpy(sqlStmt
, "SELECT COUNT(*) FROM ");
1642 strcat(sqlStmt
, queryTableName
);
1644 if (from
&& strlen(from
))
1645 strcat(sqlStmt
, from
);
1647 // Add the where clause if one is provided
1648 if (where
&& strlen(where
))
1650 strcat(sqlStmt
, " WHERE ");
1651 strcat(sqlStmt
, where
);
1654 pDb
->WriteSqlLog(sqlStmt
);
1656 // Initialize the Count cursor if it's not already initialized
1659 hstmtCount
= NewCursor(FALSE
,FALSE
);
1665 // Execute the SQL statement
1666 if (SQLExecDirect(*hstmtCount
, (UCHAR FAR
*) sqlStmt
, SQL_NTS
) != SQL_SUCCESS
)
1668 pDb
->DispAllErrors(henv
, hdbc
, *hstmtCount
);
1673 if (SQLFetch(*hstmtCount
) != SQL_SUCCESS
)
1675 pDb
->DispAllErrors(henv
, hdbc
, *hstmtCount
);
1679 // Obtain the result
1680 if (SQLGetData(*hstmtCount
, 1, SQL_C_ULONG
, &l
, sizeof(l
), &cb
) != SQL_SUCCESS
)
1682 pDb
->DispAllErrors(henv
, hdbc
, *hstmtCount
);
1687 if (SQLFreeStmt(*hstmtCount
, SQL_CLOSE
) != SQL_SUCCESS
)
1688 pDb
->DispAllErrors(henv
, hdbc
, *hstmtCount
);
1690 // Return the record count
1693 } // wxTable::Count()
1695 /********** wxTable::Refresh() **********/
1696 bool wxTable::Refresh(void)
1700 // Switch to the internal cursor so any active cursors are not corrupted
1701 HSTMT currCursor
= GetCursor();
1702 hstmt
= hstmtInternal
;
1704 // Save the where and order by clauses
1705 char *saveWhere
= where
;
1706 char *saveOrderBy
= orderBy
;
1708 // Build a where clause to refetch the record with. Try and use the
1709 // ROWID if it's available, ow use the key fields.
1710 char whereClause
[DB_MAX_WHERE_CLAUSE_LEN
+1];
1711 strcpy(whereClause
, "");
1712 if (CanUpdByROWID())
1715 char rowid
[ROWID_LEN
+1];
1717 // Get the ROWID value. If not successful retreiving the ROWID,
1718 // simply fall down through the code and build the WHERE clause
1719 // based on the key fields.
1720 if (SQLGetData(hstmt
, noCols
+1, SQL_C_CHAR
, (UCHAR
*) rowid
, ROWID_LEN
, &cb
) == SQL_SUCCESS
)
1722 strcat(whereClause
, queryTableName
);
1723 strcat(whereClause
, ".ROWID = '");
1724 strcat(whereClause
, rowid
);
1725 strcat(whereClause
, "'");
1729 // If unable to use the ROWID, build a where clause from the keyfields
1730 if (strlen(whereClause
) == 0)
1731 GetWhereClause(whereClause
, DB_WHERE_KEYFIELDS
, queryTableName
);
1733 // Requery the record
1734 where
= whereClause
;
1739 if (result
&& !GetNext())
1742 // Switch back to original cursor
1743 SetCursor(&currCursor
);
1745 // Free the internal cursor
1746 if (SQLFreeStmt(hstmtInternal
, SQL_CLOSE
) != SQL_SUCCESS
)
1747 pDb
->DispAllErrors(henv
, hdbc
, hstmtInternal
);
1749 // Restore the original where and order by clauses
1751 orderBy
= saveOrderBy
;
1755 } // wxTable::Refresh()
1757 /********** wxTable::SetNull(UINT colNo) **********/
1758 bool wxTable::SetNull(int colNo
)
1761 return(colDefs
[colNo
].Null
= TRUE
);
1765 } // wxTable::SetNull(UINT colNo)
1767 /********** wxTable::SetNull(char *colName) **********/
1768 bool wxTable::SetNull(char *colName
)
1771 for (i
= 0; i
< noCols
; i
++)
1773 if (!wxStricmp(colName
, colDefs
[i
].ColName
))
1778 return(colDefs
[i
].Null
= TRUE
);
1782 } // wxTable::SetNull(char *colName)
1784 /********** wxTable::NewCursor() **********/
1785 HSTMT
*wxTable::NewCursor(bool setCursor
, bool bindColumns
)
1787 HSTMT
*newHSTMT
= new HSTMT
;
1792 if (SQLAllocStmt(hdbc
, newHSTMT
) != SQL_SUCCESS
)
1794 pDb
->DispAllErrors(henv
, hdbc
);
1799 if (SQLSetStmtOption(*newHSTMT
, SQL_CURSOR_TYPE
, cursorType
) != SQL_SUCCESS
)
1801 pDb
->DispAllErrors(henv
, hdbc
, *newHSTMT
);
1808 if(!bindCols(*newHSTMT
))
1816 SetCursor(newHSTMT
);
1820 } // wxTable::NewCursor()
1822 /********** wxTable::DeleteCursor() **********/
1823 bool wxTable::DeleteCursor(HSTMT
*hstmtDel
)
1827 if (!hstmtDel
) // Cursor already deleted
1830 if (SQLFreeStmt(*hstmtDel
, SQL_DROP
) != SQL_SUCCESS
)
1832 pDb
->DispAllErrors(henv
, hdbc
);
1840 } // wxTable::DeleteCursor()
1842 #endif // wxUSE_ODBC