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;
96 char const *SQL_LOG_FILENAME
= "sqllog.txt";
97 char const *SQL_CATALOG_FILENAME
= "catalog.txt";
100 extern wxList TablesInUse
;
103 // SQL Log defaults to be used by GetDbConnection
104 enum sqlLog SQLLOGstate
= sqlLogOFF
;
106 //char SQLLOGfn[DB_PATH_MAX+1] = SQL_LOG_FILENAME;
107 char *SQLLOGfn
= (char*) SQL_LOG_FILENAME
;
109 // The wxDB::errorList is copied to this variable when the wxDB object
110 // is closed. This way, the error list is still available after the
111 // database object is closed. This is necessary if the database
112 // connection fails so the calling application can show the operator
113 // why the connection failed. Note: as each wxDB object is closed, it
114 // will overwrite the errors of the previously destroyed wxDB object in
116 char DBerrorList
[DB_MAX_ERROR_HISTORY
][DB_MAX_ERROR_MSG_LEN
];
119 /********** wxColFor Constructor **********/
122 i_Nation
= 0; // 0=EU, 1=UK, 2=International, 3=US
131 Format(1,DB_DATA_TYPE_VARCHAR
,0,0,0); // the Function that does the work
132 } // wxColFor::wxColFor()
135 wxColFor::~wxColFor()
137 } // wxColFor::~wxColFor()
140 int wxColFor::Format(int Nation
,int dbDataType
,SWORD sqlDataType
,short columnSize
,short decimalDigits
)
142 // ----------------------------------------------------------------------------------------
143 // -- 19991224 : mj10777@gmx.net : Create
144 // There is still a lot of work to do here, but it is a start
145 // It handles all the basic data-types that I have run into up to now
146 // The main work will have be with Dates and float Formatting (US 1,000.00 ; EU 1.000,00)
147 // There are wxWindow plans for locale support and the new wxDateTime.
148 // - if they define some constants (wxEUROPEAN) that can be gloably used,
149 // they should be used here.
150 // ----------------------------------------------------------------------------------------
151 // There should also be a Function to scan in a string to fill the variable
152 // ----------------------------------------------------------------------------------------
154 i_Nation
= Nation
; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
155 i_dbDataType
= dbDataType
;
156 i_sqlDataType
= sqlDataType
;
157 s_Field
.Printf("%s%d",s_Menge
[1].c_str(),i_Menge
[1]); // OK for VARCHAR, INTEGER and FLOAT
158 if (i_dbDataType
== 0) // Filter unsupported dbDataTypes
160 if ((i_sqlDataType
== SQL_VARCHAR
) || (i_sqlDataType
== SQL_LONGVARCHAR
))
161 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
162 if (i_sqlDataType
== SQL_C_DATE
)
163 i_dbDataType
= DB_DATA_TYPE_DATE
;
164 if (i_sqlDataType
== SQL_C_BIT
)
165 i_dbDataType
= DB_DATA_TYPE_INTEGER
;
166 if (i_sqlDataType
== SQL_NUMERIC
)
167 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
168 if (i_sqlDataType
== SQL_REAL
)
169 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
171 if ((i_dbDataType
== DB_DATA_TYPE_INTEGER
) && (i_sqlDataType
== SQL_C_DOUBLE
))
173 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
175 switch(i_dbDataType
) // -A-> Still a lot of proper formatting to do
177 case DB_DATA_TYPE_VARCHAR
:
180 case DB_DATA_TYPE_INTEGER
:
183 case DB_DATA_TYPE_FLOAT
:
184 if (decimalDigits
== 0)
187 Temp0
.Printf("%s%d.%d",Temp0
.c_str(),columnSize
,decimalDigits
);
188 s_Field
.Printf("%sf",Temp0
.c_str()); //
190 case DB_DATA_TYPE_DATE
:
191 if (i_Nation
== 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
193 s_Field
= "%04d-%02d-%02d %02d:%02d:%02d.%03d";
195 if (i_Nation
== 1) // European DD.MM.YYYY HH:MM:SS.SSS
197 s_Field
= "%02d.%02d.%04d %02d:%02d:%02d.%03d";
199 if (i_Nation
== 2) // UK DD/MM/YYYY HH:MM:SS.SSS
201 s_Field
= "%02d/%02d/%04d %02d:%02d:%02d.%03d";
203 if (i_Nation
== 3) // International YYYY-MM-DD HH:MM:SS.SSS
205 s_Field
= "%04d-%02d-%02d %02d:%02d:%02d.%03d";
207 if (i_Nation
== 4) // US MM/DD/YYYY HH:MM:SS.SSS
209 s_Field
= "%02d/%02d/%04d %02d:%02d:%02d.%03d";
213 s_Field
.Printf("-E-> unknown Format(%d)-sql(%d)",dbDataType
,sqlDataType
); //
217 } // wxColFor::Format()
220 /********** wxDB Constructor **********/
221 wxDB::wxDB(HENV
&aHenv
, bool FwdOnlyCursors
)
225 fpSqlLog
= 0; // Sql Log file pointer
226 sqlLogState
= sqlLogOFF
; // By default, logging is turned off
229 wxStrcpy(sqlState
,"");
230 wxStrcpy(errorMsg
,"");
231 nativeError
= cbErrorMsg
= 0;
232 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
233 wxStrcpy(errorList
[i
], "");
235 // Init typeInf structures
236 wxStrcpy(typeInfVarchar
.TypeName
,"");
237 typeInfVarchar
.FsqlType
= 0;
238 typeInfVarchar
.Precision
= 0;
239 typeInfVarchar
.CaseSensitive
= 0;
240 typeInfVarchar
.MaximumScale
= 0;
242 wxStrcpy(typeInfInteger
.TypeName
,"");
243 typeInfInteger
.FsqlType
= 0;
244 typeInfInteger
.Precision
= 0;
245 typeInfInteger
.CaseSensitive
= 0;
246 typeInfInteger
.MaximumScale
= 0;
248 wxStrcpy(typeInfFloat
.TypeName
,"");
249 typeInfFloat
.FsqlType
= 0;
250 typeInfFloat
.Precision
= 0;
251 typeInfFloat
.CaseSensitive
= 0;
252 typeInfFloat
.MaximumScale
= 0;
254 wxStrcpy(typeInfDate
.TypeName
,"");
255 typeInfDate
.FsqlType
= 0;
256 typeInfDate
.Precision
= 0;
257 typeInfDate
.CaseSensitive
= 0;
258 typeInfDate
.MaximumScale
= 0;
260 // Error reporting is turned OFF by default
263 // Copy the HENV into the db class
265 fwdOnlyCursors
= FwdOnlyCursors
;
267 // Allocate a data source connection handle
268 if (SQLAllocConnect(henv
, &hdbc
) != SQL_SUCCESS
)
271 // Initialize the db status flag
274 // Mark database as not open as of yet
280 /********** wxDB::Open() **********/
281 bool wxDB::Open(char *Dsn
, char *Uid
, char *AuthStr
)
283 assert(Dsn
&& wxStrlen(Dsn
));
290 if (!FwdOnlyCursors())
292 // Specify that the ODBC cursor library be used, if needed. This must be
293 // specified before the connection is made.
294 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
296 #ifdef DBDEBUG_CONSOLE
297 if (retcode
== SQL_SUCCESS
)
298 cout
<< "SQLSetConnectOption(CURSOR_LIB) successful" << endl
;
300 cout
<< "SQLSetConnectOption(CURSOR_LIB) failed" << endl
;
304 // Connect to the data source
305 retcode
= SQLConnect(hdbc
, (UCHAR FAR
*) Dsn
, SQL_NTS
,
306 (UCHAR FAR
*) Uid
, SQL_NTS
,
307 (UCHAR FAR
*) AuthStr
,SQL_NTS
);
308 if (retcode
== SQL_SUCCESS_WITH_INFO
)
309 DispAllErrors(henv
, hdbc
);
310 else if (retcode
!= SQL_SUCCESS
)
311 return(DispAllErrors(henv
, hdbc
));
314 If using Intersolv branded ODBC drivers, this is the place where you would substitute
315 your branded driver license information
317 SQLSetConnectOption(hdbc, 1041, (UDWORD) "");
318 SQLSetConnectOption(hdbc, 1042, (UDWORD) "");
321 // Mark database as open
324 // Allocate a statement handle for the database connection
325 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
326 return(DispAllErrors(henv
, hdbc
));
328 // Set Connection Options
329 if (! setConnectionOptions())
332 // Query the data source for inf. about itself
336 // Query the data source regarding data type information
339 // The way I determined which SQL data types to use was by calling SQLGetInfo
340 // for all of the possible SQL data types to see which ones were supported. If
341 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
342 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
343 // types I've selected below will not alway's be what we want. These are just
344 // what happened to work against an Oracle 7/Intersolv combination. The following is
345 // a complete list of the results I got back against the Oracle 7 database:
347 // SQL_BIGINT SQL_NO_DATA_FOUND
348 // SQL_BINARY SQL_NO_DATA_FOUND
349 // SQL_BIT SQL_NO_DATA_FOUND
350 // SQL_CHAR type name = 'CHAR', Precision = 255
351 // SQL_DATE SQL_NO_DATA_FOUND
352 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
353 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
354 // SQL_FLOAT SQL_NO_DATA_FOUND
355 // SQL_INTEGER SQL_NO_DATA_FOUND
356 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
357 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
358 // SQL_NUMERIC SQL_NO_DATA_FOUND
359 // SQL_REAL SQL_NO_DATA_FOUND
360 // SQL_SMALLINT SQL_NO_DATA_FOUND
361 // SQL_TIME SQL_NO_DATA_FOUND
362 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
363 // SQL_VARBINARY type name = 'RAW', Precision = 255
364 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
365 // =====================================================================
366 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
368 // SQL_VARCHAR type name = 'TEXT', Precision = 255
369 // SQL_TIMESTAMP type name = 'DATETIME'
370 // SQL_DECIMAL SQL_NO_DATA_FOUND
371 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
372 // SQL_FLOAT SQL_NO_DATA_FOUND
373 // SQL_REAL type name = 'SINGLE', Precision = 7
374 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
375 // SQL_INTEGER type name = 'LONG', Precision = 10
377 // VARCHAR = Variable length character string
378 if (! getDataTypeInfo(SQL_VARCHAR
, typeInfVarchar
))
379 if (! getDataTypeInfo(SQL_CHAR
, typeInfVarchar
))
382 typeInfVarchar
.FsqlType
= SQL_CHAR
;
384 typeInfVarchar
.FsqlType
= SQL_VARCHAR
;
387 if (! getDataTypeInfo(SQL_DOUBLE
, typeInfFloat
))
388 if (! getDataTypeInfo(SQL_REAL
, typeInfFloat
))
389 if (! getDataTypeInfo(SQL_FLOAT
, typeInfFloat
))
390 if (! getDataTypeInfo(SQL_DECIMAL
, typeInfFloat
))
391 if (! getDataTypeInfo(SQL_NUMERIC
, typeInfFloat
))
394 typeInfFloat
.FsqlType
= SQL_NUMERIC
;
396 typeInfFloat
.FsqlType
= SQL_DECIMAL
;
398 typeInfFloat
.FsqlType
= SQL_FLOAT
;
400 typeInfFloat
.FsqlType
= SQL_REAL
;
402 typeInfFloat
.FsqlType
= SQL_DOUBLE
;
405 if (! getDataTypeInfo(SQL_INTEGER
, typeInfInteger
))
406 // If SQL_INTEGER is not supported, use the floating point
407 // data type to store integers as well as floats
408 if (! getDataTypeInfo(typeInfFloat
.FsqlType
, typeInfInteger
))
411 typeInfInteger
.FsqlType
= typeInfFloat
.FsqlType
;
413 typeInfInteger
.FsqlType
= SQL_INTEGER
;
416 if (Dbms() != dbmsDBASE
)
418 if (! getDataTypeInfo(SQL_TIMESTAMP
, typeInfDate
))
421 typeInfDate
.FsqlType
= SQL_TIMESTAMP
;
425 if (! getDataTypeInfo(SQL_DATE
, typeInfDate
))
428 typeInfDate
.FsqlType
= SQL_DATE
;
431 #ifdef DBDEBUG_CONSOLE
432 cout
<< "VARCHAR DATA TYPE: " << typeInfVarchar
.TypeName
<< endl
;
433 cout
<< "INTEGER DATA TYPE: " << typeInfInteger
.TypeName
<< endl
;
434 cout
<< "FLOAT DATA TYPE: " << typeInfFloat
.TypeName
<< endl
;
435 cout
<< "DATE DATA TYPE: " << typeInfDate
.TypeName
<< endl
;
439 // Completed Successfully
445 /********** wxDB::setConnectionOptions() **********/
446 bool wxDB::setConnectionOptions(void)
448 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
451 SQLSetConnectOption(hdbc
, SQL_AUTOCOMMIT
, SQL_AUTOCOMMIT_OFF
);
452 SQLSetConnectOption(hdbc
, SQL_OPT_TRACE
, SQL_OPT_TRACE_OFF
);
454 // Display the connection options to verify them
455 #ifdef DBDEBUG_CONSOLE
457 cout
<< "****** CONNECTION OPTIONS ******" << endl
;
459 if (SQLGetConnectOption(hdbc
, SQL_AUTOCOMMIT
, &l
) != SQL_SUCCESS
)
460 return(DispAllErrors(henv
, hdbc
));
461 cout
<< "AUTOCOMMIT: " << (l
== SQL_AUTOCOMMIT_OFF
? "OFF" : "ON") << endl
;
463 if (SQLGetConnectOption(hdbc
, SQL_ODBC_CURSORS
, &l
) != SQL_SUCCESS
)
464 return(DispAllErrors(henv
, hdbc
));
465 cout
<< "ODBC CURSORS: ";
468 case(SQL_CUR_USE_IF_NEEDED
):
469 cout
<< "SQL_CUR_USE_IF_NEEDED";
471 case(SQL_CUR_USE_ODBC
):
472 cout
<< "SQL_CUR_USE_ODBC";
474 case(SQL_CUR_USE_DRIVER
):
475 cout
<< "SQL_CUR_USE_DRIVER";
480 if (SQLGetConnectOption(hdbc
, SQL_OPT_TRACE
, &l
) != SQL_SUCCESS
)
481 return(DispAllErrors(henv
, hdbc
));
482 cout
<< "TRACING: " << (l
== SQL_OPT_TRACE_OFF
? "OFF" : "ON") << endl
;
487 // Completed Successfully
490 } // wxDB::setConnectionOptions()
493 /********** wxDB::getDbInfo() **********/
494 bool wxDB::getDbInfo(void)
499 if (SQLGetInfo(hdbc
, SQL_SERVER_NAME
, (UCHAR
*) dbInf
.serverName
, 80, &cb
) != SQL_SUCCESS
)
500 return(DispAllErrors(henv
, hdbc
));
502 if (SQLGetInfo(hdbc
, SQL_DATABASE_NAME
, (UCHAR
*) dbInf
.databaseName
, 128, &cb
) != SQL_SUCCESS
)
503 return(DispAllErrors(henv
, hdbc
));
505 if (SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, 40, &cb
) != SQL_SUCCESS
)
506 return(DispAllErrors(henv
, hdbc
));
509 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
510 // causing database connectivity to fail in some cases.
511 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_VER
, (UCHAR
*) dbInf
.dbmsVer
, 64, &cb
);
513 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
514 return(DispAllErrors(henv
, hdbc
));
516 if (SQLGetInfo(hdbc
, SQL_ACTIVE_CONNECTIONS
, (UCHAR
*) &dbInf
.maxConnections
, sizeof(dbInf
.maxConnections
), &cb
) != SQL_SUCCESS
)
517 return(DispAllErrors(henv
, hdbc
));
519 if (SQLGetInfo(hdbc
, SQL_ACTIVE_STATEMENTS
, (UCHAR
*) &dbInf
.maxStmts
, sizeof(dbInf
.maxStmts
), &cb
) != SQL_SUCCESS
)
520 return(DispAllErrors(henv
, hdbc
));
522 if (SQLGetInfo(hdbc
, SQL_DRIVER_NAME
, (UCHAR
*) dbInf
.driverName
, 40, &cb
) != SQL_SUCCESS
)
523 return(DispAllErrors(henv
, hdbc
));
525 if (SQLGetInfo(hdbc
, SQL_DRIVER_ODBC_VER
, (UCHAR
*) dbInf
.odbcVer
, 60, &cb
) == SQL_ERROR
)
526 return(DispAllErrors(henv
, hdbc
));
528 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_VER
, (UCHAR
*) dbInf
.drvMgrOdbcVer
, 60, &cb
);
529 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
530 return(DispAllErrors(henv
, hdbc
));
532 if (SQLGetInfo(hdbc
, SQL_DRIVER_VER
, (UCHAR
*) dbInf
.driverVer
, 60, &cb
) == SQL_ERROR
)
533 return(DispAllErrors(henv
, hdbc
));
535 if (SQLGetInfo(hdbc
, SQL_ODBC_API_CONFORMANCE
, (UCHAR
*) &dbInf
.apiConfLvl
, sizeof(dbInf
.apiConfLvl
), &cb
) != SQL_SUCCESS
)
536 return(DispAllErrors(henv
, hdbc
));
538 if (SQLGetInfo(hdbc
, SQL_ODBC_SAG_CLI_CONFORMANCE
, (UCHAR
*) &dbInf
.cliConfLvl
, sizeof(dbInf
.cliConfLvl
), &cb
) != SQL_SUCCESS
)
539 return(DispAllErrors(henv
, hdbc
));
541 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_CONFORMANCE
, (UCHAR
*) &dbInf
.sqlConfLvl
, sizeof(dbInf
.sqlConfLvl
), &cb
) != SQL_SUCCESS
)
542 return(DispAllErrors(henv
, hdbc
));
544 if (SQLGetInfo(hdbc
, SQL_OUTER_JOINS
, (UCHAR
*) dbInf
.outerJoins
, 2, &cb
) != SQL_SUCCESS
)
545 return(DispAllErrors(henv
, hdbc
));
547 if (SQLGetInfo(hdbc
, SQL_PROCEDURES
, (UCHAR
*) dbInf
.procedureSupport
, 2, &cb
) != SQL_SUCCESS
)
548 return(DispAllErrors(henv
, hdbc
));
550 if (SQLGetInfo(hdbc
, SQL_ACCESSIBLE_TABLES
, (UCHAR
*) dbInf
.accessibleTables
, 2, &cb
) != SQL_SUCCESS
)
551 return(DispAllErrors(henv
, hdbc
));
553 if (SQLGetInfo(hdbc
, SQL_CURSOR_COMMIT_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorCommitBehavior
, sizeof(dbInf
.cursorCommitBehavior
), &cb
) != SQL_SUCCESS
)
554 return(DispAllErrors(henv
, hdbc
));
556 if (SQLGetInfo(hdbc
, SQL_CURSOR_ROLLBACK_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorRollbackBehavior
, sizeof(dbInf
.cursorRollbackBehavior
), &cb
) != SQL_SUCCESS
)
557 return(DispAllErrors(henv
, hdbc
));
559 if (SQLGetInfo(hdbc
, SQL_NON_NULLABLE_COLUMNS
, (UCHAR
*) &dbInf
.supportNotNullClause
, sizeof(dbInf
.supportNotNullClause
), &cb
) != SQL_SUCCESS
)
560 return(DispAllErrors(henv
, hdbc
));
562 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_OPT_IEF
, (UCHAR
*) dbInf
.supportIEF
, 2, &cb
) != SQL_SUCCESS
)
563 return(DispAllErrors(henv
, hdbc
));
565 if (SQLGetInfo(hdbc
, SQL_DEFAULT_TXN_ISOLATION
, (UCHAR
*) &dbInf
.txnIsolation
, sizeof(dbInf
.txnIsolation
), &cb
) != SQL_SUCCESS
)
566 return(DispAllErrors(henv
, hdbc
));
568 if (SQLGetInfo(hdbc
, SQL_TXN_ISOLATION_OPTION
, (UCHAR
*) &dbInf
.txnIsolationOptions
, sizeof(dbInf
.txnIsolationOptions
), &cb
) != SQL_SUCCESS
)
569 return(DispAllErrors(henv
, hdbc
));
571 if (SQLGetInfo(hdbc
, SQL_FETCH_DIRECTION
, (UCHAR
*) &dbInf
.fetchDirections
, sizeof(dbInf
.fetchDirections
), &cb
) != SQL_SUCCESS
)
572 return(DispAllErrors(henv
, hdbc
));
574 if (SQLGetInfo(hdbc
, SQL_LOCK_TYPES
, (UCHAR
*) &dbInf
.lockTypes
, sizeof(dbInf
.lockTypes
), &cb
) != SQL_SUCCESS
)
575 return(DispAllErrors(henv
, hdbc
));
577 if (SQLGetInfo(hdbc
, SQL_POS_OPERATIONS
, (UCHAR
*) &dbInf
.posOperations
, sizeof(dbInf
.posOperations
), &cb
) != SQL_SUCCESS
)
578 return(DispAllErrors(henv
, hdbc
));
580 if (SQLGetInfo(hdbc
, SQL_POSITIONED_STATEMENTS
, (UCHAR
*) &dbInf
.posStmts
, sizeof(dbInf
.posStmts
), &cb
) != SQL_SUCCESS
)
581 return(DispAllErrors(henv
, hdbc
));
583 if (SQLGetInfo(hdbc
, SQL_SCROLL_CONCURRENCY
, (UCHAR
*) &dbInf
.scrollConcurrency
, sizeof(dbInf
.scrollConcurrency
), &cb
) != SQL_SUCCESS
)
584 return(DispAllErrors(henv
, hdbc
));
586 if (SQLGetInfo(hdbc
, SQL_SCROLL_OPTIONS
, (UCHAR
*) &dbInf
.scrollOptions
, sizeof(dbInf
.scrollOptions
), &cb
) != SQL_SUCCESS
)
587 return(DispAllErrors(henv
, hdbc
));
589 if (SQLGetInfo(hdbc
, SQL_STATIC_SENSITIVITY
, (UCHAR
*) &dbInf
.staticSensitivity
, sizeof(dbInf
.staticSensitivity
), &cb
) != SQL_SUCCESS
)
590 return(DispAllErrors(henv
, hdbc
));
592 if (SQLGetInfo(hdbc
, SQL_TXN_CAPABLE
, (UCHAR
*) &dbInf
.txnCapable
, sizeof(dbInf
.txnCapable
), &cb
) != SQL_SUCCESS
)
593 return(DispAllErrors(henv
, hdbc
));
595 if (SQLGetInfo(hdbc
, SQL_LOGIN_TIMEOUT
, (UCHAR
*) &dbInf
.loginTimeout
, sizeof(dbInf
.loginTimeout
), &cb
) != SQL_SUCCESS
)
596 return(DispAllErrors(henv
, hdbc
));
598 #ifdef DBDEBUG_CONSOLE
599 cout
<< "***** DATA SOURCE INFORMATION *****" << endl
;
600 cout
<< "SERVER Name: " << dbInf
.serverName
<< endl
;
601 cout
<< "DBMS Name: " << dbInf
.dbmsName
<< "; DBMS Version: " << dbInf
.dbmsVer
<< endl
;
602 cout
<< "ODBC Version: " << dbInf
.odbcVer
<< "; Driver Version: " << dbInf
.driverVer
<< endl
;
604 cout
<< "API Conf. Level: ";
605 switch(dbInf
.apiConfLvl
)
607 case SQL_OAC_NONE
: cout
<< "None"; break;
608 case SQL_OAC_LEVEL1
: cout
<< "Level 1"; break;
609 case SQL_OAC_LEVEL2
: cout
<< "Level 2"; break;
613 cout
<< "SAG CLI Conf. Level: ";
614 switch(dbInf
.cliConfLvl
)
616 case SQL_OSCC_NOT_COMPLIANT
: cout
<< "Not Compliant"; break;
617 case SQL_OSCC_COMPLIANT
: cout
<< "Compliant"; break;
621 cout
<< "SQL Conf. Level: ";
622 switch(dbInf
.sqlConfLvl
)
624 case SQL_OSC_MINIMUM
: cout
<< "Minimum Grammer"; break;
625 case SQL_OSC_CORE
: cout
<< "Core Grammer"; break;
626 case SQL_OSC_EXTENDED
: cout
<< "Extended Grammer"; break;
630 cout
<< "Max. Connections: " << dbInf
.maxConnections
<< endl
;
631 cout
<< "Outer Joins: " << dbInf
.outerJoins
<< endl
;
632 cout
<< "Support for Procedures: " << dbInf
.procedureSupport
<< endl
;
633 cout
<< "All tables accessible : " << dbInf
.accessibleTables
<< endl
;
635 cout
<< "Cursor COMMIT Behavior: ";
636 switch(dbInf
.cursorCommitBehavior
)
638 case SQL_CB_DELETE
: cout
<< "Delete cursors"; break;
639 case SQL_CB_CLOSE
: cout
<< "Close cursors"; break;
640 case SQL_CB_PRESERVE
: cout
<< "Preserve cursors"; break;
644 cout
<< "Cursor ROLLBACK Behavior: ";
645 switch(dbInf
.cursorRollbackBehavior
)
647 case SQL_CB_DELETE
: cout
<< "Delete cursors"; break;
648 case SQL_CB_CLOSE
: cout
<< "Close cursors"; break;
649 case SQL_CB_PRESERVE
: cout
<< "Preserve cursors"; break;
653 cout
<< "Support NOT NULL clause: ";
654 switch(dbInf
.supportNotNullClause
)
656 case SQL_NNC_NULL
: cout
<< "No"; break;
657 case SQL_NNC_NON_NULL
: cout
<< "Yes"; break;
661 cout
<< "Support IEF (Ref. Integrity): " << dbInf
.supportIEF
<< endl
;
662 cout
<< "Login Timeout: " << dbInf
.loginTimeout
<< endl
;
664 cout
<< endl
<< endl
<< "more ..." << endl
;
667 cout
<< "Default Transaction Isolation: ";
668 switch(dbInf
.txnIsolation
)
670 case SQL_TXN_READ_UNCOMMITTED
: cout
<< "Read Uncommitted"; break;
671 case SQL_TXN_READ_COMMITTED
: cout
<< "Read Committed"; break;
672 case SQL_TXN_REPEATABLE_READ
: cout
<< "Repeatable Read"; break;
673 case SQL_TXN_SERIALIZABLE
: cout
<< "Serializable"; break;
675 case SQL_TXN_VERSIONING
: cout
<< "Versioning"; break;
680 cout
<< "Transaction Isolation Options: ";
681 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_UNCOMMITTED
)
682 cout
<< "Read Uncommitted, ";
683 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_COMMITTED
)
684 cout
<< "Read Committed, ";
685 if (dbInf
.txnIsolationOptions
& SQL_TXN_REPEATABLE_READ
)
686 cout
<< "Repeatable Read, ";
687 if (dbInf
.txnIsolationOptions
& SQL_TXN_SERIALIZABLE
)
688 cout
<< "Serializable, ";
690 if (dbInf
.txnIsolationOptions
& SQL_TXN_VERSIONING
)
691 cout
<< "Versioning";
695 cout
<< "Fetch Directions Supported:" << endl
<< " ";
696 if (dbInf
.fetchDirections
& SQL_FD_FETCH_NEXT
)
698 if (dbInf
.fetchDirections
& SQL_FD_FETCH_PRIOR
)
700 if (dbInf
.fetchDirections
& SQL_FD_FETCH_FIRST
)
702 if (dbInf
.fetchDirections
& SQL_FD_FETCH_LAST
)
704 if (dbInf
.fetchDirections
& SQL_FD_FETCH_ABSOLUTE
)
705 cout
<< "Absolute, ";
706 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RELATIVE
)
707 cout
<< "Relative, ";
709 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RESUME
)
712 if (dbInf
.fetchDirections
& SQL_FD_FETCH_BOOKMARK
)
716 cout
<< "Lock Types Supported (SQLSetPos): ";
717 if (dbInf
.lockTypes
& SQL_LCK_NO_CHANGE
)
718 cout
<< "No Change, ";
719 if (dbInf
.lockTypes
& SQL_LCK_EXCLUSIVE
)
720 cout
<< "Exclusive, ";
721 if (dbInf
.lockTypes
& SQL_LCK_UNLOCK
)
725 cout
<< "Position Operations Supported (SQLSetPos): ";
726 if (dbInf
.posOperations
& SQL_POS_POSITION
)
727 cout
<< "Position, ";
728 if (dbInf
.posOperations
& SQL_POS_REFRESH
)
730 if (dbInf
.posOperations
& SQL_POS_UPDATE
)
732 if (dbInf
.posOperations
& SQL_POS_DELETE
)
734 if (dbInf
.posOperations
& SQL_POS_ADD
)
738 cout
<< "Positioned Statements Supported: ";
739 if (dbInf
.posStmts
& SQL_PS_POSITIONED_DELETE
)
740 cout
<< "Pos delete, ";
741 if (dbInf
.posStmts
& SQL_PS_POSITIONED_UPDATE
)
742 cout
<< "Pos update, ";
743 if (dbInf
.posStmts
& SQL_PS_SELECT_FOR_UPDATE
)
744 cout
<< "Select for update";
747 cout
<< "Scroll Concurrency: ";
748 if (dbInf
.scrollConcurrency
& SQL_SCCO_READ_ONLY
)
749 cout
<< "Read Only, ";
750 if (dbInf
.scrollConcurrency
& SQL_SCCO_LOCK
)
752 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_ROWVER
)
753 cout
<< "Opt. Rowver, ";
754 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_VALUES
)
755 cout
<< "Opt. Values";
758 cout
<< "Scroll Options: ";
759 if (dbInf
.scrollOptions
& SQL_SO_FORWARD_ONLY
)
760 cout
<< "Fwd Only, ";
761 if (dbInf
.scrollOptions
& SQL_SO_STATIC
)
763 if (dbInf
.scrollOptions
& SQL_SO_KEYSET_DRIVEN
)
764 cout
<< "Keyset Driven, ";
765 if (dbInf
.scrollOptions
& SQL_SO_DYNAMIC
)
767 if (dbInf
.scrollOptions
& SQL_SO_MIXED
)
771 cout
<< "Static Sensitivity: ";
772 if (dbInf
.staticSensitivity
& SQL_SS_ADDITIONS
)
773 cout
<< "Additions, ";
774 if (dbInf
.staticSensitivity
& SQL_SS_DELETIONS
)
775 cout
<< "Deletions, ";
776 if (dbInf
.staticSensitivity
& SQL_SS_UPDATES
)
780 cout
<< "Transaction Capable?: ";
781 switch(dbInf
.txnCapable
)
783 case SQL_TC_NONE
: cout
<< "No"; break;
784 case SQL_TC_DML
: cout
<< "DML Only"; break;
785 case SQL_TC_DDL_COMMIT
: cout
<< "DDL Commit"; break;
786 case SQL_TC_DDL_IGNORE
: cout
<< "DDL Ignore"; break;
787 case SQL_TC_ALL
: cout
<< "DDL & DML"; break;
794 // Completed Successfully
797 } // wxDB::getDbInfo()
800 /********** wxDB::getDataTypeInfo() **********/
801 bool wxDB::getDataTypeInfo(SWORD fSqlType
, SqlTypeInfo
&structSQLTypeInfo
)
804 * fSqlType will be something like SQL_VARCHAR. This parameter determines
805 * the data type inf. is gathered for.
807 * SqlTypeInfo is a structure that is filled in with data type information,
812 // Get information about the data type specified
813 if (SQLGetTypeInfo(hstmt
, fSqlType
) != SQL_SUCCESS
)
814 return(DispAllErrors(henv
, hdbc
, hstmt
));
816 if ((retcode
= SQLFetch(hstmt
)) != SQL_SUCCESS
)
818 #ifdef DBDEBUG_CONSOLE
819 if (retcode
== SQL_NO_DATA_FOUND
)
820 cout
<< "SQL_NO_DATA_FOUND fetching inf. about data type." << endl
;
822 DispAllErrors(henv
, hdbc
, hstmt
);
823 SQLFreeStmt(hstmt
, SQL_CLOSE
);
826 // Obtain columns from the record
827 if (SQLGetData(hstmt
, 1, SQL_C_CHAR
, (UCHAR
*) structSQLTypeInfo
.TypeName
, DB_TYPE_NAME_LEN
, &cbRet
) != SQL_SUCCESS
)
828 return(DispAllErrors(henv
, hdbc
, hstmt
));
831 if (Dbms() == dbmsMY_SQL
)
833 if (!strcmp(structSQLTypeInfo
.TypeName
, "middleint")) strcpy(structSQLTypeInfo
.TypeName
, "mediumint");
834 if (!strcmp(structSQLTypeInfo
.TypeName
, "middleint unsigned")) strcpy(structSQLTypeInfo
.TypeName
, "mediumint unsigned");
835 if (!strcmp(structSQLTypeInfo
.TypeName
, "integer")) strcpy(structSQLTypeInfo
.TypeName
, "int");
836 if (!strcmp(structSQLTypeInfo
.TypeName
, "integer unsigned")) strcpy(structSQLTypeInfo
.TypeName
, "int unsigned");
837 if (!strcmp(structSQLTypeInfo
.TypeName
, "middleint")) strcpy(structSQLTypeInfo
.TypeName
, "mediumint");
838 if (!strcmp(structSQLTypeInfo
.TypeName
, "varchar")) strcpy(structSQLTypeInfo
.TypeName
, "char");
841 if (SQLGetData(hstmt
, 3, SQL_C_LONG
, (UCHAR
*) &structSQLTypeInfo
.Precision
, 0, &cbRet
) != SQL_SUCCESS
)
842 return(DispAllErrors(henv
, hdbc
, hstmt
));
843 if (SQLGetData(hstmt
, 8, SQL_C_SHORT
, (UCHAR
*) &structSQLTypeInfo
.CaseSensitive
, 0, &cbRet
) != SQL_SUCCESS
)
844 return(DispAllErrors(henv
, hdbc
, hstmt
));
845 // if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
846 // return(DispAllErrors(henv, hdbc, hstmt));
848 if (SQLGetData(hstmt
, 15, SQL_C_SHORT
,(UCHAR
*) &structSQLTypeInfo
.MaximumScale
, 0, &cbRet
) != SQL_SUCCESS
)
849 return(DispAllErrors(henv
, hdbc
, hstmt
));
851 if (structSQLTypeInfo
.MaximumScale
< 0)
852 structSQLTypeInfo
.MaximumScale
= 0;
854 // Close the statement handle which closes open cursors
855 if (SQLFreeStmt(hstmt
, SQL_CLOSE
) != SQL_SUCCESS
)
856 return(DispAllErrors(henv
, hdbc
, hstmt
));
858 // Completed Successfully
861 } // wxDB::getDataTypeInfo()
864 /********** wxDB::Close() **********/
865 void wxDB::Close(void)
867 // Close the Sql Log file
874 // Free statement handle
877 if (SQLFreeStmt(hstmt
, SQL_DROP
) != SQL_SUCCESS
)
878 DispAllErrors(henv
, hdbc
);
881 // Disconnect from the datasource
882 if (SQLDisconnect(hdbc
) != SQL_SUCCESS
)
883 DispAllErrors(henv
, hdbc
);
885 // Free the connection to the datasource
886 if (SQLFreeConnect(hdbc
) != SQL_SUCCESS
)
887 DispAllErrors(henv
, hdbc
);
889 // There should be zero Ctable objects still connected to this db object
890 assert(nTables
== 0);
893 CstructTablesInUse
*tiu
;
895 pNode
= TablesInUse
.First();
899 tiu
= (CstructTablesInUse
*)pNode
->Data();
900 if (tiu
->pDb
== this)
902 s
.sprintf("(%-20s) tableID:[%6lu] pDb:[%p]", tiu
->tableName
,tiu
->tableID
,tiu
->pDb
);
903 s2
.sprintf("Orphaned found using pDb:[%p]",this);
906 pNode
= pNode
->Next();
910 // Copy the error messages to a global variable
912 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
913 wxStrcpy(DBerrorList
[i
],errorList
[i
]);
918 /********** wxDB::CommitTrans() **********/
919 bool wxDB::CommitTrans(void)
923 // Commit the transaction
924 if (SQLTransact(henv
, hdbc
, SQL_COMMIT
) != SQL_SUCCESS
)
925 return(DispAllErrors(henv
, hdbc
));
928 // Completed successfully
931 } // wxDB::CommitTrans()
934 /********** wxDB::RollbackTrans() **********/
935 bool wxDB::RollbackTrans(void)
937 // Rollback the transaction
938 if (SQLTransact(henv
, hdbc
, SQL_ROLLBACK
) != SQL_SUCCESS
)
939 return(DispAllErrors(henv
, hdbc
));
941 // Completed successfully
944 } // wxDB::RollbackTrans()
947 /********** wxDB::DispAllErrors() **********/
948 bool wxDB::DispAllErrors(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
950 // char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
953 while (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
955 odbcErrMsg
.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState
, nativeError
, errorMsg
);
956 logError(odbcErrMsg
.GetData(), sqlState
);
959 #ifdef DBDEBUG_CONSOLE
960 // When run in console mode, use standard out to display errors.
961 cout
<< odbcErrMsg
.GetData() << endl
;
962 cout
<< "Press any key to continue..." << endl
;
968 wxMessageBox(odbcErrMsg
.GetData(),"DEBUG MESSAGE from DispAllErrors()");
972 return(FALSE
); // This function always returns false.
974 } // wxDB::DispAllErrors()
977 /********** wxDB::GetNextError() **********/
978 bool wxDB::GetNextError(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
980 if (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
985 } // wxDB::GetNextError()
988 /********** wxDB::DispNextError() **********/
989 void wxDB::DispNextError(void)
991 // char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
994 odbcErrMsg
.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState
, nativeError
, errorMsg
);
995 logError(odbcErrMsg
.GetData(), sqlState
);
1000 #ifdef DBDEBUG_CONSOLE
1001 // When run in console mode, use standard out to display errors.
1002 cout
<< odbcErrMsg
.GetData() << endl
;
1003 cout
<< "Press any key to continue..." << endl
;
1007 } // wxDB::DispNextError()
1010 /********** wxDB::logError() **********/
1011 void wxDB::logError(const char *errMsg
, const char *SQLState
)
1013 assert(errMsg
&& wxStrlen(errMsg
));
1015 static int pLast
= -1;
1018 if (++pLast
== DB_MAX_ERROR_HISTORY
)
1021 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1022 wxStrcpy(errorList
[i
], errorList
[i
+1]);
1026 wxStrcpy(errorList
[pLast
], errMsg
);
1028 if (SQLState
&& wxStrlen(SQLState
))
1029 if ((dbStatus
= TranslateSqlState(SQLState
)) != DB_ERR_FUNCTION_SEQUENCE_ERROR
)
1030 DB_STATUS
= dbStatus
;
1032 // Add the errmsg to the sql log
1033 WriteSqlLog(errMsg
);
1035 } // wxDB::logError()
1038 /**********wxDB::TranslateSqlState() **********/
1039 int wxDB::TranslateSqlState(const char *SQLState
)
1041 if (!wxStrcmp(SQLState
, "01000"))
1042 return(DB_ERR_GENERAL_WARNING
);
1043 if (!wxStrcmp(SQLState
, "01002"))
1044 return(DB_ERR_DISCONNECT_ERROR
);
1045 if (!wxStrcmp(SQLState
, "01004"))
1046 return(DB_ERR_DATA_TRUNCATED
);
1047 if (!wxStrcmp(SQLState
, "01006"))
1048 return(DB_ERR_PRIV_NOT_REVOKED
);
1049 if (!wxStrcmp(SQLState
, "01S00"))
1050 return(DB_ERR_INVALID_CONN_STR_ATTR
);
1051 if (!wxStrcmp(SQLState
, "01S01"))
1052 return(DB_ERR_ERROR_IN_ROW
);
1053 if (!wxStrcmp(SQLState
, "01S02"))
1054 return(DB_ERR_OPTION_VALUE_CHANGED
);
1055 if (!wxStrcmp(SQLState
, "01S03"))
1056 return(DB_ERR_NO_ROWS_UPD_OR_DEL
);
1057 if (!wxStrcmp(SQLState
, "01S04"))
1058 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL
);
1059 if (!wxStrcmp(SQLState
, "07001"))
1060 return(DB_ERR_WRONG_NO_OF_PARAMS
);
1061 if (!wxStrcmp(SQLState
, "07006"))
1062 return(DB_ERR_DATA_TYPE_ATTR_VIOL
);
1063 if (!wxStrcmp(SQLState
, "08001"))
1064 return(DB_ERR_UNABLE_TO_CONNECT
);
1065 if (!wxStrcmp(SQLState
, "08002"))
1066 return(DB_ERR_CONNECTION_IN_USE
);
1067 if (!wxStrcmp(SQLState
, "08003"))
1068 return(DB_ERR_CONNECTION_NOT_OPEN
);
1069 if (!wxStrcmp(SQLState
, "08004"))
1070 return(DB_ERR_REJECTED_CONNECTION
);
1071 if (!wxStrcmp(SQLState
, "08007"))
1072 return(DB_ERR_CONN_FAIL_IN_TRANS
);
1073 if (!wxStrcmp(SQLState
, "08S01"))
1074 return(DB_ERR_COMM_LINK_FAILURE
);
1075 if (!wxStrcmp(SQLState
, "21S01"))
1076 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH
);
1077 if (!wxStrcmp(SQLState
, "21S02"))
1078 return(DB_ERR_DERIVED_TABLE_MISMATCH
);
1079 if (!wxStrcmp(SQLState
, "22001"))
1080 return(DB_ERR_STRING_RIGHT_TRUNC
);
1081 if (!wxStrcmp(SQLState
, "22003"))
1082 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG
);
1083 if (!wxStrcmp(SQLState
, "22005"))
1084 return(DB_ERR_ERROR_IN_ASSIGNMENT
);
1085 if (!wxStrcmp(SQLState
, "22008"))
1086 return(DB_ERR_DATETIME_FLD_OVERFLOW
);
1087 if (!wxStrcmp(SQLState
, "22012"))
1088 return(DB_ERR_DIVIDE_BY_ZERO
);
1089 if (!wxStrcmp(SQLState
, "22026"))
1090 return(DB_ERR_STR_DATA_LENGTH_MISMATCH
);
1091 if (!wxStrcmp(SQLState
, "23000"))
1092 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL
);
1093 if (!wxStrcmp(SQLState
, "24000"))
1094 return(DB_ERR_INVALID_CURSOR_STATE
);
1095 if (!wxStrcmp(SQLState
, "25000"))
1096 return(DB_ERR_INVALID_TRANS_STATE
);
1097 if (!wxStrcmp(SQLState
, "28000"))
1098 return(DB_ERR_INVALID_AUTH_SPEC
);
1099 if (!wxStrcmp(SQLState
, "34000"))
1100 return(DB_ERR_INVALID_CURSOR_NAME
);
1101 if (!wxStrcmp(SQLState
, "37000"))
1102 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL
);
1103 if (!wxStrcmp(SQLState
, "3C000"))
1104 return(DB_ERR_DUPLICATE_CURSOR_NAME
);
1105 if (!wxStrcmp(SQLState
, "40001"))
1106 return(DB_ERR_SERIALIZATION_FAILURE
);
1107 if (!wxStrcmp(SQLState
, "42000"))
1108 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2
);
1109 if (!wxStrcmp(SQLState
, "70100"))
1110 return(DB_ERR_OPERATION_ABORTED
);
1111 if (!wxStrcmp(SQLState
, "IM001"))
1112 return(DB_ERR_UNSUPPORTED_FUNCTION
);
1113 if (!wxStrcmp(SQLState
, "IM002"))
1114 return(DB_ERR_NO_DATA_SOURCE
);
1115 if (!wxStrcmp(SQLState
, "IM003"))
1116 return(DB_ERR_DRIVER_LOAD_ERROR
);
1117 if (!wxStrcmp(SQLState
, "IM004"))
1118 return(DB_ERR_SQLALLOCENV_FAILED
);
1119 if (!wxStrcmp(SQLState
, "IM005"))
1120 return(DB_ERR_SQLALLOCCONNECT_FAILED
);
1121 if (!wxStrcmp(SQLState
, "IM006"))
1122 return(DB_ERR_SQLSETCONNECTOPTION_FAILED
);
1123 if (!wxStrcmp(SQLState
, "IM007"))
1124 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB
);
1125 if (!wxStrcmp(SQLState
, "IM008"))
1126 return(DB_ERR_DIALOG_FAILED
);
1127 if (!wxStrcmp(SQLState
, "IM009"))
1128 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL
);
1129 if (!wxStrcmp(SQLState
, "IM010"))
1130 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG
);
1131 if (!wxStrcmp(SQLState
, "IM011"))
1132 return(DB_ERR_DRIVER_NAME_TOO_LONG
);
1133 if (!wxStrcmp(SQLState
, "IM012"))
1134 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR
);
1135 if (!wxStrcmp(SQLState
, "IM013"))
1136 return(DB_ERR_TRACE_FILE_ERROR
);
1137 if (!wxStrcmp(SQLState
, "S0001"))
1138 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS
);
1139 if (!wxStrcmp(SQLState
, "S0002"))
1140 return(DB_ERR_TABLE_NOT_FOUND
);
1141 if (!wxStrcmp(SQLState
, "S0011"))
1142 return(DB_ERR_INDEX_ALREADY_EXISTS
);
1143 if (!wxStrcmp(SQLState
, "S0012"))
1144 return(DB_ERR_INDEX_NOT_FOUND
);
1145 if (!wxStrcmp(SQLState
, "S0021"))
1146 return(DB_ERR_COLUMN_ALREADY_EXISTS
);
1147 if (!wxStrcmp(SQLState
, "S0022"))
1148 return(DB_ERR_COLUMN_NOT_FOUND
);
1149 if (!wxStrcmp(SQLState
, "S0023"))
1150 return(DB_ERR_NO_DEFAULT_FOR_COLUMN
);
1151 if (!wxStrcmp(SQLState
, "S1000"))
1152 return(DB_ERR_GENERAL_ERROR
);
1153 if (!wxStrcmp(SQLState
, "S1001"))
1154 return(DB_ERR_MEMORY_ALLOCATION_FAILURE
);
1155 if (!wxStrcmp(SQLState
, "S1002"))
1156 return(DB_ERR_INVALID_COLUMN_NUMBER
);
1157 if (!wxStrcmp(SQLState
, "S1003"))
1158 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE
);
1159 if (!wxStrcmp(SQLState
, "S1004"))
1160 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE
);
1161 if (!wxStrcmp(SQLState
, "S1008"))
1162 return(DB_ERR_OPERATION_CANCELLED
);
1163 if (!wxStrcmp(SQLState
, "S1009"))
1164 return(DB_ERR_INVALID_ARGUMENT_VALUE
);
1165 if (!wxStrcmp(SQLState
, "S1010"))
1166 return(DB_ERR_FUNCTION_SEQUENCE_ERROR
);
1167 if (!wxStrcmp(SQLState
, "S1011"))
1168 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME
);
1169 if (!wxStrcmp(SQLState
, "S1012"))
1170 return(DB_ERR_INVALID_TRANS_OPERATION_CODE
);
1171 if (!wxStrcmp(SQLState
, "S1015"))
1172 return(DB_ERR_NO_CURSOR_NAME_AVAIL
);
1173 if (!wxStrcmp(SQLState
, "S1090"))
1174 return(DB_ERR_INVALID_STR_OR_BUF_LEN
);
1175 if (!wxStrcmp(SQLState
, "S1091"))
1176 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE
);
1177 if (!wxStrcmp(SQLState
, "S1092"))
1178 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE
);
1179 if (!wxStrcmp(SQLState
, "S1093"))
1180 return(DB_ERR_INVALID_PARAM_NO
);
1181 if (!wxStrcmp(SQLState
, "S1094"))
1182 return(DB_ERR_INVALID_SCALE_VALUE
);
1183 if (!wxStrcmp(SQLState
, "S1095"))
1184 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE
);
1185 if (!wxStrcmp(SQLState
, "S1096"))
1186 return(DB_ERR_INF_TYPE_OUT_OF_RANGE
);
1187 if (!wxStrcmp(SQLState
, "S1097"))
1188 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE
);
1189 if (!wxStrcmp(SQLState
, "S1098"))
1190 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE
);
1191 if (!wxStrcmp(SQLState
, "S1099"))
1192 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE
);
1193 if (!wxStrcmp(SQLState
, "S1100"))
1194 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE
);
1195 if (!wxStrcmp(SQLState
, "S1101"))
1196 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE
);
1197 if (!wxStrcmp(SQLState
, "S1103"))
1198 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE
);
1199 if (!wxStrcmp(SQLState
, "S1104"))
1200 return(DB_ERR_INVALID_PRECISION_VALUE
);
1201 if (!wxStrcmp(SQLState
, "S1105"))
1202 return(DB_ERR_INVALID_PARAM_TYPE
);
1203 if (!wxStrcmp(SQLState
, "S1106"))
1204 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE
);
1205 if (!wxStrcmp(SQLState
, "S1107"))
1206 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE
);
1207 if (!wxStrcmp(SQLState
, "S1108"))
1208 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE
);
1209 if (!wxStrcmp(SQLState
, "S1109"))
1210 return(DB_ERR_INVALID_CURSOR_POSITION
);
1211 if (!wxStrcmp(SQLState
, "S1110"))
1212 return(DB_ERR_INVALID_DRIVER_COMPLETION
);
1213 if (!wxStrcmp(SQLState
, "S1111"))
1214 return(DB_ERR_INVALID_BOOKMARK_VALUE
);
1215 if (!wxStrcmp(SQLState
, "S1C00"))
1216 return(DB_ERR_DRIVER_NOT_CAPABLE
);
1217 if (!wxStrcmp(SQLState
, "S1T00"))
1218 return(DB_ERR_TIMEOUT_EXPIRED
);
1223 } // wxDB::TranslateSqlState()
1226 /********** wxDB::Grant() **********/
1227 bool wxDB::Grant(int privileges
, const char *tableName
, const char *userList
)
1229 // char sqlStmt[DB_MAX_STATEMENT_LEN];
1232 // Build the grant statement
1234 if (privileges
== DB_GRANT_ALL
)
1239 if (privileges
& DB_GRANT_SELECT
)
1241 sqlStmt
+= "SELECT";
1244 if (privileges
& DB_GRANT_INSERT
)
1248 sqlStmt
+= "INSERT";
1250 if (privileges
& DB_GRANT_UPDATE
)
1254 sqlStmt
+= "UPDATE";
1256 if (privileges
& DB_GRANT_DELETE
)
1260 sqlStmt
+= "DELETE";
1265 sqlStmt
+= tableName
;
1267 sqlStmt
+= userList
;
1269 #ifdef DBDEBUG_CONSOLE
1270 cout
<< endl
<< sqlStmt
.GetData() << endl
;
1273 WriteSqlLog(sqlStmt
.GetData());
1275 return(ExecSql(sqlStmt
.GetData()));
1280 /********** wxDB::CreateView() **********/
1281 bool wxDB::CreateView(const char *viewName
, const char *colList
, const char *pSqlStmt
, bool attemptDrop
)
1283 // char sqlStmt[DB_MAX_STATEMENT_LEN];
1286 // Drop the view first
1287 if (attemptDrop
&& !DropView(viewName
))
1290 // Build the create view statement
1291 sqlStmt
= "CREATE VIEW ";
1292 sqlStmt
+= viewName
;
1294 if (wxStrlen(colList
))
1302 sqlStmt
+= pSqlStmt
;
1304 WriteSqlLog(sqlStmt
.GetData());
1306 #ifdef DBDEBUG_CONSOLE
1307 cout
<< sqlStmt
.GetData() << endl
;
1310 return(ExecSql(sqlStmt
.GetData()));
1312 } // wxDB::CreateView()
1315 /********** wxDB::DropView() **********/
1316 bool wxDB::DropView(const char *viewName
)
1319 * NOTE: This function returns TRUE if the View does not exist, but
1320 * only for identified databases. Code will need to be added
1321 * below for any other databases when those databases are defined
1322 * to handle this situation consistently
1324 // char sqlStmt[DB_MAX_STATEMENT_LEN];
1327 sqlStmt
.sprintf("DROP VIEW %s", viewName
);
1329 WriteSqlLog(sqlStmt
.GetData());
1331 #ifdef DBDEBUG_CONSOLE
1332 cout
<< endl
<< sqlStmt
.GetData() << endl
;
1335 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
.GetData(), SQL_NTS
) != SQL_SUCCESS
)
1337 // Check for "Base table not found" error and ignore
1338 GetNextError(henv
, hdbc
, hstmt
);
1339 if (wxStrcmp(sqlState
,"S0002")) // "Base table not found"
1341 // Check for product specific error codes
1342 if (!((Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(sqlState
,"42000")))) // 5.x (and lower?)
1345 DispAllErrors(henv
, hdbc
, hstmt
);
1352 // Commit the transaction
1353 if (! CommitTrans())
1358 } // wxDB::DropView()
1361 /********** wxDB::ExecSql() **********/
1362 bool wxDB::ExecSql(const char *pSqlStmt
)
1364 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1365 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) pSqlStmt
, SQL_NTS
) == SQL_SUCCESS
)
1369 DispAllErrors(henv
, hdbc
, hstmt
);
1373 } // wxDB::ExecSql()
1376 /********** wxDB::GetNext() **********/
1377 bool wxDB::GetNext(void)
1379 if (SQLFetch(hstmt
) == SQL_SUCCESS
)
1383 DispAllErrors(henv
, hdbc
, hstmt
);
1387 } // wxDB::GetNext()
1390 /********** wxDB::GetData() **********/
1391 bool wxDB::GetData(UWORD colNo
, SWORD cType
, PTR pData
, SDWORD maxLen
, SDWORD FAR
*cbReturned
)
1396 if (SQLGetData(hstmt
, colNo
, cType
, pData
, maxLen
, cbReturned
) == SQL_SUCCESS
)
1400 DispAllErrors(henv
, hdbc
, hstmt
);
1404 } // wxDB::GetData()
1407 /********** wxDB::GetKeyFields() **********/
1408 int wxDB::GetKeyFields(char *tableName
, wxColInf
* colInf
,int noCols
)
1410 char szPkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Primary key table name */
1411 char szFkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Foreign key table name */
1413 // SQLSMALLINT iKeySeq;
1414 char szPkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Primary key column */
1415 char szFkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Foreign key column */
1421 * ---------------------------------------------------------------------
1422 * -- 19991224 : mj10777@gmx.net : Create ------
1423 * -- : Three things are done and stored here : ------
1424 * -- : 1) which Column(s) is/are Primary Key(s) ------
1425 * -- : 2) which tables use this Key as a Foreign Key ------
1426 * -- : 3) which columns are Foreign Key and the name ------
1427 * -- : of the Table where the Key is the Primary Key -----
1428 * -- : Called from GetColumns(char *tableName, ------
1429 * -- int *numCols,const char *userID ) ------
1430 * ---------------------------------------------------------------------
1433 /*---------------------------------------------------------------------*/
1434 /* Get the names of the columns in the primary key. */
1435 /*---------------------------------------------------------------------*/
1436 retcode
= SQLPrimaryKeys(hstmt
,
1437 NULL
, 0, /* Catalog name */
1438 NULL
, 0, /* Schema name */
1439 (UCHAR
*) tableName
, SQL_NTS
); /* Table name */
1441 /*---------------------------------------------------------------------*/
1442 /* Fetch and display the result set. This will be a list of the */
1443 /* columns in the primary key of the tableName table. */
1444 /*---------------------------------------------------------------------*/
1445 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1447 retcode
= SQLFetch(hstmt
);
1448 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1450 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1451 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1453 for (i
=0;i
<noCols
;i
++) // Find the Column name
1454 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column
1455 colInf
[i
].PkCol
= iKeySeq
; // Which Primary Key is this (first, second usw.) ?
1456 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1457 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1458 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1460 /*---------------------------------------------------------------------*/
1461 /* Get all the foreign keys that refer to tableName primary key. */
1462 /*---------------------------------------------------------------------*/
1463 retcode
= SQLForeignKeys(hstmt
,
1464 NULL
, 0, /* Primary catalog */
1465 NULL
, 0, /* Primary schema */
1466 (UCHAR
*)tableName
, SQL_NTS
, /* Primary table */
1467 NULL
, 0, /* Foreign catalog */
1468 NULL
, 0, /* Foreign schema */
1469 NULL
, 0); /* Foreign table */
1471 /*---------------------------------------------------------------------*/
1472 /* Fetch and display the result set. This will be all of the foreign */
1473 /* keys in other tables that refer to the tableName primary key. */
1474 /*---------------------------------------------------------------------*/
1477 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1479 retcode
= SQLFetch(hstmt
);
1480 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1482 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1483 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1484 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1485 GetData( 7, SQL_C_CHAR
, szFkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1486 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1487 Temp0
.Printf("%s[%s] ",Temp0
.c_str(),szFkTable
); // [ ] in case there is a blank in the Table name
1488 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1489 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1490 Temp0
.Trim(); // Get rid of any unneeded blanks
1493 for (i
=0;i
<noCols
;i
++) // Find the Column name
1494 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column, store the Information
1495 strcpy(colInf
[i
].PkTableName
,Temp0
); // Name of the Tables where this Primary Key is used as a Foreign Key
1496 } // if (Temp0 != "")
1497 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1499 /*---------------------------------------------------------------------*/
1500 /* Get all the foreign keys in the tablename table. */
1501 /*---------------------------------------------------------------------*/
1502 retcode
= SQLForeignKeys(hstmt
,
1503 NULL
, 0, /* Primary catalog */
1504 NULL
, 0, /* Primary schema */
1505 NULL
, 0, /* Primary table */
1506 NULL
, 0, /* Foreign catalog */
1507 NULL
, 0, /* Foreign schema */
1508 (UCHAR
*)tableName
, SQL_NTS
); /* Foreign table */
1510 /*---------------------------------------------------------------------*/
1511 /* Fetch and display the result set. This will be all of the */
1512 /* primary keys in other tables that are referred to by foreign */
1513 /* keys in the tableName table. */
1514 /*---------------------------------------------------------------------*/
1516 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1518 retcode
= SQLFetch(hstmt
);
1519 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1521 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1522 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1523 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1525 for (i
=0;i
<noCols
;i
++) // Find the Column name
1527 if (!wxStrcmp(colInf
[i
].colName
,szFkCol
)) // We have found the (Foreign Key) Column
1529 colInf
[i
].FkCol
= iKeySeq
; // Which Foreign Key is this (first, second usw.) ?
1530 strcpy(colInf
[i
].FkTableName
,szPkTable
); // Name of the Table where this Foriegn is the Primary Key
1531 } // if (!wxStrcmp(colInf[i].colName,szFkCol))
1532 } // for (i=0;i<noCols;i++)
1533 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1534 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1535 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1537 /*---------------------------------------------------------------------*/
1539 } // wxDB::GetKeyFields()
1542 /********** wxDB::GetColumns() **********/
1543 wxColInf
*wxDB::GetColumns(char *tableName
[], const char *userID
)
1545 * 1) The last array element of the tableName[] argument must be zero (null).
1546 * This is how the end of the array is detected.
1547 * 2) This function returns an array of wxColInf structures. If no columns
1548 * were found, or an error occured, this pointer will be zero (null). THE
1549 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
1550 * IS FINISHED WITH IT. i.e.
1552 * wxColInf *colInf = pDb->GetColumns(tableList, userID);
1555 * // Use the column inf
1557 * // Destroy the memory
1561 * userID is evaluated in the following manner:
1562 * userID == NULL ... UserID is ignored
1563 * userID == "" ... UserID set equal to 'this->uid'
1564 * userID != "" ... UserID set equal to 'userID'
1570 wxColInf
*colInf
= 0;
1580 if (!wxStrlen(userID
))
1588 // dBase does not use user names, and some drivers fail if you try to pass one
1589 if (Dbms() == dbmsDBASE
)
1592 // Oracle user names may only be in uppercase, so force
1593 // the name to uppercase
1594 if (Dbms() == dbmsORACLE
)
1595 UserID
= UserID
.Upper();
1597 // Pass 1 - Determine how many columns there are.
1598 // Pass 2 - Allocate the wxColInf array and fill in
1599 // the array with the column information.
1601 for (pass
= 1; pass
<= 2; pass
++)
1605 if (noCols
== 0) // Probably a bogus table name(s)
1607 // Allocate n wxColInf objects to hold the column information
1608 colInf
= new wxColInf
[noCols
+1];
1611 // Mark the end of the array
1612 wxStrcpy(colInf
[noCols
].tableName
, "");
1613 wxStrcpy(colInf
[noCols
].colName
, "");
1614 colInf
[noCols
].sqlDataType
= 0;
1616 // Loop through each table name
1618 for (tbl
= 0; tableName
[tbl
]; tbl
++)
1620 TableName
= tableName
[tbl
];
1621 // Oracle table names are uppercase only, so force
1622 // the name to uppercase just in case programmer forgot to do this
1623 if (Dbms() == dbmsORACLE
)
1624 TableName
= TableName
.Upper();
1626 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1628 // MySQL and Access cannot accept a user name when looking up column names, so we
1629 // use the call below that leaves out the user name
1630 if (wxStrcmp(UserID
.GetData(),"") &&
1631 Dbms() != dbmsMY_SQL
&&
1632 Dbms() != dbmsACCESS
)
1634 retcode
= SQLColumns(hstmt
,
1635 NULL
, 0, // All qualifiers
1636 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // Owner
1637 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1638 NULL
, 0); // All columns
1642 retcode
= SQLColumns(hstmt
,
1643 NULL
, 0, // All qualifiers
1645 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1646 NULL
, 0); // All columns
1648 if (retcode
!= SQL_SUCCESS
)
1649 { // Error occured, abort
1650 DispAllErrors(henv
, hdbc
, hstmt
);
1653 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1657 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
1659 if (pass
== 1) // First pass, just add up the number of columns
1661 else // Pass 2; Fill in the array of structures
1663 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
1665 // NOTE: Only the ODBC 1.x fields are retrieved
1666 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
1667 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
1668 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1669 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1670 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
1671 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
1672 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
1673 GetData( 8, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
1674 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
1675 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
1676 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
1677 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
1679 // Determine the wxDB data type that is used to represent the native data type of this data source
1680 colInf
[colNo
].dbDataType
= 0;
1681 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
1682 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
1683 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
1684 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
1685 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
1686 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
1687 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
1688 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
1694 if (retcode
!= SQL_NO_DATA_FOUND
)
1695 { // Error occured, abort
1696 DispAllErrors(henv
, hdbc
, hstmt
);
1699 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1705 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1708 } // wxDB::GetColumns()
1711 /********** wxDB::GetColumns() **********/
1712 wxColInf
*wxDB::GetColumns(char *tableName
, int *numCols
, const char *userID
)
1714 * Same as the above GetColumns() function except this one gets columns
1715 * only for a single table, and if 'numCols' is not NULL, the number of
1716 * columns stored in the returned wxColInf is set in '*numCols'
1718 * userID is evaluated in the following manner:
1719 * userID == NULL ... UserID is ignored
1720 * userID == "" ... UserID set equal to 'this->uid'
1721 * userID != "" ... UserID set equal to 'userID'
1723 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1724 * by this function. This function should use its own wxDB instance
1725 * to avoid undesired unbinding of columns.
1730 wxColInf
*colInf
= 0;
1740 if (!wxStrlen(userID
))
1748 // dBase does not use user names, and some drivers fail if you try to pass one
1749 if (Dbms() == dbmsDBASE
)
1752 // Oracle user names may only be in uppercase, so force
1753 // the name to uppercase
1754 if (Dbms() == dbmsORACLE
)
1755 UserID
= UserID
.Upper();
1757 // Pass 1 - Determine how many columns there are.
1758 // Pass 2 - Allocate the wxColInf array and fill in
1759 // the array with the column information.
1761 for (pass
= 1; pass
<= 2; pass
++)
1765 if (noCols
== 0) // Probably a bogus table name(s)
1767 // Allocate n wxColInf objects to hold the column information
1768 colInf
= new wxColInf
[noCols
+1];
1771 // Mark the end of the array
1772 wxStrcpy(colInf
[noCols
].tableName
, "");
1773 wxStrcpy(colInf
[noCols
].colName
, "");
1774 colInf
[noCols
].sqlDataType
= 0;
1777 TableName
= tableName
;
1778 // Oracle table names are uppercase only, so force
1779 // the name to uppercase just in case programmer forgot to do this
1780 if (Dbms() == dbmsORACLE
)
1781 TableName
= TableName
.Upper();
1783 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1785 // MySQL and Access cannot accept a user name when looking up column names, so we
1786 // use the call below that leaves out the user name
1787 if (wxStrcmp(UserID
.GetData(),"") &&
1788 Dbms() != dbmsMY_SQL
&&
1789 Dbms() != dbmsACCESS
)
1791 retcode
= SQLColumns(hstmt
,
1792 NULL
, 0, // All qualifiers
1793 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // Owner
1794 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1795 NULL
, 0); // All columns
1799 retcode
= SQLColumns(hstmt
,
1800 NULL
, 0, // All qualifiers
1802 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1803 NULL
, 0); // All columns
1805 if (retcode
!= SQL_SUCCESS
)
1806 { // Error occured, abort
1807 DispAllErrors(henv
, hdbc
, hstmt
);
1810 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1816 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
1818 if (pass
== 1) // First pass, just add up the number of columns
1820 else // Pass 2; Fill in the array of structures
1822 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
1824 // NOTE: Only the ODBC 1.x fields are retrieved
1825 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
1826 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
1827 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1828 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1829 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
1830 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
1831 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
1832 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
1833 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
1834 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
1835 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
1836 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
1837 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
1838 // Start Values for Primary/Foriegn Key (=No)
1839 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
1840 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
1841 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
1842 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
1844 // Determine the wxDB data type that is used to represent the native data type of this data source
1845 colInf
[colNo
].dbDataType
= 0;
1846 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
1847 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
1848 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
1849 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
1850 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
1851 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
1852 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
1853 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
1859 if (retcode
!= SQL_NO_DATA_FOUND
)
1860 { // Error occured, abort
1861 DispAllErrors(henv
, hdbc
, hstmt
);
1864 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1871 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1873 // Store Primary and Foriegn Keys
1874 GetKeyFields(tableName
,colInf
,noCols
);
1880 } // wxDB::GetColumns()
1883 /********** wxDB::GetColumnCount() **********/
1884 int wxDB::GetColumnCount(char *tableName
, const char *userID
)
1886 * Returns a count of how many columns are in a table.
1887 * If an error occurs in computing the number of columns
1888 * this function will return a -1 for the count
1890 * userID is evaluated in the following manner:
1891 * userID == NULL ... UserID is ignored
1892 * userID == "" ... UserID set equal to 'this->uid'
1893 * userID != "" ... UserID set equal to 'userID'
1895 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1896 * by this function. This function should use its own wxDB instance
1897 * to avoid undesired unbinding of columns.
1909 if (!wxStrlen(userID
))
1917 // dBase does not use user names, and some drivers fail if you try to pass one
1918 if (Dbms() == dbmsDBASE
)
1921 // Oracle user names may only be in uppercase, so force
1922 // the name to uppercase
1923 if (Dbms() == dbmsORACLE
)
1924 UserID
= UserID
.Upper();
1927 // Loop through each table name
1929 TableName
= tableName
;
1930 // Oracle table names are uppercase only, so force
1931 // the name to uppercase just in case programmer forgot to do this
1932 if (Dbms() == dbmsORACLE
)
1933 TableName
= TableName
.Upper();
1935 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1937 // MySQL and Access cannot accept a user name when looking up column names, so we
1938 // use the call below that leaves out the user name
1939 if (wxStrcmp(UserID
.GetData(),"") &&
1940 Dbms() != dbmsMY_SQL
&&
1941 Dbms() != dbmsACCESS
)
1943 retcode
= SQLColumns(hstmt
,
1944 NULL
, 0, // All qualifiers
1945 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // Owner
1946 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1947 NULL
, 0); // All columns
1951 retcode
= SQLColumns(hstmt
,
1952 NULL
, 0, // All qualifiers
1954 (UCHAR
*) TableName
.GetData(), SQL_NTS
,
1955 NULL
, 0); // All columns
1957 if (retcode
!= SQL_SUCCESS
)
1958 { // Error occured, abort
1959 DispAllErrors(henv
, hdbc
, hstmt
);
1960 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1964 // Count the columns
1965 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
1968 if (retcode
!= SQL_NO_DATA_FOUND
)
1969 { // Error occured, abort
1970 DispAllErrors(henv
, hdbc
, hstmt
);
1971 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1977 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1980 } // wxDB::GetColumnCount()
1983 /********** wxDB::GetCatalog() *******/
1984 wxDbInf
*wxDB::GetCatalog(char *userID
)
1986 * ---------------------------------------------------------------------
1987 * -- 19991203 : mj10777@gmx.net : Create ------
1988 * -- : Creates a wxDbInf with Tables / Cols Array ------
1989 * -- : uses SQLTables and fills pTableInf; ------
1990 * -- : pColInf is set to NULL and numCols to 0; ------
1991 * -- : returns pDbInf (wxDbInf) ------
1992 * -- - if unsuccesfull (pDbInf == NULL) ------
1993 * -- : pColInf can be filled with GetColumns(..); ------
1994 * -- : numCols can be filled with GetColumnCount(..); ------
1995 * ---------------------------------------------------------------------
1997 * userID is evaluated in the following manner:
1998 * userID == NULL ... UserID is ignored
1999 * userID == "" ... UserID set equal to 'this->uid'
2000 * userID != "" ... UserID set equal to 'userID'
2002 * NOTE: ALL column bindings associated with this wxDB instance are unbound
2003 * by this function. This function should use its own wxDB instance
2004 * to avoid undesired unbinding of columns.
2007 wxDbInf
*pDbInf
= NULL
; // Array of catalog entries
2008 int noTab
= 0; // Counter while filling table entries
2012 // char tblNameSave[DB_MAX_TABLE_NAME_LEN+1];
2013 wxString tblNameSave
;
2019 if (!wxStrlen(userID
))
2027 // dBase does not use user names, and some drivers fail if you try to pass one
2028 if (Dbms() == dbmsDBASE
)
2031 // Oracle user names may only be in uppercase, so force
2032 // the name to uppercase
2033 if (Dbms() == dbmsORACLE
)
2034 UserID
= UserID
.Upper();
2036 //-------------------------------------------------------------
2037 pDbInf
= new wxDbInf
; // Create the Database Arrray
2038 pDbInf
->catalog
[0] = 0;
2039 pDbInf
->schema
[0] = 0;
2040 pDbInf
->numTables
= 0; // Counter for Tables
2041 pDbInf
->pTableInf
= NULL
; // Array of Tables
2042 //-------------------------------------------------------------
2043 // Table Information
2044 // Pass 1 - Determine how many Tables there are.
2045 // Pass 2 - Create the Table array and fill it
2046 // - Create the Cols array = NULL
2047 //-------------------------------------------------------------
2048 for (pass
= 1; pass
<= 2; pass
++)
2050 SQLFreeStmt(hstmt
, SQL_CLOSE
); // Close if Open
2053 if (wxStrcmp(UserID
.GetData(),"") &&
2054 Dbms() != dbmsMY_SQL
&&
2055 Dbms() != dbmsACCESS
)
2057 retcode
= SQLTables(hstmt
,
2058 NULL
, 0, // All qualifiers
2059 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // User specified
2060 NULL
, 0, // All tables
2061 NULL
, 0); // All columns
2065 retcode
= SQLTables(hstmt
,
2066 NULL
, 0, // All qualifiers
2067 NULL
, 0, // User specified
2068 NULL
, 0, // All tables
2069 NULL
, 0); // All columns
2071 if (retcode
!= SQL_SUCCESS
)
2073 DispAllErrors(henv
, hdbc
, hstmt
);
2075 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2079 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
) // Table Information
2081 if (pass
== 1) // First pass, just count the Tables
2083 if (pDbInf
->numTables
== 0)
2085 GetData( 1, SQL_C_CHAR
, (UCHAR
*) pDbInf
->catalog
, 128+1, &cb
);
2086 GetData( 2, SQL_C_CHAR
, (UCHAR
*) pDbInf
->schema
, 128+1, &cb
);
2088 pDbInf
->numTables
++; // Counter for Tables
2090 if (pass
== 2) // Create and fill the Table entries
2092 if (pDbInf
->pTableInf
== NULL
) // Has the Table Array been created
2093 { // no, then create the Array
2094 pDbInf
->pTableInf
= new wxTableInf
[pDbInf
->numTables
];
2095 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
2097 (pDbInf
->pTableInf
+noTab
)->tableName
[0] = 0;
2098 (pDbInf
->pTableInf
+noTab
)->tableType
[0] = 0;
2099 (pDbInf
->pTableInf
+noTab
)->tableRemarks
[0] = 0;
2100 (pDbInf
->pTableInf
+noTab
)->numCols
= 0;
2101 (pDbInf
->pTableInf
+noTab
)->pColInf
= NULL
;
2104 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
2105 GetData( 3, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2106 GetData( 4, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableType
, 30+1, &cb
);
2107 GetData( 5, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableRemarks
, 254+1, &cb
);
2109 } // if (pass == 2) We now know the amount of Tables
2110 } // while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2111 } // for (pass = 1; pass <= 2; pass++)
2112 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2114 // Query how many columns are in each table
2115 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
2117 (pDbInf
->pTableInf
+noTab
)->numCols
= GetColumnCount((pDbInf
->pTableInf
+noTab
)->tableName
,UserID
);
2120 } // wxDB::GetCatalog()
2123 /********** wxDB::Catalog() **********/
2124 bool wxDB::Catalog(const char *userID
, const char *fileName
)
2126 * Creates the text file specified in 'filename' which will contain
2127 * a minimal data dictionary of all tables accessible by the user specified
2130 * userID is evaluated in the following manner:
2131 * userID == NULL ... UserID is ignored
2132 * userID == "" ... UserID set equal to 'this->uid'
2133 * userID != "" ... UserID set equal to 'userID'
2135 * NOTE: ALL column bindings associated with this wxDB instance are unbound
2136 * by this function. This function should use its own wxDB instance
2137 * to avoid undesired unbinding of columns.
2140 assert(fileName
&& wxStrlen(fileName
));
2144 char tblName
[DB_MAX_TABLE_NAME_LEN
+1];
2145 wxString tblNameSave
;
2146 char colName
[DB_MAX_COLUMN_NAME_LEN
+1];
2148 char typeName
[30+1];
2149 SWORD precision
, length
;
2153 FILE *fp
= fopen(fileName
,"wt");
2157 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2161 if (!wxStrlen(userID
))
2169 // dBase does not use user names, and some drivers fail if you try to pass one
2170 if (Dbms() == dbmsDBASE
)
2173 // Oracle user names may only be in uppercase, so force
2174 // the name to uppercase
2175 if (Dbms() == dbmsORACLE
)
2176 UserID
= UserID
.Upper();
2178 if (wxStrcmp(UserID
.GetData(),"") &&
2179 Dbms() != dbmsMY_SQL
&&
2180 Dbms() != dbmsACCESS
)
2182 retcode
= SQLColumns(hstmt
,
2183 NULL
, 0, // All qualifiers
2184 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // User specified
2185 NULL
, 0, // All tables
2186 NULL
, 0); // All columns
2190 retcode
= SQLColumns(hstmt
,
2191 NULL
, 0, // All qualifiers
2192 NULL
, 0, // User specified
2193 NULL
, 0, // All tables
2194 NULL
, 0); // All columns
2196 if (retcode
!= SQL_SUCCESS
)
2198 DispAllErrors(henv
, hdbc
, hstmt
);
2207 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2209 if (wxStrcmp(tblName
,tblNameSave
.GetData()))
2213 fputs("================================ ", fp
);
2214 fputs("================================ ", fp
);
2215 fputs("===================== ", fp
);
2216 fputs("========= ", fp
);
2217 fputs("=========\n", fp
);
2218 outStr
.sprintf("%-32s %-32s %-21s %9s %9s\n",
2219 "TABLE NAME", "COLUMN NAME", "DATA TYPE", "PRECISION", "LENGTH");
2220 fputs(outStr
.GetData(), fp
);
2221 fputs("================================ ", fp
);
2222 fputs("================================ ", fp
);
2223 fputs("===================== ", fp
);
2224 fputs("========= ", fp
);
2225 fputs("=========\n", fp
);
2226 tblNameSave
= tblName
;
2229 GetData(3,SQL_C_CHAR
, (UCHAR
*)tblName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2230 GetData(4,SQL_C_CHAR
, (UCHAR
*)colName
, DB_MAX_COLUMN_NAME_LEN
+1,&cb
);
2231 GetData(5,SQL_C_SSHORT
,(UCHAR
*)&sqlDataType
,0, &cb
);
2232 GetData(6,SQL_C_CHAR
, (UCHAR
*)typeName
, sizeof(typeName
), &cb
);
2233 GetData(7,SQL_C_SSHORT
,(UCHAR
*)&precision
, 0, &cb
);
2234 GetData(8,SQL_C_SSHORT
,(UCHAR
*)&length
, 0, &cb
);
2236 outStr
.sprintf("%-32s %-32s (%04d)%-15s %9d %9d\n",
2237 tblName
, colName
, sqlDataType
, typeName
, precision
, length
);
2238 if (fputs(outStr
.GetData(), fp
) == EOF
)
2240 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2247 if (retcode
!= SQL_NO_DATA_FOUND
)
2248 DispAllErrors(henv
, hdbc
, hstmt
);
2250 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2253 return(retcode
== SQL_NO_DATA_FOUND
);
2255 } // wxDB::Catalog()
2258 bool wxDB::TableExists(const char *tableName
, const char *userID
, const char *tablePath
)
2260 * Table name can refer to a table, view, alias or synonym. Returns true
2261 * if the object exists in the database. This function does not indicate
2262 * whether or not the user has privleges to query or perform other functions
2265 * userID is evaluated in the following manner:
2266 * userID == NULL ... UserID is ignored
2267 * userID == "" ... UserID set equal to 'this->uid'
2268 * userID != "" ... UserID set equal to 'userID'
2274 assert(tableName
&& wxStrlen(tableName
));
2276 if (Dbms() == dbmsDBASE
)
2279 if (tablePath
&& wxStrlen(tablePath
))
2280 dbName
.sprintf("%s/%s.dbf",tablePath
,tableName
);
2282 dbName
.sprintf("%s.dbf",tableName
);
2285 exists
= wxFileExists(dbName
.GetData());
2291 if (!wxStrlen(userID
))
2299 // Oracle user names may only be in uppercase, so force
2300 // the name to uppercase
2301 if (Dbms() == dbmsORACLE
)
2302 UserID
= UserID
.Upper();
2304 TableName
= tableName
;
2305 // Oracle table names are uppercase only, so force
2306 // the name to uppercase just in case programmer forgot to do this
2307 if (Dbms() == dbmsORACLE
)
2308 TableName
= TableName
.Upper();
2310 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2313 // MySQL and Access cannot accept a user name when looking up table names, so we
2314 // use the call below that leaves out the user name
2315 if (wxStrcmp(UserID
,"") &&
2316 Dbms() != dbmsMY_SQL
&&
2317 Dbms() != dbmsACCESS
)
2319 retcode
= SQLTables(hstmt
,
2320 NULL
, 0, // All qualifiers
2321 (UCHAR
*) UserID
.GetData(), SQL_NTS
, // All owners
2322 (UCHAR FAR
*)TableName
.GetData(), SQL_NTS
,
2323 NULL
, 0); // All table types
2327 retcode
= SQLTables(hstmt
,
2328 NULL
, 0, // All qualifiers
2329 NULL
, 0, // All owners
2330 (UCHAR FAR
*)TableName
.GetData(), SQL_NTS
,
2331 NULL
, 0); // All table types
2333 if (retcode
!= SQL_SUCCESS
)
2334 return(DispAllErrors(henv
, hdbc
, hstmt
));
2336 retcode
= SQLFetch(hstmt
);
2337 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
2339 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2340 return(DispAllErrors(henv
, hdbc
, hstmt
));
2343 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2346 } // wxDB::TableExists()
2350 /********** wxDB::TablePrivileges() **********/
2351 bool wxDB::TablePrivileges(const char* privilege
, const char *tableName
,
2352 const char *userID
, const char *tablePath
)
2354 SqlPrivilegesInfo result
;
2358 //We probably need to be able to dynamically set this based on
2359 //the driver type, and state. - roger gammans
2360 char curRole
[]="public";
2365 assert(tableName
&& wxStrlen(tableName
));
2369 if (!wxStrlen(userID
))
2377 // Oracle user names may only be in uppercase, so force
2378 // the name to uppercase
2379 // if (Dbms() == dbmsORACLE)
2380 // UserID = UserID.Upper();
2382 // However we fors case-insentive compare so it shouldn't matter.
2385 TableName
= tableName
;
2386 // Oracle table names are uppercase only, so force
2387 // the name to uppercase just in case programmer forgot to do this
2388 if (Dbms() == dbmsORACLE
)
2389 TableName
= TableName
.Upper();
2391 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2393 retcode
= SQLTablePrivileges(hstmt
,
2394 NULL
, 0, // All qualifiers
2395 NULL
, 0, // All owners
2396 (UCHAR FAR
*)TableName
.GetData(), SQL_NTS
);
2398 #ifdef DBDEBUG_CONSOLE
2399 fprintf(stderr
,"SQLTablePrivileges() returned %i \n",retcode
);
2402 retcode = SQLBindCol (hstmt, 1, SQL_C_CHAR, &result.TableQualifier, 128, &cbRetVal);
2403 retcode = SQLBindCol (hstmt, 2, SQL_C_CHAR, &result.TableOwner, 128, &cbRetVal);
2404 retcode = SQLBindCol (hstmt, 3, SQL_C_CHAR, &result.TableName, 128, &cbRetVal);
2405 retcode = SQLBindCol (hstmt, 4, SQL_C_CHAR, &result.Grantor, 128, &cbRetVal);
2406 retcode = SQLBindCol (hstmt, 5, SQL_C_CHAR, &result.Grantee, 128, &cbRetVal);
2407 retcode = SQLBindCol (hstmt, 6, SQL_C_CHAR, &result.Privilege, 128, &cbRetVal);
2408 retcode = SQLBindCol (hstmt, 7, SQL_C_CHAR, &result.Grantable, 3, &cbRetVal);
2410 retcode
= SQLFetch(hstmt
);
2411 while (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
2413 GetData(1, SQL_C_CHAR
, &result
.TableQualifier
, 128, &cbRetVal
);
2414 GetData(2, SQL_C_CHAR
, &result
.TableOwner
, 128, &cbRetVal
);
2415 GetData(3, SQL_C_CHAR
, &result
.TableName
, 128, &cbRetVal
);
2416 GetData(4, SQL_C_CHAR
, &result
.Grantor
, 128, &cbRetVal
);
2417 GetData(5, SQL_C_CHAR
, &result
.Grantee
, 128, &cbRetVal
);
2418 GetData(6, SQL_C_CHAR
, &result
.Privilege
, 128, &cbRetVal
);
2419 GetData(7, SQL_C_CHAR
, &result
.Grantable
, 3, &cbRetVal
);
2421 #ifdef DBDEBUG_CONSOLE
2422 fprintf(stderr
,"Scanning %s privilege on table %s.%s granted by %s to %s\n",
2423 result
.Privilege
,result
.TableOwner
,result
.TableName
,
2424 result
.Grantor
, result
.Grantee
);
2426 if (UserID
.IsSameAs(result
.TableOwner
,false))
2428 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2431 if (UserID
.IsSameAs(result
.Grantee
,false) &&
2432 !strcmp(result
.Privilege
, privilege
))
2434 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2437 if (!strcmp(result
.Grantee
,curRole
) &&
2438 !strcmp(result
.Privilege
, privilege
))
2440 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2443 retcode
= SQLFetch(hstmt
);
2446 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2448 } // wxDB::TablePrivileges()
2451 /********** wxDB::SqlLog() **********/
2452 bool wxDB::SqlLog(enum sqlLog state
, const char *filename
, bool append
)
2454 assert(state
== sqlLogON
|| state
== sqlLogOFF
);
2455 assert(state
== sqlLogOFF
|| filename
);
2457 if (state
== sqlLogON
)
2461 fpSqlLog
= fopen(filename
, (append
? "at" : "wt"));
2462 if (fpSqlLog
== NULL
)
2470 if (fclose(fpSqlLog
))
2476 sqlLogState
= state
;
2482 /********** wxDB::WriteSqlLog() **********/
2483 bool wxDB::WriteSqlLog(const char *logMsg
)
2487 if (fpSqlLog
== 0 || sqlLogState
== sqlLogOFF
)
2490 if (fputs("\n", fpSqlLog
) == EOF
) return(FALSE
);
2491 if (fputs(logMsg
, fpSqlLog
) == EOF
) return(FALSE
);
2492 if (fputs("\n", fpSqlLog
) == EOF
) return(FALSE
);
2496 } // wxDB::WriteSqlLog()
2499 /********** wxDB::Dbms() **********/
2500 DBMS
wxDB::Dbms(void)
2502 * Be aware that not all database engines use the exact same syntax, and not
2503 * every ODBC compliant database is compliant to the same level of compliancy.
2504 * Some manufacturers support the minimum Level 1 compliancy, and others up
2505 * through Level 3. Others support subsets of features for levels above 1.
2507 * If you find an inconsistency between the wxDB class and a specific database
2508 * engine, and an identifier to this section, and special handle the database in
2509 * the area where behavior is non-conforming with the other databases.
2512 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
2513 * ---------------------------------------------------
2516 * - Currently the only database supported by the class to support VIEWS
2519 * - Does not support the SQL_TIMESTAMP structure
2520 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
2521 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
2522 * is TRUE. The user must create ALL indexes from their program.
2523 * - Table names can only be 8 characters long
2524 * - Column names can only be 10 characters long
2527 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
2528 * after every table name involved in the query/join if that tables matching record(s)
2530 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
2532 * SYBASE (Enterprise)
2533 * - If a column is part of the Primary Key, the column cannot be NULL
2536 * - If a column is part of the Primary Key, the column cannot be NULL
2537 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
2540 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
2545 wxChar baseName
[25+1];
2547 wxStrncpy(baseName
,dbInf
.dbmsName
,25);
2548 if (!wxStricmp(dbInf
.dbmsName
,"Adaptive Server Anywhere"))
2549 return(dbmsSYBASE_ASA
);
2550 if (!wxStricmp(dbInf
.dbmsName
,"SQL Server")) // Sybase Adaptive Server
2551 return(dbmsSYBASE_ASE
);
2552 if (!wxStricmp(dbInf
.dbmsName
,"Microsoft SQL Server"))
2553 return(dbmsMS_SQL_SERVER
);
2554 if (!wxStricmp(dbInf
.dbmsName
,"MySQL"))
2556 if (!wxStricmp(dbInf
.dbmsName
,"PostgreSQL")) // v6.5.0
2557 return(dbmsPOSTGRES
);
2560 if (!wxStricmp(baseName
,"Informix"))
2561 return(dbmsINFORMIX
);
2564 if (!wxStricmp(baseName
,"Oracle"))
2566 if (!wxStricmp(dbInf
.dbmsName
,"ACCESS"))
2568 if (!wxStricmp(dbInf
.dbmsName
,"MySQL"))
2572 if (!wxStricmp(baseName
,"DBASE"))
2575 return(dbmsUNIDENTIFIED
);
2579 /********** GetDbConnection() **********/
2580 wxDB WXDLLEXPORT
*GetDbConnection(DbStuff
*pDbStuff
, bool FwdOnlyCursors
)
2584 // Scan the linked list searching for an available database connection
2585 // that's already been opened but is currently not in use.
2586 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2588 // The database connection must be for the same datasource
2589 // name and must currently not be in use.
2590 if (pList
->Free
&& (! wxStrcmp(pDbStuff
->Dsn
, pList
->Dsn
))) // Found a free connection
2592 pList
->Free
= FALSE
;
2593 return(pList
->PtrDb
);
2597 // No available connections. A new connection must be made and
2598 // appended to the end of the linked list.
2601 // Find the end of the list
2602 for (pList
= PtrBegDbList
; pList
->PtrNext
; pList
= pList
->PtrNext
);
2603 // Append a new list item
2604 pList
->PtrNext
= new DbList
;
2605 pList
->PtrNext
->PtrPrev
= pList
;
2606 pList
= pList
->PtrNext
;
2610 // Create the first node on the list
2611 pList
= PtrBegDbList
= new DbList
;
2615 // Initialize new node in the linked list
2617 pList
->Free
= FALSE
;
2618 wxStrcpy(pList
->Dsn
, pDbStuff
->Dsn
);
2619 pList
->PtrDb
= new wxDB(pDbStuff
->Henv
,FwdOnlyCursors
);
2621 // Connect to the datasource
2622 if (pList
->PtrDb
->Open(pDbStuff
->Dsn
, pDbStuff
->Uid
, pDbStuff
->AuthStr
))
2624 pList
->PtrDb
->SqlLog(SQLLOGstate
,SQLLOGfn
,TRUE
);
2625 return(pList
->PtrDb
);
2627 else // Unable to connect, destroy list item
2630 pList
->PtrPrev
->PtrNext
= 0;
2632 PtrBegDbList
= 0; // Empty list again
2633 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDB object
2634 pList
->PtrDb
->Close(); // Close the wxDB object
2635 delete pList
->PtrDb
; // Deletes the wxDB object
2636 delete pList
; // Deletes the linked list object
2640 } // GetDbConnection()
2643 /********** FreeDbConnection() **********/
2644 bool WXDLLEXPORT
FreeDbConnection(wxDB
*pDb
)
2648 // Scan the linked list searching for the database connection
2649 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2651 if (pList
->PtrDb
== pDb
) // Found it!!!
2652 return(pList
->Free
= TRUE
);
2655 // Never found the database object, return failure
2658 } // FreeDbConnection()
2661 /********** CloseDbConnections() **********/
2662 void WXDLLEXPORT
CloseDbConnections(void)
2664 DbList
*pList
, *pNext
;
2666 // Traverse the linked list closing database connections and freeing memory as I go.
2667 for (pList
= PtrBegDbList
; pList
; pList
= pNext
)
2669 pNext
= pList
->PtrNext
; // Save the pointer to next
2670 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDB object
2671 pList
->PtrDb
->Close(); // Close the wxDB object
2672 delete pList
->PtrDb
; // Deletes the wxDB object
2673 delete pList
; // Deletes the linked list object
2676 // Mark the list as empty
2679 } // CloseDbConnections()
2682 /********** NumberDbConnectionsInUse() **********/
2683 int WXDLLEXPORT
NumberDbConnectionsInUse(void)
2688 // Scan the linked list counting db connections that are currently in use
2689 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2691 if (pList
->Free
== FALSE
)
2697 } // NumberDbConnectionsInUse()
2700 /********** SqlLog() **********/
2701 bool SqlLog(enum sqlLog state
, char *filename
)
2703 bool append
= FALSE
;
2706 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2708 if (!pList
->PtrDb
->SqlLog(state
,filename
,append
))
2713 SQLLOGstate
= state
;
2714 wxStrcpy(SQLLOGfn
,filename
);
2721 /********** GetDataSource() **********/
2722 bool GetDataSource(HENV henv
, char *Dsn
, SWORD DsnMax
, char *DsDesc
, SWORD DsDescMax
,
2725 * Dsn and DsDesc will contain the data source name and data source
2726 * description upon return
2731 if (SQLDataSources(henv
, direction
, (UCHAR FAR
*) Dsn
, DsnMax
, &cb1
,
2732 (UCHAR FAR
*) DsDesc
, DsDescMax
, &cb2
) == SQL_SUCCESS
)
2737 } // GetDataSource()