1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: Implementation of the wxDB class. The wxDB class represents a connection
4 // to an ODBC data source. The wxDB class allows operations on the data
5 // source such as opening and closing the data source.
7 // Modified by: George Tasker
9 // -Added support for SQL statement logging and database cataloging
11 // -Added QUERY_ONLY mode support to reduce default number of cursors
12 // -Added additional SQL logging code
13 // -Added DEBUG-ONLY tracking of wxTable objects to detect orphaned DB connections
14 // -Set ODBC option to only read committed writes to the DB so all
15 // databases operate the same in that respect
18 // Copyright: (c) 1996 Remstar International, Inc.
19 // Licence: wxWindows licence, plus:
20 // Notice: This class library and its intellectual design are free of charge for use,
21 // modification, enhancement, debugging under the following conditions:
22 // 1) These classes may only be used as part of the implementation of a
23 // wxWindows-based application
24 // 2) All enhancements and bug fixes are to be submitted back to the wxWindows
25 // user groups free of all charges for use with the wxWindows library.
26 // 3) These classes may not be distributed as part of any other class library,
27 // DLL, text (written or electronic), other than a complete distribution of
28 // the wxWindows GUI development toolkit.
29 ///////////////////////////////////////////////////////////////////////////////
36 #include "wx/wxprec.h"
38 // Use this line for wxWindows v1.x
40 // Use this line for wxWindows v2.x
41 #include "wx/version.h"
43 #if wxMAJOR_VERSION == 2
45 #pragma implementation "db.h"
49 #ifdef DBDEBUG_CONSOLE
57 #if wxMAJOR_VERSION == 2
59 #include "wx/string.h"
60 #include "wx/object.h"
63 #include "wx/msgdlg.h"
65 #include "wx/filefn.h"
66 #include "wx/wxchar.h"
69 #if wxMAJOR_VERSION == 1
70 # if defined(wx_msw) || defined(wx_x)
88 #if wxMAJOR_VERSION == 1
90 #elif wxMAJOR_VERSION == 2
94 DbList WXDLLEXPORT
*PtrBegDbList
= 0;
97 extern wxList TablesInUse
;
100 // SQL Log defaults to be used by GetDbConnection
101 enum sqlLog SQLLOGstate
= sqlLogOFF
;
103 //char SQLLOGfn[DB_PATH_MAX+1] = SQL_LOG_FILENAME;
104 char *SQLLOGfn
= SQL_LOG_FILENAME
;
106 // The wxDB::errorList is copied to this variable when the wxDB object
107 // is closed. This way, the error list is still available after the
108 // database object is closed. This is necessary if the database
109 // connection fails so the calling application can show the operator
110 // why the connection failed. Note: as each wxDB object is closed, it
111 // will overwrite the errors of the previously destroyed wxDB object in
113 char DBerrorList
[DB_MAX_ERROR_HISTORY
][DB_MAX_ERROR_MSG_LEN
];
116 /********** wxColFor Constructor **********/
119 i_Nation
= 0; // 0=EU, 1=UK, 2=International, 3=US
128 Format(1,DB_DATA_TYPE_VARCHAR
,0,0,0); // the Function that does the work
129 } // wxColFor::wxColFor()
132 wxColFor::~wxColFor()
134 } // wxColFor::~wxColFor()
137 int wxColFor::Format(int Nation
,int dbDataType
,SWORD sqlDataType
,short columnSize
,short decimalDigits
)
139 // ----------------------------------------------------------------------------------------
140 // -- 19991224 : mj10777@gmx.net : Create
141 // There is still a lot of work to do here, but it is a start
142 // It handles all the basic data-types that I have run into up to now
143 // The main work will have be with Dates and float Formatting (US 1,000.00 ; EU 1.000,00)
144 // There are wxWindow plans for locale support and the new wxDateTime.
145 // - if they define some constants (wxEUROPEAN) that can be gloably used,
146 // they should be used here.
147 // ----------------------------------------------------------------------------------------
148 // There should also be a Function to scan in a string to fill the variable
149 // ----------------------------------------------------------------------------------------
151 i_Nation
= Nation
; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
152 i_dbDataType
= dbDataType
;
153 i_sqlDataType
= sqlDataType
;
154 s_Field
.Printf("%s%d",s_Menge
[1].c_str(),i_Menge
[1]); // OK for VARCHAR, INTEGER and FLOAT
155 if (i_dbDataType
== 0) // Filter unsupported dbDataTypes
157 if ((i_sqlDataType
== SQL_VARCHAR
) || (i_sqlDataType
== SQL_LONGVARCHAR
))
158 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
159 if (i_sqlDataType
== SQL_C_DATE
)
160 i_dbDataType
= DB_DATA_TYPE_DATE
;
161 if (i_sqlDataType
== SQL_C_BIT
)
162 i_dbDataType
= DB_DATA_TYPE_INTEGER
;
163 if (i_sqlDataType
== SQL_NUMERIC
)
164 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
165 if (i_sqlDataType
== SQL_REAL
)
166 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
168 if ((i_dbDataType
== DB_DATA_TYPE_INTEGER
) && (i_sqlDataType
== SQL_C_DOUBLE
))
170 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
172 switch(i_dbDataType
) // -A-> Still a lot of proper formatting to do
174 case DB_DATA_TYPE_VARCHAR
:
177 case DB_DATA_TYPE_INTEGER
:
180 case DB_DATA_TYPE_FLOAT
:
181 if (decimalDigits
== 0)
184 Temp0
.Printf("%s%d.%d",Temp0
.c_str(),columnSize
,decimalDigits
);
185 s_Field
.Printf("%sf",Temp0
.c_str()); //
187 case DB_DATA_TYPE_DATE
:
188 if (i_Nation
== 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
190 s_Field
= "%04d-%02d-%02d %02d:%02d:%02d.%03d";
192 if (i_Nation
== 1) // European DD.MM.YYYY HH:MM:SS.SSS
194 s_Field
= "%02d.%02d.%04d %02d:%02d:%02d.%03d";
196 if (i_Nation
== 2) // UK DD/MM/YYYY HH:MM:SS.SSS
198 s_Field
= "%02d/%02d/%04d %02d:%02d:%02d.%03d";
200 if (i_Nation
== 3) // International YYYY-MM-DD HH:MM:SS.SSS
202 s_Field
= "%04d-%02d-%02d %02d:%02d:%02d.%03d";
204 if (i_Nation
== 4) // US MM/DD/YYYY HH:MM:SS.SSS
206 s_Field
= "%02d/%02d/%04d %02d:%02d:%02d.%03d";
210 s_Field
.Printf("-E-> unknown Format(%d)-sql(%d)",dbDataType
,sqlDataType
); //
214 } // wxColFor::Format()
217 /********** wxDB Constructor **********/
218 wxDB::wxDB(HENV
&aHenv
, bool FwdOnlyCursors
)
222 fpSqlLog
= 0; // Sql Log file pointer
223 sqlLogState
= sqlLogOFF
; // By default, logging is turned off
226 wxStrcpy(sqlState
,"");
227 wxStrcpy(errorMsg
,"");
228 nativeError
= cbErrorMsg
= 0;
229 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
230 wxStrcpy(errorList
[i
], "");
232 // Init typeInf structures
233 wxStrcpy(typeInfVarchar
.TypeName
,"");
234 typeInfVarchar
.FsqlType
= 0;
235 typeInfVarchar
.Precision
= 0;
236 typeInfVarchar
.CaseSensitive
= 0;
237 typeInfVarchar
.MaximumScale
= 0;
239 wxStrcpy(typeInfInteger
.TypeName
,"");
240 typeInfInteger
.FsqlType
= 0;
241 typeInfInteger
.Precision
= 0;
242 typeInfInteger
.CaseSensitive
= 0;
243 typeInfInteger
.MaximumScale
= 0;
245 wxStrcpy(typeInfFloat
.TypeName
,"");
246 typeInfFloat
.FsqlType
= 0;
247 typeInfFloat
.Precision
= 0;
248 typeInfFloat
.CaseSensitive
= 0;
249 typeInfFloat
.MaximumScale
= 0;
251 wxStrcpy(typeInfDate
.TypeName
,"");
252 typeInfDate
.FsqlType
= 0;
253 typeInfDate
.Precision
= 0;
254 typeInfDate
.CaseSensitive
= 0;
255 typeInfDate
.MaximumScale
= 0;
257 // Error reporting is turned OFF by default
260 // Copy the HENV into the db class
262 fwdOnlyCursors
= FwdOnlyCursors
;
264 // Allocate a data source connection handle
265 if (SQLAllocConnect(henv
, &hdbc
) != SQL_SUCCESS
)
268 // Initialize the db status flag
271 // Mark database as not open as of yet
277 /********** wxDB::Open() **********/
278 bool wxDB::Open(char *Dsn
, char *Uid
, char *AuthStr
)
280 assert(Dsn
&& wxStrlen(Dsn
));
287 if (!FwdOnlyCursors())
289 // Specify that the ODBC cursor library be used, if needed. This must be
290 // specified before the connection is made.
291 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
293 #ifdef DBDEBUG_CONSOLE
294 if (retcode
== SQL_SUCCESS
)
295 cout
<< "SQLSetConnectOption(CURSOR_LIB) successful" << endl
;
297 cout
<< "SQLSetConnectOption(CURSOR_LIB) failed" << endl
;
301 // Connect to the data source
302 retcode
= SQLConnect(hdbc
, (UCHAR FAR
*) Dsn
, SQL_NTS
,
303 (UCHAR FAR
*) Uid
, SQL_NTS
,
304 (UCHAR FAR
*) AuthStr
,SQL_NTS
);
305 if (retcode
== SQL_SUCCESS_WITH_INFO
)
306 DispAllErrors(henv
, hdbc
);
307 else if (retcode
!= SQL_SUCCESS
)
308 return(DispAllErrors(henv
, hdbc
));
311 If using Intersolv branded ODBC drivers, this is the place where you would substitute
312 your branded driver license information
314 SQLSetConnectOption(hdbc, 1041, (UDWORD) "");
315 SQLSetConnectOption(hdbc, 1042, (UDWORD) "");
318 // Mark database as open
321 // Allocate a statement handle for the database connection
322 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
323 return(DispAllErrors(henv
, hdbc
));
325 // Set Connection Options
326 if (! setConnectionOptions())
329 // Query the data source for inf. about itself
333 // Query the data source regarding data type information
336 // The way I determined which SQL data types to use was by calling SQLGetInfo
337 // for all of the possible SQL data types to see which ones were supported. If
338 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
339 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
340 // types I've selected below will not alway's be what we want. These are just
341 // what happened to work against an Oracle 7/Intersolv combination. The following is
342 // a complete list of the results I got back against the Oracle 7 database:
344 // SQL_BIGINT SQL_NO_DATA_FOUND
345 // SQL_BINARY SQL_NO_DATA_FOUND
346 // SQL_BIT SQL_NO_DATA_FOUND
347 // SQL_CHAR type name = 'CHAR', Precision = 255
348 // SQL_DATE SQL_NO_DATA_FOUND
349 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
350 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
351 // SQL_FLOAT SQL_NO_DATA_FOUND
352 // SQL_INTEGER SQL_NO_DATA_FOUND
353 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
354 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
355 // SQL_NUMERIC SQL_NO_DATA_FOUND
356 // SQL_REAL SQL_NO_DATA_FOUND
357 // SQL_SMALLINT SQL_NO_DATA_FOUND
358 // SQL_TIME SQL_NO_DATA_FOUND
359 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
360 // SQL_VARBINARY type name = 'RAW', Precision = 255
361 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
362 // =====================================================================
363 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
365 // SQL_VARCHAR type name = 'TEXT', Precision = 255
366 // SQL_TIMESTAMP type name = 'DATETIME'
367 // SQL_DECIMAL SQL_NO_DATA_FOUND
368 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
369 // SQL_FLOAT SQL_NO_DATA_FOUND
370 // SQL_REAL type name = 'SINGLE', Precision = 7
371 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
372 // SQL_INTEGER type name = 'LONG', Precision = 10
374 // VARCHAR = Variable length character string
375 if (! getDataTypeInfo(SQL_VARCHAR
, typeInfVarchar
))
376 if (! getDataTypeInfo(SQL_CHAR
, typeInfVarchar
))
379 typeInfVarchar
.FsqlType
= SQL_CHAR
;
381 typeInfVarchar
.FsqlType
= SQL_VARCHAR
;
384 if (! getDataTypeInfo(SQL_DOUBLE
, typeInfFloat
))
385 if (! getDataTypeInfo(SQL_REAL
, typeInfFloat
))
386 if (! getDataTypeInfo(SQL_FLOAT
, typeInfFloat
))
387 if (! getDataTypeInfo(SQL_DECIMAL
, typeInfFloat
))
388 if (! getDataTypeInfo(SQL_NUMERIC
, typeInfFloat
))
391 typeInfFloat
.FsqlType
= SQL_NUMERIC
;
393 typeInfFloat
.FsqlType
= SQL_DECIMAL
;
395 typeInfFloat
.FsqlType
= SQL_FLOAT
;
397 typeInfFloat
.FsqlType
= SQL_REAL
;
399 typeInfFloat
.FsqlType
= SQL_DOUBLE
;
402 if (! getDataTypeInfo(SQL_INTEGER
, typeInfInteger
))
403 // If SQL_INTEGER is not supported, use the floating point
404 // data type to store integers as well as floats
405 if (! getDataTypeInfo(typeInfFloat
.FsqlType
, typeInfInteger
))
408 typeInfInteger
.FsqlType
= typeInfFloat
.FsqlType
;
410 typeInfInteger
.FsqlType
= SQL_INTEGER
;
413 if (Dbms() != dbmsDBASE
)
415 if (! getDataTypeInfo(SQL_TIMESTAMP
, typeInfDate
))
418 typeInfDate
.FsqlType
= SQL_TIMESTAMP
;
422 if (! getDataTypeInfo(SQL_DATE
, typeInfDate
))
425 typeInfDate
.FsqlType
= SQL_DATE
;
428 #ifdef DBDEBUG_CONSOLE
429 cout
<< "VARCHAR DATA TYPE: " << typeInfVarchar
.TypeName
<< endl
;
430 cout
<< "INTEGER DATA TYPE: " << typeInfInteger
.TypeName
<< endl
;
431 cout
<< "FLOAT DATA TYPE: " << typeInfFloat
.TypeName
<< endl
;
432 cout
<< "DATE DATA TYPE: " << typeInfDate
.TypeName
<< endl
;
436 // Completed Successfully
442 /********** wxDB::setConnectionOptions() **********/
443 bool wxDB::setConnectionOptions(void)
445 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
448 SQLSetConnectOption(hdbc
, SQL_AUTOCOMMIT
, SQL_AUTOCOMMIT_OFF
);
449 SQLSetConnectOption(hdbc
, SQL_OPT_TRACE
, SQL_OPT_TRACE_OFF
);
451 // Display the connection options to verify them
452 #ifdef DBDEBUG_CONSOLE
454 cout
<< ">>>>> CONNECTION OPTIONS <<<<<<" << endl
;
456 if (SQLGetConnectOption(hdbc
, SQL_AUTOCOMMIT
, &l
) != SQL_SUCCESS
)
457 return(DispAllErrors(henv
, hdbc
));
458 cout
<< "AUTOCOMMIT: " << (l
== SQL_AUTOCOMMIT_OFF
? "OFF" : "ON") << endl
;
460 if (SQLGetConnectOption(hdbc
, SQL_ODBC_CURSORS
, &l
) != SQL_SUCCESS
)
461 return(DispAllErrors(henv
, hdbc
));
462 cout
<< "ODBC CURSORS: ";
465 case(SQL_CUR_USE_IF_NEEDED
):
466 cout
<< "SQL_CUR_USE_IF_NEEDED";
468 case(SQL_CUR_USE_ODBC
):
469 cout
<< "SQL_CUR_USE_ODBC";
471 case(SQL_CUR_USE_DRIVER
):
472 cout
<< "SQL_CUR_USE_DRIVER";
477 if (SQLGetConnectOption(hdbc
, SQL_OPT_TRACE
, &l
) != SQL_SUCCESS
)
478 return(DispAllErrors(henv
, hdbc
));
479 cout
<< "TRACING: " << (l
== SQL_OPT_TRACE_OFF
? "OFF" : "ON") << endl
;
484 // Completed Successfully
487 } // wxDB::setConnectionOptions()
490 /********** wxDB::getDbInfo() **********/
491 bool wxDB::getDbInfo(void)
496 if (SQLGetInfo(hdbc
, SQL_SERVER_NAME
, (UCHAR
*) dbInf
.serverName
, 80, &cb
) != SQL_SUCCESS
)
497 return(DispAllErrors(henv
, hdbc
));
499 if (SQLGetInfo(hdbc
, SQL_DATABASE_NAME
, (UCHAR
*) dbInf
.databaseName
, 128, &cb
) != SQL_SUCCESS
)
500 return(DispAllErrors(henv
, hdbc
));
502 if (SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, 40, &cb
) != SQL_SUCCESS
)
503 return(DispAllErrors(henv
, hdbc
));
506 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
507 // causing database connectivity to fail in some cases.
508 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_VER
, (UCHAR
*) dbInf
.dbmsVer
, 64, &cb
);
510 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
511 return(DispAllErrors(henv
, hdbc
));
513 if (SQLGetInfo(hdbc
, SQL_ACTIVE_CONNECTIONS
, (UCHAR
*) &dbInf
.maxConnections
, sizeof(dbInf
.maxConnections
), &cb
) != SQL_SUCCESS
)
514 return(DispAllErrors(henv
, hdbc
));
516 if (SQLGetInfo(hdbc
, SQL_ACTIVE_STATEMENTS
, (UCHAR
*) &dbInf
.maxStmts
, sizeof(dbInf
.maxStmts
), &cb
) != SQL_SUCCESS
)
517 return(DispAllErrors(henv
, hdbc
));
519 if (SQLGetInfo(hdbc
, SQL_DRIVER_NAME
, (UCHAR
*) dbInf
.driverName
, 40, &cb
) != SQL_SUCCESS
)
520 return(DispAllErrors(henv
, hdbc
));
522 if (SQLGetInfo(hdbc
, SQL_DRIVER_ODBC_VER
, (UCHAR
*) dbInf
.odbcVer
, 60, &cb
) == SQL_ERROR
)
523 return(DispAllErrors(henv
, hdbc
));
525 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_VER
, (UCHAR
*) dbInf
.drvMgrOdbcVer
, 60, &cb
);
526 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
527 return(DispAllErrors(henv
, hdbc
));
529 if (SQLGetInfo(hdbc
, SQL_DRIVER_VER
, (UCHAR
*) dbInf
.driverVer
, 60, &cb
) == SQL_ERROR
)
530 return(DispAllErrors(henv
, hdbc
));
532 if (SQLGetInfo(hdbc
, SQL_ODBC_API_CONFORMANCE
, (UCHAR
*) &dbInf
.apiConfLvl
, sizeof(dbInf
.apiConfLvl
), &cb
) != SQL_SUCCESS
)
533 return(DispAllErrors(henv
, hdbc
));
535 if (SQLGetInfo(hdbc
, SQL_ODBC_SAG_CLI_CONFORMANCE
, (UCHAR
*) &dbInf
.cliConfLvl
, sizeof(dbInf
.cliConfLvl
), &cb
) != SQL_SUCCESS
)
536 return(DispAllErrors(henv
, hdbc
));
538 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_CONFORMANCE
, (UCHAR
*) &dbInf
.sqlConfLvl
, sizeof(dbInf
.sqlConfLvl
), &cb
) != SQL_SUCCESS
)
539 return(DispAllErrors(henv
, hdbc
));
541 if (SQLGetInfo(hdbc
, SQL_OUTER_JOINS
, (UCHAR
*) dbInf
.outerJoins
, 2, &cb
) != SQL_SUCCESS
)
542 return(DispAllErrors(henv
, hdbc
));
544 if (SQLGetInfo(hdbc
, SQL_PROCEDURES
, (UCHAR
*) dbInf
.procedureSupport
, 2, &cb
) != SQL_SUCCESS
)
545 return(DispAllErrors(henv
, hdbc
));
547 if (SQLGetInfo(hdbc
, SQL_CURSOR_COMMIT_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorCommitBehavior
, sizeof(dbInf
.cursorCommitBehavior
), &cb
) != SQL_SUCCESS
)
548 return(DispAllErrors(henv
, hdbc
));
550 if (SQLGetInfo(hdbc
, SQL_CURSOR_ROLLBACK_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorRollbackBehavior
, sizeof(dbInf
.cursorRollbackBehavior
), &cb
) != SQL_SUCCESS
)
551 return(DispAllErrors(henv
, hdbc
));
553 if (SQLGetInfo(hdbc
, SQL_NON_NULLABLE_COLUMNS
, (UCHAR
*) &dbInf
.supportNotNullClause
, sizeof(dbInf
.supportNotNullClause
), &cb
) != SQL_SUCCESS
)
554 return(DispAllErrors(henv
, hdbc
));
556 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_OPT_IEF
, (UCHAR
*) dbInf
.supportIEF
, 2, &cb
) != SQL_SUCCESS
)
557 return(DispAllErrors(henv
, hdbc
));
559 if (SQLGetInfo(hdbc
, SQL_DEFAULT_TXN_ISOLATION
, (UCHAR
*) &dbInf
.txnIsolation
, sizeof(dbInf
.txnIsolation
), &cb
) != SQL_SUCCESS
)
560 return(DispAllErrors(henv
, hdbc
));
562 if (SQLGetInfo(hdbc
, SQL_TXN_ISOLATION_OPTION
, (UCHAR
*) &dbInf
.txnIsolationOptions
, sizeof(dbInf
.txnIsolationOptions
), &cb
) != SQL_SUCCESS
)
563 return(DispAllErrors(henv
, hdbc
));
565 if (SQLGetInfo(hdbc
, SQL_FETCH_DIRECTION
, (UCHAR
*) &dbInf
.fetchDirections
, sizeof(dbInf
.fetchDirections
), &cb
) != SQL_SUCCESS
)
566 return(DispAllErrors(henv
, hdbc
));
568 if (SQLGetInfo(hdbc
, SQL_LOCK_TYPES
, (UCHAR
*) &dbInf
.lockTypes
, sizeof(dbInf
.lockTypes
), &cb
) != SQL_SUCCESS
)
569 return(DispAllErrors(henv
, hdbc
));
571 if (SQLGetInfo(hdbc
, SQL_POS_OPERATIONS
, (UCHAR
*) &dbInf
.posOperations
, sizeof(dbInf
.posOperations
), &cb
) != SQL_SUCCESS
)
572 return(DispAllErrors(henv
, hdbc
));
574 if (SQLGetInfo(hdbc
, SQL_POSITIONED_STATEMENTS
, (UCHAR
*) &dbInf
.posStmts
, sizeof(dbInf
.posStmts
), &cb
) != SQL_SUCCESS
)
575 return(DispAllErrors(henv
, hdbc
));
577 if (SQLGetInfo(hdbc
, SQL_SCROLL_CONCURRENCY
, (UCHAR
*) &dbInf
.scrollConcurrency
, sizeof(dbInf
.scrollConcurrency
), &cb
) != SQL_SUCCESS
)
578 return(DispAllErrors(henv
, hdbc
));
580 if (SQLGetInfo(hdbc
, SQL_SCROLL_OPTIONS
, (UCHAR
*) &dbInf
.scrollOptions
, sizeof(dbInf
.scrollOptions
), &cb
) != SQL_SUCCESS
)
581 return(DispAllErrors(henv
, hdbc
));
583 if (SQLGetInfo(hdbc
, SQL_STATIC_SENSITIVITY
, (UCHAR
*) &dbInf
.staticSensitivity
, sizeof(dbInf
.staticSensitivity
), &cb
) != SQL_SUCCESS
)
584 return(DispAllErrors(henv
, hdbc
));
586 if (SQLGetInfo(hdbc
, SQL_TXN_CAPABLE
, (UCHAR
*) &dbInf
.txnCapable
, sizeof(dbInf
.txnCapable
), &cb
) != SQL_SUCCESS
)
587 return(DispAllErrors(henv
, hdbc
));
589 if (SQLGetInfo(hdbc
, SQL_LOGIN_TIMEOUT
, (UCHAR
*) &dbInf
.loginTimeout
, sizeof(dbInf
.loginTimeout
), &cb
) != SQL_SUCCESS
)
590 return(DispAllErrors(henv
, hdbc
));
592 #ifdef DBDEBUG_CONSOLE
593 cout
<< ">>>>> DATA SOURCE INFORMATION <<<<<" << endl
;
594 cout
<< "SERVER Name: " << dbInf
.serverName
<< endl
;
595 cout
<< "DBMS Name: " << dbInf
.dbmsName
<< "; DBMS Version: " << dbInf
.dbmsVer
<< endl
;
596 cout
<< "ODBC Version: " << dbInf
.odbcVer
<< "; Driver Version: " << dbInf
.driverVer
<< endl
;
598 cout
<< "API Conf. Level: ";
599 switch(dbInf
.apiConfLvl
)
601 case SQL_OAC_NONE
: cout
<< "None"; break;
602 case SQL_OAC_LEVEL1
: cout
<< "Level 1"; break;
603 case SQL_OAC_LEVEL2
: cout
<< "Level 2"; break;
607 cout
<< "SAG CLI Conf. Level: ";
608 switch(dbInf
.cliConfLvl
)
610 case SQL_OSCC_NOT_COMPLIANT
: cout
<< "Not Compliant"; break;
611 case SQL_OSCC_COMPLIANT
: cout
<< "Compliant"; break;
615 cout
<< "SQL Conf. Level: ";
616 switch(dbInf
.sqlConfLvl
)
618 case SQL_OSC_MINIMUM
: cout
<< "Minimum Grammer"; break;
619 case SQL_OSC_CORE
: cout
<< "Core Grammer"; break;
620 case SQL_OSC_EXTENDED
: cout
<< "Extended Grammer"; break;
624 cout
<< "Max. Connections: " << dbInf
.maxConnections
<< endl
;
625 cout
<< "Outer Joins: " << dbInf
.outerJoins
<< endl
;
626 cout
<< "Support for Procedures: " << dbInf
.procedureSupport
<< endl
;
628 cout
<< "Cursor COMMIT Behavior: ";
629 switch(dbInf
.cursorCommitBehavior
)
631 case SQL_CB_DELETE
: cout
<< "Delete cursors"; break;
632 case SQL_CB_CLOSE
: cout
<< "Close cursors"; break;
633 case SQL_CB_PRESERVE
: cout
<< "Preserve cursors"; break;
637 cout
<< "Cursor ROLLBACK Behavior: ";
638 switch(dbInf
.cursorRollbackBehavior
)
640 case SQL_CB_DELETE
: cout
<< "Delete cursors"; break;
641 case SQL_CB_CLOSE
: cout
<< "Close cursors"; break;
642 case SQL_CB_PRESERVE
: cout
<< "Preserve cursors"; break;
646 cout
<< "Support NOT NULL clause: ";
647 switch(dbInf
.supportNotNullClause
)
649 case SQL_NNC_NULL
: cout
<< "No"; break;
650 case SQL_NNC_NON_NULL
: cout
<< "Yes"; break;
654 cout
<< "Support IEF (Ref. Integrity): " << dbInf
.supportIEF
<< endl
;
655 cout
<< "Login Timeout: " << dbInf
.loginTimeout
<< endl
;
657 cout
<< endl
<< endl
<< "more ..." << endl
;
660 cout
<< "Default Transaction Isolation: ";
661 switch(dbInf
.txnIsolation
)
663 case SQL_TXN_READ_UNCOMMITTED
: cout
<< "Read Uncommitted"; break;
664 case SQL_TXN_READ_COMMITTED
: cout
<< "Read Committed"; break;
665 case SQL_TXN_REPEATABLE_READ
: cout
<< "Repeatable Read"; break;
666 case SQL_TXN_SERIALIZABLE
: cout
<< "Serializable"; break;
668 case SQL_TXN_VERSIONING
: cout
<< "Versioning"; break;
673 cout
<< "Transaction Isolation Options: ";
674 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_UNCOMMITTED
)
675 cout
<< "Read Uncommitted, ";
676 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_COMMITTED
)
677 cout
<< "Read Committed, ";
678 if (dbInf
.txnIsolationOptions
& SQL_TXN_REPEATABLE_READ
)
679 cout
<< "Repeatable Read, ";
680 if (dbInf
.txnIsolationOptions
& SQL_TXN_SERIALIZABLE
)
681 cout
<< "Serializable, ";
683 if (dbInf
.txnIsolationOptions
& SQL_TXN_VERSIONING
)
684 cout
<< "Versioning";
688 cout
<< "Fetch Directions Supported:" << endl
<< " ";
689 if (dbInf
.fetchDirections
& SQL_FD_FETCH_NEXT
)
691 if (dbInf
.fetchDirections
& SQL_FD_FETCH_PRIOR
)
693 if (dbInf
.fetchDirections
& SQL_FD_FETCH_FIRST
)
695 if (dbInf
.fetchDirections
& SQL_FD_FETCH_LAST
)
697 if (dbInf
.fetchDirections
& SQL_FD_FETCH_ABSOLUTE
)
698 cout
<< "Absolute, ";
699 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RELATIVE
)
700 cout
<< "Relative, ";
702 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RESUME
)
705 if (dbInf
.fetchDirections
& SQL_FD_FETCH_BOOKMARK
)
709 cout
<< "Lock Types Supported (SQLSetPos): ";
710 if (dbInf
.lockTypes
& SQL_LCK_NO_CHANGE
)
711 cout
<< "No Change, ";
712 if (dbInf
.lockTypes
& SQL_LCK_EXCLUSIVE
)
713 cout
<< "Exclusive, ";
714 if (dbInf
.lockTypes
& SQL_LCK_UNLOCK
)
718 cout
<< "Position Operations Supported (SQLSetPos): ";
719 if (dbInf
.posOperations
& SQL_POS_POSITION
)
720 cout
<< "Position, ";
721 if (dbInf
.posOperations
& SQL_POS_REFRESH
)
723 if (dbInf
.posOperations
& SQL_POS_UPDATE
)
725 if (dbInf
.posOperations
& SQL_POS_DELETE
)
727 if (dbInf
.posOperations
& SQL_POS_ADD
)
731 cout
<< "Positioned Statements Supported: ";
732 if (dbInf
.posStmts
& SQL_PS_POSITIONED_DELETE
)
733 cout
<< "Pos delete, ";
734 if (dbInf
.posStmts
& SQL_PS_POSITIONED_UPDATE
)
735 cout
<< "Pos update, ";
736 if (dbInf
.posStmts
& SQL_PS_SELECT_FOR_UPDATE
)
737 cout
<< "Select for update";
740 cout
<< "Scroll Concurrency: ";
741 if (dbInf
.scrollConcurrency
& SQL_SCCO_READ_ONLY
)
742 cout
<< "Read Only, ";
743 if (dbInf
.scrollConcurrency
& SQL_SCCO_LOCK
)
745 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_ROWVER
)
746 cout
<< "Opt. Rowver, ";
747 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_VALUES
)
748 cout
<< "Opt. Values";
751 cout
<< "Scroll Options: ";
752 if (dbInf
.scrollOptions
& SQL_SO_FORWARD_ONLY
)
753 cout
<< "Fwd Only, ";
754 if (dbInf
.scrollOptions
& SQL_SO_STATIC
)
756 if (dbInf
.scrollOptions
& SQL_SO_KEYSET_DRIVEN
)
757 cout
<< "Keyset Driven, ";
758 if (dbInf
.scrollOptions
& SQL_SO_DYNAMIC
)
760 if (dbInf
.scrollOptions
& SQL_SO_MIXED
)
764 cout
<< "Static Sensitivity: ";
765 if (dbInf
.staticSensitivity
& SQL_SS_ADDITIONS
)
766 cout
<< "Additions, ";
767 if (dbInf
.staticSensitivity
& SQL_SS_DELETIONS
)
768 cout
<< "Deletions, ";
769 if (dbInf
.staticSensitivity
& SQL_SS_UPDATES
)
773 cout
<< "Transaction Capable?: ";
774 switch(dbInf
.txnCapable
)
776 case SQL_TC_NONE
: cout
<< "No"; break;
777 case SQL_TC_DML
: cout
<< "DML Only"; break;
778 case SQL_TC_DDL_COMMIT
: cout
<< "DDL Commit"; break;
779 case SQL_TC_DDL_IGNORE
: cout
<< "DDL Ignore"; break;
780 case SQL_TC_ALL
: cout
<< "DDL & DML"; break;
787 // Completed Successfully
790 } // wxDB::getDbInfo()
793 /********** wxDB::getDataTypeInfo() **********/
794 bool wxDB::getDataTypeInfo(SWORD fSqlType
, SqlTypeInfo
&structSQLTypeInfo
)
797 * fSqlType will be something like SQL_VARCHAR. This parameter determines
798 * the data type inf. is gathered for.
800 * SqlTypeInfo is a structure that is filled in with data type information,
805 // Get information about the data type specified
806 if (SQLGetTypeInfo(hstmt
, fSqlType
) != SQL_SUCCESS
)
807 return(DispAllErrors(henv
, hdbc
, hstmt
));
809 if ((retcode
= SQLFetch(hstmt
)) != SQL_SUCCESS
)
811 #ifdef DBDEBUG_CONSOLE
812 if (retcode
== SQL_NO_DATA_FOUND
)
813 cout
<< "SQL_NO_DATA_FOUND fetching inf. about data type." << endl
;
815 DispAllErrors(henv
, hdbc
, hstmt
);
816 SQLFreeStmt(hstmt
, SQL_CLOSE
);
819 // Obtain columns from the record
820 if (SQLGetData(hstmt
, 1, SQL_C_CHAR
, (UCHAR
*) structSQLTypeInfo
.TypeName
, DB_TYPE_NAME_LEN
, &cbRet
) != SQL_SUCCESS
)
821 return(DispAllErrors(henv
, hdbc
, hstmt
));
824 if (Dbms() == dbmsMY_SQL
)
826 if (!strcmp(structSQLTypeInfo
.TypeName
, "middleint")) strcpy(structSQLTypeInfo
.TypeName
, "mediumint");
827 if (!strcmp(structSQLTypeInfo
.TypeName
, "middleint unsigned")) strcpy(structSQLTypeInfo
.TypeName
, "mediumint unsigned");
828 if (!strcmp(structSQLTypeInfo
.TypeName
, "integer")) strcpy(structSQLTypeInfo
.TypeName
, "int");
829 if (!strcmp(structSQLTypeInfo
.TypeName
, "integer unsigned")) strcpy(structSQLTypeInfo
.TypeName
, "int unsigned");
830 if (!strcmp(structSQLTypeInfo
.TypeName
, "middleint")) strcpy(structSQLTypeInfo
.TypeName
, "mediumint");
831 if (!strcmp(structSQLTypeInfo
.TypeName
, "varchar")) strcpy(structSQLTypeInfo
.TypeName
, "char");
834 if (SQLGetData(hstmt
, 3, SQL_C_LONG
, (UCHAR
*) &structSQLTypeInfo
.Precision
, 0, &cbRet
) != SQL_SUCCESS
)
835 return(DispAllErrors(henv
, hdbc
, hstmt
));
836 if (SQLGetData(hstmt
, 8, SQL_C_SHORT
, (UCHAR
*) &structSQLTypeInfo
.CaseSensitive
, 0, &cbRet
) != SQL_SUCCESS
)
837 return(DispAllErrors(henv
, hdbc
, hstmt
));
838 // if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
839 // return(DispAllErrors(henv, hdbc, hstmt));
841 if (SQLGetData(hstmt
, 15, SQL_C_SHORT
,(UCHAR
*) &structSQLTypeInfo
.MaximumScale
, 0, &cbRet
) != SQL_SUCCESS
)
842 return(DispAllErrors(henv
, hdbc
, hstmt
));
844 if (structSQLTypeInfo
.MaximumScale
< 0)
845 structSQLTypeInfo
.MaximumScale
= 0;
847 // Close the statement handle which closes open cursors
848 if (SQLFreeStmt(hstmt
, SQL_CLOSE
) != SQL_SUCCESS
)
849 return(DispAllErrors(henv
, hdbc
, hstmt
));
851 // Completed Successfully
854 } // wxDB::getDataTypeInfo()
857 /********** wxDB::Close() **********/
858 void wxDB::Close(void)
860 // Close the Sql Log file
867 // Free statement handle
870 if (SQLFreeStmt(hstmt
, SQL_DROP
) != SQL_SUCCESS
)
871 DispAllErrors(henv
, hdbc
);
874 // Disconnect from the datasource
875 if (SQLDisconnect(hdbc
) != SQL_SUCCESS
)
876 DispAllErrors(henv
, hdbc
);
878 // Free the connection to the datasource
879 if (SQLFreeConnect(hdbc
) != SQL_SUCCESS
)
880 DispAllErrors(henv
, hdbc
);
882 // There should be zero Ctable objects still connected to this db object
883 assert(nTables
== 0);
886 CstructTablesInUse
*tiu
;
888 pNode
= TablesInUse
.First();
892 tiu
= (CstructTablesInUse
*)pNode
->Data();
893 if (tiu
->pDb
== this)
895 s
.sprintf("(%-20s) tableID:[%6lu] pDb:[%p]", tiu
->tableName
,tiu
->tableID
,tiu
->pDb
);
896 s2
.sprintf("Orphaned found using pDb:[%p]",this);
899 pNode
= pNode
->Next();
903 // Copy the error messages to a global variable
905 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
906 wxStrcpy(DBerrorList
[i
],errorList
[i
]);
911 /********** wxDB::CommitTrans() **********/
912 bool wxDB::CommitTrans(void)
916 // Commit the transaction
917 if (SQLTransact(henv
, hdbc
, SQL_COMMIT
) != SQL_SUCCESS
)
918 return(DispAllErrors(henv
, hdbc
));
921 // Completed successfully
924 } // wxDB::CommitTrans()
927 /********** wxDB::RollbackTrans() **********/
928 bool wxDB::RollbackTrans(void)
930 // Rollback the transaction
931 if (SQLTransact(henv
, hdbc
, SQL_ROLLBACK
) != SQL_SUCCESS
)
932 return(DispAllErrors(henv
, hdbc
));
934 // Completed successfully
937 } // wxDB::RollbackTrans()
940 /********** wxDB::DispAllErrors() **********/
941 bool wxDB::DispAllErrors(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
943 // char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
946 while (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
948 odbcErrMsg
.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState
, nativeError
, errorMsg
);
949 logError(odbcErrMsg
.GetData(), sqlState
);
952 #ifdef DBDEBUG_CONSOLE
953 // When run in console mode, use standard out to display errors.
954 cout
<< odbcErrMsg
.GetData() << endl
;
955 cout
<< "Press any key to continue..." << endl
;
961 wxMessageBox(odbcErrMsg
.GetData(),"DEBUG MESSAGE from DispAllErrors()");
965 return(FALSE
); // This function always returns false.
967 } // wxDB::DispAllErrors()
970 /********** wxDB::GetNextError() **********/
971 bool wxDB::GetNextError(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
973 if (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
978 } // wxDB::GetNextError()
981 /********** wxDB::DispNextError() **********/
982 void wxDB::DispNextError(void)
984 // char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
987 odbcErrMsg
.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState
, nativeError
, errorMsg
);
988 logError(odbcErrMsg
.GetData(), sqlState
);
993 #ifdef DBDEBUG_CONSOLE
994 // When run in console mode, use standard out to display errors.
995 cout
<< odbcErrMsg
.GetData() << endl
;
996 cout
<< "Press any key to continue..." << endl
;
1000 } // wxDB::DispNextError()
1003 /********** wxDB::logError() **********/
1004 void wxDB::logError(const char *errMsg
, const char *SQLState
)
1006 assert(errMsg
&& wxStrlen(errMsg
));
1008 static int pLast
= -1;
1011 if (++pLast
== DB_MAX_ERROR_HISTORY
)
1014 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1015 wxStrcpy(errorList
[i
], errorList
[i
+1]);
1019 wxStrcpy(errorList
[pLast
], errMsg
);
1021 if (SQLState
&& wxStrlen(SQLState
))
1022 if ((dbStatus
= TranslateSqlState(SQLState
)) != DB_ERR_FUNCTION_SEQUENCE_ERROR
)
1023 DB_STATUS
= dbStatus
;
1025 // Add the errmsg to the sql log
1026 WriteSqlLog(errMsg
);
1028 } // wxDB::logError()
1031 /**********wxDB::TranslateSqlState() **********/
1032 int wxDB::TranslateSqlState(const char *SQLState
)
1034 if (!wxStrcmp(SQLState
, "01000"))
1035 return(DB_ERR_GENERAL_WARNING
);
1036 if (!wxStrcmp(SQLState
, "01002"))
1037 return(DB_ERR_DISCONNECT_ERROR
);
1038 if (!wxStrcmp(SQLState
, "01004"))
1039 return(DB_ERR_DATA_TRUNCATED
);
1040 if (!wxStrcmp(SQLState
, "01006"))
1041 return(DB_ERR_PRIV_NOT_REVOKED
);
1042 if (!wxStrcmp(SQLState
, "01S00"))
1043 return(DB_ERR_INVALID_CONN_STR_ATTR
);
1044 if (!wxStrcmp(SQLState
, "01S01"))
1045 return(DB_ERR_ERROR_IN_ROW
);
1046 if (!wxStrcmp(SQLState
, "01S02"))
1047 return(DB_ERR_OPTION_VALUE_CHANGED
);
1048 if (!wxStrcmp(SQLState
, "01S03"))
1049 return(DB_ERR_NO_ROWS_UPD_OR_DEL
);
1050 if (!wxStrcmp(SQLState
, "01S04"))
1051 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL
);
1052 if (!wxStrcmp(SQLState
, "07001"))
1053 return(DB_ERR_WRONG_NO_OF_PARAMS
);
1054 if (!wxStrcmp(SQLState
, "07006"))
1055 return(DB_ERR_DATA_TYPE_ATTR_VIOL
);
1056 if (!wxStrcmp(SQLState
, "08001"))
1057 return(DB_ERR_UNABLE_TO_CONNECT
);
1058 if (!wxStrcmp(SQLState
, "08002"))
1059 return(DB_ERR_CONNECTION_IN_USE
);
1060 if (!wxStrcmp(SQLState
, "08003"))
1061 return(DB_ERR_CONNECTION_NOT_OPEN
);
1062 if (!wxStrcmp(SQLState
, "08004"))
1063 return(DB_ERR_REJECTED_CONNECTION
);
1064 if (!wxStrcmp(SQLState
, "08007"))
1065 return(DB_ERR_CONN_FAIL_IN_TRANS
);
1066 if (!wxStrcmp(SQLState
, "08S01"))
1067 return(DB_ERR_COMM_LINK_FAILURE
);
1068 if (!wxStrcmp(SQLState
, "21S01"))
1069 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH
);
1070 if (!wxStrcmp(SQLState
, "21S02"))
1071 return(DB_ERR_DERIVED_TABLE_MISMATCH
);
1072 if (!wxStrcmp(SQLState
, "22001"))
1073 return(DB_ERR_STRING_RIGHT_TRUNC
);
1074 if (!wxStrcmp(SQLState
, "22003"))
1075 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG
);
1076 if (!wxStrcmp(SQLState
, "22005"))
1077 return(DB_ERR_ERROR_IN_ASSIGNMENT
);
1078 if (!wxStrcmp(SQLState
, "22008"))
1079 return(DB_ERR_DATETIME_FLD_OVERFLOW
);
1080 if (!wxStrcmp(SQLState
, "22012"))
1081 return(DB_ERR_DIVIDE_BY_ZERO
);
1082 if (!wxStrcmp(SQLState
, "22026"))
1083 return(DB_ERR_STR_DATA_LENGTH_MISMATCH
);
1084 if (!wxStrcmp(SQLState
, "23000"))
1085 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL
);
1086 if (!wxStrcmp(SQLState
, "24000"))
1087 return(DB_ERR_INVALID_CURSOR_STATE
);
1088 if (!wxStrcmp(SQLState
, "25000"))
1089 return(DB_ERR_INVALID_TRANS_STATE
);
1090 if (!wxStrcmp(SQLState
, "28000"))
1091 return(DB_ERR_INVALID_AUTH_SPEC
);
1092 if (!wxStrcmp(SQLState
, "34000"))
1093 return(DB_ERR_INVALID_CURSOR_NAME
);
1094 if (!wxStrcmp(SQLState
, "37000"))
1095 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL
);
1096 if (!wxStrcmp(SQLState
, "3C000"))
1097 return(DB_ERR_DUPLICATE_CURSOR_NAME
);
1098 if (!wxStrcmp(SQLState
, "40001"))
1099 return(DB_ERR_SERIALIZATION_FAILURE
);
1100 if (!wxStrcmp(SQLState
, "42000"))
1101 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2
);
1102 if (!wxStrcmp(SQLState
, "70100"))
1103 return(DB_ERR_OPERATION_ABORTED
);
1104 if (!wxStrcmp(SQLState
, "IM001"))
1105 return(DB_ERR_UNSUPPORTED_FUNCTION
);
1106 if (!wxStrcmp(SQLState
, "IM002"))
1107 return(DB_ERR_NO_DATA_SOURCE
);
1108 if (!wxStrcmp(SQLState
, "IM003"))
1109 return(DB_ERR_DRIVER_LOAD_ERROR
);
1110 if (!wxStrcmp(SQLState
, "IM004"))
1111 return(DB_ERR_SQLALLOCENV_FAILED
);
1112 if (!wxStrcmp(SQLState
, "IM005"))
1113 return(DB_ERR_SQLALLOCCONNECT_FAILED
);
1114 if (!wxStrcmp(SQLState
, "IM006"))
1115 return(DB_ERR_SQLSETCONNECTOPTION_FAILED
);
1116 if (!wxStrcmp(SQLState
, "IM007"))
1117 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB
);
1118 if (!wxStrcmp(SQLState
, "IM008"))
1119 return(DB_ERR_DIALOG_FAILED
);
1120 if (!wxStrcmp(SQLState
, "IM009"))
1121 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL
);
1122 if (!wxStrcmp(SQLState
, "IM010"))
1123 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG
);
1124 if (!wxStrcmp(SQLState
, "IM011"))
1125 return(DB_ERR_DRIVER_NAME_TOO_LONG
);
1126 if (!wxStrcmp(SQLState
, "IM012"))
1127 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR
);
1128 if (!wxStrcmp(SQLState
, "IM013"))
1129 return(DB_ERR_TRACE_FILE_ERROR
);
1130 if (!wxStrcmp(SQLState
, "S0001"))
1131 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS
);
1132 if (!wxStrcmp(SQLState
, "S0002"))
1133 return(DB_ERR_TABLE_NOT_FOUND
);
1134 if (!wxStrcmp(SQLState
, "S0011"))
1135 return(DB_ERR_INDEX_ALREADY_EXISTS
);
1136 if (!wxStrcmp(SQLState
, "S0012"))
1137 return(DB_ERR_INDEX_NOT_FOUND
);
1138 if (!wxStrcmp(SQLState
, "S0021"))
1139 return(DB_ERR_COLUMN_ALREADY_EXISTS
);
1140 if (!wxStrcmp(SQLState
, "S0022"))
1141 return(DB_ERR_COLUMN_NOT_FOUND
);
1142 if (!wxStrcmp(SQLState
, "S0023"))
1143 return(DB_ERR_NO_DEFAULT_FOR_COLUMN
);
1144 if (!wxStrcmp(SQLState
, "S1000"))
1145 return(DB_ERR_GENERAL_ERROR
);
1146 if (!wxStrcmp(SQLState
, "S1001"))
1147 return(DB_ERR_MEMORY_ALLOCATION_FAILURE
);
1148 if (!wxStrcmp(SQLState
, "S1002"))
1149 return(DB_ERR_INVALID_COLUMN_NUMBER
);
1150 if (!wxStrcmp(SQLState
, "S1003"))
1151 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE
);
1152 if (!wxStrcmp(SQLState
, "S1004"))
1153 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE
);
1154 if (!wxStrcmp(SQLState
, "S1008"))
1155 return(DB_ERR_OPERATION_CANCELLED
);
1156 if (!wxStrcmp(SQLState
, "S1009"))
1157 return(DB_ERR_INVALID_ARGUMENT_VALUE
);
1158 if (!wxStrcmp(SQLState
, "S1010"))
1159 return(DB_ERR_FUNCTION_SEQUENCE_ERROR
);
1160 if (!wxStrcmp(SQLState
, "S1011"))
1161 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME
);
1162 if (!wxStrcmp(SQLState
, "S1012"))
1163 return(DB_ERR_INVALID_TRANS_OPERATION_CODE
);
1164 if (!wxStrcmp(SQLState
, "S1015"))
1165 return(DB_ERR_NO_CURSOR_NAME_AVAIL
);
1166 if (!wxStrcmp(SQLState
, "S1090"))
1167 return(DB_ERR_INVALID_STR_OR_BUF_LEN
);
1168 if (!wxStrcmp(SQLState
, "S1091"))
1169 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE
);
1170 if (!wxStrcmp(SQLState
, "S1092"))
1171 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE
);
1172 if (!wxStrcmp(SQLState
, "S1093"))
1173 return(DB_ERR_INVALID_PARAM_NO
);
1174 if (!wxStrcmp(SQLState
, "S1094"))
1175 return(DB_ERR_INVALID_SCALE_VALUE
);
1176 if (!wxStrcmp(SQLState
, "S1095"))
1177 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE
);
1178 if (!wxStrcmp(SQLState
, "S1096"))
1179 return(DB_ERR_INF_TYPE_OUT_OF_RANGE
);
1180 if (!wxStrcmp(SQLState
, "S1097"))
1181 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE
);
1182 if (!wxStrcmp(SQLState
, "S1098"))
1183 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE
);
1184 if (!wxStrcmp(SQLState
, "S1099"))
1185 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE
);
1186 if (!wxStrcmp(SQLState
, "S1100"))
1187 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE
);
1188 if (!wxStrcmp(SQLState
, "S1101"))
1189 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE
);
1190 if (!wxStrcmp(SQLState
, "S1103"))
1191 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE
);
1192 if (!wxStrcmp(SQLState
, "S1104"))
1193 return(DB_ERR_INVALID_PRECISION_VALUE
);
1194 if (!wxStrcmp(SQLState
, "S1105"))
1195 return(DB_ERR_INVALID_PARAM_TYPE
);
1196 if (!wxStrcmp(SQLState
, "S1106"))
1197 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE
);
1198 if (!wxStrcmp(SQLState
, "S1107"))
1199 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE
);
1200 if (!wxStrcmp(SQLState
, "S1108"))
1201 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE
);
1202 if (!wxStrcmp(SQLState
, "S1109"))
1203 return(DB_ERR_INVALID_CURSOR_POSITION
);
1204 if (!wxStrcmp(SQLState
, "S1110"))
1205 return(DB_ERR_INVALID_DRIVER_COMPLETION
);
1206 if (!wxStrcmp(SQLState
, "S1111"))
1207 return(DB_ERR_INVALID_BOOKMARK_VALUE
);
1208 if (!wxStrcmp(SQLState
, "S1C00"))
1209 return(DB_ERR_DRIVER_NOT_CAPABLE
);
1210 if (!wxStrcmp(SQLState
, "S1T00"))
1211 return(DB_ERR_TIMEOUT_EXPIRED
);
1216 } // wxDB::TranslateSqlState()
1219 /********** wxDB::Grant() **********/
1220 bool wxDB::Grant(int privileges
, const char *tableName
, const char *userList
)
1222 // char sqlStmt[DB_MAX_STATEMENT_LEN];
1225 // Build the grant statement
1227 if (privileges
== DB_GRANT_ALL
)
1232 if (privileges
& DB_GRANT_SELECT
)
1234 sqlStmt
+= "SELECT";
1237 if (privileges
& DB_GRANT_INSERT
)
1241 sqlStmt
+= "INSERT";
1243 if (privileges
& DB_GRANT_UPDATE
)
1247 sqlStmt
+= "UPDATE";
1249 if (privileges
& DB_GRANT_DELETE
)
1253 sqlStmt
+= "DELETE";
1258 sqlStmt
+= tableName
;
1260 sqlStmt
+= userList
;
1262 #ifdef DBDEBUG_CONSOLE
1263 cout
<< endl
<< sqlStmt
.GetData() << endl
;
1266 WriteSqlLog(sqlStmt
.GetData());
1268 return(ExecSql(sqlStmt
.GetData()));
1273 /********** wxDB::CreateView() **********/
1274 bool wxDB::CreateView(const char *viewName
, const char *colList
, const char *pSqlStmt
, bool attemptDrop
)
1276 // char sqlStmt[DB_MAX_STATEMENT_LEN];
1279 // Drop the view first
1280 if (attemptDrop
&& !DropView(viewName
))
1283 // Build the create view statement
1284 sqlStmt
= "CREATE VIEW ";
1285 sqlStmt
+= viewName
;
1287 if (wxStrlen(colList
))
1295 sqlStmt
+= pSqlStmt
;
1297 WriteSqlLog(sqlStmt
.GetData());
1299 #ifdef DBDEBUG_CONSOLE
1300 cout
<< sqlStmt
.GetData() << endl
;
1303 return(ExecSql(sqlStmt
.GetData()));
1305 } // wxDB::CreateView()
1308 /********** wxDB::DropView() **********/
1309 bool wxDB::DropView(const char *viewName
)
1312 * NOTE: This function returns TRUE if the View does not exist, but
1313 * only for identified databases. Code will need to be added
1314 * below for any other databases when those databases are defined
1315 * to handle this situation consistently
1317 // char sqlStmt[DB_MAX_STATEMENT_LEN];
1320 sqlStmt
.sprintf("DROP VIEW %s", viewName
);
1322 WriteSqlLog(sqlStmt
.GetData());
1324 #ifdef DBDEBUG_CONSOLE
1325 cout
<< endl
<< sqlStmt
.GetData() << endl
;
1328 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
.GetData(), SQL_NTS
) != SQL_SUCCESS
)
1330 // Check for "Base table not found" error and ignore
1331 GetNextError(henv
, hdbc
, hstmt
);
1332 if (wxStrcmp(sqlState
,"S0002")) // "Base table not found"
1334 // Check for product specific error codes
1335 if (!((Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(sqlState
,"42000")))) // 5.x (and lower?)
1338 DispAllErrors(henv
, hdbc
, hstmt
);
1345 // Commit the transaction
1346 if (! CommitTrans())
1351 } // wxDB::DropView()
1354 /********** wxDB::ExecSql() **********/
1355 bool wxDB::ExecSql(const char *pSqlStmt
)
1357 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1358 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) pSqlStmt
, SQL_NTS
) == SQL_SUCCESS
)
1362 DispAllErrors(henv
, hdbc
, hstmt
);
1366 } // wxDB::ExecSql()
1369 /********** wxDB::GetNext() **********/
1370 bool wxDB::GetNext(void)
1372 if (SQLFetch(hstmt
) == SQL_SUCCESS
)
1376 DispAllErrors(henv
, hdbc
, hstmt
);
1380 } // wxDB::GetNext()
1383 /********** wxDB::GetData() **********/
1384 bool wxDB::GetData(UWORD colNo
, SWORD cType
, PTR pData
, SDWORD maxLen
, SDWORD FAR
*cbReturned
)
1389 if (SQLGetData(hstmt
, colNo
, cType
, pData
, maxLen
, cbReturned
) == SQL_SUCCESS
)
1393 DispAllErrors(henv
, hdbc
, hstmt
);
1397 } // wxDB::GetData()
1400 /********** wxDB::GetKeyFields() **********/
1401 int wxDB::GetKeyFields(char *tableName
, wxColInf
* colInf
,int noCols
)
1403 char szPkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Primary key table name */
1404 char szFkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Foreign key table name */
1406 // SQLSMALLINT iKeySeq;
1407 char szPkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Primary key column */
1408 char szFkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Foreign key column */
1414 * ---------------------------------------------------------------------
1415 * -- 19991224 : mj10777@gmx.net : Create ------
1416 * -- : Three things are done and stored here : ------
1417 * -- : 1) which Column(s) is/are Primary Key(s) ------
1418 * -- : 2) which tables use this Key as a Foreign Key ------
1419 * -- : 3) which columns are Foreign Key and the name ------
1420 * -- : of the Table where the Key is the Primary Key -----
1421 * -- : Called from GetColumns(char *tableName, ------
1422 * -- int *numCols,const char *userID ) ------
1423 * ---------------------------------------------------------------------
1426 /*---------------------------------------------------------------------*/
1427 /* Get the names of the columns in the primary key. */
1428 /*---------------------------------------------------------------------*/
1429 retcode
= SQLPrimaryKeys(hstmt
,
1430 NULL
, 0, /* Catalog name */
1431 NULL
, 0, /* Schema name */
1432 (UCHAR
*) tableName
, SQL_NTS
); /* Table name */
1434 /*---------------------------------------------------------------------*/
1435 /* Fetch and display the result set. This will be a list of the */
1436 /* columns in the primary key of the tableName table. */
1437 /*---------------------------------------------------------------------*/
1438 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1440 retcode
= SQLFetch(hstmt
);
1441 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1443 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1444 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1446 for (i
=0;i
<noCols
;i
++) // Find the Column name
1447 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column
1448 colInf
[i
].PkCol
= iKeySeq
; // Which Primary Key is this (first, second usw.) ?
1449 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1450 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1451 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1453 /*---------------------------------------------------------------------*/
1454 /* Get all the foreign keys that refer to tableName primary key. */
1455 /*---------------------------------------------------------------------*/
1456 retcode
= SQLForeignKeys(hstmt
,
1457 NULL
, 0, /* Primary catalog */
1458 NULL
, 0, /* Primary schema */
1459 (UCHAR
*)tableName
, SQL_NTS
, /* Primary table */
1460 NULL
, 0, /* Foreign catalog */
1461 NULL
, 0, /* Foreign schema */
1462 NULL
, 0); /* Foreign table */
1464 /*---------------------------------------------------------------------*/
1465 /* Fetch and display the result set. This will be all of the foreign */
1466 /* keys in other tables that refer to the tableName primary key. */
1467 /*---------------------------------------------------------------------*/
1470 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1472 retcode
= SQLFetch(hstmt
);
1473 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1475 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1476 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1477 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1478 GetData( 7, SQL_C_CHAR
, szFkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1479 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1480 Temp0
.Printf("%s[%s] ",Temp0
.c_str(),szFkTable
); // [ ] in case there is a blank in the Table name
1481 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1482 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1483 Temp0
.Trim(); // Get rid of any unneeded blanks
1486 for (i
=0;i
<noCols
;i
++) // Find the Column name
1487 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column, store the Information
1488 strcpy(colInf
[i
].PkTableName
,Temp0
); // Name of the Tables where this Primary Key is used as a Foreign Key
1489 } // if (Temp0 != "")
1490 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1492 /*---------------------------------------------------------------------*/
1493 /* Get all the foreign keys in the tablename table. */
1494 /*---------------------------------------------------------------------*/
1495 retcode
= SQLForeignKeys(hstmt
,
1496 NULL
, 0, /* Primary catalog */
1497 NULL
, 0, /* Primary schema */
1498 NULL
, 0, /* Primary table */
1499 NULL
, 0, /* Foreign catalog */
1500 NULL
, 0, /* Foreign schema */
1501 (UCHAR
*)tableName
, SQL_NTS
); /* Foreign table */
1503 /*---------------------------------------------------------------------*/
1504 /* Fetch and display the result set. This will be all of the */
1505 /* primary keys in other tables that are referred to by foreign */
1506 /* keys in the tableName table. */
1507 /*---------------------------------------------------------------------*/
1509 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1511 retcode
= SQLFetch(hstmt
);
1512 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1514 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1515 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1516 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1518 for (i
=0;i
<noCols
;i
++) // Find the Column name
1520 if (!wxStrcmp(colInf
[i
].colName
,szFkCol
)) // We have found the (Foreign Key) Column
1522 colInf
[i
].FkCol
= iKeySeq
; // Which Foreign Key is this (first, second usw.) ?
1523 strcpy(colInf
[i
].FkTableName
,szPkTable
); // Name of the Table where this Foriegn is the Primary Key
1524 } // if (!wxStrcmp(colInf[i].colName,szFkCol))
1525 } // for (i=0;i<noCols;i++)
1526 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1527 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1528 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1530 /*---------------------------------------------------------------------*/
1532 } // wxDB::GetKeyFields()
1535 /********** wxDB::GetColumns() **********/
1536 wxColInf
*wxDB::GetColumns(char *tableName
[], const char *userID
)
1538 * 1) The last array element of the tableName[] argument must be zero (null).
1539 * This is how the end of the array is detected.
1540 * 2) This function returns an array of wxColInf structures. If no columns
1541 * were found, or an error occured, this pointer will be zero (null). THE
1542 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
1543 * IS FINISHED WITH IT. i.e.
1545 * wxColInf *colInf = pDb->GetColumns(tableList, userID);
1548 * // Use the column inf
1550 * // Destroy the memory
1554 * userID is evaluated in the following manner:
1555 * userID == NULL ... UserID is ignored
1556 * userID == "" ... UserID set equal to 'this->uid'
1557 * userID != "" ... UserID set equal to 'userID'
1559 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1560 * by this function. This function should use its own wxDB instance
1561 * to avoid undesired unbinding of columns.
1566 wxColInf
*colInf
= 0;
1576 if (!wxStrlen(userID
))
1584 // dBase does not use user names, and some drivers fail if you try to pass one
1585 if (Dbms() == dbmsDBASE
)
1588 // Oracle user names may only be in uppercase, so force
1589 // the name to uppercase
1590 if (Dbms() == dbmsORACLE
)
1591 UserID
= UserID
.Upper();
1593 // Pass 1 - Determine how many columns there are.
1594 // Pass 2 - Allocate the wxColInf array and fill in
1595 // the array with the column information.
1597 for (pass
= 1; pass
<= 2; pass
++)
1601 if (noCols
== 0) // Probably a bogus table name(s)
1603 // Allocate n wxColInf objects to hold the column information
1604 colInf
= new wxColInf
[noCols
+1];
1607 // Mark the end of the array
1608 wxStrcpy(colInf
[noCols
].tableName
, "");
1609 wxStrcpy(colInf
[noCols
].colName
, "");
1610 colInf
[noCols
].sqlDataType
= 0;
1612 // Loop through each table name
1614 for (tbl
= 0; tableName
[tbl
]; tbl
++)
1616 TableName
= tableName
[tbl
];
1617 // Oracle table names are uppercase only, so force
1618 // the name to uppercase just in case programmer forgot to do this
1619 if (Dbms() == dbmsORACLE
)
1620 TableName
= TableName
.Upper();
1622 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1624 // MySQL and Access cannot accept a user name when looking up column names, so we
1625 // use the call below that leaves out the user name
1626 if (wxStrcmp(UserID
.GetData(),"") &&
1627 Dbms() != dbmsMY_SQL
&&
1628 Dbms() != dbmsACCESS
)
1630 retcode
= SQLColumns(hstmt
,
1631 NULL
, 0, // All qualifiers
1632 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // Owner
1633 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1634 NULL
, 0); // All columns
1638 retcode
= SQLColumns(hstmt
,
1639 NULL
, 0, // All qualifiers
1641 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1642 NULL
, 0); // All columns
1644 if (retcode
!= SQL_SUCCESS
)
1645 { // Error occured, abort
1646 DispAllErrors(henv
, hdbc
, hstmt
);
1649 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1653 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
1655 if (pass
== 1) // First pass, just add up the number of columns
1657 else // Pass 2; Fill in the array of structures
1659 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
1661 // NOTE: Only the ODBC 1.x fields are retrieved
1662 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
1663 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
1664 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1665 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1666 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
1667 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
1668 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
1669 GetData( 8, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
1670 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
1671 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
1672 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
1673 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
1675 // Determine the wxDB data type that is used to represent the native data type of this data source
1676 colInf
[colNo
].dbDataType
= 0;
1677 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
1678 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
1679 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
1680 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
1681 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
1682 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
1683 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
1684 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
1690 if (retcode
!= SQL_NO_DATA_FOUND
)
1691 { // Error occured, abort
1692 DispAllErrors(henv
, hdbc
, hstmt
);
1695 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1701 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1704 } // wxDB::GetColumns()
1707 /********** wxDB::GetColumns() **********/
1708 wxColInf
*wxDB::GetColumns(char *tableName
, int *numCols
, const char *userID
)
1710 * Same as the above GetColumns() function except this one gets columns
1711 * only for a single table, and if 'numCols' is not NULL, the number of
1712 * columns stored in the returned wxColInf is set in '*numCols'
1714 * userID is evaluated in the following manner:
1715 * userID == NULL ... UserID is ignored
1716 * userID == "" ... UserID set equal to 'this->uid'
1717 * userID != "" ... UserID set equal to 'userID'
1719 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1720 * by this function. This function should use its own wxDB instance
1721 * to avoid undesired unbinding of columns.
1726 wxColInf
*colInf
= 0;
1736 if (!wxStrlen(userID
))
1744 // dBase does not use user names, and some drivers fail if you try to pass one
1745 if (Dbms() == dbmsDBASE
)
1748 // Oracle user names may only be in uppercase, so force
1749 // the name to uppercase
1750 if (Dbms() == dbmsORACLE
)
1751 UserID
= UserID
.Upper();
1753 // Pass 1 - Determine how many columns there are.
1754 // Pass 2 - Allocate the wxColInf array and fill in
1755 // the array with the column information.
1757 for (pass
= 1; pass
<= 2; pass
++)
1761 if (noCols
== 0) // Probably a bogus table name(s)
1763 // Allocate n wxColInf objects to hold the column information
1764 colInf
= new wxColInf
[noCols
+1];
1767 // Mark the end of the array
1768 wxStrcpy(colInf
[noCols
].tableName
, "");
1769 wxStrcpy(colInf
[noCols
].colName
, "");
1770 colInf
[noCols
].sqlDataType
= 0;
1773 TableName
= tableName
;
1774 // Oracle table names are uppercase only, so force
1775 // the name to uppercase just in case programmer forgot to do this
1776 if (Dbms() == dbmsORACLE
)
1777 TableName
= TableName
.Upper();
1779 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1781 // MySQL and Access cannot accept a user name when looking up column names, so we
1782 // use the call below that leaves out the user name
1783 if (wxStrcmp(UserID
.GetData(),"") &&
1784 Dbms() != dbmsMY_SQL
&&
1785 Dbms() != dbmsACCESS
)
1787 retcode
= SQLColumns(hstmt
,
1788 NULL
, 0, // All qualifiers
1789 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // Owner
1790 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1791 NULL
, 0); // All columns
1795 retcode
= SQLColumns(hstmt
,
1796 NULL
, 0, // All qualifiers
1798 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1799 NULL
, 0); // All columns
1801 if (retcode
!= SQL_SUCCESS
)
1802 { // Error occured, abort
1803 DispAllErrors(henv
, hdbc
, hstmt
);
1806 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1812 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
1814 if (pass
== 1) // First pass, just add up the number of columns
1816 else // Pass 2; Fill in the array of structures
1818 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
1820 // NOTE: Only the ODBC 1.x fields are retrieved
1821 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
1822 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
1823 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1824 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1825 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
1826 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
1827 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
1828 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
1829 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
1830 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
1831 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
1832 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
1833 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
1834 // Start Values for Primary/Foriegn Key (=No)
1835 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
1836 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
1837 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
1838 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
1840 // Determine the wxDB data type that is used to represent the native data type of this data source
1841 colInf
[colNo
].dbDataType
= 0;
1842 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
1843 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
1844 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
1845 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
1846 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
1847 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
1848 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
1849 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
1855 if (retcode
!= SQL_NO_DATA_FOUND
)
1856 { // Error occured, abort
1857 DispAllErrors(henv
, hdbc
, hstmt
);
1860 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1867 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1869 // Store Primary and Foriegn Keys
1870 GetKeyFields(tableName
,colInf
,noCols
);
1876 } // wxDB::GetColumns()
1879 /********** wxDB::GetColumnCount() **********/
1880 int wxDB::GetColumnCount(char *tableName
, const char *userID
)
1882 * Returns a count of how many columns are in a table.
1883 * If an error occurs in computing the number of columns
1884 * this function will return a -1 for the count
1886 * userID is evaluated in the following manner:
1887 * userID == NULL ... UserID is ignored
1888 * userID == "" ... UserID set equal to 'this->uid'
1889 * userID != "" ... UserID set equal to 'userID'
1891 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1892 * by this function. This function should use its own wxDB instance
1893 * to avoid undesired unbinding of columns.
1905 if (!wxStrlen(userID
))
1913 // dBase does not use user names, and some drivers fail if you try to pass one
1914 if (Dbms() == dbmsDBASE
)
1917 // Oracle user names may only be in uppercase, so force
1918 // the name to uppercase
1919 if (Dbms() == dbmsORACLE
)
1920 UserID
= UserID
.Upper();
1923 // Loop through each table name
1925 TableName
= tableName
;
1926 // Oracle table names are uppercase only, so force
1927 // the name to uppercase just in case programmer forgot to do this
1928 if (Dbms() == dbmsORACLE
)
1929 TableName
= TableName
.Upper();
1931 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1933 // MySQL and Access cannot accept a user name when looking up column names, so we
1934 // use the call below that leaves out the user name
1935 if (wxStrcmp(UserID
.GetData(),"") &&
1936 Dbms() != dbmsMY_SQL
&&
1937 Dbms() != dbmsACCESS
)
1939 retcode
= SQLColumns(hstmt
,
1940 NULL
, 0, // All qualifiers
1941 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // Owner
1942 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1943 NULL
, 0); // All columns
1947 retcode
= SQLColumns(hstmt
,
1948 NULL
, 0, // All qualifiers
1950 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1951 NULL
, 0); // All columns
1953 if (retcode
!= SQL_SUCCESS
)
1954 { // Error occured, abort
1955 DispAllErrors(henv
, hdbc
, hstmt
);
1956 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1960 // Count the columns
1961 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
1964 if (retcode
!= SQL_NO_DATA_FOUND
)
1965 { // Error occured, abort
1966 DispAllErrors(henv
, hdbc
, hstmt
);
1967 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1973 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1976 } // wxDB::GetColumnCount()
1979 /********** wxDB::GetCatalog() *******/
1980 wxDbInf
*wxDB::GetCatalog(char *userID
)
1982 * ---------------------------------------------------------------------
1983 * -- 19991203 : mj10777@gmx.net : Create ------
1984 * -- : Creates a wxDbInf with Tables / Cols Array ------
1985 * -- : uses SQLTables and fills pTableInf; ------
1986 * -- : pColInf is set to NULL and numCols to 0; ------
1987 * -- : returns pDbInf (wxDbInf) ------
1988 * -- - if unsuccesfull (pDbInf == NULL) ------
1989 * -- : pColInf can be filled with GetColumns(..); ------
1990 * -- : numCols can be filled with GetColumnCount(..); ------
1991 * ---------------------------------------------------------------------
1993 * userID is evaluated in the following manner:
1994 * userID == NULL ... UserID is ignored
1995 * userID == "" ... UserID set equal to 'this->uid'
1996 * userID != "" ... UserID set equal to 'userID'
1998 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1999 * by this function. This function should use its own wxDB instance
2000 * to avoid undesired unbinding of columns.
2003 wxDbInf
*pDbInf
= NULL
; // Array of catalog entries
2004 int noTab
= 0; // Counter while filling table entries
2008 // char tblNameSave[DB_MAX_TABLE_NAME_LEN+1];
2009 wxString tblNameSave
;
2015 if (!wxStrlen(userID
))
2023 // dBase does not use user names, and some drivers fail if you try to pass one
2024 if (Dbms() == dbmsDBASE
)
2027 // Oracle user names may only be in uppercase, so force
2028 // the name to uppercase
2029 if (Dbms() == dbmsORACLE
)
2030 UserID
= UserID
.Upper();
2032 //-------------------------------------------------------------
2033 pDbInf
= new wxDbInf
; // Create the Database Arrray
2034 pDbInf
->catalog
[0] = 0;
2035 pDbInf
->schema
[0] = 0;
2036 pDbInf
->numTables
= 0; // Counter for Tables
2037 pDbInf
->pTableInf
= NULL
; // Array of Tables
2038 //-------------------------------------------------------------
2039 // Table Information
2040 // Pass 1 - Determine how many Tables there are.
2041 // Pass 2 - Create the Table array and fill it
2042 // - Create the Cols array = NULL
2043 //-------------------------------------------------------------
2044 for (pass
= 1; pass
<= 2; pass
++)
2046 SQLFreeStmt(hstmt
, SQL_CLOSE
); // Close if Open
2049 if (wxStrcmp(UserID
.GetData(),"") &&
2050 Dbms() != dbmsMY_SQL
&&
2051 Dbms() != dbmsACCESS
)
2053 retcode
= SQLTables(hstmt
,
2054 NULL
, 0, // All qualifiers
2055 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // User specified
2056 NULL
, 0, // All tables
2057 NULL
, 0); // All columns
2061 retcode
= SQLTables(hstmt
,
2062 NULL
, 0, // All qualifiers
2063 NULL
, 0, // User specified
2064 NULL
, 0, // All tables
2065 NULL
, 0); // All columns
2067 if (retcode
!= SQL_SUCCESS
)
2069 DispAllErrors(henv
, hdbc
, hstmt
);
2071 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2075 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
) // Table Information
2077 if (pass
== 1) // First pass, just count the Tables
2079 if (pDbInf
->numTables
== 0)
2081 GetData( 1, SQL_C_CHAR
, (UCHAR
*) pDbInf
->catalog
, 128+1, &cb
);
2082 GetData( 2, SQL_C_CHAR
, (UCHAR
*) pDbInf
->schema
, 128+1, &cb
);
2084 pDbInf
->numTables
++; // Counter for Tables
2086 if (pass
== 2) // Create and fill the Table entries
2088 if (pDbInf
->pTableInf
== NULL
) // Has the Table Array been created
2089 { // no, then create the Array
2090 pDbInf
->pTableInf
= new wxTableInf
[pDbInf
->numTables
];
2091 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
2093 (pDbInf
->pTableInf
+noTab
)->tableName
[0] = 0;
2094 (pDbInf
->pTableInf
+noTab
)->tableType
[0] = 0;
2095 (pDbInf
->pTableInf
+noTab
)->tableRemarks
[0] = 0;
2096 (pDbInf
->pTableInf
+noTab
)->numCols
= 0;
2097 (pDbInf
->pTableInf
+noTab
)->pColInf
= NULL
;
2100 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
2101 GetData( 3, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2102 GetData( 4, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableType
, 30+1, &cb
);
2103 GetData( 5, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableRemarks
, 254+1, &cb
);
2105 } // if (pass == 2) We now know the amount of Tables
2106 } // while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2107 } // for (pass = 1; pass <= 2; pass++)
2108 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2110 // Query how many columns are in each table
2111 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
2113 (pDbInf
->pTableInf
+noTab
)->numCols
= GetColumnCount((pDbInf
->pTableInf
+noTab
)->tableName
,UserID
);
2116 } // wxDB::GetCatalog()
2119 /********** wxDB::Catalog() **********/
2120 bool wxDB::Catalog(const char *userID
, const char *fileName
)
2122 * Creates the text file specified in 'filename' which will contain
2123 * a minimal data dictionary of all tables accessible by the user specified
2126 * userID is evaluated in the following manner:
2127 * userID == NULL ... UserID is ignored
2128 * userID == "" ... UserID set equal to 'this->uid'
2129 * userID != "" ... UserID set equal to 'userID'
2131 * NOTE: ALL column bindings associated with this wxDB instance are unbound
2132 * by this function. This function should use its own wxDB instance
2133 * to avoid undesired unbinding of columns.
2136 assert(fileName
&& wxStrlen(fileName
));
2140 char tblName
[DB_MAX_TABLE_NAME_LEN
+1];
2141 wxString tblNameSave
;
2142 char colName
[DB_MAX_COLUMN_NAME_LEN
+1];
2144 char typeName
[30+1];
2145 SWORD precision
, length
;
2149 FILE *fp
= fopen(fileName
,"wt");
2153 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2157 if (!wxStrlen(userID
))
2165 // dBase does not use user names, and some drivers fail if you try to pass one
2166 if (Dbms() == dbmsDBASE
)
2169 // Oracle user names may only be in uppercase, so force
2170 // the name to uppercase
2171 if (Dbms() == dbmsORACLE
)
2172 UserID
= UserID
.Upper();
2174 if (wxStrcmp(UserID
.GetData(),"") &&
2175 Dbms() != dbmsMY_SQL
&&
2176 Dbms() != dbmsACCESS
)
2178 retcode
= SQLColumns(hstmt
,
2179 NULL
, 0, // All qualifiers
2180 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // User specified
2181 NULL
, 0, // All tables
2182 NULL
, 0); // All columns
2186 retcode
= SQLColumns(hstmt
,
2187 NULL
, 0, // All qualifiers
2188 NULL
, 0, // User specified
2189 NULL
, 0, // All tables
2190 NULL
, 0); // All columns
2192 if (retcode
!= SQL_SUCCESS
)
2194 DispAllErrors(henv
, hdbc
, hstmt
);
2203 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2205 if (wxStrcmp(tblName
,tblNameSave
.GetData()))
2209 fputs("================================ ", fp
);
2210 fputs("================================ ", fp
);
2211 fputs("===================== ", fp
);
2212 fputs("========= ", fp
);
2213 fputs("=========\n", fp
);
2214 outStr
.sprintf("%-32s %-32s %-21s %9s %9s\n",
2215 "TABLE NAME", "COLUMN NAME", "DATA TYPE", "PRECISION", "LENGTH");
2216 fputs(outStr
.GetData(), fp
);
2217 fputs("================================ ", fp
);
2218 fputs("================================ ", fp
);
2219 fputs("===================== ", fp
);
2220 fputs("========= ", fp
);
2221 fputs("=========\n", fp
);
2222 tblNameSave
= tblName
;
2225 GetData(3,SQL_C_CHAR
, (UCHAR
*)tblName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2226 GetData(4,SQL_C_CHAR
, (UCHAR
*)colName
, DB_MAX_COLUMN_NAME_LEN
+1,&cb
);
2227 GetData(5,SQL_C_SSHORT
,(UCHAR
*)&sqlDataType
,0, &cb
);
2228 GetData(6,SQL_C_CHAR
, (UCHAR
*)typeName
, sizeof(typeName
), &cb
);
2229 GetData(7,SQL_C_SSHORT
,(UCHAR
*)&precision
, 0, &cb
);
2230 GetData(8,SQL_C_SSHORT
,(UCHAR
*)&length
, 0, &cb
);
2232 outStr
.sprintf("%-32s %-32s (%04d)%-15s %9d %9d\n",
2233 tblName
, colName
, sqlDataType
, typeName
, precision
, length
);
2234 if (fputs(outStr
.GetData(), fp
) == EOF
)
2236 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2243 if (retcode
!= SQL_NO_DATA_FOUND
)
2244 DispAllErrors(henv
, hdbc
, hstmt
);
2246 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2249 return(retcode
== SQL_NO_DATA_FOUND
);
2251 } // wxDB::Catalog()
2254 bool wxDB::TableExists(const char *tableName
, const char *userID
, const char *tablePath
)
2256 * Table name can refer to a table, view, alias or synonym. Returns true
2257 * if the object exists in the database. This function does not indicate
2258 * whether or not the user has privleges to query or perform other functions
2261 * userID is evaluated in the following manner:
2262 * userID == NULL ... UserID is ignored
2263 * userID == "" ... UserID set equal to 'this->uid'
2264 * userID != "" ... UserID set equal to 'userID'
2270 assert(tableName
&& wxStrlen(tableName
));
2272 if (Dbms() == dbmsDBASE
)
2275 if (tablePath
&& wxStrlen(tablePath
))
2276 dbName
.sprintf("%s/%s.dbf",tablePath
,tableName
);
2278 dbName
.sprintf("%s.dbf",tableName
);
2281 exists
= wxFileExists(dbName
.GetData());
2287 if (!wxStrlen(userID
))
2295 // Oracle user names may only be in uppercase, so force
2296 // the name to uppercase
2297 if (Dbms() == dbmsORACLE
)
2298 UserID
= UserID
.Upper();
2300 TableName
= tableName
;
2301 // Oracle table names are uppercase only, so force
2302 // the name to uppercase just in case programmer forgot to do this
2303 if (Dbms() == dbmsORACLE
)
2304 TableName
= TableName
.Upper();
2306 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2309 // MySQL and Access cannot accept a user name when looking up table names, so we
2310 // use the call below that leaves out the user name
2311 if (wxStrcmp(UserID
,"") &&
2312 Dbms() != dbmsMY_SQL
&&
2313 Dbms() != dbmsACCESS
)
2315 retcode
= SQLTables(hstmt
,
2316 NULL
, 0, // All qualifiers
2317 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // All owners
2318 (UCHAR FAR
*)TableName
.GetData(), SQL_NTS
,
2319 NULL
, 0); // All table types
2323 retcode
= SQLTables(hstmt
,
2324 NULL
, 0, // All qualifiers
2325 NULL
, 0, // All owners
2326 (UCHAR FAR
*)TableName
.GetData(), SQL_NTS
,
2327 NULL
, 0); // All table types
2329 if (retcode
!= SQL_SUCCESS
)
2330 return(DispAllErrors(henv
, hdbc
, hstmt
));
2332 retcode
= SQLFetch(hstmt
);
2333 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
2335 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2336 return(DispAllErrors(henv
, hdbc
, hstmt
));
2339 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2342 } // wxDB::TableExists()
2345 /********** wxDB::SqlLog() **********/
2346 bool wxDB::SqlLog(enum sqlLog state
, const char *filename
, bool append
)
2348 assert(state
== sqlLogON
|| state
== sqlLogOFF
);
2349 assert(state
== sqlLogOFF
|| filename
);
2351 if (state
== sqlLogON
)
2355 fpSqlLog
= fopen(filename
, (append
? "at" : "wt"));
2356 if (fpSqlLog
== NULL
)
2364 if (fclose(fpSqlLog
))
2370 sqlLogState
= state
;
2376 /********** wxDB::WriteSqlLog() **********/
2377 bool wxDB::WriteSqlLog(const char *logMsg
)
2381 if (fpSqlLog
== 0 || sqlLogState
== sqlLogOFF
)
2384 if (fputs("\n", fpSqlLog
) == EOF
) return(FALSE
);
2385 if (fputs(logMsg
, fpSqlLog
) == EOF
) return(FALSE
);
2386 if (fputs("\n", fpSqlLog
) == EOF
) return(FALSE
);
2390 } // wxDB::WriteSqlLog()
2393 /********** wxDB::Dbms() **********/
2394 DBMS
wxDB::Dbms(void)
2396 * Be aware that not all database engines use the exact same syntax, and not
2397 * every ODBC compliant database is compliant to the same level of compliancy.
2398 * Some manufacturers support the minimum Level 1 compliancy, and others up
2399 * through Level 3. Others support subsets of features for levels above 1.
2401 * If you find an inconsistency between the wxDB class and a specific database
2402 * engine, and an identifier to this section, and special handle the database in
2403 * the area where behavior is non-conforming with the other databases.
2406 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
2407 * ---------------------------------------------------
2410 * - Currently the only database supported by the class to support VIEWS
2413 * - Does not support the SQL_TIMESTAMP structure
2414 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
2415 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
2416 * is TRUE. The user must create ALL indexes from their program.
2417 * - Table names can only be 8 characters long
2418 * - Column names can only be 10 characters long
2421 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
2422 * after every table name involved in the query/join if that tables matching record(s)
2424 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
2426 * SYBASE (Enterprise)
2427 * - If a column is part of the Primary Key, the column cannot be NULL
2430 * - If a column is part of the Primary Key, the column cannot be NULL
2431 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
2434 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
2439 wxChar baseName
[25+1];
2441 wxStrncpy(baseName
,dbInf
.dbmsName
,25);
2442 if (!wxStricmp(dbInf
.dbmsName
,"Adaptive Server Anywhere"))
2443 return(dbmsSYBASE_ASA
);
2444 if (!wxStricmp(dbInf
.dbmsName
,"SQL Server")) // Sybase Adaptive Server
2445 return(dbmsSYBASE_ASE
);
2446 if (!wxStricmp(dbInf
.dbmsName
,"Microsoft SQL Server"))
2447 return(dbmsMS_SQL_SERVER
);
2448 if (!wxStricmp(dbInf
.dbmsName
,"MySQL"))
2450 if (!wxStricmp(dbInf
.dbmsName
,"PostgreSQL")) // v6.5.0
2451 return(dbmsPOSTGRES
);
2454 if (!wxStricmp(baseName
,"Informix"))
2455 return(dbmsINFORMIX
);
2458 if (!wxStricmp(baseName
,"Oracle"))
2460 if (!wxStricmp(dbInf
.dbmsName
,"ACCESS"))
2462 if (!wxStricmp(dbInf
.dbmsName
,"MySQL"))
2466 if (!wxStricmp(baseName
,"DBASE"))
2469 return(dbmsUNIDENTIFIED
);
2473 /********** GetDbConnection() **********/
2474 wxDB WXDLLEXPORT
*GetDbConnection(DbStuff
*pDbStuff
, bool FwdOnlyCursors
)
2478 // Scan the linked list searching for an available database connection
2479 // that's already been opened but is currently not in use.
2480 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2482 // The database connection must be for the same datasource
2483 // name and must currently not be in use.
2484 if (pList
->Free
&& (! wxStrcmp(pDbStuff
->Dsn
, pList
->Dsn
))) // Found a free connection
2486 pList
->Free
= FALSE
;
2487 return(pList
->PtrDb
);
2491 // No available connections. A new connection must be made and
2492 // appended to the end of the linked list.
2495 // Find the end of the list
2496 for (pList
= PtrBegDbList
; pList
->PtrNext
; pList
= pList
->PtrNext
);
2497 // Append a new list item
2498 pList
->PtrNext
= new DbList
;
2499 pList
->PtrNext
->PtrPrev
= pList
;
2500 pList
= pList
->PtrNext
;
2504 // Create the first node on the list
2505 pList
= PtrBegDbList
= new DbList
;
2509 // Initialize new node in the linked list
2511 pList
->Free
= FALSE
;
2512 wxStrcpy(pList
->Dsn
, pDbStuff
->Dsn
);
2513 pList
->PtrDb
= new wxDB(pDbStuff
->Henv
,FwdOnlyCursors
);
2515 // Connect to the datasource
2516 if (pList
->PtrDb
->Open(pDbStuff
->Dsn
, pDbStuff
->Uid
, pDbStuff
->AuthStr
))
2518 pList
->PtrDb
->SqlLog(SQLLOGstate
,SQLLOGfn
,TRUE
);
2519 return(pList
->PtrDb
);
2521 else // Unable to connect, destroy list item
2524 pList
->PtrPrev
->PtrNext
= 0;
2526 PtrBegDbList
= 0; // Empty list again
2527 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDB object
2528 pList
->PtrDb
->Close(); // Close the wxDB object
2529 delete pList
->PtrDb
; // Deletes the wxDB object
2530 delete pList
; // Deletes the linked list object
2534 } // GetDbConnection()
2537 /********** FreeDbConnection() **********/
2538 bool WXDLLEXPORT
FreeDbConnection(wxDB
*pDb
)
2542 // Scan the linked list searching for the database connection
2543 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2545 if (pList
->PtrDb
== pDb
) // Found it!!!
2546 return(pList
->Free
= TRUE
);
2549 // Never found the database object, return failure
2552 } // FreeDbConnection()
2555 /********** CloseDbConnections() **********/
2556 void WXDLLEXPORT
CloseDbConnections(void)
2558 DbList
*pList
, *pNext
;
2560 // Traverse the linked list closing database connections and freeing memory as I go.
2561 for (pList
= PtrBegDbList
; pList
; pList
= pNext
)
2563 pNext
= pList
->PtrNext
; // Save the pointer to next
2564 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDB object
2565 pList
->PtrDb
->Close(); // Close the wxDB object
2566 delete pList
->PtrDb
; // Deletes the wxDB object
2567 delete pList
; // Deletes the linked list object
2570 // Mark the list as empty
2573 } // CloseDbConnections()
2576 /********** NumberDbConnectionsInUse() **********/
2577 int WXDLLEXPORT
NumberDbConnectionsInUse(void)
2582 // Scan the linked list counting db connections that are currently in use
2583 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2585 if (pList
->Free
== FALSE
)
2591 } // NumberDbConnectionsInUse()
2594 /********** SqlLog() **********/
2595 bool SqlLog(enum sqlLog state
, char *filename
)
2597 bool append
= FALSE
;
2600 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2602 if (!pList
->PtrDb
->SqlLog(state
,filename
,append
))
2607 SQLLOGstate
= state
;
2608 wxStrcpy(SQLLOGfn
,filename
);
2615 /********** GetDataSource() **********/
2616 bool GetDataSource(HENV henv
, char *Dsn
, SWORD DsnMax
, char *DsDesc
, SWORD DsDescMax
,
2619 * Dsn and DsDesc will contain the data source name and data source
2620 * description upon return
2625 if (SQLDataSources(henv
, direction
, (UCHAR FAR
*) Dsn
, DsnMax
, &cb1
,
2626 (UCHAR FAR
*) DsDesc
, DsDescMax
, &cb2
) == SQL_SUCCESS
)
2631 } // GetDataSource()