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"
39 // Use this line for wxWindows v1.x
41 // Use this line for wxWindows v2.x
42 #include "wx/version.h"
44 #if wxMAJOR_VERSION == 2
46 #pragma implementation "db.h"
50 #ifdef DBDEBUG_CONSOLE
51 #include "wx/ioswrap.h"
58 #if wxMAJOR_VERSION == 2
60 #include "wx/string.h"
61 #include "wx/object.h"
64 #include "wx/msgdlg.h"
67 #include "wx/filefn.h"
68 #include "wx/wxchar.h"
72 #if wxMAJOR_VERSION == 1
73 # if defined(wx_msw) || defined(wx_x)
91 #if wxMAJOR_VERSION == 1
93 #elif wxMAJOR_VERSION == 2
97 WXDLLEXPORT_DATA(wxDbList
*) PtrBegDbList
= 0;
100 char const *SQL_LOG_FILENAME
= "sqllog.txt";
101 char const *SQL_CATALOG_FILENAME
= "catalog.txt";
104 extern wxList TablesInUse
;
107 // SQL Log defaults to be used by GetDbConnection
108 wxDbSqlLogState SQLLOGstate
= sqlLogOFF
;
110 //char SQLLOGfn[wxDB_PATH_MAX+1] = SQL_LOG_FILENAME;
111 wxChar
*SQLLOGfn
= (wxChar
*) SQL_LOG_FILENAME
;
113 // The wxDb::errorList is copied to this variable when the wxDb object
114 // is closed. This way, the error list is still available after the
115 // database object is closed. This is necessary if the database
116 // connection fails so the calling application can show the operator
117 // why the connection failed. Note: as each wxDb object is closed, it
118 // will overwrite the errors of the previously destroyed wxDb object in
120 char DBerrorList
[DB_MAX_ERROR_HISTORY
][DB_MAX_ERROR_MSG_LEN
];
123 /********** wxDbColFor Constructor **********/
124 wxDbColFor::wxDbColFor()
126 i_Nation
= 0; // 0=EU, 1=UK, 2=International, 3=US
135 Format(1,DB_DATA_TYPE_VARCHAR
,0,0,0); // the Function that does the work
136 } // wxDbColFor::wxDbColFor()
139 wxDbColFor::~wxDbColFor()
141 } // wxDbColFor::~wxDbColFor()
144 int wxDbColFor::Format(int Nation
,int dbDataType
,SWORD sqlDataType
,short columnSize
,short decimalDigits
)
146 // ----------------------------------------------------------------------------------------
147 // -- 19991224 : mj10777@gmx.net : Create
148 // There is still a lot of work to do here, but it is a start
149 // It handles all the basic data-types that I have run into up to now
150 // The main work will have be with Dates and float Formatting (US 1,000.00 ; EU 1.000,00)
151 // There are wxWindow plans for locale support and the new wxDateTime.
152 // - if they define some constants (wxEUROPEAN) that can be gloably used,
153 // they should be used here.
154 // ----------------------------------------------------------------------------------------
155 // There should also be a Function to scan in a string to fill the variable
156 // ----------------------------------------------------------------------------------------
158 i_Nation
= Nation
; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
159 i_dbDataType
= dbDataType
;
160 i_sqlDataType
= sqlDataType
;
161 s_Field
.Printf(wxT("%s%d"),s_Menge
[1].c_str(),i_Menge
[1]); // OK for VARCHAR, INTEGER and FLOAT
162 if (i_dbDataType
== 0) // Filter unsupported dbDataTypes
164 if ((i_sqlDataType
== SQL_VARCHAR
) || (i_sqlDataType
== SQL_LONGVARCHAR
))
165 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
166 if (i_sqlDataType
== SQL_C_DATE
)
167 i_dbDataType
= DB_DATA_TYPE_DATE
;
168 if (i_sqlDataType
== SQL_C_BIT
)
169 i_dbDataType
= DB_DATA_TYPE_INTEGER
;
170 if (i_sqlDataType
== SQL_NUMERIC
)
171 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
172 if (i_sqlDataType
== SQL_REAL
)
173 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
175 if ((i_dbDataType
== DB_DATA_TYPE_INTEGER
) && (i_sqlDataType
== SQL_C_DOUBLE
))
177 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
179 switch(i_dbDataType
) // -A-> Still a lot of proper formatting to do
181 case DB_DATA_TYPE_VARCHAR
:
184 case DB_DATA_TYPE_INTEGER
:
187 case DB_DATA_TYPE_FLOAT
:
188 if (decimalDigits
== 0)
191 Temp0
.Printf(wxT("%s%d.%d"),Temp0
.c_str(),columnSize
,decimalDigits
);
192 s_Field
.Printf(wxT("%sf"),Temp0
.c_str()); //
194 case DB_DATA_TYPE_DATE
:
195 if (i_Nation
== 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
197 s_Field
= "%04d-%02d-%02d %02d:%02d:%02d.%03d";
199 if (i_Nation
== 1) // European DD.MM.YYYY HH:MM:SS.SSS
201 s_Field
= "%02d.%02d.%04d %02d:%02d:%02d.%03d";
203 if (i_Nation
== 2) // UK DD/MM/YYYY HH:MM:SS.SSS
205 s_Field
= "%02d/%02d/%04d %02d:%02d:%02d.%03d";
207 if (i_Nation
== 3) // International YYYY-MM-DD HH:MM:SS.SSS
209 s_Field
= "%04d-%02d-%02d %02d:%02d:%02d.%03d";
211 if (i_Nation
== 4) // US MM/DD/YYYY HH:MM:SS.SSS
213 s_Field
= "%02d/%02d/%04d %02d:%02d:%02d.%03d";
217 s_Field
.Printf(wxT("-E-> unknown Format(%d)-sql(%d)"),dbDataType
,sqlDataType
); //
221 } // wxDbColFor::Format()
224 /********** wxDb Constructor **********/
225 wxDb::wxDb(HENV
&aHenv
, bool FwdOnlyCursors
)
229 fpSqlLog
= 0; // Sql Log file pointer
230 sqlLogState
= sqlLogOFF
; // By default, logging is turned off
233 wxStrcpy(sqlState
,wxT(""));
234 wxStrcpy(errorMsg
,wxT(""));
235 nativeError
= cbErrorMsg
= 0;
236 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
237 wxStrcpy(errorList
[i
], wxT(""));
239 // Init typeInf structures
240 wxStrcpy(typeInfVarchar
.TypeName
,wxT(""));
241 typeInfVarchar
.FsqlType
= 0;
242 typeInfVarchar
.Precision
= 0;
243 typeInfVarchar
.CaseSensitive
= 0;
244 typeInfVarchar
.MaximumScale
= 0;
246 wxStrcpy(typeInfInteger
.TypeName
,wxT(""));
247 typeInfInteger
.FsqlType
= 0;
248 typeInfInteger
.Precision
= 0;
249 typeInfInteger
.CaseSensitive
= 0;
250 typeInfInteger
.MaximumScale
= 0;
252 wxStrcpy(typeInfFloat
.TypeName
,wxT(""));
253 typeInfFloat
.FsqlType
= 0;
254 typeInfFloat
.Precision
= 0;
255 typeInfFloat
.CaseSensitive
= 0;
256 typeInfFloat
.MaximumScale
= 0;
258 wxStrcpy(typeInfDate
.TypeName
,wxT(""));
259 typeInfDate
.FsqlType
= 0;
260 typeInfDate
.Precision
= 0;
261 typeInfDate
.CaseSensitive
= 0;
262 typeInfDate
.MaximumScale
= 0;
264 // Error reporting is turned OFF by default
267 // Copy the HENV into the db class
269 fwdOnlyCursors
= FwdOnlyCursors
;
271 // Allocate a data source connection handle
272 if (SQLAllocConnect(henv
, &hdbc
) != SQL_SUCCESS
)
275 // Initialize the db status flag
278 // Mark database as not open as of yet
284 /********** wxDb::Open() **********/
285 bool wxDb::Open(char *Dsn
, char *Uid
, char *AuthStr
)
287 assert(Dsn
&& wxStrlen(Dsn
));
294 if (!FwdOnlyCursors())
296 // Specify that the ODBC cursor library be used, if needed. This must be
297 // specified before the connection is made.
298 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
300 #ifdef DBDEBUG_CONSOLE
301 if (retcode
== SQL_SUCCESS
)
302 cout
<< "SQLSetConnectOption(CURSOR_LIB) successful" << endl
;
304 cout
<< "SQLSetConnectOption(CURSOR_LIB) failed" << endl
;
308 // Connect to the data source
309 retcode
= SQLConnect(hdbc
, (UCHAR FAR
*) Dsn
, SQL_NTS
,
310 (UCHAR FAR
*) Uid
, SQL_NTS
,
311 (UCHAR FAR
*) AuthStr
,SQL_NTS
);
313 if (retcode
== SQL_SUCCESS_WITH_INFO
)
314 DispAllErrors(henv
, hdbc
);
315 else if (retcode
!= SQL_SUCCESS
)
316 return(DispAllErrors(henv
, hdbc
));
319 If using Intersolv branded ODBC drivers, this is the place where you would substitute
320 your branded driver license information
322 SQLSetConnectOption(hdbc, 1041, (UDWORD) "");
323 SQLSetConnectOption(hdbc, 1042, (UDWORD) "");
326 // Mark database as open
329 // Allocate a statement handle for the database connection
330 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
331 return(DispAllErrors(henv
, hdbc
));
333 // Set Connection Options
334 if (! setConnectionOptions())
337 // Query the data source for inf. about itself
341 // Query the data source regarding data type information
344 // The way I determined which SQL data types to use was by calling SQLGetInfo
345 // for all of the possible SQL data types to see which ones were supported. If
346 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
347 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
348 // types I've selected below will not alway's be what we want. These are just
349 // what happened to work against an Oracle 7/Intersolv combination. The following is
350 // a complete list of the results I got back against the Oracle 7 database:
352 // SQL_BIGINT SQL_NO_DATA_FOUND
353 // SQL_BINARY SQL_NO_DATA_FOUND
354 // SQL_BIT SQL_NO_DATA_FOUND
355 // SQL_CHAR type name = 'CHAR', Precision = 255
356 // SQL_DATE SQL_NO_DATA_FOUND
357 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
358 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
359 // SQL_FLOAT SQL_NO_DATA_FOUND
360 // SQL_INTEGER SQL_NO_DATA_FOUND
361 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
362 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
363 // SQL_NUMERIC SQL_NO_DATA_FOUND
364 // SQL_REAL SQL_NO_DATA_FOUND
365 // SQL_SMALLINT SQL_NO_DATA_FOUND
366 // SQL_TIME SQL_NO_DATA_FOUND
367 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
368 // SQL_VARBINARY type name = 'RAW', Precision = 255
369 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
370 // =====================================================================
371 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
373 // SQL_VARCHAR type name = 'TEXT', Precision = 255
374 // SQL_TIMESTAMP type name = 'DATETIME'
375 // SQL_DECIMAL SQL_NO_DATA_FOUND
376 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
377 // SQL_FLOAT SQL_NO_DATA_FOUND
378 // SQL_REAL type name = 'SINGLE', Precision = 7
379 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
380 // SQL_INTEGER type name = 'LONG', Precision = 10
382 // VARCHAR = Variable length character string
383 if (! getDataTypeInfo(SQL_VARCHAR
, typeInfVarchar
))
384 if (! getDataTypeInfo(SQL_CHAR
, typeInfVarchar
))
387 typeInfVarchar
.FsqlType
= SQL_CHAR
;
389 typeInfVarchar
.FsqlType
= SQL_VARCHAR
;
392 if (! getDataTypeInfo(SQL_DOUBLE
, typeInfFloat
))
394 if (! getDataTypeInfo(SQL_REAL
, typeInfFloat
))
395 if (! getDataTypeInfo(SQL_FLOAT
, typeInfFloat
))
396 if (! getDataTypeInfo(SQL_DECIMAL
, typeInfFloat
))
397 if (! getDataTypeInfo(SQL_NUMERIC
, typeInfFloat
))
400 typeInfFloat
.FsqlType
= SQL_NUMERIC
;
402 typeInfFloat
.FsqlType
= SQL_DECIMAL
;
404 typeInfFloat
.FsqlType
= SQL_FLOAT
;
406 typeInfFloat
.FsqlType
= SQL_REAL
;
408 typeInfFloat
.FsqlType
= SQL_DOUBLE
;
412 if (! getDataTypeInfo(SQL_INTEGER
, typeInfInteger
))
413 // If SQL_INTEGER is not supported, use the floating point
414 // data type to store integers as well as floats
415 if (! getDataTypeInfo(typeInfFloat
.FsqlType
, typeInfInteger
))
418 typeInfInteger
.FsqlType
= typeInfFloat
.FsqlType
;
420 typeInfInteger
.FsqlType
= SQL_INTEGER
;
423 if (Dbms() != dbmsDBASE
)
425 if (! getDataTypeInfo(SQL_TIMESTAMP
, typeInfDate
))
428 typeInfDate
.FsqlType
= SQL_TIMESTAMP
;
432 if (! getDataTypeInfo(SQL_DATE
, typeInfDate
))
435 typeInfDate
.FsqlType
= SQL_DATE
;
438 #ifdef DBDEBUG_CONSOLE
439 cout
<< "VARCHAR DATA TYPE: " << typeInfVarchar
.TypeName
<< endl
;
440 cout
<< "INTEGER DATA TYPE: " << typeInfInteger
.TypeName
<< endl
;
441 cout
<< "FLOAT DATA TYPE: " << typeInfFloat
.TypeName
<< endl
;
442 cout
<< "DATE DATA TYPE: " << typeInfDate
.TypeName
<< endl
;
446 // Completed Successfully
452 /********** wxDb::setConnectionOptions() **********/
453 bool wxDb::setConnectionOptions(void)
455 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
458 SQLSetConnectOption(hdbc
, SQL_AUTOCOMMIT
, SQL_AUTOCOMMIT_OFF
);
459 SQLSetConnectOption(hdbc
, SQL_OPT_TRACE
, SQL_OPT_TRACE_OFF
);
461 // Display the connection options to verify them
462 #ifdef DBDEBUG_CONSOLE
464 cout
<< "****** CONNECTION OPTIONS ******" << endl
;
466 if (SQLGetConnectOption(hdbc
, SQL_AUTOCOMMIT
, &l
) != SQL_SUCCESS
)
467 return(DispAllErrors(henv
, hdbc
));
468 cout
<< "AUTOCOMMIT: " << (l
== SQL_AUTOCOMMIT_OFF
? "OFF" : "ON") << endl
;
470 if (SQLGetConnectOption(hdbc
, SQL_ODBC_CURSORS
, &l
) != SQL_SUCCESS
)
471 return(DispAllErrors(henv
, hdbc
));
472 cout
<< "ODBC CURSORS: ";
475 case(SQL_CUR_USE_IF_NEEDED
):
476 cout
<< "SQL_CUR_USE_IF_NEEDED";
478 case(SQL_CUR_USE_ODBC
):
479 cout
<< "SQL_CUR_USE_ODBC";
481 case(SQL_CUR_USE_DRIVER
):
482 cout
<< "SQL_CUR_USE_DRIVER";
487 if (SQLGetConnectOption(hdbc
, SQL_OPT_TRACE
, &l
) != SQL_SUCCESS
)
488 return(DispAllErrors(henv
, hdbc
));
489 cout
<< "TRACING: " << (l
== SQL_OPT_TRACE_OFF
? "OFF" : "ON") << endl
;
494 // Completed Successfully
497 } // wxDb::setConnectionOptions()
500 /********** wxDb::getDbInfo() **********/
501 bool wxDb::getDbInfo(void)
506 if (SQLGetInfo(hdbc
, SQL_SERVER_NAME
, (UCHAR
*) dbInf
.serverName
, 80, &cb
) != SQL_SUCCESS
)
507 return(DispAllErrors(henv
, hdbc
));
509 if (SQLGetInfo(hdbc
, SQL_DATABASE_NAME
, (UCHAR
*) dbInf
.databaseName
, 128, &cb
) != SQL_SUCCESS
)
510 return(DispAllErrors(henv
, hdbc
));
512 if (SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, 40, &cb
) != SQL_SUCCESS
)
513 return(DispAllErrors(henv
, hdbc
));
516 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
517 // causing database connectivity to fail in some cases.
518 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_VER
, (UCHAR
*) dbInf
.dbmsVer
, 64, &cb
);
520 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
521 return(DispAllErrors(henv
, hdbc
));
523 if (SQLGetInfo(hdbc
, SQL_ACTIVE_CONNECTIONS
, (UCHAR
*) &dbInf
.maxConnections
, sizeof(dbInf
.maxConnections
), &cb
) != SQL_SUCCESS
)
524 return(DispAllErrors(henv
, hdbc
));
526 if (SQLGetInfo(hdbc
, SQL_ACTIVE_STATEMENTS
, (UCHAR
*) &dbInf
.maxStmts
, sizeof(dbInf
.maxStmts
), &cb
) != SQL_SUCCESS
)
527 return(DispAllErrors(henv
, hdbc
));
529 if (SQLGetInfo(hdbc
, SQL_DRIVER_NAME
, (UCHAR
*) dbInf
.driverName
, 40, &cb
) != SQL_SUCCESS
)
530 return(DispAllErrors(henv
, hdbc
));
532 if (SQLGetInfo(hdbc
, SQL_DRIVER_ODBC_VER
, (UCHAR
*) dbInf
.odbcVer
, 60, &cb
) == SQL_ERROR
)
533 return(DispAllErrors(henv
, hdbc
));
535 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_VER
, (UCHAR
*) dbInf
.drvMgrOdbcVer
, 60, &cb
);
536 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
537 return(DispAllErrors(henv
, hdbc
));
539 if (SQLGetInfo(hdbc
, SQL_DRIVER_VER
, (UCHAR
*) dbInf
.driverVer
, 60, &cb
) == SQL_ERROR
)
540 return(DispAllErrors(henv
, hdbc
));
542 if (SQLGetInfo(hdbc
, SQL_ODBC_API_CONFORMANCE
, (UCHAR
*) &dbInf
.apiConfLvl
, sizeof(dbInf
.apiConfLvl
), &cb
) != SQL_SUCCESS
)
543 return(DispAllErrors(henv
, hdbc
));
545 if (SQLGetInfo(hdbc
, SQL_ODBC_SAG_CLI_CONFORMANCE
, (UCHAR
*) &dbInf
.cliConfLvl
, sizeof(dbInf
.cliConfLvl
), &cb
) != SQL_SUCCESS
)
546 return(DispAllErrors(henv
, hdbc
));
548 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_CONFORMANCE
, (UCHAR
*) &dbInf
.sqlConfLvl
, sizeof(dbInf
.sqlConfLvl
), &cb
) != SQL_SUCCESS
)
549 return(DispAllErrors(henv
, hdbc
));
551 if (SQLGetInfo(hdbc
, SQL_OUTER_JOINS
, (UCHAR
*) dbInf
.outerJoins
, 2, &cb
) != SQL_SUCCESS
)
552 return(DispAllErrors(henv
, hdbc
));
554 if (SQLGetInfo(hdbc
, SQL_PROCEDURES
, (UCHAR
*) dbInf
.procedureSupport
, 2, &cb
) != SQL_SUCCESS
)
555 return(DispAllErrors(henv
, hdbc
));
557 if (SQLGetInfo(hdbc
, SQL_CURSOR_COMMIT_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorCommitBehavior
, sizeof(dbInf
.cursorCommitBehavior
), &cb
) != SQL_SUCCESS
)
558 return(DispAllErrors(henv
, hdbc
));
560 if (SQLGetInfo(hdbc
, SQL_CURSOR_ROLLBACK_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorRollbackBehavior
, sizeof(dbInf
.cursorRollbackBehavior
), &cb
) != SQL_SUCCESS
)
561 return(DispAllErrors(henv
, hdbc
));
563 if (SQLGetInfo(hdbc
, SQL_NON_NULLABLE_COLUMNS
, (UCHAR
*) &dbInf
.supportNotNullClause
, sizeof(dbInf
.supportNotNullClause
), &cb
) != SQL_SUCCESS
)
564 return(DispAllErrors(henv
, hdbc
));
566 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_OPT_IEF
, (UCHAR
*) dbInf
.supportIEF
, 2, &cb
) != SQL_SUCCESS
)
567 return(DispAllErrors(henv
, hdbc
));
569 if (SQLGetInfo(hdbc
, SQL_DEFAULT_TXN_ISOLATION
, (UCHAR
*) &dbInf
.txnIsolation
, sizeof(dbInf
.txnIsolation
), &cb
) != SQL_SUCCESS
)
570 return(DispAllErrors(henv
, hdbc
));
572 if (SQLGetInfo(hdbc
, SQL_TXN_ISOLATION_OPTION
, (UCHAR
*) &dbInf
.txnIsolationOptions
, sizeof(dbInf
.txnIsolationOptions
), &cb
) != SQL_SUCCESS
)
573 return(DispAllErrors(henv
, hdbc
));
575 if (SQLGetInfo(hdbc
, SQL_FETCH_DIRECTION
, (UCHAR
*) &dbInf
.fetchDirections
, sizeof(dbInf
.fetchDirections
), &cb
) != SQL_SUCCESS
)
576 return(DispAllErrors(henv
, hdbc
));
578 if (SQLGetInfo(hdbc
, SQL_LOCK_TYPES
, (UCHAR
*) &dbInf
.lockTypes
, sizeof(dbInf
.lockTypes
), &cb
) != SQL_SUCCESS
)
579 return(DispAllErrors(henv
, hdbc
));
581 if (SQLGetInfo(hdbc
, SQL_POS_OPERATIONS
, (UCHAR
*) &dbInf
.posOperations
, sizeof(dbInf
.posOperations
), &cb
) != SQL_SUCCESS
)
582 return(DispAllErrors(henv
, hdbc
));
584 if (SQLGetInfo(hdbc
, SQL_POSITIONED_STATEMENTS
, (UCHAR
*) &dbInf
.posStmts
, sizeof(dbInf
.posStmts
), &cb
) != SQL_SUCCESS
)
585 return(DispAllErrors(henv
, hdbc
));
587 if (SQLGetInfo(hdbc
, SQL_SCROLL_CONCURRENCY
, (UCHAR
*) &dbInf
.scrollConcurrency
, sizeof(dbInf
.scrollConcurrency
), &cb
) != SQL_SUCCESS
)
588 return(DispAllErrors(henv
, hdbc
));
590 if (SQLGetInfo(hdbc
, SQL_SCROLL_OPTIONS
, (UCHAR
*) &dbInf
.scrollOptions
, sizeof(dbInf
.scrollOptions
), &cb
) != SQL_SUCCESS
)
591 return(DispAllErrors(henv
, hdbc
));
593 if (SQLGetInfo(hdbc
, SQL_STATIC_SENSITIVITY
, (UCHAR
*) &dbInf
.staticSensitivity
, sizeof(dbInf
.staticSensitivity
), &cb
) != SQL_SUCCESS
)
594 return(DispAllErrors(henv
, hdbc
));
596 if (SQLGetInfo(hdbc
, SQL_TXN_CAPABLE
, (UCHAR
*) &dbInf
.txnCapable
, sizeof(dbInf
.txnCapable
), &cb
) != SQL_SUCCESS
)
597 return(DispAllErrors(henv
, hdbc
));
599 if (SQLGetInfo(hdbc
, SQL_LOGIN_TIMEOUT
, (UCHAR
*) &dbInf
.loginTimeout
, sizeof(dbInf
.loginTimeout
), &cb
) != SQL_SUCCESS
)
600 return(DispAllErrors(henv
, hdbc
));
602 #ifdef DBDEBUG_CONSOLE
603 cout
<< "***** DATA SOURCE INFORMATION *****" << endl
;
604 cout
<< "SERVER Name: " << dbInf
.serverName
<< endl
;
605 cout
<< "DBMS Name: " << dbInf
.dbmsName
<< "; DBMS Version: " << dbInf
.dbmsVer
<< endl
;
606 cout
<< "ODBC Version: " << dbInf
.odbcVer
<< "; Driver Version: " << dbInf
.driverVer
<< endl
;
608 cout
<< "API Conf. Level: ";
609 switch(dbInf
.apiConfLvl
)
611 case SQL_OAC_NONE
: cout
<< "None"; break;
612 case SQL_OAC_LEVEL1
: cout
<< "Level 1"; break;
613 case SQL_OAC_LEVEL2
: cout
<< "Level 2"; break;
617 cout
<< "SAG CLI Conf. Level: ";
618 switch(dbInf
.cliConfLvl
)
620 case SQL_OSCC_NOT_COMPLIANT
: cout
<< "Not Compliant"; break;
621 case SQL_OSCC_COMPLIANT
: cout
<< "Compliant"; break;
625 cout
<< "SQL Conf. Level: ";
626 switch(dbInf
.sqlConfLvl
)
628 case SQL_OSC_MINIMUM
: cout
<< "Minimum Grammer"; break;
629 case SQL_OSC_CORE
: cout
<< "Core Grammer"; break;
630 case SQL_OSC_EXTENDED
: cout
<< "Extended Grammer"; break;
634 cout
<< "Max. Connections: " << dbInf
.maxConnections
<< endl
;
635 cout
<< "Outer Joins: " << dbInf
.outerJoins
<< endl
;
636 cout
<< "Support for Procedures: " << dbInf
.procedureSupport
<< endl
;
638 cout
<< "Cursor COMMIT Behavior: ";
639 switch(dbInf
.cursorCommitBehavior
)
641 case SQL_CB_DELETE
: cout
<< "Delete cursors"; break;
642 case SQL_CB_CLOSE
: cout
<< "Close cursors"; break;
643 case SQL_CB_PRESERVE
: cout
<< "Preserve cursors"; break;
647 cout
<< "Cursor ROLLBACK Behavior: ";
648 switch(dbInf
.cursorRollbackBehavior
)
650 case SQL_CB_DELETE
: cout
<< "Delete cursors"; break;
651 case SQL_CB_CLOSE
: cout
<< "Close cursors"; break;
652 case SQL_CB_PRESERVE
: cout
<< "Preserve cursors"; break;
656 cout
<< "Support NOT NULL clause: ";
657 switch(dbInf
.supportNotNullClause
)
659 case SQL_NNC_NULL
: cout
<< "No"; break;
660 case SQL_NNC_NON_NULL
: cout
<< "Yes"; break;
664 cout
<< "Support IEF (Ref. Integrity): " << dbInf
.supportIEF
<< endl
;
665 cout
<< "Login Timeout: " << dbInf
.loginTimeout
<< endl
;
667 cout
<< endl
<< endl
<< "more ..." << endl
;
670 cout
<< "Default Transaction Isolation: ";
671 switch(dbInf
.txnIsolation
)
673 case SQL_TXN_READ_UNCOMMITTED
: cout
<< "Read Uncommitted"; break;
674 case SQL_TXN_READ_COMMITTED
: cout
<< "Read Committed"; break;
675 case SQL_TXN_REPEATABLE_READ
: cout
<< "Repeatable Read"; break;
676 case SQL_TXN_SERIALIZABLE
: cout
<< "Serializable"; break;
678 case SQL_TXN_VERSIONING
: cout
<< "Versioning"; break;
683 cout
<< "Transaction Isolation Options: ";
684 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_UNCOMMITTED
)
685 cout
<< "Read Uncommitted, ";
686 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_COMMITTED
)
687 cout
<< "Read Committed, ";
688 if (dbInf
.txnIsolationOptions
& SQL_TXN_REPEATABLE_READ
)
689 cout
<< "Repeatable Read, ";
690 if (dbInf
.txnIsolationOptions
& SQL_TXN_SERIALIZABLE
)
691 cout
<< "Serializable, ";
693 if (dbInf
.txnIsolationOptions
& SQL_TXN_VERSIONING
)
694 cout
<< "Versioning";
698 cout
<< "Fetch Directions Supported:" << endl
<< " ";
699 if (dbInf
.fetchDirections
& SQL_FD_FETCH_NEXT
)
701 if (dbInf
.fetchDirections
& SQL_FD_FETCH_PRIOR
)
703 if (dbInf
.fetchDirections
& SQL_FD_FETCH_FIRST
)
705 if (dbInf
.fetchDirections
& SQL_FD_FETCH_LAST
)
707 if (dbInf
.fetchDirections
& SQL_FD_FETCH_ABSOLUTE
)
708 cout
<< "Absolute, ";
709 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RELATIVE
)
710 cout
<< "Relative, ";
712 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RESUME
)
715 if (dbInf
.fetchDirections
& SQL_FD_FETCH_BOOKMARK
)
719 cout
<< "Lock Types Supported (SQLSetPos): ";
720 if (dbInf
.lockTypes
& SQL_LCK_NO_CHANGE
)
721 cout
<< "No Change, ";
722 if (dbInf
.lockTypes
& SQL_LCK_EXCLUSIVE
)
723 cout
<< "Exclusive, ";
724 if (dbInf
.lockTypes
& SQL_LCK_UNLOCK
)
728 cout
<< "Position Operations Supported (SQLSetPos): ";
729 if (dbInf
.posOperations
& SQL_POS_POSITION
)
730 cout
<< "Position, ";
731 if (dbInf
.posOperations
& SQL_POS_REFRESH
)
733 if (dbInf
.posOperations
& SQL_POS_UPDATE
)
735 if (dbInf
.posOperations
& SQL_POS_DELETE
)
737 if (dbInf
.posOperations
& SQL_POS_ADD
)
741 cout
<< "Positioned Statements Supported: ";
742 if (dbInf
.posStmts
& SQL_PS_POSITIONED_DELETE
)
743 cout
<< "Pos delete, ";
744 if (dbInf
.posStmts
& SQL_PS_POSITIONED_UPDATE
)
745 cout
<< "Pos update, ";
746 if (dbInf
.posStmts
& SQL_PS_SELECT_FOR_UPDATE
)
747 cout
<< "Select for update";
750 cout
<< "Scroll Concurrency: ";
751 if (dbInf
.scrollConcurrency
& SQL_SCCO_READ_ONLY
)
752 cout
<< "Read Only, ";
753 if (dbInf
.scrollConcurrency
& SQL_SCCO_LOCK
)
755 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_ROWVER
)
756 cout
<< "Opt. Rowver, ";
757 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_VALUES
)
758 cout
<< "Opt. Values";
761 cout
<< "Scroll Options: ";
762 if (dbInf
.scrollOptions
& SQL_SO_FORWARD_ONLY
)
763 cout
<< "Fwd Only, ";
764 if (dbInf
.scrollOptions
& SQL_SO_STATIC
)
766 if (dbInf
.scrollOptions
& SQL_SO_KEYSET_DRIVEN
)
767 cout
<< "Keyset Driven, ";
768 if (dbInf
.scrollOptions
& SQL_SO_DYNAMIC
)
770 if (dbInf
.scrollOptions
& SQL_SO_MIXED
)
774 cout
<< "Static Sensitivity: ";
775 if (dbInf
.staticSensitivity
& SQL_SS_ADDITIONS
)
776 cout
<< "Additions, ";
777 if (dbInf
.staticSensitivity
& SQL_SS_DELETIONS
)
778 cout
<< "Deletions, ";
779 if (dbInf
.staticSensitivity
& SQL_SS_UPDATES
)
783 cout
<< "Transaction Capable?: ";
784 switch(dbInf
.txnCapable
)
786 case SQL_TC_NONE
: cout
<< "No"; break;
787 case SQL_TC_DML
: cout
<< "DML Only"; break;
788 case SQL_TC_DDL_COMMIT
: cout
<< "DDL Commit"; break;
789 case SQL_TC_DDL_IGNORE
: cout
<< "DDL Ignore"; break;
790 case SQL_TC_ALL
: cout
<< "DDL & DML"; break;
797 // Completed Successfully
800 } // wxDb::getDbInfo()
803 /********** wxDb::getDataTypeInfo() **********/
804 bool wxDb::getDataTypeInfo(SWORD fSqlType
, wxDbSqlTypeInfo
&structSQLTypeInfo
)
807 * fSqlType will be something like SQL_VARCHAR. This parameter determines
808 * the data type inf. is gathered for.
810 * wxDbSqlTypeInfo is a structure that is filled in with data type information,
815 // Get information about the data type specified
816 if (SQLGetTypeInfo(hstmt
, fSqlType
) != SQL_SUCCESS
)
817 return(DispAllErrors(henv
, hdbc
, hstmt
));
819 if ((retcode
= SQLFetch(hstmt
)) != SQL_SUCCESS
)
821 #ifdef DBDEBUG_CONSOLE
822 if (retcode
== SQL_NO_DATA_FOUND
)
823 cout
<< "SQL_NO_DATA_FOUND fetching inf. about data type." << endl
;
825 DispAllErrors(henv
, hdbc
, hstmt
);
826 SQLFreeStmt(hstmt
, SQL_CLOSE
);
829 // Obtain columns from the record
830 if (SQLGetData(hstmt
, 1, SQL_C_CHAR
, (UCHAR
*) structSQLTypeInfo
.TypeName
, DB_TYPE_NAME_LEN
, &cbRet
) != SQL_SUCCESS
)
831 return(DispAllErrors(henv
, hdbc
, hstmt
));
834 // BJO 20000503: no more needed with new GetColumns...
837 if (Dbms() == dbmsMY_SQL
)
839 if (!wxStrcmp(structSQLTypeInfo
.TypeName
, "middleint")) wxStrcpy(structSQLTypeInfo
.TypeName
, "mediumint");
840 if (!wxStrcmp(structSQLTypeInfo
.TypeName
, "middleint unsigned")) wxStrcpy(structSQLTypeInfo
.TypeName
, "mediumint unsigned");
841 if (!wxStrcmp(structSQLTypeInfo
.TypeName
, "integer")) wxStrcpy(structSQLTypeInfo
.TypeName
, "int");
842 if (!wxStrcmp(structSQLTypeInfo
.TypeName
, "integer unsigned")) wxStrcpy(structSQLTypeInfo
.TypeName
, "int unsigned");
843 if (!wxStrcmp(structSQLTypeInfo
.TypeName
, "middleint")) wxStrcpy(structSQLTypeInfo
.TypeName
, "mediumint");
844 if (!wxStrcmp(structSQLTypeInfo
.TypeName
, "varchar")) wxStrcpy(structSQLTypeInfo
.TypeName
, "char");
847 // BJO 20000427 : OpenLink driver
848 if (!wxStrncmp(dbInf
.driverName
, "oplodbc", 7) ||
849 !wxStrncmp(dbInf
.driverName
, "OLOD", 4))
850 if (!wxStrcmp(structSQLTypeInfo
.TypeName
, "double precision")) wxStrcpy(structSQLTypeInfo
.TypeName
, "real");
853 if (SQLGetData(hstmt
, 3, SQL_C_LONG
, (UCHAR
*) &structSQLTypeInfo
.Precision
, 0, &cbRet
) != SQL_SUCCESS
)
854 return(DispAllErrors(henv
, hdbc
, hstmt
));
855 if (SQLGetData(hstmt
, 8, SQL_C_SHORT
, (UCHAR
*) &structSQLTypeInfo
.CaseSensitive
, 0, &cbRet
) != SQL_SUCCESS
)
856 return(DispAllErrors(henv
, hdbc
, hstmt
));
857 // if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
858 // return(DispAllErrors(henv, hdbc, hstmt));
860 if (SQLGetData(hstmt
, 15, SQL_C_SHORT
,(UCHAR
*) &structSQLTypeInfo
.MaximumScale
, 0, &cbRet
) != SQL_SUCCESS
)
861 return(DispAllErrors(henv
, hdbc
, hstmt
));
863 if (structSQLTypeInfo
.MaximumScale
< 0)
864 structSQLTypeInfo
.MaximumScale
= 0;
866 // Close the statement handle which closes open cursors
867 if (SQLFreeStmt(hstmt
, SQL_CLOSE
) != SQL_SUCCESS
)
868 return(DispAllErrors(henv
, hdbc
, hstmt
));
870 // Completed Successfully
873 } // wxDb::getDataTypeInfo()
876 /********** wxDb::Close() **********/
877 void wxDb::Close(void)
879 // Close the Sql Log file
886 // Free statement handle
889 if (SQLFreeStmt(hstmt
, SQL_DROP
) != SQL_SUCCESS
)
890 DispAllErrors(henv
, hdbc
);
893 // Disconnect from the datasource
894 if (SQLDisconnect(hdbc
) != SQL_SUCCESS
)
895 DispAllErrors(henv
, hdbc
);
897 // Free the connection to the datasource
898 if (SQLFreeConnect(hdbc
) != SQL_SUCCESS
)
899 DispAllErrors(henv
, hdbc
);
901 // There should be zero Ctable objects still connected to this db object
902 assert(nTables
== 0);
907 pNode
= TablesInUse
.First();
911 tiu
= (wxTablesInUse
*)pNode
->Data();
912 if (tiu
->pDb
== this)
914 s
.sprintf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu
->tableName
,tiu
->tableID
,tiu
->pDb
);
915 s2
.sprintf(wxT("Orphaned found using pDb:[%p]"),this);
916 wxLogDebug (s
.c_str(),s2
.c_str());
918 pNode
= pNode
->Next();
922 // Copy the error messages to a global variable
924 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
925 wxStrcpy(DBerrorList
[i
],errorList
[i
]);
930 /********** wxDb::CommitTrans() **********/
931 bool wxDb::CommitTrans(void)
935 // Commit the transaction
936 if (SQLTransact(henv
, hdbc
, SQL_COMMIT
) != SQL_SUCCESS
)
937 return(DispAllErrors(henv
, hdbc
));
940 // Completed successfully
943 } // wxDb::CommitTrans()
946 /********** wxDb::RollbackTrans() **********/
947 bool wxDb::RollbackTrans(void)
949 // Rollback the transaction
950 if (SQLTransact(henv
, hdbc
, SQL_ROLLBACK
) != SQL_SUCCESS
)
951 return(DispAllErrors(henv
, hdbc
));
953 // Completed successfully
956 } // wxDb::RollbackTrans()
959 /********** wxDb::DispAllErrors() **********/
960 bool wxDb::DispAllErrors(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
962 // char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
965 while (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
967 odbcErrMsg
.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState
, nativeError
, errorMsg
);
968 logError(odbcErrMsg
.c_str(), sqlState
);
971 #ifdef DBDEBUG_CONSOLE
972 // When run in console mode, use standard out to display errors.
973 cout
<< odbcErrMsg
.c_str() << endl
;
974 cout
<< "Press any key to continue..." << endl
;
979 wxLogDebug(odbcErrMsg
.c_str(),wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
984 return(FALSE
); // This function always returns false.
986 } // wxDb::DispAllErrors()
989 /********** wxDb::GetNextError() **********/
990 bool wxDb::GetNextError(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
992 if (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
997 } // wxDb::GetNextError()
1000 /********** wxDb::DispNextError() **********/
1001 void wxDb::DispNextError(void)
1003 // char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
1004 wxString odbcErrMsg
;
1006 odbcErrMsg
.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState
, nativeError
, errorMsg
);
1007 logError(odbcErrMsg
.c_str(), sqlState
);
1012 #ifdef DBDEBUG_CONSOLE
1013 // When run in console mode, use standard out to display errors.
1014 cout
<< odbcErrMsg
.c_str() << endl
;
1015 cout
<< "Press any key to continue..." << endl
;
1020 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE"));
1021 #endif // __WXDEBUG__
1024 } // wxDb::DispNextError()
1027 /********** wxDb::logError() **********/
1028 void wxDb::logError(const char *errMsg
, const char *SQLState
)
1030 assert(errMsg
&& wxStrlen(errMsg
));
1032 static int pLast
= -1;
1035 if (++pLast
== DB_MAX_ERROR_HISTORY
)
1038 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1039 wxStrcpy(errorList
[i
], errorList
[i
+1]);
1043 wxStrcpy(errorList
[pLast
], errMsg
);
1045 if (SQLState
&& wxStrlen(SQLState
))
1046 if ((dbStatus
= TranslateSqlState(SQLState
)) != DB_ERR_FUNCTION_SEQUENCE_ERROR
)
1047 DB_STATUS
= dbStatus
;
1049 // Add the errmsg to the sql log
1050 WriteSqlLog(errMsg
);
1052 } // wxDb::logError()
1055 /**********wxDb::TranslateSqlState() **********/
1056 int wxDb::TranslateSqlState(const wxChar
*SQLState
)
1058 if (!wxStrcmp(SQLState
, wxT("01000")))
1059 return(DB_ERR_GENERAL_WARNING
);
1060 if (!wxStrcmp(SQLState
, wxT("01002")))
1061 return(DB_ERR_DISCONNECT_ERROR
);
1062 if (!wxStrcmp(SQLState
, wxT("01004")))
1063 return(DB_ERR_DATA_TRUNCATED
);
1064 if (!wxStrcmp(SQLState
, wxT("01006")))
1065 return(DB_ERR_PRIV_NOT_REVOKED
);
1066 if (!wxStrcmp(SQLState
, wxT("01S00")))
1067 return(DB_ERR_INVALID_CONN_STR_ATTR
);
1068 if (!wxStrcmp(SQLState
, wxT("01S01")))
1069 return(DB_ERR_ERROR_IN_ROW
);
1070 if (!wxStrcmp(SQLState
, wxT("01S02")))
1071 return(DB_ERR_OPTION_VALUE_CHANGED
);
1072 if (!wxStrcmp(SQLState
, wxT("01S03")))
1073 return(DB_ERR_NO_ROWS_UPD_OR_DEL
);
1074 if (!wxStrcmp(SQLState
, wxT("01S04")))
1075 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL
);
1076 if (!wxStrcmp(SQLState
, wxT("07001")))
1077 return(DB_ERR_WRONG_NO_OF_PARAMS
);
1078 if (!wxStrcmp(SQLState
, wxT("07006")))
1079 return(DB_ERR_DATA_TYPE_ATTR_VIOL
);
1080 if (!wxStrcmp(SQLState
, wxT("08001")))
1081 return(DB_ERR_UNABLE_TO_CONNECT
);
1082 if (!wxStrcmp(SQLState
, wxT("08002")))
1083 return(DB_ERR_CONNECTION_IN_USE
);
1084 if (!wxStrcmp(SQLState
, wxT("08003")))
1085 return(DB_ERR_CONNECTION_NOT_OPEN
);
1086 if (!wxStrcmp(SQLState
, wxT("08004")))
1087 return(DB_ERR_REJECTED_CONNECTION
);
1088 if (!wxStrcmp(SQLState
, wxT("08007")))
1089 return(DB_ERR_CONN_FAIL_IN_TRANS
);
1090 if (!wxStrcmp(SQLState
, wxT("08S01")))
1091 return(DB_ERR_COMM_LINK_FAILURE
);
1092 if (!wxStrcmp(SQLState
, wxT("21S01")))
1093 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH
);
1094 if (!wxStrcmp(SQLState
, wxT("21S02")))
1095 return(DB_ERR_DERIVED_TABLE_MISMATCH
);
1096 if (!wxStrcmp(SQLState
, wxT("22001")))
1097 return(DB_ERR_STRING_RIGHT_TRUNC
);
1098 if (!wxStrcmp(SQLState
, wxT("22003")))
1099 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG
);
1100 if (!wxStrcmp(SQLState
, wxT("22005")))
1101 return(DB_ERR_ERROR_IN_ASSIGNMENT
);
1102 if (!wxStrcmp(SQLState
, wxT("22008")))
1103 return(DB_ERR_DATETIME_FLD_OVERFLOW
);
1104 if (!wxStrcmp(SQLState
, wxT("22012")))
1105 return(DB_ERR_DIVIDE_BY_ZERO
);
1106 if (!wxStrcmp(SQLState
, wxT("22026")))
1107 return(DB_ERR_STR_DATA_LENGTH_MISMATCH
);
1108 if (!wxStrcmp(SQLState
, wxT("23000")))
1109 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL
);
1110 if (!wxStrcmp(SQLState
, wxT("24000")))
1111 return(DB_ERR_INVALID_CURSOR_STATE
);
1112 if (!wxStrcmp(SQLState
, wxT("25000")))
1113 return(DB_ERR_INVALID_TRANS_STATE
);
1114 if (!wxStrcmp(SQLState
, wxT("28000")))
1115 return(DB_ERR_INVALID_AUTH_SPEC
);
1116 if (!wxStrcmp(SQLState
, wxT("34000")))
1117 return(DB_ERR_INVALID_CURSOR_NAME
);
1118 if (!wxStrcmp(SQLState
, wxT("37000")))
1119 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL
);
1120 if (!wxStrcmp(SQLState
, wxT("3C000")))
1121 return(DB_ERR_DUPLICATE_CURSOR_NAME
);
1122 if (!wxStrcmp(SQLState
, wxT("40001")))
1123 return(DB_ERR_SERIALIZATION_FAILURE
);
1124 if (!wxStrcmp(SQLState
, wxT("42000")))
1125 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2
);
1126 if (!wxStrcmp(SQLState
, wxT("70100")))
1127 return(DB_ERR_OPERATION_ABORTED
);
1128 if (!wxStrcmp(SQLState
, wxT("IM001")))
1129 return(DB_ERR_UNSUPPORTED_FUNCTION
);
1130 if (!wxStrcmp(SQLState
, wxT("IM002")))
1131 return(DB_ERR_NO_DATA_SOURCE
);
1132 if (!wxStrcmp(SQLState
, wxT("IM003")))
1133 return(DB_ERR_DRIVER_LOAD_ERROR
);
1134 if (!wxStrcmp(SQLState
, wxT("IM004")))
1135 return(DB_ERR_SQLALLOCENV_FAILED
);
1136 if (!wxStrcmp(SQLState
, wxT("IM005")))
1137 return(DB_ERR_SQLALLOCCONNECT_FAILED
);
1138 if (!wxStrcmp(SQLState
, wxT("IM006")))
1139 return(DB_ERR_SQLSETCONNECTOPTION_FAILED
);
1140 if (!wxStrcmp(SQLState
, wxT("IM007")))
1141 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB
);
1142 if (!wxStrcmp(SQLState
, wxT("IM008")))
1143 return(DB_ERR_DIALOG_FAILED
);
1144 if (!wxStrcmp(SQLState
, wxT("IM009")))
1145 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL
);
1146 if (!wxStrcmp(SQLState
, wxT("IM010")))
1147 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG
);
1148 if (!wxStrcmp(SQLState
, wxT("IM011")))
1149 return(DB_ERR_DRIVER_NAME_TOO_LONG
);
1150 if (!wxStrcmp(SQLState
, wxT("IM012")))
1151 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR
);
1152 if (!wxStrcmp(SQLState
, wxT("IM013")))
1153 return(DB_ERR_TRACE_FILE_ERROR
);
1154 if (!wxStrcmp(SQLState
, wxT("S0001")))
1155 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS
);
1156 if (!wxStrcmp(SQLState
, wxT("S0002")))
1157 return(DB_ERR_TABLE_NOT_FOUND
);
1158 if (!wxStrcmp(SQLState
, wxT("S0011")))
1159 return(DB_ERR_INDEX_ALREADY_EXISTS
);
1160 if (!wxStrcmp(SQLState
, wxT("S0012")))
1161 return(DB_ERR_INDEX_NOT_FOUND
);
1162 if (!wxStrcmp(SQLState
, wxT("S0021")))
1163 return(DB_ERR_COLUMN_ALREADY_EXISTS
);
1164 if (!wxStrcmp(SQLState
, wxT("S0022")))
1165 return(DB_ERR_COLUMN_NOT_FOUND
);
1166 if (!wxStrcmp(SQLState
, wxT("S0023")))
1167 return(DB_ERR_NO_DEFAULT_FOR_COLUMN
);
1168 if (!wxStrcmp(SQLState
, wxT("S1000")))
1169 return(DB_ERR_GENERAL_ERROR
);
1170 if (!wxStrcmp(SQLState
, wxT("S1001")))
1171 return(DB_ERR_MEMORY_ALLOCATION_FAILURE
);
1172 if (!wxStrcmp(SQLState
, wxT("S1002")))
1173 return(DB_ERR_INVALID_COLUMN_NUMBER
);
1174 if (!wxStrcmp(SQLState
, wxT("S1003")))
1175 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE
);
1176 if (!wxStrcmp(SQLState
, wxT("S1004")))
1177 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE
);
1178 if (!wxStrcmp(SQLState
, wxT("S1008")))
1179 return(DB_ERR_OPERATION_CANCELLED
);
1180 if (!wxStrcmp(SQLState
, wxT("S1009")))
1181 return(DB_ERR_INVALID_ARGUMENT_VALUE
);
1182 if (!wxStrcmp(SQLState
, wxT("S1010")))
1183 return(DB_ERR_FUNCTION_SEQUENCE_ERROR
);
1184 if (!wxStrcmp(SQLState
, wxT("S1011")))
1185 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME
);
1186 if (!wxStrcmp(SQLState
, wxT("S1012")))
1187 return(DB_ERR_INVALID_TRANS_OPERATION_CODE
);
1188 if (!wxStrcmp(SQLState
, wxT("S1015")))
1189 return(DB_ERR_NO_CURSOR_NAME_AVAIL
);
1190 if (!wxStrcmp(SQLState
, wxT("S1090")))
1191 return(DB_ERR_INVALID_STR_OR_BUF_LEN
);
1192 if (!wxStrcmp(SQLState
, wxT("S1091")))
1193 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE
);
1194 if (!wxStrcmp(SQLState
, wxT("S1092")))
1195 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE
);
1196 if (!wxStrcmp(SQLState
, wxT("S1093")))
1197 return(DB_ERR_INVALID_PARAM_NO
);
1198 if (!wxStrcmp(SQLState
, wxT("S1094")))
1199 return(DB_ERR_INVALID_SCALE_VALUE
);
1200 if (!wxStrcmp(SQLState
, wxT("S1095")))
1201 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE
);
1202 if (!wxStrcmp(SQLState
, wxT("S1096")))
1203 return(DB_ERR_INF_TYPE_OUT_OF_RANGE
);
1204 if (!wxStrcmp(SQLState
, wxT("S1097")))
1205 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE
);
1206 if (!wxStrcmp(SQLState
, wxT("S1098")))
1207 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE
);
1208 if (!wxStrcmp(SQLState
, wxT("S1099")))
1209 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE
);
1210 if (!wxStrcmp(SQLState
, wxT("S1100")))
1211 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE
);
1212 if (!wxStrcmp(SQLState
, wxT("S1101")))
1213 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE
);
1214 if (!wxStrcmp(SQLState
, wxT("S1103")))
1215 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE
);
1216 if (!wxStrcmp(SQLState
, wxT("S1104")))
1217 return(DB_ERR_INVALID_PRECISION_VALUE
);
1218 if (!wxStrcmp(SQLState
, wxT("S1105")))
1219 return(DB_ERR_INVALID_PARAM_TYPE
);
1220 if (!wxStrcmp(SQLState
, wxT("S1106")))
1221 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE
);
1222 if (!wxStrcmp(SQLState
, wxT("S1107")))
1223 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE
);
1224 if (!wxStrcmp(SQLState
, wxT("S1108")))
1225 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE
);
1226 if (!wxStrcmp(SQLState
, wxT("S1109")))
1227 return(DB_ERR_INVALID_CURSOR_POSITION
);
1228 if (!wxStrcmp(SQLState
, wxT("S1110")))
1229 return(DB_ERR_INVALID_DRIVER_COMPLETION
);
1230 if (!wxStrcmp(SQLState
, wxT("S1111")))
1231 return(DB_ERR_INVALID_BOOKMARK_VALUE
);
1232 if (!wxStrcmp(SQLState
, wxT("S1C00")))
1233 return(DB_ERR_DRIVER_NOT_CAPABLE
);
1234 if (!wxStrcmp(SQLState
, wxT("S1T00")))
1235 return(DB_ERR_TIMEOUT_EXPIRED
);
1240 } // wxDb::TranslateSqlState()
1243 /********** wxDb::Grant() **********/
1244 bool wxDb::Grant(int privileges
, const char *tableName
, const char *userList
)
1246 // char sqlStmt[DB_MAX_STATEMENT_LEN];
1249 // Build the grant statement
1251 if (privileges
== DB_GRANT_ALL
)
1256 if (privileges
& DB_GRANT_SELECT
)
1258 sqlStmt
+= "SELECT";
1261 if (privileges
& DB_GRANT_INSERT
)
1265 sqlStmt
+= "INSERT";
1267 if (privileges
& DB_GRANT_UPDATE
)
1271 sqlStmt
+= "UPDATE";
1273 if (privileges
& DB_GRANT_DELETE
)
1277 sqlStmt
+= "DELETE";
1282 sqlStmt
+= tableName
;
1284 sqlStmt
+= userList
;
1286 #ifdef DBDEBUG_CONSOLE
1287 cout
<< endl
<< sqlStmt
.c_str() << endl
;
1290 WriteSqlLog(sqlStmt
.c_str());
1292 return(ExecSql(sqlStmt
.c_str()));
1297 /********** wxDb::CreateView() **********/
1298 bool wxDb::CreateView(const char *viewName
, const char *colList
, const char *pSqlStmt
, bool attemptDrop
)
1300 // char sqlStmt[DB_MAX_STATEMENT_LEN];
1303 // Drop the view first
1304 if (attemptDrop
&& !DropView(viewName
))
1307 // Build the create view statement
1308 sqlStmt
= "CREATE VIEW ";
1309 sqlStmt
+= viewName
;
1311 if (wxStrlen(colList
))
1319 sqlStmt
+= pSqlStmt
;
1321 WriteSqlLog(sqlStmt
.c_str());
1323 #ifdef DBDEBUG_CONSOLE
1324 cout
<< sqlStmt
.c_str() << endl
;
1327 return(ExecSql(sqlStmt
.c_str()));
1329 } // wxDb::CreateView()
1332 /********** wxDb::DropView() **********/
1333 bool wxDb::DropView(const char *viewName
)
1336 * NOTE: This function returns TRUE if the View does not exist, but
1337 * only for identified databases. Code will need to be added
1338 * below for any other databases when those databases are defined
1339 * to handle this situation consistently
1341 // char sqlStmt[DB_MAX_STATEMENT_LEN];
1344 sqlStmt
.sprintf("DROP VIEW %s", viewName
);
1346 WriteSqlLog(sqlStmt
.c_str());
1348 #ifdef DBDEBUG_CONSOLE
1349 cout
<< endl
<< sqlStmt
.c_str() << endl
;
1352 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
1354 // Check for "Base table not found" error and ignore
1355 GetNextError(henv
, hdbc
, hstmt
);
1356 if (wxStrcmp(sqlState
,wxT("S0002"))) // "Base table not found"
1358 // Check for product specific error codes
1359 if (!((Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(sqlState
,wxT("42000"))))) // 5.x (and lower?)
1362 DispAllErrors(henv
, hdbc
, hstmt
);
1369 // Commit the transaction
1370 if (! CommitTrans())
1375 } // wxDb::DropView()
1378 /********** wxDb::ExecSql() **********/
1379 bool wxDb::ExecSql(const char *pSqlStmt
)
1381 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1382 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) pSqlStmt
, SQL_NTS
) == SQL_SUCCESS
)
1386 DispAllErrors(henv
, hdbc
, hstmt
);
1390 } // wxDb::ExecSql()
1393 /********** wxDb::GetNext() **********/
1394 bool wxDb::GetNext(void)
1396 if (SQLFetch(hstmt
) == SQL_SUCCESS
)
1400 DispAllErrors(henv
, hdbc
, hstmt
);
1404 } // wxDb::GetNext()
1407 /********** wxDb::GetData() **********/
1408 bool wxDb::GetData(UWORD colNo
, SWORD cType
, PTR pData
, SDWORD maxLen
, SDWORD FAR
*cbReturned
)
1413 if (SQLGetData(hstmt
, colNo
, cType
, pData
, maxLen
, cbReturned
) == SQL_SUCCESS
)
1417 DispAllErrors(henv
, hdbc
, hstmt
);
1421 } // wxDb::GetData()
1424 /********** wxDb::GetKeyFields() **********/
1425 int wxDb::GetKeyFields(char *tableName
, wxDbColInf
* colInf
, int noCols
)
1427 char szPkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Primary key table name */
1428 char szFkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Foreign key table name */
1430 // SQLSMALLINT iKeySeq;
1431 char szPkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Primary key column */
1432 char szFkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Foreign key column */
1438 * ---------------------------------------------------------------------
1439 * -- 19991224 : mj10777@gmx.net : Create ------
1440 * -- : Three things are done and stored here : ------
1441 * -- : 1) which Column(s) is/are Primary Key(s) ------
1442 * -- : 2) which tables use this Key as a Foreign Key ------
1443 * -- : 3) which columns are Foreign Key and the name ------
1444 * -- : of the Table where the Key is the Primary Key -----
1445 * -- : Called from GetColumns(char *tableName, ------
1446 * -- int *numCols,const char *userID ) ------
1447 * ---------------------------------------------------------------------
1450 /*---------------------------------------------------------------------*/
1451 /* Get the names of the columns in the primary key. */
1452 /*---------------------------------------------------------------------*/
1453 retcode
= SQLPrimaryKeys(hstmt
,
1454 NULL
, 0, /* Catalog name */
1455 NULL
, 0, /* Schema name */
1456 (UCHAR
*) tableName
, SQL_NTS
); /* Table name */
1458 /*---------------------------------------------------------------------*/
1459 /* Fetch and display the result set. This will be a list of the */
1460 /* columns in the primary key of the tableName table. */
1461 /*---------------------------------------------------------------------*/
1462 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1464 retcode
= SQLFetch(hstmt
);
1465 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1467 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1468 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1470 for (i
=0;i
<noCols
;i
++) // Find the Column name
1471 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column
1472 colInf
[i
].PkCol
= iKeySeq
; // Which Primary Key is this (first, second usw.) ?
1473 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1474 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1475 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1477 /*---------------------------------------------------------------------*/
1478 /* Get all the foreign keys that refer to tableName primary key. */
1479 /*---------------------------------------------------------------------*/
1480 retcode
= SQLForeignKeys(hstmt
,
1481 NULL
, 0, /* Primary catalog */
1482 NULL
, 0, /* Primary schema */
1483 (UCHAR
*)tableName
, SQL_NTS
, /* Primary table */
1484 NULL
, 0, /* Foreign catalog */
1485 NULL
, 0, /* Foreign schema */
1486 NULL
, 0); /* Foreign table */
1488 /*---------------------------------------------------------------------*/
1489 /* Fetch and display the result set. This will be all of the foreign */
1490 /* keys in other tables that refer to the tableName primary key. */
1491 /*---------------------------------------------------------------------*/
1494 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1496 retcode
= SQLFetch(hstmt
);
1497 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1499 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1500 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1501 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1502 GetData( 7, SQL_C_CHAR
, szFkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1503 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1504 Temp0
.Printf(wxT("%s[%s] "),Temp0
.c_str(),szFkTable
); // [ ] in case there is a blank in the Table name
1505 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1506 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1507 Temp0
.Trim(); // Get rid of any unneeded blanks
1508 if (Temp0
!= wxT(""))
1510 for (i
=0;i
<noCols
;i
++) // Find the Column name
1511 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column, store the Information
1512 wxStrcpy(colInf
[i
].PkTableName
,Temp0
.c_str()); // Name of the Tables where this Primary Key is used as a Foreign Key
1513 } // if (Temp0 != "")
1514 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1516 /*---------------------------------------------------------------------*/
1517 /* Get all the foreign keys in the tablename table. */
1518 /*---------------------------------------------------------------------*/
1519 retcode
= SQLForeignKeys(hstmt
,
1520 NULL
, 0, /* Primary catalog */
1521 NULL
, 0, /* Primary schema */
1522 NULL
, 0, /* Primary table */
1523 NULL
, 0, /* Foreign catalog */
1524 NULL
, 0, /* Foreign schema */
1525 (UCHAR
*)tableName
, SQL_NTS
); /* Foreign table */
1527 /*---------------------------------------------------------------------*/
1528 /* Fetch and display the result set. This will be all of the */
1529 /* primary keys in other tables that are referred to by foreign */
1530 /* keys in the tableName table. */
1531 /*---------------------------------------------------------------------*/
1533 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1535 retcode
= SQLFetch(hstmt
);
1536 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1538 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1539 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1540 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1542 for (i
=0;i
<noCols
;i
++) // Find the Column name
1544 if (!wxStrcmp(colInf
[i
].colName
,szFkCol
)) // We have found the (Foreign Key) Column
1546 colInf
[i
].FkCol
= iKeySeq
; // Which Foreign Key is this (first, second usw.) ?
1547 wxStrcpy(colInf
[i
].FkTableName
,szPkTable
); // Name of the Table where this Foriegn is the Primary Key
1548 } // if (!wxStrcmp(colInf[i].colName,szFkCol))
1549 } // for (i=0;i<noCols;i++)
1550 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1551 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1552 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1554 /*---------------------------------------------------------------------*/
1556 } // wxDb::GetKeyFields()
1560 /********** wxDb::GetColumns() **********/
1561 wxDbColInf
*wxDb::GetColumns(char *tableName
[], const char *userID
)
1563 * 1) The last array element of the tableName[] argument must be zero (null).
1564 * This is how the end of the array is detected.
1565 * 2) This function returns an array of wxDbColInf structures. If no columns
1566 * were found, or an error occured, this pointer will be zero (null). THE
1567 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
1568 * IS FINISHED WITH IT. i.e.
1570 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
1573 * // Use the column inf
1575 * // Destroy the memory
1579 * userID is evaluated in the following manner:
1580 * userID == NULL ... UserID is ignored
1581 * userID == "" ... UserID set equal to 'this->uid'
1582 * userID != "" ... UserID set equal to 'userID'
1584 * NOTE: ALL column bindings associated with this wxDb instance are unbound
1585 * by this function. This function should use its own wxDb instance
1586 * to avoid undesired unbinding of columns.
1591 wxDbColInf
*colInf
= 0;
1601 if (!wxStrlen(userID
))
1609 // dBase does not use user names, and some drivers fail if you try to pass one
1610 if (Dbms() == dbmsDBASE
)
1613 // Oracle user names may only be in uppercase, so force
1614 // the name to uppercase
1615 if (Dbms() == dbmsORACLE
)
1616 UserID
= UserID
.Upper();
1618 // Pass 1 - Determine how many columns there are.
1619 // Pass 2 - Allocate the wxDbColInf array and fill in
1620 // the array with the column information.
1622 for (pass
= 1; pass
<= 2; pass
++)
1626 if (noCols
== 0) // Probably a bogus table name(s)
1628 // Allocate n wxDbColInf objects to hold the column information
1629 colInf
= new wxDbColInf
[noCols
+1];
1632 // Mark the end of the array
1633 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
1634 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
1635 colInf
[noCols
].sqlDataType
= 0;
1637 // Loop through each table name
1639 for (tbl
= 0; tableName
[tbl
]; tbl
++)
1641 TableName
= tableName
[tbl
];
1642 // Oracle table names are uppercase only, so force
1643 // the name to uppercase just in case programmer forgot to do this
1644 if (Dbms() == dbmsORACLE
)
1645 TableName
= TableName
.Upper();
1647 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1649 // MySQL and Access cannot accept a user name when looking up column names, so we
1650 // use the call below that leaves out the user name
1651 if (wxStrcmp(UserID
.c_str(),wxT("")) &&
1652 Dbms() != dbmsMY_SQL
&&
1653 Dbms() != dbmsACCESS
)
1655 retcode
= SQLColumns(hstmt
,
1656 NULL
, 0, // All qualifiers
1657 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
1658 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
1659 NULL
, 0); // All columns
1663 retcode
= SQLColumns(hstmt
,
1664 NULL
, 0, // All qualifiers
1666 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
1667 NULL
, 0); // All columns
1669 if (retcode
!= SQL_SUCCESS
)
1670 { // Error occured, abort
1671 DispAllErrors(henv
, hdbc
, hstmt
);
1674 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1678 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
1680 if (pass
== 1) // First pass, just add up the number of columns
1682 else // Pass 2; Fill in the array of structures
1684 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
1686 // NOTE: Only the ODBC 1.x fields are retrieved
1687 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
1688 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
1689 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1690 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1691 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
1692 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
1693 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
1694 GetData( 8, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
1695 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
1696 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
1697 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
1698 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
1700 // Determine the wxDb data type that is used to represent the native data type of this data source
1701 colInf
[colNo
].dbDataType
= 0;
1702 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
1704 if (colInf
[colNo
].columnSize
< 1)
1706 // IODBC does not return a correct columnSize, so we set
1707 // columnSize = bufferLength if no column size was returned
1708 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
1710 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
1712 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
1713 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
1714 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
1715 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
1716 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
1717 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
1723 if (retcode
!= SQL_NO_DATA_FOUND
)
1724 { // Error occured, abort
1725 DispAllErrors(henv
, hdbc
, hstmt
);
1728 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1734 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1737 } // wxDb::GetColumns()
1740 /********** wxDb::GetColumns() **********/
1742 wxDbColInf
*wxDb::GetColumns(char *tableName
, int *numCols
, const char *userID
)
1744 // Same as the above GetColumns() function except this one gets columns
1745 // only for a single table, and if 'numCols' is not NULL, the number of
1746 // columns stored in the returned wxDbColInf is set in '*numCols'
1748 // userID is evaluated in the following manner:
1749 // userID == NULL ... UserID is ignored
1750 // userID == "" ... UserID set equal to 'this->uid'
1751 // userID != "" ... UserID set equal to 'userID'
1753 // NOTE: ALL column bindings associated with this wxDb instance are unbound
1754 // by this function. This function should use its own wxDb instance
1755 // to avoid undesired unbinding of columns.
1760 wxDbColInf
*colInf
= 0;
1770 if (!wxStrlen(userID
))
1778 // dBase does not use user names, and some drivers fail if you try to pass one
1779 if (Dbms() == dbmsDBASE
)
1782 // Oracle user names may only be in uppercase, so force
1783 // the name to uppercase
1784 if (Dbms() == dbmsORACLE
)
1785 UserID
= UserID
.Upper();
1787 // Pass 1 - Determine how many columns there are.
1788 // Pass 2 - Allocate the wxDbColInf array and fill in
1789 // the array with the column information.
1791 for (pass
= 1; pass
<= 2; pass
++)
1795 if (noCols
== 0) // Probably a bogus table name(s)
1797 // Allocate n wxDbColInf objects to hold the column information
1798 colInf
= new wxDbColInf
[noCols
+1];
1801 // Mark the end of the array
1802 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
1803 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
1804 colInf
[noCols
].sqlDataType
= 0;
1807 TableName
= tableName
;
1808 // Oracle table names are uppercase only, so force
1809 // the name to uppercase just in case programmer forgot to do this
1810 if (Dbms() == dbmsORACLE
)
1811 TableName
= TableName
.Upper();
1813 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1815 // MySQL and Access cannot accept a user name when looking up column names, so we
1816 // use the call below that leaves out the user name
1817 if (wxStrcmp(UserID
.c_str(),wxT("")) &&
1818 Dbms() != dbmsMY_SQL
&&
1819 Dbms() != dbmsACCESS
)
1821 retcode
= SQLColumns(hstmt
,
1822 NULL
, 0, // All qualifiers
1823 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
1824 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
1825 NULL
, 0); // All columns
1829 retcode
= SQLColumns(hstmt
,
1830 NULL
, 0, // All qualifiers
1832 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
1833 NULL
, 0); // All columns
1835 if (retcode
!= SQL_SUCCESS
)
1836 { // Error occured, abort
1837 DispAllErrors(henv
, hdbc
, hstmt
);
1840 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1846 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
1848 if (pass
== 1) // First pass, just add up the number of columns
1850 else // Pass 2; Fill in the array of structures
1852 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
1854 // NOTE: Only the ODBC 1.x fields are retrieved
1855 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
1856 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
1857 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1858 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1859 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
1860 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
1861 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
1862 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
1863 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
1864 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
1865 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
1866 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
1867 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
1868 // Start Values for Primary/Foriegn Key (=No)
1869 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
1870 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
1871 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
1872 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
1874 // BJO 20000428 : Virtuoso returns type names with upper cases!
1875 if (Dbms() == dbmsVIRTUOSO
)
1877 wxString s
= colInf
[colNo
].typeName
;
1879 wxStrcmp(colInf
[colNo
].typeName
, s
.c_str());
1882 // Determine the wxDb data type that is used to represent the native data type of this data source
1883 colInf
[colNo
].dbDataType
= 0;
1884 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
1886 if (colInf
[colNo
].columnSize
< 1)
1888 // IODBC does not return a correct columnSize, so we set
1889 // columnSize = bufferLength if no column size was returned
1890 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
1892 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
1894 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
1895 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
1896 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
1897 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
1898 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
1899 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
1905 if (retcode
!= SQL_NO_DATA_FOUND
)
1906 { // Error occured, abort
1907 DispAllErrors(henv
, hdbc
, hstmt
);
1910 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1917 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1919 // Store Primary and Foriegn Keys
1920 GetKeyFields(tableName
,colInf
,noCols
);
1926 } // wxDb::GetColumns()
1928 #else // New GetColumns
1936 These are tentative new GetColumns members:
1938 - The first one (wxDbColInf *wxDb::GetColumns(char *tableName[], const char* userID)) calls
1939 the second implementation for each separate table before merging the results. This makes the
1940 code easier to maintain as only one member (the second) makes the real work
1941 - wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID) is a little bit improved
1942 - It doesn't anymore rely on the type-name to find out which database-type each column has
1943 - It ends by sorting the columns, so that they are returned in the same order they were created
1953 wxDbColInf
*wxDb::GetColumns(char *tableName
[], const char* userID
)
1956 // The last array element of the tableName[] argument must be zero (null).
1957 // This is how the end of the array is detected.
1961 // How many tables ?
1963 for (tbl
= 0 ; tableName
[tbl
]; tbl
++);
1965 // Create a table to maintain the columns for each separate table
1966 _TableColumns
*TableColumns
= new _TableColumns
[tbl
];
1969 for (i
= 0 ; i
< tbl
; i
++)
1972 TableColumns
[i
].colInf
= GetColumns(tableName
[i
], &TableColumns
[i
].noCols
, userID
);
1973 if (TableColumns
[i
].colInf
== NULL
) return NULL
;
1974 noCols
+= TableColumns
[i
].noCols
;
1977 // Now merge all the separate table infos
1978 wxDbColInf
*colInf
= new wxDbColInf
[noCols
+1];
1980 // Mark the end of the array
1981 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
1982 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
1983 colInf
[noCols
].sqlDataType
= 0;
1988 for (i
= 0 ; i
< tbl
; i
++)
1990 for (j
= 0 ; j
< TableColumns
[i
].noCols
; j
++)
1992 colInf
[offset
++] = TableColumns
[i
].colInf
[j
];
1996 delete [] TableColumns
;
2002 wxDbColInf
*wxDb::GetColumns(char *tableName
, int *numCols
, const char *userID
)
2004 // Same as the above GetColumns() function except this one gets columns
2005 // only for a single table, and if 'numCols' is not NULL, the number of
2006 // columns stored in the returned wxDbColInf is set in '*numCols'
2008 // userID is evaluated in the following manner:
2009 // userID == NULL ... UserID is ignored
2010 // userID == "" ... UserID set equal to 'this->uid'
2011 // userID != "" ... UserID set equal to 'userID'
2013 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2014 // by this function. This function should use its own wxDb instance
2015 // to avoid undesired unbinding of columns.
2020 wxDbColInf
*colInf
= 0;
2030 if (!wxStrlen(userID
))
2038 // dBase does not use user names, and some drivers fail if you try to pass one
2039 if (Dbms() == dbmsDBASE
)
2042 // Oracle user names may only be in uppercase, so force
2043 // the name to uppercase
2044 if (Dbms() == dbmsORACLE
)
2045 UserID
= UserID
.Upper();
2047 // Pass 1 - Determine how many columns there are.
2048 // Pass 2 - Allocate the wxDbColInf array and fill in
2049 // the array with the column information.
2051 for (pass
= 1; pass
<= 2; pass
++)
2055 if (noCols
== 0) // Probably a bogus table name(s)
2057 // Allocate n wxDbColInf objects to hold the column information
2058 colInf
= new wxDbColInf
[noCols
+1];
2061 // Mark the end of the array
2062 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
2063 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
2064 colInf
[noCols
].sqlDataType
= 0;
2067 TableName
= tableName
;
2068 // Oracle table names are uppercase only, so force
2069 // the name to uppercase just in case programmer forgot to do this
2070 if (Dbms() == dbmsORACLE
)
2071 TableName
= TableName
.Upper();
2073 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2075 // MySQL and Access cannot accept a user name when looking up column names, so we
2076 // use the call below that leaves out the user name
2077 if (wxStrcmp(UserID
.c_str(),wxT("")) &&
2078 Dbms() != dbmsMY_SQL
&&
2079 Dbms() != dbmsACCESS
)
2081 retcode
= SQLColumns(hstmt
,
2082 NULL
, 0, // All qualifiers
2083 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2084 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2085 NULL
, 0); // All columns
2089 retcode
= SQLColumns(hstmt
,
2090 NULL
, 0, // All qualifiers
2092 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2093 NULL
, 0); // All columns
2095 if (retcode
!= SQL_SUCCESS
)
2096 { // Error occured, abort
2097 DispAllErrors(henv
, hdbc
, hstmt
);
2100 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2106 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2108 if (pass
== 1) // First pass, just add up the number of columns
2110 else // Pass 2; Fill in the array of structures
2112 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2114 // NOTE: Only the ODBC 1.x fields are retrieved
2115 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2116 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2117 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2118 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2119 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2120 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2121 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2122 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2123 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2124 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2125 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2126 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2127 // Start Values for Primary/Foriegn Key (=No)
2128 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2129 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2130 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2131 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
2134 // IODBC returns the columnSize in bufferLength.. (bug)
2135 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2138 // Determine the wxDb data type that is used to represent the native data type of this data source
2139 colInf
[colNo
].dbDataType
= 0;
2140 // Get the intern datatype
2141 switch (colInf
[colNo
].sqlDataType
)
2145 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2151 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2158 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2161 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2168 errMsg
.sprintf("SQL Data type %d currently not supported by wxWindows", colInf
[colNo
].sqlDataType
);
2169 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
2179 if (retcode
!= SQL_NO_DATA_FOUND
)
2180 { // Error occured, abort
2181 DispAllErrors(henv
, hdbc
, hstmt
);
2184 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2191 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2193 // Store Primary and Foreign Keys
2194 GetKeyFields(tableName
,colInf
,noCols
);
2198 ///////////////////////////////////////////////////////////////////////////
2199 // Now sort the the columns in order to make them appear in the right order
2200 ///////////////////////////////////////////////////////////////////////////
2202 // Build a generic SELECT statement which returns 0 rows
2205 Stmt
.sprintf("select * from %s where 0=1", tableName
);
2208 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) Stmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
2210 DispAllErrors(henv
, hdbc
, hstmt
);
2214 // Get the number of result columns
2215 if (SQLNumResultCols (hstmt
, &noCols
) != SQL_SUCCESS
)
2217 DispAllErrors(henv
, hdbc
, hstmt
);
2221 if (noCols
== 0) // Probably a bogus table name
2230 for (colNum
= 0; colNum
< noCols
; colNum
++)
2232 if (SQLColAttributes(hstmt
,colNum
+1, SQL_COLUMN_NAME
,
2234 &Sword
, &Sdword
) != SQL_SUCCESS
)
2236 DispAllErrors(henv
, hdbc
, hstmt
);
2240 wxString Name1
= name
;
2241 Name1
= Name1
.Upper();
2243 // Where is this name in the array ?
2244 for (i
= colNum
; i
< noCols
; i
++)
2246 wxString Name2
= colInf
[i
].colName
;
2247 Name2
= Name2
.Upper();
2250 if (colNum
!= i
) // swap to sort
2252 wxDbColInf tmpColInf
= colInf
[colNum
];
2253 colInf
[colNum
] = colInf
[i
];
2254 colInf
[i
] = tmpColInf
;
2260 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2262 ///////////////////////////////////////////////////////////////////////////
2264 ///////////////////////////////////////////////////////////////////////////
2273 } // wxDb::GetColumns()
2279 /********** wxDb::GetColumnCount() **********/
2280 int wxDb::GetColumnCount(char *tableName
, const char *userID
)
2282 * Returns a count of how many columns are in a table.
2283 * If an error occurs in computing the number of columns
2284 * this function will return a -1 for the count
2286 * userID is evaluated in the following manner:
2287 * userID == NULL ... UserID is ignored
2288 * userID == "" ... UserID set equal to 'this->uid'
2289 * userID != "" ... UserID set equal to 'userID'
2291 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2292 * by this function. This function should use its own wxDb instance
2293 * to avoid undesired unbinding of columns.
2305 if (!wxStrlen(userID
))
2313 // dBase does not use user names, and some drivers fail if you try to pass one
2314 if (Dbms() == dbmsDBASE
)
2317 // Oracle user names may only be in uppercase, so force
2318 // the name to uppercase
2319 if (Dbms() == dbmsORACLE
)
2320 UserID
= UserID
.Upper();
2323 // Loop through each table name
2325 TableName
= tableName
;
2326 // Oracle table names are uppercase only, so force
2327 // the name to uppercase just in case programmer forgot to do this
2328 if (Dbms() == dbmsORACLE
)
2329 TableName
= TableName
.Upper();
2331 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2333 // MySQL and Access cannot accept a user name when looking up column names, so we
2334 // use the call below that leaves out the user name
2335 if (wxStrcmp(UserID
.c_str(),wxT("")) &&
2336 Dbms() != dbmsMY_SQL
&&
2337 Dbms() != dbmsACCESS
)
2339 retcode
= SQLColumns(hstmt
,
2340 NULL
, 0, // All qualifiers
2341 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2342 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2343 NULL
, 0); // All columns
2347 retcode
= SQLColumns(hstmt
,
2348 NULL
, 0, // All qualifiers
2350 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2351 NULL
, 0); // All columns
2353 if (retcode
!= SQL_SUCCESS
)
2354 { // Error occured, abort
2355 DispAllErrors(henv
, hdbc
, hstmt
);
2356 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2360 // Count the columns
2361 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2364 if (retcode
!= SQL_NO_DATA_FOUND
)
2365 { // Error occured, abort
2366 DispAllErrors(henv
, hdbc
, hstmt
);
2367 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2373 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2376 } // wxDb::GetColumnCount()
2379 /********** wxDb::GetCatalog() *******/
2380 wxDbInf
*wxDb::GetCatalog(char *userID
)
2382 * ---------------------------------------------------------------------
2383 * -- 19991203 : mj10777@gmx.net : Create ------
2384 * -- : Creates a wxDbInf with Tables / Cols Array ------
2385 * -- : uses SQLTables and fills pTableInf; ------
2386 * -- : pColInf is set to NULL and numCols to 0; ------
2387 * -- : returns pDbInf (wxDbInf) ------
2388 * -- - if unsuccesfull (pDbInf == NULL) ------
2389 * -- : pColInf can be filled with GetColumns(..); ------
2390 * -- : numCols can be filled with GetColumnCount(..); ------
2391 * ---------------------------------------------------------------------
2393 * userID is evaluated in the following manner:
2394 * userID == NULL ... UserID is ignored
2395 * userID == "" ... UserID set equal to 'this->uid'
2396 * userID != "" ... UserID set equal to 'userID'
2398 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2399 * by this function. This function should use its own wxDb instance
2400 * to avoid undesired unbinding of columns.
2403 wxDbInf
*pDbInf
= NULL
; // Array of catalog entries
2404 int noTab
= 0; // Counter while filling table entries
2408 // char tblNameSave[DB_MAX_TABLE_NAME_LEN+1];
2409 wxString tblNameSave
;
2415 if (!wxStrlen(userID
))
2423 // dBase does not use user names, and some drivers fail if you try to pass one
2424 if (Dbms() == dbmsDBASE
)
2427 // Oracle user names may only be in uppercase, so force
2428 // the name to uppercase
2429 if (Dbms() == dbmsORACLE
)
2430 UserID
= UserID
.Upper();
2432 //-------------------------------------------------------------
2433 pDbInf
= new wxDbInf
; // Create the Database Arrray
2434 pDbInf
->catalog
[0] = 0;
2435 pDbInf
->schema
[0] = 0;
2436 pDbInf
->numTables
= 0; // Counter for Tables
2437 pDbInf
->pTableInf
= NULL
; // Array of Tables
2438 //-------------------------------------------------------------
2439 // Table Information
2440 // Pass 1 - Determine how many Tables there are.
2441 // Pass 2 - Create the Table array and fill it
2442 // - Create the Cols array = NULL
2443 //-------------------------------------------------------------
2446 for (pass
= 1; pass
<= 2; pass
++)
2448 SQLFreeStmt(hstmt
, SQL_CLOSE
); // Close if Open
2449 tblNameSave
= wxT("");
2451 if (wxStrcmp(UserID
.c_str(),wxT("")) &&
2452 Dbms() != dbmsMY_SQL
&&
2453 Dbms() != dbmsACCESS
)
2456 retcode
= SQLTables(hstmt
,
2457 NULL
, 0, // All qualifiers
2458 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
2459 NULL
, 0, // All tables
2460 NULL
, 0); // All columns
2465 retcode
= SQLTables(hstmt
,
2466 NULL
, 0, // All qualifiers
2467 NULL
, 0, // User specified
2468 NULL
, 0, // All tables
2469 NULL
, 0); // All columns
2472 if (retcode
!= SQL_SUCCESS
)
2475 DispAllErrors(henv
, hdbc
, hstmt
);
2477 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2481 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
) // Table Information
2484 if (pass
== 1) // First pass, just count the Tables
2486 if (pDbInf
->numTables
== 0)
2488 GetData( 1, SQL_C_CHAR
, (UCHAR
*) pDbInf
->catalog
, 128+1, &cb
);
2489 GetData( 2, SQL_C_CHAR
, (UCHAR
*) pDbInf
->schema
, 128+1, &cb
);
2491 pDbInf
->numTables
++; // Counter for Tables
2493 if (pass
== 2) // Create and fill the Table entries
2495 if (pDbInf
->pTableInf
== NULL
) // Has the Table Array been created
2496 { // no, then create the Array
2497 pDbInf
->pTableInf
= new wxDbTableInf
[pDbInf
->numTables
];
2498 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
2500 (pDbInf
->pTableInf
+noTab
)->tableName
[0] = 0;
2501 (pDbInf
->pTableInf
+noTab
)->tableType
[0] = 0;
2502 (pDbInf
->pTableInf
+noTab
)->tableRemarks
[0] = 0;
2503 (pDbInf
->pTableInf
+noTab
)->numCols
= 0;
2504 (pDbInf
->pTableInf
+noTab
)->pColInf
= NULL
;
2507 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
2509 GetData( 3, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2510 GetData( 4, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableType
, 30+1, &cb
);
2511 GetData( 5, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableRemarks
, 254+1, &cb
);
2514 } // if (pass == 2) We now know the amount of Tables
2515 } // while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2516 } // for (pass = 1; pass <= 2; pass++)
2517 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2519 // Query how many columns are in each table
2520 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
2522 (pDbInf
->pTableInf
+noTab
)->numCols
= GetColumnCount((pDbInf
->pTableInf
+noTab
)->tableName
,UserID
);
2525 } // wxDb::GetCatalog()
2528 /********** wxDb::Catalog() **********/
2529 bool wxDb::Catalog(const char *userID
, const char *fileName
)
2531 * Creates the text file specified in 'filename' which will contain
2532 * a minimal data dictionary of all tables accessible by the user specified
2535 * userID is evaluated in the following manner:
2536 * userID == NULL ... UserID is ignored
2537 * userID == "" ... UserID set equal to 'this->uid'
2538 * userID != "" ... UserID set equal to 'userID'
2540 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2541 * by this function. This function should use its own wxDb instance
2542 * to avoid undesired unbinding of columns.
2545 assert(fileName
&& wxStrlen(fileName
));
2549 char tblName
[DB_MAX_TABLE_NAME_LEN
+1];
2550 wxString tblNameSave
;
2551 char colName
[DB_MAX_COLUMN_NAME_LEN
+1];
2553 char typeName
[30+1];
2554 SWORD precision
, length
;
2558 FILE *fp
= fopen(fileName
,"wt");
2562 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2566 if (!wxStrlen(userID
))
2574 // dBase does not use user names, and some drivers fail if you try to pass one
2575 if (Dbms() == dbmsDBASE
)
2578 // Oracle user names may only be in uppercase, so force
2579 // the name to uppercase
2580 if (Dbms() == dbmsORACLE
)
2581 UserID
= UserID
.Upper();
2583 if (wxStrcmp(UserID
.c_str(),wxT("")) &&
2584 Dbms() != dbmsMY_SQL
&&
2585 Dbms() != dbmsACCESS
)
2587 retcode
= SQLColumns(hstmt
,
2588 NULL
, 0, // All qualifiers
2589 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
2590 NULL
, 0, // All tables
2591 NULL
, 0); // All columns
2595 retcode
= SQLColumns(hstmt
,
2596 NULL
, 0, // All qualifiers
2597 NULL
, 0, // User specified
2598 NULL
, 0, // All tables
2599 NULL
, 0); // All columns
2601 if (retcode
!= SQL_SUCCESS
)
2603 DispAllErrors(henv
, hdbc
, hstmt
);
2609 tblNameSave
= wxT("");
2612 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2614 if (wxStrcmp(tblName
,tblNameSave
.c_str()))
2618 fputs("================================ ", fp
);
2619 fputs("================================ ", fp
);
2620 fputs("===================== ", fp
);
2621 fputs("========= ", fp
);
2622 fputs("=========\n", fp
);
2623 outStr
.sprintf(wxT("%-32s %-32s %-21s %9s %9s\n"),
2624 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
2625 fputs(outStr
.c_str(), fp
);
2626 fputs("================================ ", fp
);
2627 fputs("================================ ", fp
);
2628 fputs("===================== ", fp
);
2629 fputs("========= ", fp
);
2630 fputs("=========\n", fp
);
2631 tblNameSave
= tblName
;
2634 GetData(3,SQL_C_CHAR
, (UCHAR
*)tblName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2635 GetData(4,SQL_C_CHAR
, (UCHAR
*)colName
, DB_MAX_COLUMN_NAME_LEN
+1,&cb
);
2636 GetData(5,SQL_C_SSHORT
,(UCHAR
*)&sqlDataType
,0, &cb
);
2637 GetData(6,SQL_C_CHAR
, (UCHAR
*)typeName
, sizeof(typeName
), &cb
);
2638 GetData(7,SQL_C_SSHORT
,(UCHAR
*)&precision
, 0, &cb
);
2639 GetData(8,SQL_C_SSHORT
,(UCHAR
*)&length
, 0, &cb
);
2641 outStr
.sprintf("%-32s %-32s (%04d)%-15s %9d %9d\n",
2642 tblName
, colName
, sqlDataType
, typeName
, precision
, length
);
2643 if (fputs(outStr
.c_str(), fp
) == EOF
)
2645 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2652 if (retcode
!= SQL_NO_DATA_FOUND
)
2653 DispAllErrors(henv
, hdbc
, hstmt
);
2655 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2658 return(retcode
== SQL_NO_DATA_FOUND
);
2660 } // wxDb::Catalog()
2663 bool wxDb::TableExists(const char *tableName
, const char *userID
, const char *tablePath
)
2665 * Table name can refer to a table, view, alias or synonym. Returns true
2666 * if the object exists in the database. This function does not indicate
2667 * whether or not the user has privleges to query or perform other functions
2670 * userID is evaluated in the following manner:
2671 * userID == NULL ... UserID is ignored
2672 * userID == "" ... UserID set equal to 'this->uid'
2673 * userID != "" ... UserID set equal to 'userID'
2679 assert(tableName
&& wxStrlen(tableName
));
2681 if (Dbms() == dbmsDBASE
)
2685 if (tablePath
&& wxStrlen(tablePath
))
2686 dbName
.sprintf("%s\\%s.dbf",tablePath
,tableName
);
2688 dbName
.sprintf("%s.dbf",tableName
);
2691 exists
= wxFileExists(dbName
.c_str());
2697 if (!wxStrlen(userID
))
2705 // Oracle user names may only be in uppercase, so force
2706 // the name to uppercase
2707 if (Dbms() == dbmsORACLE
)
2708 UserID
= UserID
.Upper();
2710 TableName
= tableName
;
2711 // Oracle table names are uppercase only, so force
2712 // the name to uppercase just in case programmer forgot to do this
2713 if (Dbms() == dbmsORACLE
)
2714 TableName
= TableName
.Upper();
2716 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2719 // MySQL and Access cannot accept a user name when looking up table names, so we
2720 // use the call below that leaves out the user name
2721 if (wxStrcmp(UserID
,"") &&
2722 Dbms() != dbmsMY_SQL
&&
2723 Dbms() != dbmsACCESS
)
2725 retcode
= SQLTables(hstmt
,
2726 NULL
, 0, // All qualifiers
2727 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // All owners
2728 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
2729 NULL
, 0); // All table types
2733 retcode
= SQLTables(hstmt
,
2734 NULL
, 0, // All qualifiers
2735 NULL
, 0, // All owners
2736 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
2737 NULL
, 0); // All table types
2739 if (retcode
!= SQL_SUCCESS
)
2740 return(DispAllErrors(henv
, hdbc
, hstmt
));
2742 retcode
= SQLFetch(hstmt
);
2743 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
2745 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2746 return(DispAllErrors(henv
, hdbc
, hstmt
));
2749 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2752 } // wxDb::TableExists()
2755 /********** wxDb::SetSqlLogging() **********/
2756 bool wxDb::SetSqlLogging(wxDbSqlLogState state
, const char *filename
, bool append
)
2758 assert(state
== sqlLogON
|| state
== sqlLogOFF
);
2759 assert(state
== sqlLogOFF
|| filename
);
2761 if (state
== sqlLogON
)
2765 fpSqlLog
= fopen(filename
, (append
? "at" : "wt"));
2766 if (fpSqlLog
== NULL
)
2774 if (fclose(fpSqlLog
))
2780 sqlLogState
= state
;
2783 } // wxDb::SetSqlLogging()
2786 /********** wxDb::WriteSqlLog() **********/
2787 bool wxDb::WriteSqlLog(const wxChar
*logMsg
)
2791 if (fpSqlLog
== 0 || sqlLogState
== sqlLogOFF
)
2794 if (fputs("\n", fpSqlLog
) == EOF
) return(FALSE
);
2795 if (fputs(logMsg
, fpSqlLog
) == EOF
) return(FALSE
);
2796 if (fputs("\n", fpSqlLog
) == EOF
) return(FALSE
);
2800 } // wxDb::WriteSqlLog()
2803 /********** wxDb::Dbms() **********/
2804 wxDBMS
wxDb::Dbms(void)
2806 * Be aware that not all database engines use the exact same syntax, and not
2807 * every ODBC compliant database is compliant to the same level of compliancy.
2808 * Some manufacturers support the minimum Level 1 compliancy, and others up
2809 * through Level 3. Others support subsets of features for levels above 1.
2811 * If you find an inconsistency between the wxDb class and a specific database
2812 * engine, and an identifier to this section, and special handle the database in
2813 * the area where behavior is non-conforming with the other databases.
2816 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
2817 * ---------------------------------------------------
2820 * - Currently the only database supported by the class to support VIEWS
2823 * - Does not support the SQL_TIMESTAMP structure
2824 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
2825 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
2826 * is TRUE. The user must create ALL indexes from their program.
2827 * - Table names can only be 8 characters long
2828 * - Column names can only be 10 characters long
2831 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
2832 * after every table name involved in the query/join if that tables matching record(s)
2834 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
2836 * SYBASE (Enterprise)
2837 * - If a column is part of the Primary Key, the column cannot be NULL
2840 * - If a column is part of the Primary Key, the column cannot be NULL
2841 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
2844 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
2849 wxChar baseName
[25+1];
2850 wxStrncpy(baseName
,dbInf
.dbmsName
,25);
2852 // BJO 20000428 : add support for Virtuoso
2853 if (!wxStricmp(dbInf
.dbmsName
,"OpenLink Virtuoso VDBMS"))
2854 return(dbmsVIRTUOSO
);
2857 if (!wxStricmp(dbInf
.dbmsName
,"Adaptive Server Anywhere"))
2858 return(dbmsSYBASE_ASA
);
2860 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
2861 // connected through an OpenLink driver.
2862 // Is it also returned by Sybase Adapatitve server?
2863 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
2864 if (!wxStricmp(dbInf
.dbmsName
,"SQL Server"))
2865 if (!wxStrncmp(dbInf
.driverName
, "oplodbc", 7) ||
2866 !wxStrncmp(dbInf
.driverName
, "OLOD", 4))
2867 return dbmsMS_SQL_SERVER
; else return dbmsSYBASE_ASE
;
2870 if (!wxStricmp(dbInf
.dbmsName
,"Microsoft SQL Server"))
2871 return(dbmsMS_SQL_SERVER
);
2872 if (!wxStricmp(dbInf
.dbmsName
,"MySQL"))
2874 if (!wxStricmp(dbInf
.dbmsName
,"PostgreSQL")) // v6.5.0
2875 return(dbmsPOSTGRES
);
2878 if (!wxStricmp(baseName
,"Informix"))
2879 return(dbmsINFORMIX
);
2883 if (!wxStricmp(baseName
,"Oracle"))
2885 if (!wxStricmp(dbInf
.dbmsName
,"ACCESS"))
2887 if (!wxStricmp(dbInf
.dbmsName
,"MySQL"))
2889 if (!wxStricmp(baseName
,"Sybase"))
2890 return(dbmsSYBASE_ASE
);
2893 if (!wxStricmp(baseName
,"DBASE"))
2896 return(dbmsUNIDENTIFIED
);
2900 /********** wxDbGetConnection() **********/
2901 wxDb WXDLLEXPORT
*wxDbGetConnection(wxDbConnectInf
*pDbConfig
, bool FwdOnlyCursors
)
2905 // Scan the linked list searching for an available database connection
2906 // that's already been opened but is currently not in use.
2907 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2909 // The database connection must be for the same datasource
2910 // name and must currently not be in use.
2911 if (pList
->Free
&& (! wxStrcmp(pDbConfig
->Dsn
, pList
->Dsn
))) // Found a free connection
2913 pList
->Free
= FALSE
;
2914 return(pList
->PtrDb
);
2918 // No available connections. A new connection must be made and
2919 // appended to the end of the linked list.
2922 // Find the end of the list
2923 for (pList
= PtrBegDbList
; pList
->PtrNext
; pList
= pList
->PtrNext
);
2924 // Append a new list item
2925 pList
->PtrNext
= new wxDbList
;
2926 pList
->PtrNext
->PtrPrev
= pList
;
2927 pList
= pList
->PtrNext
;
2931 // Create the first node on the list
2932 pList
= PtrBegDbList
= new wxDbList
;
2936 // Initialize new node in the linked list
2938 pList
->Free
= FALSE
;
2939 wxStrcpy(pList
->Dsn
, pDbConfig
->Dsn
);
2940 pList
->PtrDb
= new wxDb(pDbConfig
->Henv
,FwdOnlyCursors
);
2942 // Connect to the datasource
2943 if (pList
->PtrDb
->Open(pDbConfig
->Dsn
, pDbConfig
->Uid
, pDbConfig
->AuthStr
))
2945 pList
->PtrDb
->SetSqlLogging(SQLLOGstate
,SQLLOGfn
,TRUE
);
2946 return(pList
->PtrDb
);
2948 else // Unable to connect, destroy list item
2951 pList
->PtrPrev
->PtrNext
= 0;
2953 PtrBegDbList
= 0; // Empty list again
2954 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
2955 pList
->PtrDb
->Close(); // Close the wxDb object
2956 delete pList
->PtrDb
; // Deletes the wxDb object
2957 delete pList
; // Deletes the linked list object
2961 } // wxDbGetConnection()
2964 /********** wxDbFreeConnection() **********/
2965 bool WXDLLEXPORT
wxDbFreeConnection(wxDb
*pDb
)
2969 // Scan the linked list searching for the database connection
2970 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
2972 if (pList
->PtrDb
== pDb
) // Found it!!!
2973 return(pList
->Free
= TRUE
);
2976 // Never found the database object, return failure
2979 } // wxDbFreeConnection()
2982 /********** wxDbCloseConnections() **********/
2983 void WXDLLEXPORT
wxDbCloseConnections(void)
2985 wxDbList
*pList
, *pNext
;
2987 // Traverse the linked list closing database connections and freeing memory as I go.
2988 for (pList
= PtrBegDbList
; pList
; pList
= pNext
)
2990 pNext
= pList
->PtrNext
; // Save the pointer to next
2991 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
2992 pList
->PtrDb
->Close(); // Close the wxDb object
2993 delete pList
->PtrDb
; // Deletes the wxDb object
2994 delete pList
; // Deletes the linked list object
2997 // Mark the list as empty
3000 } // wxDbCloseConnections()
3003 /********** wxDbNumberConnectionsInUse() **********/
3004 int WXDLLEXPORT
wxDbConnectionsInUse(void)
3009 // Scan the linked list counting db connections that are currently in use
3010 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3012 if (pList
->Free
== FALSE
)
3018 } // wxDbConnectionsInUse()
3021 /********** wxDbSqlLog() **********/
3022 bool wxDbSqlLog(wxDbSqlLogState state
, const wxChar
*filename
)
3024 bool append
= FALSE
;
3027 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3029 if (!pList
->PtrDb
->SetSqlLogging(state
,filename
,append
))
3034 SQLLOGstate
= state
;
3035 wxStrcpy(SQLLOGfn
,filename
);
3043 /********** wxDbCreateDataSource() **********/
3044 int wxDbCreateDataSource(const char *driverName
, const char *dsn
, const char *description
,
3045 bool sysDSN
, const char *defDir
, wxWindow
*parent
)
3047 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3048 * Very rudimentary creation of an ODBC data source.
3058 dsnLocation
= ODBC_ADD_SYS_DSN
;
3060 dsnLocation
= ODBC_ADD_DSN
;
3062 // NOTE: The decimal 2 is an invalid character in all keyword pairs
3063 // so that is why I used it, as wxString does not deal well with
3064 // embedded nulls in strings
3065 setupStr
.sprintf("DSN=%s%cDescription=%s%cDefaultDir=%s%c",dsn
,2,description
,2,defDir
,2);
3067 // Replace the separator from above with the '\0' seperator needed
3068 // by the SQLConfigDataSource() function
3072 k
= setupStr
.Find((wxChar
)2,TRUE
);
3073 if (k
!= wxNOT_FOUND
)
3074 setupStr
[(UINT
)k
] = '\0';
3076 while (k
!= wxNOT_FOUND
);
3078 result
= SQLConfigDataSource((HWND
)parent
->GetHWND(), dsnLocation
,
3079 driverName
, setupStr
.c_str());
3083 // check for errors caused by ConfigDSN based functions
3086 wxChar errMsg
[500+1];
3089 SQLInstallerError(1,&retcode
,errMsg
,500,&cb
);
3094 #ifdef DBDEBUG_CONSOLE
3095 // When run in console mode, use standard out to display errors.
3096 cout
<< errMsg
<< endl
;
3097 cout
<< "Press any key to continue..." << endl
;
3099 #endif // DBDEBUG_CONSOLE
3102 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
3103 #endif // __WXDEBUG__
3112 wxLogDebug("wxDbCreateDataSource() not available except under MSW","DEBUG MESSAGE");
3118 } // wxDbCreateDataSource()
3122 /********** wxDbGetDataSource() **********/
3123 bool wxDbGetDataSource(HENV henv
, char *Dsn
, SWORD DsnMax
, char *DsDesc
, SWORD DsDescMax
,
3126 * Dsn and DsDesc will contain the data source name and data source
3127 * description upon return
3132 if (SQLDataSources(henv
, direction
, (UCHAR FAR
*) Dsn
, DsnMax
, &cb1
,
3133 (UCHAR FAR
*) DsDesc
, DsDescMax
, &cb2
) == SQL_SUCCESS
)
3138 } // wxDbGetDataSource()
3141 // Change this to 0 to remove use of all deprecated functions
3142 #if wxODBC_BACKWARD_COMPATABILITY
3143 /********************************************************************
3144 ********************************************************************
3146 * The following functions are all DEPRECATED and are included for
3147 * backward compatability reasons only
3149 ********************************************************************
3150 ********************************************************************/
3151 bool SqlLog(sqlLog state
, const wxChar
*filename
)
3153 return wxDbSqlLog((enum wxDbSqlLogState
)state
, filename
);
3155 /***** DEPRECATED: use wxGetDataSource() *****/
3156 bool GetDataSource(HENV henv
, char *Dsn
, SWORD DsnMax
, char *DsDesc
, SWORD DsDescMax
,
3159 return wxDbGetDataSource(henv
, Dsn
, DsnMax
, DsDesc
, DsDescMax
, direction
);
3161 /***** DEPRECATED: use wxDbGetConnection() *****/
3162 wxDb WXDLLEXPORT
*GetDbConnection(DbStuff
*pDbStuff
, bool FwdOnlyCursors
)
3164 return wxDbGetConnection((wxDbConnectInf
*)pDbStuff
, FwdOnlyCursors
);
3166 /***** DEPRECATED: use wxDbFreeConnection() *****/
3167 bool WXDLLEXPORT
FreeDbConnection(wxDb
*pDb
)
3169 return wxDbFreeConnection(pDb
);
3171 /***** DEPRECATED: use wxDbCloseConnections() *****/
3172 void WXDLLEXPORT
CloseDbConnections(void)
3174 wxDbCloseConnections();
3176 /***** DEPRECATED: use wxDbConnectionsInUse() *****/
3177 int WXDLLEXPORT
NumberDbConnectionsInUse(void)
3179 return wxDbConnectionsInUse();