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 // Mark Johnson, wxWindows@mj10777.de
11 // -Added support for SQL statement logging and database cataloging
13 // -Added QUERY_ONLY mode support to reduce default number of cursors
14 // -Added additional SQL logging code
15 // -Added DEBUG-ONLY tracking of wxTable objects to detect orphaned DB connections
16 // -Set ODBC option to only read committed writes to the DB so all
17 // databases operate the same in that respect
20 // Copyright: (c) 1996 Remstar International, Inc.
21 // Licence: wxWindows licence, plus:
22 // Notice: This class library and its intellectual design are free of charge for use,
23 // modification, enhancement, debugging under the following conditions:
24 // 1) These classes may only be used as part of the implementation of a
25 // wxWindows-based application
26 // 2) All enhancements and bug fixes are to be submitted back to the wxWindows
27 // user groups free of all charges for use with the wxWindows library.
28 // 3) These classes may not be distributed as part of any other class library,
29 // DLL, text (written or electronic), other than a complete distribution of
30 // the wxWindows GUI development toolkit.
31 ///////////////////////////////////////////////////////////////////////////////
38 #include "wx/wxprec.h"
41 // Use this line for wxWindows v1.x
43 // Use this line for wxWindows v2.x
44 #include "wx/version.h"
46 #if wxMAJOR_VERSION == 2
48 #pragma implementation "db.h"
52 #ifdef DBDEBUG_CONSOLE
53 #include "wx/ioswrap.h"
60 #if wxMAJOR_VERSION == 2
62 #include "wx/string.h"
63 #include "wx/object.h"
66 #include "wx/msgdlg.h"
69 #include "wx/filefn.h"
70 #include "wx/wxchar.h"
74 #if wxMAJOR_VERSION == 1
75 # if defined(wx_msw) || defined(wx_x)
93 #if wxMAJOR_VERSION == 1
95 #elif wxMAJOR_VERSION == 2
99 WXDLLEXPORT_DATA(wxDbList
*) PtrBegDbList
= 0;
102 wxChar
const *SQL_LOG_FILENAME
= wxT("sqllog.txt");
103 wxChar
const *SQL_CATALOG_FILENAME
= wxT("catalog.txt");
106 extern wxList TablesInUse
;
109 // SQL Log defaults to be used by GetDbConnection
110 wxDbSqlLogState SQLLOGstate
= sqlLogOFF
;
112 static wxString SQLLOGfn
= SQL_LOG_FILENAME
;
114 // The wxDb::errorList is copied to this variable when the wxDb object
115 // is closed. This way, the error list is still available after the
116 // database object is closed. This is necessary if the database
117 // connection fails so the calling application can show the operator
118 // why the connection failed. Note: as each wxDb object is closed, it
119 // will overwrite the errors of the previously destroyed wxDb object in
120 // this variable. NOTE: This occurs during a CLOSE, not a FREEing of the
122 wxChar DBerrorList
[DB_MAX_ERROR_HISTORY
][DB_MAX_ERROR_MSG_LEN
];
124 // This type defines the return row-struct form
125 // SQLTablePrivileges, and is used by wxDB::TablePrivileges.
128 wxChar tableQual
[128+1];
129 wxChar tableOwner
[128+1];
130 wxChar tableName
[128+1];
131 wxChar grantor
[128+1];
132 wxChar grantee
[128+1];
133 wxChar privilege
[128+1];
134 wxChar grantable
[3+1];
135 } wxDbTablePrivilegeInfo
;
138 /********** wxDbConnectInf Constructor - form 1 **********/
139 wxDbConnectInf::wxDbConnectInf()
142 freeHenvOnDestroy
= FALSE
;
148 /********** wxDbConnectInf Constructor - form 2 **********/
149 wxDbConnectInf::wxDbConnectInf(HENV henv
, const wxString
&dsn
, const wxString
&userID
,
150 const wxString
&password
, const wxString
&defaultDir
,
151 const wxString
&fileType
, const wxString
&description
)
153 wxASSERT(dsn
.Length());
156 freeHenvOnDestroy
= FALSE
;
167 SetPassword(password
);
168 SetDescription(description
);
169 SetFileType(fileType
);
170 SetDefaultDir(defaultDir
);
171 } // wxDbConnectInf Constructor
174 wxDbConnectInf::~wxDbConnectInf()
176 if (freeHenvOnDestroy
)
180 } // wxDbConnectInf Destructor
184 /********** wxDbConnectInf::Initialize() **********/
185 bool wxDbConnectInf::Initialize()
187 freeHenvOnDestroy
= FALSE
;
189 if (freeHenvOnDestroy
&& Henv
)
201 } // wxDbConnectInf::Initialize()
204 /********** wxDbConnectInf::AllocHenv() **********/
205 bool wxDbConnectInf::AllocHenv()
207 // This is here to help trap if you are getting a new henv
208 // without releasing an existing henv
211 // Initialize the ODBC Environment for Database Operations
212 if (SQLAllocEnv(&Henv
) != SQL_SUCCESS
)
214 wxLogDebug(wxT("A problem occured while trying to get a connection to the data source"));
218 freeHenvOnDestroy
= TRUE
;
221 } // wxDbConnectInf::AllocHenv()
224 void wxDbConnectInf::FreeHenv()
232 freeHenvOnDestroy
= FALSE
;
234 } // wxDbConnectInf::FreeHenv()
237 void wxDbConnectInf::SetDsn(const wxString
&dsn
)
239 wxASSERT(dsn
.Length() < sizeof(Dsn
));
242 } // wxDbConnectInf::SetDsn()
245 void wxDbConnectInf::SetUserID(const wxString
&uid
)
247 wxASSERT(uid
.Length() < sizeof(Uid
));
249 } // wxDbConnectInf::SetUserID()
252 void wxDbConnectInf::SetPassword(const wxString
&password
)
254 wxASSERT(password
.Length() < sizeof(AuthStr
));
256 wxStrcpy(AuthStr
,password
);
257 } // wxDbConnectInf::SetPassword()
261 /********** wxDbColFor Constructor **********/
262 wxDbColFor::wxDbColFor()
265 } // wxDbColFor::wxDbColFor()
268 wxDbColFor::~wxDbColFor()
270 } // wxDbColFor::~wxDbColFor()
273 /********** wxDbColFor::Initialize() **********/
274 void wxDbColFor::Initialize()
284 i_Nation
= 0; // 0=EU, 1=UK, 2=International, 3=US
287 Format(1,DB_DATA_TYPE_VARCHAR
,0,0,0); // the Function that does the work
288 } // wxDbColFor::Initialize()
291 /********** wxDbColFor::Format() **********/
292 int wxDbColFor::Format(int Nation
, int dbDataType
, SWORD sqlDataType
,
293 short columnSize
, short decimalDigits
)
295 // ----------------------------------------------------------------------------------------
296 // -- 19991224 : mj10777 : Create
297 // There is still a lot of work to do here, but it is a start
298 // It handles all the basic data-types that I have run into up to now
299 // The main work will have be with Dates and float Formatting
300 // (US 1,000.00 ; EU 1.000,00)
301 // There are wxWindow plans for locale support and the new wxDateTime. If
302 // they define some constants (wxEUROPEAN) that can be gloably used,
303 // they should be used here.
304 // ----------------------------------------------------------------------------------------
305 // There should also be a function to scan in a string to fill the variable
306 // ----------------------------------------------------------------------------------------
308 i_Nation
= Nation
; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
309 i_dbDataType
= dbDataType
;
310 i_sqlDataType
= sqlDataType
;
311 s_Field
.Printf(wxT("%s%d"),s_Amount
[1].c_str(),i_Amount
[1]); // OK for VARCHAR, INTEGER and FLOAT
313 if (i_dbDataType
== 0) // Filter unsupported dbDataTypes
315 if ((i_sqlDataType
== SQL_VARCHAR
) || (i_sqlDataType
== SQL_LONGVARCHAR
))
316 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
317 if ((i_sqlDataType
== SQL_C_DATE
) || (i_sqlDataType
== SQL_C_TIMESTAMP
))
318 i_dbDataType
= DB_DATA_TYPE_DATE
;
319 if (i_sqlDataType
== SQL_C_BIT
)
320 i_dbDataType
= DB_DATA_TYPE_INTEGER
;
321 if (i_sqlDataType
== SQL_NUMERIC
)
322 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
323 if (i_sqlDataType
== SQL_REAL
)
324 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
327 if ((i_dbDataType
== DB_DATA_TYPE_INTEGER
) && (i_sqlDataType
== SQL_C_DOUBLE
))
329 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
332 switch(i_dbDataType
) // TBD: Still a lot of proper formatting to do
334 case DB_DATA_TYPE_VARCHAR
:
337 case DB_DATA_TYPE_INTEGER
:
340 case DB_DATA_TYPE_FLOAT
:
341 if (decimalDigits
== 0)
344 tempStr
.Printf(wxT("%s%d.%d"),tempStr
.c_str(),columnSize
,decimalDigits
);
345 s_Field
.Printf(wxT("%sf"),tempStr
.c_str());
347 case DB_DATA_TYPE_DATE
:
348 if (i_Nation
== 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
350 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
352 if (i_Nation
== 1) // European DD.MM.YYYY HH:MM:SS.SSS
354 s_Field
= wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d");
356 if (i_Nation
== 2) // UK DD/MM/YYYY HH:MM:SS.SSS
358 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
360 if (i_Nation
== 3) // International YYYY-MM-DD HH:MM:SS.SSS
362 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
364 if (i_Nation
== 4) // US MM/DD/YYYY HH:MM:SS.SSS
366 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
370 s_Field
.Printf(wxT("Unknown Format(%d)-SQL(%d)"),dbDataType
,sqlDataType
); //
374 } // wxDbColFor::Format()
378 /********** wxDbColInf Constructor **********/
379 wxDbColInf::wxDbColInf()
382 } // wxDbColInf::wxDbColInf()
385 /********** wxDbColInf Destructor ********/
386 wxDbColInf::~wxDbColInf()
391 } // wxDbColInf::~wxDbColInf()
394 bool wxDbColInf::Initialize()
416 } // wxDbColInf::Initialize()
419 /********** wxDbTableInf Constructor ********/
420 wxDbTableInf::wxDbTableInf()
423 } // wxDbTableInf::wxDbTableInf()
426 /********** wxDbTableInf Constructor ********/
427 wxDbTableInf::~wxDbTableInf()
432 } // wxDbTableInf::~wxDbTableInf()
435 bool wxDbTableInf::Initialize()
444 } // wxDbTableInf::Initialize()
447 /********** wxDbInf Constructor *************/
451 } // wxDbInf::wxDbInf()
454 /********** wxDbInf Destructor *************/
460 } // wxDbInf::~wxDbInf()
463 /********** wxDbInf::Initialize() *************/
464 bool wxDbInf::Initialize()
472 } // wxDbInf::Initialize()
475 /********** wxDb Constructors **********/
476 wxDb::wxDb(const HENV
&aHenv
, bool FwdOnlyCursors
)
478 // Copy the HENV into the db class
480 fwdOnlyCursors
= FwdOnlyCursors
;
486 /********** PRIVATE! wxDb::initialize PRIVATE! **********/
487 /********** wxDb::initialize() **********/
488 void wxDb::initialize()
490 * Private member function that sets all wxDb member variables to
491 * known values at creation of the wxDb
496 fpSqlLog
= 0; // Sql Log file pointer
497 sqlLogState
= sqlLogOFF
; // By default, logging is turned off
499 dbmsType
= dbmsUNIDENTIFIED
;
501 wxStrcpy(sqlState
,wxEmptyString
);
502 wxStrcpy(errorMsg
,wxEmptyString
);
503 nativeError
= cbErrorMsg
= 0;
504 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
505 wxStrcpy(errorList
[i
], wxEmptyString
);
507 // Init typeInf structures
508 typeInfVarchar
.TypeName
.Empty();
509 typeInfVarchar
.FsqlType
= 0;
510 typeInfVarchar
.Precision
= 0;
511 typeInfVarchar
.CaseSensitive
= 0;
512 typeInfVarchar
.MaximumScale
= 0;
514 typeInfInteger
.TypeName
.Empty();
515 typeInfInteger
.FsqlType
= 0;
516 typeInfInteger
.Precision
= 0;
517 typeInfInteger
.CaseSensitive
= 0;
518 typeInfInteger
.MaximumScale
= 0;
520 typeInfFloat
.TypeName
.Empty();
521 typeInfFloat
.FsqlType
= 0;
522 typeInfFloat
.Precision
= 0;
523 typeInfFloat
.CaseSensitive
= 0;
524 typeInfFloat
.MaximumScale
= 0;
526 typeInfDate
.TypeName
.Empty();
527 typeInfDate
.FsqlType
= 0;
528 typeInfDate
.Precision
= 0;
529 typeInfDate
.CaseSensitive
= 0;
530 typeInfDate
.MaximumScale
= 0;
532 // Error reporting is turned OFF by default
535 // Allocate a data source connection handle
536 if (SQLAllocConnect(henv
, &hdbc
) != SQL_SUCCESS
)
539 // Initialize the db status flag
542 // Mark database as not open as of yet
544 } // wxDb::initialize()
547 /********** PRIVATE! wxDb::convertUserID PRIVATE! **********/
549 // NOTE: Return value from this function MUST be copied
550 // immediately, as the value is not good after
551 // this function has left scope.
553 const wxChar
*wxDb::convertUserID(const wxChar
*userID
, wxString
&UserID
)
557 if (!wxStrlen(userID
))
565 // dBase does not use user names, and some drivers fail if you try to pass one
566 if (Dbms() == dbmsDBASE
)
569 // Oracle user names may only be in uppercase, so force
570 // the name to uppercase
571 if (Dbms() == dbmsORACLE
)
572 UserID
= UserID
.Upper();
574 return UserID
.c_str();
575 } // wxDb::convertUserID()
578 /********** wxDb::Open() **********/
579 bool wxDb::Open(const wxString
&Dsn
, const wxString
&Uid
, const wxString
&AuthStr
)
581 wxASSERT(Dsn
.Length());
588 if (!FwdOnlyCursors())
590 // Specify that the ODBC cursor library be used, if needed. This must be
591 // specified before the connection is made.
592 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
594 #ifdef DBDEBUG_CONSOLE
595 if (retcode
== SQL_SUCCESS
)
596 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
598 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
602 // Connect to the data source
603 retcode
= SQLConnect(hdbc
, (UCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
604 (UCHAR FAR
*) uid
.c_str(), SQL_NTS
,
605 (UCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
608 if (retcode == SQL_SUCCESS_WITH_INFO)
609 DispAllErrors(henv, hdbc);
610 else if (retcode != SQL_SUCCESS)
611 return(DispAllErrors(henv, hdbc));
613 if (retcode == SQL_ERROR)
614 return(DispAllErrors(henv, hdbc));
616 if ((retcode
!= SQL_SUCCESS
) &&
617 (retcode
!= SQL_SUCCESS_WITH_INFO
))
618 return(DispAllErrors(henv
, hdbc
));
621 If using Intersolv branded ODBC drivers, this is the place where you would substitute
622 your branded driver license information
624 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
625 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
628 // Mark database as open
631 // Allocate a statement handle for the database connection
632 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
633 return(DispAllErrors(henv
, hdbc
));
635 // Set Connection Options
636 if (!setConnectionOptions())
639 // Query the data source for inf. about itself
643 // Query the data source regarding data type information
646 // The way I determined which SQL data types to use was by calling SQLGetInfo
647 // for all of the possible SQL data types to see which ones were supported. If
648 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
649 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
650 // types I've selected below will not alway's be what we want. These are just
651 // what happened to work against an Oracle 7/Intersolv combination. The following is
652 // a complete list of the results I got back against the Oracle 7 database:
654 // SQL_BIGINT SQL_NO_DATA_FOUND
655 // SQL_BINARY SQL_NO_DATA_FOUND
656 // SQL_BIT SQL_NO_DATA_FOUND
657 // SQL_CHAR type name = 'CHAR', Precision = 255
658 // SQL_DATE SQL_NO_DATA_FOUND
659 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
660 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
661 // SQL_FLOAT SQL_NO_DATA_FOUND
662 // SQL_INTEGER SQL_NO_DATA_FOUND
663 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
664 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
665 // SQL_NUMERIC SQL_NO_DATA_FOUND
666 // SQL_REAL SQL_NO_DATA_FOUND
667 // SQL_SMALLINT SQL_NO_DATA_FOUND
668 // SQL_TIME SQL_NO_DATA_FOUND
669 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
670 // SQL_VARBINARY type name = 'RAW', Precision = 255
671 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
672 // =====================================================================
673 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
675 // SQL_VARCHAR type name = 'TEXT', Precision = 255
676 // SQL_TIMESTAMP type name = 'DATETIME'
677 // SQL_DECIMAL SQL_NO_DATA_FOUND
678 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
679 // SQL_FLOAT SQL_NO_DATA_FOUND
680 // SQL_REAL type name = 'SINGLE', Precision = 7
681 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
682 // SQL_INTEGER type name = 'LONG', Precision = 10
684 // VARCHAR = Variable length character string
685 if (!getDataTypeInfo(SQL_VARCHAR
, typeInfVarchar
))
686 if (!getDataTypeInfo(SQL_CHAR
, typeInfVarchar
))
689 typeInfVarchar
.FsqlType
= SQL_CHAR
;
691 typeInfVarchar
.FsqlType
= SQL_VARCHAR
;
694 if (!getDataTypeInfo(SQL_DOUBLE
,typeInfFloat
))
696 if (!getDataTypeInfo(SQL_REAL
,typeInfFloat
))
697 if (!getDataTypeInfo(SQL_FLOAT
,typeInfFloat
))
698 if (!getDataTypeInfo(SQL_DECIMAL
,typeInfFloat
))
699 if (!getDataTypeInfo(SQL_NUMERIC
,typeInfFloat
))
702 typeInfFloat
.FsqlType
= SQL_NUMERIC
;
704 typeInfFloat
.FsqlType
= SQL_DECIMAL
;
706 typeInfFloat
.FsqlType
= SQL_FLOAT
;
708 typeInfFloat
.FsqlType
= SQL_REAL
;
710 typeInfFloat
.FsqlType
= SQL_DOUBLE
;
713 if (!getDataTypeInfo(SQL_INTEGER
, typeInfInteger
))
715 // If SQL_INTEGER is not supported, use the floating point
716 // data type to store integers as well as floats
717 if (!getDataTypeInfo(typeInfFloat
.FsqlType
, typeInfInteger
))
720 typeInfInteger
.FsqlType
= typeInfFloat
.FsqlType
;
723 typeInfInteger
.FsqlType
= SQL_INTEGER
;
726 if (Dbms() != dbmsDBASE
)
728 if (! getDataTypeInfo(SQL_TIMESTAMP
,typeInfDate
))
731 typeInfDate
.FsqlType
= SQL_TIMESTAMP
;
735 if (!getDataTypeInfo(SQL_DATE
,typeInfDate
))
738 typeInfDate
.FsqlType
= SQL_DATE
;
741 #ifdef DBDEBUG_CONSOLE
742 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
743 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
744 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
745 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
749 // Completed Successfully
755 bool wxDb::Open(wxDbConnectInf
*dbConnectInf
)
757 return Open(dbConnectInf
->GetDsn(), dbConnectInf
->GetUserID(),
758 dbConnectInf
->GetPassword());
762 bool wxDb::Open(wxDb
*copyDb
)
764 dsn
= copyDb
->GetDatasourceName();
765 uid
= copyDb
->GetUsername();
766 authStr
= copyDb
->GetPassword();
770 if (!FwdOnlyCursors())
772 // Specify that the ODBC cursor library be used, if needed. This must be
773 // specified before the connection is made.
774 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
776 #ifdef DBDEBUG_CONSOLE
777 if (retcode
== SQL_SUCCESS
)
778 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
780 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
784 // Connect to the data source
785 retcode
= SQLConnect(hdbc
, (UCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
786 (UCHAR FAR
*) uid
.c_str(), SQL_NTS
,
787 (UCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
789 if (retcode
== SQL_ERROR
)
790 return(DispAllErrors(henv
, hdbc
));
793 If using Intersolv branded ODBC drivers, this is the place where you would substitute
794 your branded driver license information
796 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
797 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
800 // Mark database as open
803 // Allocate a statement handle for the database connection
804 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
805 return(DispAllErrors(henv
, hdbc
));
807 // Set Connection Options
808 if (!setConnectionOptions())
811 // Instead of Querying the data source for info about itself, it can just be copied
812 // from the wxDb instance that was passed in (copyDb).
813 wxStrcpy(dbInf
.serverName
,copyDb
->dbInf
.serverName
);
814 wxStrcpy(dbInf
.databaseName
,copyDb
->dbInf
.databaseName
);
815 wxStrcpy(dbInf
.dbmsName
,copyDb
->dbInf
.dbmsName
);
816 wxStrcpy(dbInf
.dbmsVer
,copyDb
->dbInf
.dbmsVer
);
817 dbInf
.maxConnections
= copyDb
->dbInf
.maxConnections
;
818 dbInf
.maxStmts
= copyDb
->dbInf
.maxStmts
;
819 wxStrcpy(dbInf
.driverName
,copyDb
->dbInf
.driverName
);
820 wxStrcpy(dbInf
.odbcVer
,copyDb
->dbInf
.odbcVer
);
821 wxStrcpy(dbInf
.drvMgrOdbcVer
,copyDb
->dbInf
.drvMgrOdbcVer
);
822 wxStrcpy(dbInf
.driverVer
,copyDb
->dbInf
.driverVer
);
823 dbInf
.apiConfLvl
= copyDb
->dbInf
.apiConfLvl
;
824 dbInf
.cliConfLvl
= copyDb
->dbInf
.cliConfLvl
;
825 dbInf
.sqlConfLvl
= copyDb
->dbInf
.sqlConfLvl
;
826 wxStrcpy(dbInf
.outerJoins
,copyDb
->dbInf
.outerJoins
);
827 wxStrcpy(dbInf
.procedureSupport
,copyDb
->dbInf
.procedureSupport
);
828 wxStrcpy(dbInf
.accessibleTables
,copyDb
->dbInf
.accessibleTables
);
829 dbInf
.cursorCommitBehavior
= copyDb
->dbInf
.cursorCommitBehavior
;
830 dbInf
.cursorRollbackBehavior
= copyDb
->dbInf
.cursorRollbackBehavior
;
831 dbInf
.supportNotNullClause
= copyDb
->dbInf
.supportNotNullClause
;
832 wxStrcpy(dbInf
.supportIEF
,copyDb
->dbInf
.supportIEF
);
833 dbInf
.txnIsolation
= copyDb
->dbInf
.txnIsolation
;
834 dbInf
.txnIsolationOptions
= copyDb
->dbInf
.txnIsolationOptions
;
835 dbInf
.fetchDirections
= copyDb
->dbInf
.fetchDirections
;
836 dbInf
.lockTypes
= copyDb
->dbInf
.lockTypes
;
837 dbInf
.posOperations
= copyDb
->dbInf
.posOperations
;
838 dbInf
.posStmts
= copyDb
->dbInf
.posStmts
;
839 dbInf
.scrollConcurrency
= copyDb
->dbInf
.scrollConcurrency
;
840 dbInf
.scrollOptions
= copyDb
->dbInf
.scrollOptions
;
841 dbInf
.staticSensitivity
= copyDb
->dbInf
.staticSensitivity
;
842 dbInf
.txnCapable
= copyDb
->dbInf
.txnCapable
;
843 dbInf
.loginTimeout
= copyDb
->dbInf
.loginTimeout
;
845 // VARCHAR = Variable length character string
846 typeInfVarchar
.FsqlType
= copyDb
->typeInfVarchar
.FsqlType
;
847 typeInfVarchar
.TypeName
= copyDb
->typeInfVarchar
.TypeName
;
848 typeInfVarchar
.Precision
= copyDb
->typeInfVarchar
.Precision
;
849 typeInfVarchar
.CaseSensitive
= copyDb
->typeInfVarchar
.CaseSensitive
;
850 typeInfVarchar
.MaximumScale
= copyDb
->typeInfVarchar
.MaximumScale
;
853 typeInfFloat
.FsqlType
= copyDb
->typeInfFloat
.FsqlType
;
854 typeInfFloat
.TypeName
= copyDb
->typeInfFloat
.TypeName
;
855 typeInfFloat
.Precision
= copyDb
->typeInfFloat
.Precision
;
856 typeInfFloat
.CaseSensitive
= copyDb
->typeInfFloat
.CaseSensitive
;
857 typeInfFloat
.MaximumScale
= copyDb
->typeInfFloat
.MaximumScale
;
860 typeInfInteger
.FsqlType
= copyDb
->typeInfInteger
.FsqlType
;
861 typeInfInteger
.TypeName
= copyDb
->typeInfInteger
.TypeName
;
862 typeInfInteger
.Precision
= copyDb
->typeInfInteger
.Precision
;
863 typeInfInteger
.CaseSensitive
= copyDb
->typeInfInteger
.CaseSensitive
;
864 typeInfInteger
.MaximumScale
= copyDb
->typeInfInteger
.MaximumScale
;
867 typeInfDate
.FsqlType
= copyDb
->typeInfDate
.FsqlType
;
868 typeInfDate
.TypeName
= copyDb
->typeInfDate
.TypeName
;
869 typeInfDate
.Precision
= copyDb
->typeInfDate
.Precision
;
870 typeInfDate
.CaseSensitive
= copyDb
->typeInfDate
.CaseSensitive
;
871 typeInfDate
.MaximumScale
= copyDb
->typeInfDate
.MaximumScale
;
873 #ifdef DBDEBUG_CONSOLE
874 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
875 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
876 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
877 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
881 // Completed Successfully
886 /********** wxDb::setConnectionOptions() **********/
887 bool wxDb::setConnectionOptions(void)
889 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
894 // I need to get the DBMS name here, because some of the connection options
895 // are database specific and need to call the Dbms() function.
896 if (SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, 40, &cb
) != SQL_SUCCESS
)
897 return(DispAllErrors(henv
, hdbc
));
899 SQLSetConnectOption(hdbc
, SQL_AUTOCOMMIT
, SQL_AUTOCOMMIT_OFF
);
900 SQLSetConnectOption(hdbc
, SQL_OPT_TRACE
, SQL_OPT_TRACE_OFF
);
901 // SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads
903 // By default, MS Sql Server closes cursors on commit and rollback. The following
904 // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors
905 // after a transaction. This is a driver specific option and is not part of the
906 // ODBC standard. Note: this behavior is specific to the ODBC interface to SQL Server.
907 // The database settings don't have any effect one way or the other.
908 if (Dbms() == dbmsMS_SQL_SERVER
)
910 const long SQL_PRESERVE_CURSORS
= 1204L;
911 const long SQL_PC_ON
= 1L;
912 SQLSetConnectOption(hdbc
, SQL_PRESERVE_CURSORS
, SQL_PC_ON
);
915 // Display the connection options to verify them
916 #ifdef DBDEBUG_CONSOLE
918 cout
<< wxT("****** CONNECTION OPTIONS ******") << endl
;
920 if (SQLGetConnectOption(hdbc
, SQL_AUTOCOMMIT
, &l
) != SQL_SUCCESS
)
921 return(DispAllErrors(henv
, hdbc
));
922 cout
<< wxT("AUTOCOMMIT: ") << (l
== SQL_AUTOCOMMIT_OFF
? "OFF" : "ON") << endl
;
924 if (SQLGetConnectOption(hdbc
, SQL_ODBC_CURSORS
, &l
) != SQL_SUCCESS
)
925 return(DispAllErrors(henv
, hdbc
));
926 cout
<< wxT("ODBC CURSORS: ");
929 case(SQL_CUR_USE_IF_NEEDED
):
930 cout
<< wxT("SQL_CUR_USE_IF_NEEDED");
932 case(SQL_CUR_USE_ODBC
):
933 cout
<< wxT("SQL_CUR_USE_ODBC");
935 case(SQL_CUR_USE_DRIVER
):
936 cout
<< wxT("SQL_CUR_USE_DRIVER");
941 if (SQLGetConnectOption(hdbc
, SQL_OPT_TRACE
, &l
) != SQL_SUCCESS
)
942 return(DispAllErrors(henv
, hdbc
));
943 cout
<< wxT("TRACING: ") << (l
== SQL_OPT_TRACE_OFF
? wxT("OFF") : wxT("ON")) << endl
;
948 // Completed Successfully
951 } // wxDb::setConnectionOptions()
954 /********** wxDb::getDbInfo() **********/
955 bool wxDb::getDbInfo(void)
960 if (SQLGetInfo(hdbc
, SQL_SERVER_NAME
, (UCHAR
*) dbInf
.serverName
, 80, &cb
) != SQL_SUCCESS
)
961 return(DispAllErrors(henv
, hdbc
));
963 if (SQLGetInfo(hdbc
, SQL_DATABASE_NAME
, (UCHAR
*) dbInf
.databaseName
, 128, &cb
) != SQL_SUCCESS
)
964 return(DispAllErrors(henv
, hdbc
));
966 if (SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, 40, &cb
) != SQL_SUCCESS
)
967 return(DispAllErrors(henv
, hdbc
));
970 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
971 // causing database connectivity to fail in some cases.
972 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_VER
, (UCHAR
*) dbInf
.dbmsVer
, 64, &cb
);
974 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
975 return(DispAllErrors(henv
, hdbc
));
977 if (SQLGetInfo(hdbc
, SQL_ACTIVE_CONNECTIONS
, (UCHAR
*) &dbInf
.maxConnections
, sizeof(dbInf
.maxConnections
), &cb
) != SQL_SUCCESS
)
978 return(DispAllErrors(henv
, hdbc
));
980 if (SQLGetInfo(hdbc
, SQL_ACTIVE_STATEMENTS
, (UCHAR
*) &dbInf
.maxStmts
, sizeof(dbInf
.maxStmts
), &cb
) != SQL_SUCCESS
)
981 return(DispAllErrors(henv
, hdbc
));
983 if (SQLGetInfo(hdbc
, SQL_DRIVER_NAME
, (UCHAR
*) dbInf
.driverName
, 40, &cb
) != SQL_SUCCESS
)
984 return(DispAllErrors(henv
, hdbc
));
986 if (SQLGetInfo(hdbc
, SQL_DRIVER_ODBC_VER
, (UCHAR
*) dbInf
.odbcVer
, 60, &cb
) == SQL_ERROR
)
987 return(DispAllErrors(henv
, hdbc
));
989 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_VER
, (UCHAR
*) dbInf
.drvMgrOdbcVer
, 60, &cb
);
990 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
991 return(DispAllErrors(henv
, hdbc
));
993 if (SQLGetInfo(hdbc
, SQL_DRIVER_VER
, (UCHAR
*) dbInf
.driverVer
, 60, &cb
) == SQL_ERROR
)
994 return(DispAllErrors(henv
, hdbc
));
996 if (SQLGetInfo(hdbc
, SQL_ODBC_API_CONFORMANCE
, (UCHAR
*) &dbInf
.apiConfLvl
, sizeof(dbInf
.apiConfLvl
), &cb
) != SQL_SUCCESS
)
997 return(DispAllErrors(henv
, hdbc
));
999 if (SQLGetInfo(hdbc
, SQL_ODBC_SAG_CLI_CONFORMANCE
, (UCHAR
*) &dbInf
.cliConfLvl
, sizeof(dbInf
.cliConfLvl
), &cb
) != SQL_SUCCESS
)
1000 // return(DispAllErrors(henv, hdbc));
1002 // Not all drivers support this call - Nick Gorham(unixODBC)
1003 dbInf
.cliConfLvl
= 0;
1006 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_CONFORMANCE
, (UCHAR
*) &dbInf
.sqlConfLvl
, sizeof(dbInf
.sqlConfLvl
), &cb
) != SQL_SUCCESS
)
1007 return(DispAllErrors(henv
, hdbc
));
1009 if (SQLGetInfo(hdbc
, SQL_OUTER_JOINS
, (UCHAR
*) dbInf
.outerJoins
, 2, &cb
) != SQL_SUCCESS
)
1010 return(DispAllErrors(henv
, hdbc
));
1012 if (SQLGetInfo(hdbc
, SQL_PROCEDURES
, (UCHAR
*) dbInf
.procedureSupport
, 2, &cb
) != SQL_SUCCESS
)
1013 return(DispAllErrors(henv
, hdbc
));
1015 if (SQLGetInfo(hdbc
, SQL_ACCESSIBLE_TABLES
, (UCHAR
*) dbInf
.accessibleTables
, 2, &cb
) != SQL_SUCCESS
)
1016 return(DispAllErrors(henv
, hdbc
));
1018 if (SQLGetInfo(hdbc
, SQL_CURSOR_COMMIT_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorCommitBehavior
, sizeof(dbInf
.cursorCommitBehavior
), &cb
) != SQL_SUCCESS
)
1019 return(DispAllErrors(henv
, hdbc
));
1021 if (SQLGetInfo(hdbc
, SQL_CURSOR_ROLLBACK_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorRollbackBehavior
, sizeof(dbInf
.cursorRollbackBehavior
), &cb
) != SQL_SUCCESS
)
1022 return(DispAllErrors(henv
, hdbc
));
1024 if (SQLGetInfo(hdbc
, SQL_NON_NULLABLE_COLUMNS
, (UCHAR
*) &dbInf
.supportNotNullClause
, sizeof(dbInf
.supportNotNullClause
), &cb
) != SQL_SUCCESS
)
1025 return(DispAllErrors(henv
, hdbc
));
1027 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_OPT_IEF
, (UCHAR
*) dbInf
.supportIEF
, 2, &cb
) != SQL_SUCCESS
)
1028 return(DispAllErrors(henv
, hdbc
));
1030 if (SQLGetInfo(hdbc
, SQL_DEFAULT_TXN_ISOLATION
, (UCHAR
*) &dbInf
.txnIsolation
, sizeof(dbInf
.txnIsolation
), &cb
) != SQL_SUCCESS
)
1031 return(DispAllErrors(henv
, hdbc
));
1033 if (SQLGetInfo(hdbc
, SQL_TXN_ISOLATION_OPTION
, (UCHAR
*) &dbInf
.txnIsolationOptions
, sizeof(dbInf
.txnIsolationOptions
), &cb
) != SQL_SUCCESS
)
1034 return(DispAllErrors(henv
, hdbc
));
1036 if (SQLGetInfo(hdbc
, SQL_FETCH_DIRECTION
, (UCHAR
*) &dbInf
.fetchDirections
, sizeof(dbInf
.fetchDirections
), &cb
) != SQL_SUCCESS
)
1037 return(DispAllErrors(henv
, hdbc
));
1039 if (SQLGetInfo(hdbc
, SQL_LOCK_TYPES
, (UCHAR
*) &dbInf
.lockTypes
, sizeof(dbInf
.lockTypes
), &cb
) != SQL_SUCCESS
)
1040 return(DispAllErrors(henv
, hdbc
));
1042 if (SQLGetInfo(hdbc
, SQL_POS_OPERATIONS
, (UCHAR
*) &dbInf
.posOperations
, sizeof(dbInf
.posOperations
), &cb
) != SQL_SUCCESS
)
1043 return(DispAllErrors(henv
, hdbc
));
1045 if (SQLGetInfo(hdbc
, SQL_POSITIONED_STATEMENTS
, (UCHAR
*) &dbInf
.posStmts
, sizeof(dbInf
.posStmts
), &cb
) != SQL_SUCCESS
)
1046 return(DispAllErrors(henv
, hdbc
));
1048 if (SQLGetInfo(hdbc
, SQL_SCROLL_CONCURRENCY
, (UCHAR
*) &dbInf
.scrollConcurrency
, sizeof(dbInf
.scrollConcurrency
), &cb
) != SQL_SUCCESS
)
1049 return(DispAllErrors(henv
, hdbc
));
1051 if (SQLGetInfo(hdbc
, SQL_SCROLL_OPTIONS
, (UCHAR
*) &dbInf
.scrollOptions
, sizeof(dbInf
.scrollOptions
), &cb
) != SQL_SUCCESS
)
1052 return(DispAllErrors(henv
, hdbc
));
1054 if (SQLGetInfo(hdbc
, SQL_STATIC_SENSITIVITY
, (UCHAR
*) &dbInf
.staticSensitivity
, sizeof(dbInf
.staticSensitivity
), &cb
) != SQL_SUCCESS
)
1055 return(DispAllErrors(henv
, hdbc
));
1057 if (SQLGetInfo(hdbc
, SQL_TXN_CAPABLE
, (UCHAR
*) &dbInf
.txnCapable
, sizeof(dbInf
.txnCapable
), &cb
) != SQL_SUCCESS
)
1058 return(DispAllErrors(henv
, hdbc
));
1060 if (SQLGetInfo(hdbc
, SQL_LOGIN_TIMEOUT
, (UCHAR
*) &dbInf
.loginTimeout
, sizeof(dbInf
.loginTimeout
), &cb
) != SQL_SUCCESS
)
1061 return(DispAllErrors(henv
, hdbc
));
1063 #ifdef DBDEBUG_CONSOLE
1064 cout
<< wxT("***** DATA SOURCE INFORMATION *****") << endl
;
1065 cout
<< wxT(wxT("SERVER Name: ") << dbInf
.serverName
<< endl
;
1066 cout
<< wxT("DBMS Name: ") << dbInf
.dbmsName
<< wxT("; DBMS Version: ") << dbInf
.dbmsVer
<< endl
;
1067 cout
<< wxT("ODBC Version: ") << dbInf
.odbcVer
<< wxT("; Driver Version: ") << dbInf
.driverVer
<< endl
;
1069 cout
<< wxT("API Conf. Level: ");
1070 switch(dbInf
.apiConfLvl
)
1072 case SQL_OAC_NONE
: cout
<< wxT("None"); break;
1073 case SQL_OAC_LEVEL1
: cout
<< wxT("Level 1"); break;
1074 case SQL_OAC_LEVEL2
: cout
<< wxT("Level 2"); break;
1078 cout
<< wxT("SAG CLI Conf. Level: ");
1079 switch(dbInf
.cliConfLvl
)
1081 case SQL_OSCC_NOT_COMPLIANT
: cout
<< wxT("Not Compliant"); break;
1082 case SQL_OSCC_COMPLIANT
: cout
<< wxT("Compliant"); break;
1086 cout
<< wxT("SQL Conf. Level: ");
1087 switch(dbInf
.sqlConfLvl
)
1089 case SQL_OSC_MINIMUM
: cout
<< wxT("Minimum Grammar"); break;
1090 case SQL_OSC_CORE
: cout
<< wxT("Core Grammar"); break;
1091 case SQL_OSC_EXTENDED
: cout
<< wxT("Extended Grammar"); break;
1095 cout
<< wxT("Max. Connections: ") << dbInf
.maxConnections
<< endl
;
1096 cout
<< wxT("Outer Joins: ") << dbInf
.outerJoins
<< endl
;
1097 cout
<< wxT("Support for Procedures: ") << dbInf
.procedureSupport
<< endl
;
1098 cout
<< wxT("All tables accessible : ") << dbInf
.accessibleTables
<< endl
;
1099 cout
<< wxT("Cursor COMMIT Behavior: ");
1100 switch(dbInf
.cursorCommitBehavior
)
1102 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1103 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1104 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1108 cout
<< wxT("Cursor ROLLBACK Behavior: ");
1109 switch(dbInf
.cursorRollbackBehavior
)
1111 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1112 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1113 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1117 cout
<< wxT("Support NOT NULL clause: ");
1118 switch(dbInf
.supportNotNullClause
)
1120 case SQL_NNC_NULL
: cout
<< wxT("No"); break;
1121 case SQL_NNC_NON_NULL
: cout
<< wxT("Yes"); break;
1125 cout
<< wxT("Support IEF (Ref. Integrity): ") << dbInf
.supportIEF
<< endl
;
1126 cout
<< wxT("Login Timeout: ") << dbInf
.loginTimeout
<< endl
;
1128 cout
<< endl
<< endl
<< wxT("more ...") << endl
;
1131 cout
<< wxT("Default Transaction Isolation: ";
1132 switch(dbInf
.txnIsolation
)
1134 case SQL_TXN_READ_UNCOMMITTED
: cout
<< wxT("Read Uncommitted"); break;
1135 case SQL_TXN_READ_COMMITTED
: cout
<< wxT("Read Committed"); break;
1136 case SQL_TXN_REPEATABLE_READ
: cout
<< wxT("Repeatable Read"); break;
1137 case SQL_TXN_SERIALIZABLE
: cout
<< wxT("Serializable"); break;
1139 case SQL_TXN_VERSIONING
: cout
<< wxT("Versioning"); break;
1144 cout
<< wxT("Transaction Isolation Options: ");
1145 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_UNCOMMITTED
)
1146 cout
<< wxT("Read Uncommitted, ");
1147 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_COMMITTED
)
1148 cout
<< wxT("Read Committed, ");
1149 if (dbInf
.txnIsolationOptions
& SQL_TXN_REPEATABLE_READ
)
1150 cout
<< wxT("Repeatable Read, ");
1151 if (dbInf
.txnIsolationOptions
& SQL_TXN_SERIALIZABLE
)
1152 cout
<< wxT("Serializable, ");
1154 if (dbInf
.txnIsolationOptions
& SQL_TXN_VERSIONING
)
1155 cout
<< wxT("Versioning");
1159 cout
<< wxT("Fetch Directions Supported:") << endl
<< wxT(" ");
1160 if (dbInf
.fetchDirections
& SQL_FD_FETCH_NEXT
)
1161 cout
<< wxT("Next, ");
1162 if (dbInf
.fetchDirections
& SQL_FD_FETCH_PRIOR
)
1163 cout
<< wxT("Prev, ");
1164 if (dbInf
.fetchDirections
& SQL_FD_FETCH_FIRST
)
1165 cout
<< wxT("First, ");
1166 if (dbInf
.fetchDirections
& SQL_FD_FETCH_LAST
)
1167 cout
<< wxT("Last, ");
1168 if (dbInf
.fetchDirections
& SQL_FD_FETCH_ABSOLUTE
)
1169 cout
<< wxT("Absolute, ");
1170 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RELATIVE
)
1171 cout
<< wxT("Relative, ");
1173 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RESUME
)
1174 cout
<< wxT("Resume, ");
1176 if (dbInf
.fetchDirections
& SQL_FD_FETCH_BOOKMARK
)
1177 cout
<< wxT("Bookmark");
1180 cout
<< wxT("Lock Types Supported (SQLSetPos): ");
1181 if (dbInf
.lockTypes
& SQL_LCK_NO_CHANGE
)
1182 cout
<< wxT("No Change, ");
1183 if (dbInf
.lockTypes
& SQL_LCK_EXCLUSIVE
)
1184 cout
<< wxT("Exclusive, ");
1185 if (dbInf
.lockTypes
& SQL_LCK_UNLOCK
)
1186 cout
<< wxT("UnLock");
1189 cout
<< wxT("Position Operations Supported (SQLSetPos): ");
1190 if (dbInf
.posOperations
& SQL_POS_POSITION
)
1191 cout
<< wxT("Position, ");
1192 if (dbInf
.posOperations
& SQL_POS_REFRESH
)
1193 cout
<< wxT("Refresh, ");
1194 if (dbInf
.posOperations
& SQL_POS_UPDATE
)
1195 cout
<< wxT("Upd, "));
1196 if (dbInf
.posOperations
& SQL_POS_DELETE
)
1197 cout
<< wxT("Del, ");
1198 if (dbInf
.posOperations
& SQL_POS_ADD
)
1202 cout
<< wxT("Positioned Statements Supported: ");
1203 if (dbInf
.posStmts
& SQL_PS_POSITIONED_DELETE
)
1204 cout
<< wxT("Pos delete, ");
1205 if (dbInf
.posStmts
& SQL_PS_POSITIONED_UPDATE
)
1206 cout
<< wxT("Pos update, ");
1207 if (dbInf
.posStmts
& SQL_PS_SELECT_FOR_UPDATE
)
1208 cout
<< wxT("Select for update");
1211 cout
<< wxT("Scroll Concurrency: ");
1212 if (dbInf
.scrollConcurrency
& SQL_SCCO_READ_ONLY
)
1213 cout
<< wxT("Read Only, ");
1214 if (dbInf
.scrollConcurrency
& SQL_SCCO_LOCK
)
1215 cout
<< wxT("Lock, ");
1216 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_ROWVER
)
1217 cout
<< wxT("Opt. Rowver, ");
1218 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_VALUES
)
1219 cout
<< wxT("Opt. Values");
1222 cout
<< wxT("Scroll Options: ");
1223 if (dbInf
.scrollOptions
& SQL_SO_FORWARD_ONLY
)
1224 cout
<< wxT("Fwd Only, ");
1225 if (dbInf
.scrollOptions
& SQL_SO_STATIC
)
1226 cout
<< wxT("Static, ");
1227 if (dbInf
.scrollOptions
& SQL_SO_KEYSET_DRIVEN
)
1228 cout
<< wxT("Keyset Driven, ");
1229 if (dbInf
.scrollOptions
& SQL_SO_DYNAMIC
)
1230 cout
<< wxT("Dynamic, ");
1231 if (dbInf
.scrollOptions
& SQL_SO_MIXED
)
1232 cout
<< wxT("Mixed");
1235 cout
<< wxT("Static Sensitivity: ");
1236 if (dbInf
.staticSensitivity
& SQL_SS_ADDITIONS
)
1237 cout
<< wxT("Additions, ");
1238 if (dbInf
.staticSensitivity
& SQL_SS_DELETIONS
)
1239 cout
<< wxT("Deletions, ");
1240 if (dbInf
.staticSensitivity
& SQL_SS_UPDATES
)
1241 cout
<< wxT("Updates");
1244 cout
<< wxT("Transaction Capable?: ");
1245 switch(dbInf
.txnCapable
)
1247 case SQL_TC_NONE
: cout
<< wxT("No"); break;
1248 case SQL_TC_DML
: cout
<< wxT("DML Only"); break;
1249 case SQL_TC_DDL_COMMIT
: cout
<< wxT("DDL Commit"); break;
1250 case SQL_TC_DDL_IGNORE
: cout
<< wxT("DDL Ignore"); break;
1251 case SQL_TC_ALL
: cout
<< wxT("DDL & DML"); break;
1258 // Completed Successfully
1261 } // wxDb::getDbInfo()
1264 /********** wxDb::getDataTypeInfo() **********/
1265 bool wxDb::getDataTypeInfo(SWORD fSqlType
, wxDbSqlTypeInfo
&structSQLTypeInfo
)
1268 * fSqlType will be something like SQL_VARCHAR. This parameter determines
1269 * the data type inf. is gathered for.
1271 * wxDbSqlTypeInfo is a structure that is filled in with data type information,
1276 // Get information about the data type specified
1277 if (SQLGetTypeInfo(hstmt
, fSqlType
) != SQL_SUCCESS
)
1278 return(DispAllErrors(henv
, hdbc
, hstmt
));
1280 if ((retcode
= SQLFetch(hstmt
)) != SQL_SUCCESS
)
1282 #ifdef DBDEBUG_CONSOLE
1283 if (retcode
== SQL_NO_DATA_FOUND
)
1284 cout
<< wxT("SQL_NO_DATA_FOUND fetching inf. about data type.") << endl
;
1286 DispAllErrors(henv
, hdbc
, hstmt
);
1287 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1291 wxChar typeName
[DB_TYPE_NAME_LEN
+1];
1292 // Obtain columns from the record
1293 if (SQLGetData(hstmt
, 1, SQL_C_CHAR
, (UCHAR
*) typeName
, DB_TYPE_NAME_LEN
, &cbRet
) != SQL_SUCCESS
)
1294 return(DispAllErrors(henv
, hdbc
, hstmt
));
1296 structSQLTypeInfo
.TypeName
= typeName
;
1298 // BJO 20000503: no more needed with new GetColumns...
1301 if (Dbms() == dbmsMY_SQL
)
1303 if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1304 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1305 else if (structSQLTypeInfo
.TypeName
== wxT("middleint unsigned"))
1306 structSQLTypeInfo
.TypeName
= wxT("mediumint unsigned");
1307 else if (structSQLTypeInfo
.TypeName
== wxT("integer"))
1308 structSQLTypeInfo
.TypeName
= wxT("int");
1309 else if (structSQLTypeInfo
.TypeName
== wxT("integer unsigned"))
1310 structSQLTypeInfo
.TypeName
= wxT("int unsigned");
1311 else if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1312 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1313 else if (structSQLTypeInfo
.TypeName
== wxT("varchar"))
1314 structSQLTypeInfo
.TypeName
= wxT("char");
1317 // BJO 20000427 : OpenLink driver
1318 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
1319 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
1321 if (structSQLTypeInfo
.TypeName
== wxT("double precision"))
1322 structSQLTypeInfo
.TypeName
= wxT("real");
1326 if (SQLGetData(hstmt
, 3, SQL_C_LONG
, (UCHAR
*) &structSQLTypeInfo
.Precision
, 0, &cbRet
) != SQL_SUCCESS
)
1327 return(DispAllErrors(henv
, hdbc
, hstmt
));
1328 if (SQLGetData(hstmt
, 8, SQL_C_SHORT
, (UCHAR
*) &structSQLTypeInfo
.CaseSensitive
, 0, &cbRet
) != SQL_SUCCESS
)
1329 return(DispAllErrors(henv
, hdbc
, hstmt
));
1330 // if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
1331 // return(DispAllErrors(henv, hdbc, hstmt));
1333 if (SQLGetData(hstmt
, 15, SQL_C_SHORT
,(UCHAR
*) &structSQLTypeInfo
.MaximumScale
, 0, &cbRet
) != SQL_SUCCESS
)
1334 return(DispAllErrors(henv
, hdbc
, hstmt
));
1336 if (structSQLTypeInfo
.MaximumScale
< 0)
1337 structSQLTypeInfo
.MaximumScale
= 0;
1339 // Close the statement handle which closes open cursors
1340 if (SQLFreeStmt(hstmt
, SQL_CLOSE
) != SQL_SUCCESS
)
1341 return(DispAllErrors(henv
, hdbc
, hstmt
));
1343 // Completed Successfully
1346 } // wxDb::getDataTypeInfo()
1349 /********** wxDb::Close() **********/
1350 void wxDb::Close(void)
1352 // Close the Sql Log file
1359 // Free statement handle
1362 if (SQLFreeStmt(hstmt
, SQL_DROP
) != SQL_SUCCESS
)
1363 DispAllErrors(henv
, hdbc
);
1366 // Disconnect from the datasource
1367 if (SQLDisconnect(hdbc
) != SQL_SUCCESS
)
1368 DispAllErrors(henv
, hdbc
);
1370 // Free the connection to the datasource
1371 if (SQLFreeConnect(hdbc
) != SQL_SUCCESS
)
1372 DispAllErrors(henv
, hdbc
);
1374 // There should be zero Ctable objects still connected to this db object
1375 wxASSERT(nTables
== 0);
1380 pNode
= TablesInUse
.First();
1384 tiu
= (wxTablesInUse
*)pNode
->Data();
1385 if (tiu
->pDb
== this)
1387 s
.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu
->tableName
,tiu
->tableID
,tiu
->pDb
);
1388 s2
.Printf(wxT("Orphaned found using pDb:[%p]"),this);
1391 pNode
= pNode
->Next();
1395 // Copy the error messages to a global variable
1397 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1398 wxStrcpy(DBerrorList
[i
], errorList
[i
]);
1400 dbmsType
= dbmsUNIDENTIFIED
;
1406 /********** wxDb::CommitTrans() **********/
1407 bool wxDb::CommitTrans(void)
1411 // Commit the transaction
1412 if (SQLTransact(henv
, hdbc
, SQL_COMMIT
) != SQL_SUCCESS
)
1413 return(DispAllErrors(henv
, hdbc
));
1416 // Completed successfully
1419 } // wxDb::CommitTrans()
1422 /********** wxDb::RollbackTrans() **********/
1423 bool wxDb::RollbackTrans(void)
1425 // Rollback the transaction
1426 if (SQLTransact(henv
, hdbc
, SQL_ROLLBACK
) != SQL_SUCCESS
)
1427 return(DispAllErrors(henv
, hdbc
));
1429 // Completed successfully
1432 } // wxDb::RollbackTrans()
1435 /********** wxDb::DispAllErrors() **********/
1436 bool wxDb::DispAllErrors(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1438 * This function is called internally whenever an error condition prevents the user's
1439 * request from being executed. This function will query the datasource as to the
1440 * actual error(s) that just occured on the previous request of the datasource.
1442 * The function will retrieve each error condition from the datasource and
1443 * Printf the codes/text values into a string which it then logs via logError().
1444 * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
1445 * window and program execution will be paused until the user presses a key.
1447 * This function always returns a FALSE, so that functions which call this function
1448 * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure
1449 * of the users request, so that the calling code can then process the error msg log
1452 wxString odbcErrMsg
;
1454 while (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1456 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1457 logError(odbcErrMsg
, sqlState
);
1460 #ifdef DBDEBUG_CONSOLE
1461 // When run in console mode, use standard out to display errors.
1462 cout
<< odbcErrMsg
.c_str() << endl
;
1463 cout
<< wxT("Press any key to continue...") << endl
;
1468 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
1473 return(FALSE
); // This function always returns false.
1475 } // wxDb::DispAllErrors()
1478 /********** wxDb::GetNextError() **********/
1479 bool wxDb::GetNextError(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1481 if (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1486 } // wxDb::GetNextError()
1489 /********** wxDb::DispNextError() **********/
1490 void wxDb::DispNextError(void)
1492 wxString odbcErrMsg
;
1494 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1495 logError(odbcErrMsg
, sqlState
);
1500 #ifdef DBDEBUG_CONSOLE
1501 // When run in console mode, use standard out to display errors.
1502 cout
<< odbcErrMsg
.c_str() << endl
;
1503 cout
<< wxT("Press any key to continue...") << endl
;
1508 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE"));
1509 #endif // __WXDEBUG__
1511 } // wxDb::DispNextError()
1514 /********** wxDb::logError() **********/
1515 void wxDb::logError(const wxString
&errMsg
, const wxString
&SQLState
)
1517 wxASSERT(errMsg
.Length());
1519 static int pLast
= -1;
1522 if (++pLast
== DB_MAX_ERROR_HISTORY
)
1525 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1526 wxStrcpy(errorList
[i
], errorList
[i
+1]);
1530 wxStrcpy(errorList
[pLast
], errMsg
);
1532 if (SQLState
.Length())
1533 if ((dbStatus
= TranslateSqlState(SQLState
)) != DB_ERR_FUNCTION_SEQUENCE_ERROR
)
1534 DB_STATUS
= dbStatus
;
1536 // Add the errmsg to the sql log
1537 WriteSqlLog(errMsg
);
1539 } // wxDb::logError()
1542 /**********wxDb::TranslateSqlState() **********/
1543 int wxDb::TranslateSqlState(const wxString
&SQLState
)
1545 if (!wxStrcmp(SQLState
, wxT("01000")))
1546 return(DB_ERR_GENERAL_WARNING
);
1547 if (!wxStrcmp(SQLState
, wxT("01002")))
1548 return(DB_ERR_DISCONNECT_ERROR
);
1549 if (!wxStrcmp(SQLState
, wxT("01004")))
1550 return(DB_ERR_DATA_TRUNCATED
);
1551 if (!wxStrcmp(SQLState
, wxT("01006")))
1552 return(DB_ERR_PRIV_NOT_REVOKED
);
1553 if (!wxStrcmp(SQLState
, wxT("01S00")))
1554 return(DB_ERR_INVALID_CONN_STR_ATTR
);
1555 if (!wxStrcmp(SQLState
, wxT("01S01")))
1556 return(DB_ERR_ERROR_IN_ROW
);
1557 if (!wxStrcmp(SQLState
, wxT("01S02")))
1558 return(DB_ERR_OPTION_VALUE_CHANGED
);
1559 if (!wxStrcmp(SQLState
, wxT("01S03")))
1560 return(DB_ERR_NO_ROWS_UPD_OR_DEL
);
1561 if (!wxStrcmp(SQLState
, wxT("01S04")))
1562 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL
);
1563 if (!wxStrcmp(SQLState
, wxT("07001")))
1564 return(DB_ERR_WRONG_NO_OF_PARAMS
);
1565 if (!wxStrcmp(SQLState
, wxT("07006")))
1566 return(DB_ERR_DATA_TYPE_ATTR_VIOL
);
1567 if (!wxStrcmp(SQLState
, wxT("08001")))
1568 return(DB_ERR_UNABLE_TO_CONNECT
);
1569 if (!wxStrcmp(SQLState
, wxT("08002")))
1570 return(DB_ERR_CONNECTION_IN_USE
);
1571 if (!wxStrcmp(SQLState
, wxT("08003")))
1572 return(DB_ERR_CONNECTION_NOT_OPEN
);
1573 if (!wxStrcmp(SQLState
, wxT("08004")))
1574 return(DB_ERR_REJECTED_CONNECTION
);
1575 if (!wxStrcmp(SQLState
, wxT("08007")))
1576 return(DB_ERR_CONN_FAIL_IN_TRANS
);
1577 if (!wxStrcmp(SQLState
, wxT("08S01")))
1578 return(DB_ERR_COMM_LINK_FAILURE
);
1579 if (!wxStrcmp(SQLState
, wxT("21S01")))
1580 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH
);
1581 if (!wxStrcmp(SQLState
, wxT("21S02")))
1582 return(DB_ERR_DERIVED_TABLE_MISMATCH
);
1583 if (!wxStrcmp(SQLState
, wxT("22001")))
1584 return(DB_ERR_STRING_RIGHT_TRUNC
);
1585 if (!wxStrcmp(SQLState
, wxT("22003")))
1586 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG
);
1587 if (!wxStrcmp(SQLState
, wxT("22005")))
1588 return(DB_ERR_ERROR_IN_ASSIGNMENT
);
1589 if (!wxStrcmp(SQLState
, wxT("22008")))
1590 return(DB_ERR_DATETIME_FLD_OVERFLOW
);
1591 if (!wxStrcmp(SQLState
, wxT("22012")))
1592 return(DB_ERR_DIVIDE_BY_ZERO
);
1593 if (!wxStrcmp(SQLState
, wxT("22026")))
1594 return(DB_ERR_STR_DATA_LENGTH_MISMATCH
);
1595 if (!wxStrcmp(SQLState
, wxT("23000")))
1596 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL
);
1597 if (!wxStrcmp(SQLState
, wxT("24000")))
1598 return(DB_ERR_INVALID_CURSOR_STATE
);
1599 if (!wxStrcmp(SQLState
, wxT("25000")))
1600 return(DB_ERR_INVALID_TRANS_STATE
);
1601 if (!wxStrcmp(SQLState
, wxT("28000")))
1602 return(DB_ERR_INVALID_AUTH_SPEC
);
1603 if (!wxStrcmp(SQLState
, wxT("34000")))
1604 return(DB_ERR_INVALID_CURSOR_NAME
);
1605 if (!wxStrcmp(SQLState
, wxT("37000")))
1606 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL
);
1607 if (!wxStrcmp(SQLState
, wxT("3C000")))
1608 return(DB_ERR_DUPLICATE_CURSOR_NAME
);
1609 if (!wxStrcmp(SQLState
, wxT("40001")))
1610 return(DB_ERR_SERIALIZATION_FAILURE
);
1611 if (!wxStrcmp(SQLState
, wxT("42000")))
1612 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2
);
1613 if (!wxStrcmp(SQLState
, wxT("70100")))
1614 return(DB_ERR_OPERATION_ABORTED
);
1615 if (!wxStrcmp(SQLState
, wxT("IM001")))
1616 return(DB_ERR_UNSUPPORTED_FUNCTION
);
1617 if (!wxStrcmp(SQLState
, wxT("IM002")))
1618 return(DB_ERR_NO_DATA_SOURCE
);
1619 if (!wxStrcmp(SQLState
, wxT("IM003")))
1620 return(DB_ERR_DRIVER_LOAD_ERROR
);
1621 if (!wxStrcmp(SQLState
, wxT("IM004")))
1622 return(DB_ERR_SQLALLOCENV_FAILED
);
1623 if (!wxStrcmp(SQLState
, wxT("IM005")))
1624 return(DB_ERR_SQLALLOCCONNECT_FAILED
);
1625 if (!wxStrcmp(SQLState
, wxT("IM006")))
1626 return(DB_ERR_SQLSETCONNECTOPTION_FAILED
);
1627 if (!wxStrcmp(SQLState
, wxT("IM007")))
1628 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB
);
1629 if (!wxStrcmp(SQLState
, wxT("IM008")))
1630 return(DB_ERR_DIALOG_FAILED
);
1631 if (!wxStrcmp(SQLState
, wxT("IM009")))
1632 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL
);
1633 if (!wxStrcmp(SQLState
, wxT("IM010")))
1634 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG
);
1635 if (!wxStrcmp(SQLState
, wxT("IM011")))
1636 return(DB_ERR_DRIVER_NAME_TOO_LONG
);
1637 if (!wxStrcmp(SQLState
, wxT("IM012")))
1638 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR
);
1639 if (!wxStrcmp(SQLState
, wxT("IM013")))
1640 return(DB_ERR_TRACE_FILE_ERROR
);
1641 if (!wxStrcmp(SQLState
, wxT("S0001")))
1642 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS
);
1643 if (!wxStrcmp(SQLState
, wxT("S0002")))
1644 return(DB_ERR_TABLE_NOT_FOUND
);
1645 if (!wxStrcmp(SQLState
, wxT("S0011")))
1646 return(DB_ERR_INDEX_ALREADY_EXISTS
);
1647 if (!wxStrcmp(SQLState
, wxT("S0012")))
1648 return(DB_ERR_INDEX_NOT_FOUND
);
1649 if (!wxStrcmp(SQLState
, wxT("S0021")))
1650 return(DB_ERR_COLUMN_ALREADY_EXISTS
);
1651 if (!wxStrcmp(SQLState
, wxT("S0022")))
1652 return(DB_ERR_COLUMN_NOT_FOUND
);
1653 if (!wxStrcmp(SQLState
, wxT("S0023")))
1654 return(DB_ERR_NO_DEFAULT_FOR_COLUMN
);
1655 if (!wxStrcmp(SQLState
, wxT("S1000")))
1656 return(DB_ERR_GENERAL_ERROR
);
1657 if (!wxStrcmp(SQLState
, wxT("S1001")))
1658 return(DB_ERR_MEMORY_ALLOCATION_FAILURE
);
1659 if (!wxStrcmp(SQLState
, wxT("S1002")))
1660 return(DB_ERR_INVALID_COLUMN_NUMBER
);
1661 if (!wxStrcmp(SQLState
, wxT("S1003")))
1662 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE
);
1663 if (!wxStrcmp(SQLState
, wxT("S1004")))
1664 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE
);
1665 if (!wxStrcmp(SQLState
, wxT("S1008")))
1666 return(DB_ERR_OPERATION_CANCELLED
);
1667 if (!wxStrcmp(SQLState
, wxT("S1009")))
1668 return(DB_ERR_INVALID_ARGUMENT_VALUE
);
1669 if (!wxStrcmp(SQLState
, wxT("S1010")))
1670 return(DB_ERR_FUNCTION_SEQUENCE_ERROR
);
1671 if (!wxStrcmp(SQLState
, wxT("S1011")))
1672 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME
);
1673 if (!wxStrcmp(SQLState
, wxT("S1012")))
1674 return(DB_ERR_INVALID_TRANS_OPERATION_CODE
);
1675 if (!wxStrcmp(SQLState
, wxT("S1015")))
1676 return(DB_ERR_NO_CURSOR_NAME_AVAIL
);
1677 if (!wxStrcmp(SQLState
, wxT("S1090")))
1678 return(DB_ERR_INVALID_STR_OR_BUF_LEN
);
1679 if (!wxStrcmp(SQLState
, wxT("S1091")))
1680 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE
);
1681 if (!wxStrcmp(SQLState
, wxT("S1092")))
1682 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE
);
1683 if (!wxStrcmp(SQLState
, wxT("S1093")))
1684 return(DB_ERR_INVALID_PARAM_NO
);
1685 if (!wxStrcmp(SQLState
, wxT("S1094")))
1686 return(DB_ERR_INVALID_SCALE_VALUE
);
1687 if (!wxStrcmp(SQLState
, wxT("S1095")))
1688 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE
);
1689 if (!wxStrcmp(SQLState
, wxT("S1096")))
1690 return(DB_ERR_INF_TYPE_OUT_OF_RANGE
);
1691 if (!wxStrcmp(SQLState
, wxT("S1097")))
1692 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE
);
1693 if (!wxStrcmp(SQLState
, wxT("S1098")))
1694 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE
);
1695 if (!wxStrcmp(SQLState
, wxT("S1099")))
1696 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE
);
1697 if (!wxStrcmp(SQLState
, wxT("S1100")))
1698 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE
);
1699 if (!wxStrcmp(SQLState
, wxT("S1101")))
1700 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE
);
1701 if (!wxStrcmp(SQLState
, wxT("S1103")))
1702 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE
);
1703 if (!wxStrcmp(SQLState
, wxT("S1104")))
1704 return(DB_ERR_INVALID_PRECISION_VALUE
);
1705 if (!wxStrcmp(SQLState
, wxT("S1105")))
1706 return(DB_ERR_INVALID_PARAM_TYPE
);
1707 if (!wxStrcmp(SQLState
, wxT("S1106")))
1708 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE
);
1709 if (!wxStrcmp(SQLState
, wxT("S1107")))
1710 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE
);
1711 if (!wxStrcmp(SQLState
, wxT("S1108")))
1712 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE
);
1713 if (!wxStrcmp(SQLState
, wxT("S1109")))
1714 return(DB_ERR_INVALID_CURSOR_POSITION
);
1715 if (!wxStrcmp(SQLState
, wxT("S1110")))
1716 return(DB_ERR_INVALID_DRIVER_COMPLETION
);
1717 if (!wxStrcmp(SQLState
, wxT("S1111")))
1718 return(DB_ERR_INVALID_BOOKMARK_VALUE
);
1719 if (!wxStrcmp(SQLState
, wxT("S1C00")))
1720 return(DB_ERR_DRIVER_NOT_CAPABLE
);
1721 if (!wxStrcmp(SQLState
, wxT("S1T00")))
1722 return(DB_ERR_TIMEOUT_EXPIRED
);
1727 } // wxDb::TranslateSqlState()
1730 /********** wxDb::Grant() **********/
1731 bool wxDb::Grant(int privileges
, const wxString
&tableName
, const wxString
&userList
)
1735 // Build the grant statement
1736 sqlStmt
= wxT("GRANT ");
1737 if (privileges
== DB_GRANT_ALL
)
1738 sqlStmt
+= wxT("ALL");
1742 if (privileges
& DB_GRANT_SELECT
)
1744 sqlStmt
+= wxT("SELECT");
1747 if (privileges
& DB_GRANT_INSERT
)
1750 sqlStmt
+= wxT(", ");
1751 sqlStmt
+= wxT("INSERT");
1753 if (privileges
& DB_GRANT_UPDATE
)
1756 sqlStmt
+= wxT(", ");
1757 sqlStmt
+= wxT("UPDATE");
1759 if (privileges
& DB_GRANT_DELETE
)
1762 sqlStmt
+= wxT(", ");
1763 sqlStmt
+= wxT("DELETE");
1767 sqlStmt
+= wxT(" ON ");
1768 sqlStmt
+= tableName
;
1769 sqlStmt
+= wxT(" TO ");
1770 sqlStmt
+= userList
;
1772 #ifdef DBDEBUG_CONSOLE
1773 cout
<< endl
<< sqlStmt
.c_str() << endl
;
1776 WriteSqlLog(sqlStmt
);
1778 return(ExecSql(sqlStmt
));
1783 /********** wxDb::CreateView() **********/
1784 bool wxDb::CreateView(const wxString
&viewName
, const wxString
&colList
,
1785 const wxString
&pSqlStmt
, bool attemptDrop
)
1789 // Drop the view first
1790 if (attemptDrop
&& !DropView(viewName
))
1793 // Build the create view statement
1794 sqlStmt
= wxT("CREATE VIEW ");
1795 sqlStmt
+= viewName
;
1797 if (colList
.Length())
1799 sqlStmt
+= wxT(" (");
1801 sqlStmt
+= wxT(")");
1804 sqlStmt
+= wxT(" AS ");
1805 sqlStmt
+= pSqlStmt
;
1807 WriteSqlLog(sqlStmt
);
1809 #ifdef DBDEBUG_CONSOLE
1810 cout
<< sqlStmt
.c_str() << endl
;
1813 return(ExecSql(sqlStmt
));
1815 } // wxDb::CreateView()
1818 /********** wxDb::DropView() **********/
1819 bool wxDb::DropView(const wxString
&viewName
)
1822 * NOTE: This function returns TRUE if the View does not exist, but
1823 * only for identified databases. Code will need to be added
1824 * below for any other databases when those databases are defined
1825 * to handle this situation consistently
1829 sqlStmt
.Printf(wxT("DROP VIEW %s"), viewName
.c_str());
1831 WriteSqlLog(sqlStmt
);
1833 #ifdef DBDEBUG_CONSOLE
1834 cout
<< endl
<< sqlStmt
.c_str() << endl
;
1837 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
1839 // Check for "Base table not found" error and ignore
1840 GetNextError(henv
, hdbc
, hstmt
);
1841 if (wxStrcmp(sqlState
,wxT("S0002"))) // "Base table not found"
1843 // Check for product specific error codes
1844 if (!((Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(sqlState
,wxT("42000"))))) // 5.x (and lower?)
1847 DispAllErrors(henv
, hdbc
, hstmt
);
1854 // Commit the transaction
1855 if (! CommitTrans())
1860 } // wxDb::DropView()
1863 /********** wxDb::ExecSql() **********/
1864 bool wxDb::ExecSql(const wxString
&pSqlStmt
)
1866 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1867 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) pSqlStmt
.c_str(), SQL_NTS
) == SQL_SUCCESS
)
1871 DispAllErrors(henv
, hdbc
, hstmt
);
1875 } // wxDb::ExecSql()
1878 /********** wxDb::GetNext() **********/
1879 bool wxDb::GetNext(void)
1881 if (SQLFetch(hstmt
) == SQL_SUCCESS
)
1885 DispAllErrors(henv
, hdbc
, hstmt
);
1889 } // wxDb::GetNext()
1892 /********** wxDb::GetData() **********/
1893 bool wxDb::GetData(UWORD colNo
, SWORD cType
, PTR pData
, SDWORD maxLen
, SDWORD FAR
*cbReturned
)
1896 wxASSERT(cbReturned
);
1898 if (SQLGetData(hstmt
, colNo
, cType
, pData
, maxLen
, cbReturned
) == SQL_SUCCESS
)
1902 DispAllErrors(henv
, hdbc
, hstmt
);
1906 } // wxDb::GetData()
1909 /********** wxDb::GetKeyFields() **********/
1910 int wxDb::GetKeyFields(const wxString
&tableName
, wxDbColInf
* colInf
, int noCols
)
1912 wxChar szPkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Primary key table name */
1913 wxChar szFkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Foreign key table name */
1915 // SQLSMALLINT iKeySeq;
1916 wxChar szPkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Primary key column */
1917 wxChar szFkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Foreign key column */
1923 * -----------------------------------------------------------------------
1924 * -- 19991224 : mj10777 : Create ------
1925 * -- : Three things are done and stored here : ------
1926 * -- : 1) which Column(s) is/are Primary Key(s) ------
1927 * -- : 2) which tables use this Key as a Foreign Key ------
1928 * -- : 3) which columns are Foreign Key and the name ------
1929 * -- : of the Table where the Key is the Primary Key -----
1930 * -- : Called from GetColumns(const wxString &tableName, ------
1931 * -- int *numCols,const wxChar *userID ) ------
1932 * -----------------------------------------------------------------------
1935 /*---------------------------------------------------------------------*/
1936 /* Get the names of the columns in the primary key. */
1937 /*---------------------------------------------------------------------*/
1938 retcode
= SQLPrimaryKeys(hstmt
,
1939 NULL
, 0, /* Catalog name */
1940 NULL
, 0, /* Schema name */
1941 (UCHAR FAR
*) tableName
.c_str(), SQL_NTS
); /* Table name */
1943 /*---------------------------------------------------------------------*/
1944 /* Fetch and display the result set. This will be a list of the */
1945 /* columns in the primary key of the tableName table. */
1946 /*---------------------------------------------------------------------*/
1947 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1949 retcode
= SQLFetch(hstmt
);
1950 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1952 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1953 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1955 for (i
=0;i
<noCols
;i
++) // Find the Column name
1956 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column
1957 colInf
[i
].PkCol
= iKeySeq
; // Which Primary Key is this (first, second usw.) ?
1960 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1962 /*---------------------------------------------------------------------*/
1963 /* Get all the foreign keys that refer to tableName primary key. */
1964 /*---------------------------------------------------------------------*/
1965 retcode
= SQLForeignKeys(hstmt
,
1966 NULL
, 0, /* Primary catalog */
1967 NULL
, 0, /* Primary schema */
1968 (UCHAR FAR
*)tableName
.c_str(), SQL_NTS
,/* Primary table */
1969 NULL
, 0, /* Foreign catalog */
1970 NULL
, 0, /* Foreign schema */
1971 NULL
, 0); /* Foreign table */
1973 /*---------------------------------------------------------------------*/
1974 /* Fetch and display the result set. This will be all of the foreign */
1975 /* keys in other tables that refer to the tableName primary key. */
1976 /*---------------------------------------------------------------------*/
1979 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1981 retcode
= SQLFetch(hstmt
);
1982 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1984 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1985 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1986 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1987 GetData( 7, SQL_C_CHAR
, szFkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1988 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1989 tempStr
.Printf(wxT("%s[%s] "),tempStr
.c_str(),szFkTable
); // [ ] in case there is a blank in the Table name
1993 tempStr
.Trim(); // Get rid of any unneeded blanks
1994 if (!tempStr
.IsEmpty())
1996 for (i
=0; i
<noCols
; i
++)
1997 { // Find the Column name
1998 if (!wxStrcmp(colInf
[i
].colName
, szPkCol
)) // We have found the Column, store the Information
1999 wxStrcpy(colInf
[i
].PkTableName
, tempStr
.c_str()); // Name of the Tables where this Primary Key is used as a Foreign Key
2003 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
2005 /*---------------------------------------------------------------------*/
2006 /* Get all the foreign keys in the tablename table. */
2007 /*---------------------------------------------------------------------*/
2008 retcode
= SQLForeignKeys(hstmt
,
2009 NULL
, 0, /* Primary catalog */
2010 NULL
, 0, /* Primary schema */
2011 NULL
, 0, /* Primary table */
2012 NULL
, 0, /* Foreign catalog */
2013 NULL
, 0, /* Foreign schema */
2014 (UCHAR
*)tableName
.c_str(), SQL_NTS
);/* Foreign table */
2016 /*---------------------------------------------------------------------*/
2017 /* Fetch and display the result set. This will be all of the */
2018 /* primary keys in other tables that are referred to by foreign */
2019 /* keys in the tableName table. */
2020 /*---------------------------------------------------------------------*/
2022 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
2024 retcode
= SQLFetch(hstmt
);
2025 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
2027 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2028 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
2029 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2031 for (i
=0; i
<noCols
; i
++) // Find the Column name
2033 if (!wxStrcmp(colInf
[i
].colName
,szFkCol
)) // We have found the (Foreign Key) Column
2035 colInf
[i
].FkCol
= iKeySeq
; // Which Foreign Key is this (first, second usw.) ?
2036 wxStrcpy(colInf
[i
].FkTableName
,szPkTable
); // Name of the Table where this Foriegn is the Primary Key
2041 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
2045 } // wxDb::GetKeyFields()
2049 /********** wxDb::GetColumns() **********/
2050 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2052 * 1) The last array element of the tableName[] argument must be zero (null).
2053 * This is how the end of the array is detected.
2054 * 2) This function returns an array of wxDbColInf structures. If no columns
2055 * were found, or an error occured, this pointer will be zero (null). THE
2056 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
2057 * IS FINISHED WITH IT. i.e.
2059 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
2062 * // Use the column inf
2064 * // Destroy the memory
2068 * userID is evaluated in the following manner:
2069 * userID == NULL ... UserID is ignored
2070 * userID == "" ... UserID set equal to 'this->uid'
2071 * userID != "" ... UserID set equal to 'userID'
2073 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2074 * by this function. This function should use its own wxDb instance
2075 * to avoid undesired unbinding of columns.
2080 wxDbColInf
*colInf
= 0;
2088 convertUserID(userID
,UserID
);
2090 // Pass 1 - Determine how many columns there are.
2091 // Pass 2 - Allocate the wxDbColInf array and fill in
2092 // the array with the column information.
2094 for (pass
= 1; pass
<= 2; pass
++)
2098 if (noCols
== 0) // Probably a bogus table name(s)
2100 // Allocate n wxDbColInf objects to hold the column information
2101 colInf
= new wxDbColInf
[noCols
+1];
2104 // Mark the end of the array
2105 wxStrcpy(colInf
[noCols
].tableName
,wxEmptyString
);
2106 wxStrcpy(colInf
[noCols
].colName
,wxEmptyString
);
2107 colInf
[noCols
].sqlDataType
= 0;
2109 // Loop through each table name
2111 for (tbl
= 0; tableName
[tbl
]; tbl
++)
2113 TableName
= tableName
[tbl
];
2114 // Oracle and Interbase table names are uppercase only, so force
2115 // the name to uppercase just in case programmer forgot to do this
2116 if ((Dbms() == dbmsORACLE
) ||
2117 (Dbms() == dbmsINTERBASE
))
2118 TableName
= TableName
.Upper();
2120 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2122 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2123 // use the call below that leaves out the user name
2124 if (!UserID
.IsEmpty() &&
2125 Dbms() != dbmsMY_SQL
&&
2126 Dbms() != dbmsACCESS
&&
2127 Dbms() != dbmsMS_SQL_SERVER
)
2129 retcode
= SQLColumns(hstmt
,
2130 NULL
, 0, // All qualifiers
2131 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2132 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2133 NULL
, 0); // All columns
2137 retcode
= SQLColumns(hstmt
,
2138 NULL
, 0, // All qualifiers
2140 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2141 NULL
, 0); // All columns
2143 if (retcode
!= SQL_SUCCESS
)
2144 { // Error occured, abort
2145 DispAllErrors(henv
, hdbc
, hstmt
);
2148 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2152 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2154 if (pass
== 1) // First pass, just add up the number of columns
2156 else // Pass 2; Fill in the array of structures
2158 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2160 // NOTE: Only the ODBC 1.x fields are retrieved
2161 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2162 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2163 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2164 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2165 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2166 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2167 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2168 GetData( 8, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2169 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2170 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2171 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2172 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2174 // Determine the wxDb data type that is used to represent the native data type of this data source
2175 colInf
[colNo
].dbDataType
= 0;
2176 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
2179 // IODBC does not return a correct columnSize, so we set
2180 // columnSize = bufferLength if no column size was returned
2181 // IODBC returns the columnSize in bufferLength.. (bug)
2182 if (colInf
[colNo
].columnSize
< 1)
2184 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2187 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2189 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
2190 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2191 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
2192 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2193 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
2194 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2200 if (retcode
!= SQL_NO_DATA_FOUND
)
2201 { // Error occured, abort
2202 DispAllErrors(henv
, hdbc
, hstmt
);
2205 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2211 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2214 } // wxDb::GetColumns()
2217 /********** wxDb::GetColumns() **********/
2219 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, int *numCols
, const wxChar
*userID
)
2221 // Same as the above GetColumns() function except this one gets columns
2222 // only for a single table, and if 'numCols' is not NULL, the number of
2223 // columns stored in the returned wxDbColInf is set in '*numCols'
2225 // userID is evaluated in the following manner:
2226 // userID == NULL ... UserID is ignored
2227 // userID == "" ... UserID set equal to 'this->uid'
2228 // userID != "" ... UserID set equal to 'userID'
2230 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2231 // by this function. This function should use its own wxDb instance
2232 // to avoid undesired unbinding of columns.
2237 wxDbColInf
*colInf
= 0;
2245 convertUserID(userID
,UserID
);
2247 // Pass 1 - Determine how many columns there are.
2248 // Pass 2 - Allocate the wxDbColInf array and fill in
2249 // the array with the column information.
2251 for (pass
= 1; pass
<= 2; pass
++)
2255 if (noCols
== 0) // Probably a bogus table name(s)
2257 // Allocate n wxDbColInf objects to hold the column information
2258 colInf
= new wxDbColInf
[noCols
+1];
2261 // Mark the end of the array
2262 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2263 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2264 colInf
[noCols
].sqlDataType
= 0;
2267 TableName
= tableName
;
2268 // Oracle and Interbase table names are uppercase only, so force
2269 // the name to uppercase just in case programmer forgot to do this
2270 if ((Dbms() == dbmsORACLE
) ||
2271 (Dbms() == dbmsINTERBASE
))
2272 TableName
= TableName
.Upper();
2274 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2276 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2277 // use the call below that leaves out the user name
2278 if (!UserID
.IsEmpty() &&
2279 Dbms() != dbmsMY_SQL
&&
2280 Dbms() != dbmsACCESS
&&
2281 Dbms() != dbmsMS_SQL_SERVER
)
2283 retcode
= SQLColumns(hstmt
,
2284 NULL
, 0, // All qualifiers
2285 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2286 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2287 NULL
, 0); // All columns
2291 retcode
= SQLColumns(hstmt
,
2292 NULL
, 0, // All qualifiers
2294 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2295 NULL
, 0); // All columns
2297 if (retcode
!= SQL_SUCCESS
)
2298 { // Error occured, abort
2299 DispAllErrors(henv
, hdbc
, hstmt
);
2302 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2308 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2310 if (pass
== 1) // First pass, just add up the number of columns
2312 else // Pass 2; Fill in the array of structures
2314 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2316 // NOTE: Only the ODBC 1.x fields are retrieved
2317 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2318 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2319 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2320 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2321 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2322 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2323 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2324 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
2325 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2326 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2327 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2328 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2329 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2330 // Start Values for Primary/Foriegn Key (=No)
2331 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2332 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2333 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2334 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
2336 // BJO 20000428 : Virtuoso returns type names with upper cases!
2337 if (Dbms() == dbmsVIRTUOSO
)
2339 wxString s
= colInf
[colNo
].typeName
;
2341 wxStrcmp(colInf
[colNo
].typeName
, s
.c_str());
2344 // Determine the wxDb data type that is used to represent the native data type of this data source
2345 colInf
[colNo
].dbDataType
= 0;
2346 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
2349 // IODBC does not return a correct columnSize, so we set
2350 // columnSize = bufferLength if no column size was returned
2351 // IODBC returns the columnSize in bufferLength.. (bug)
2352 if (colInf
[colNo
].columnSize
< 1)
2354 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2358 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2360 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
2361 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2362 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
2363 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2364 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
2365 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2371 if (retcode
!= SQL_NO_DATA_FOUND
)
2372 { // Error occured, abort
2373 DispAllErrors(henv
, hdbc
, hstmt
);
2376 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2383 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2385 // Store Primary and Foriegn Keys
2386 GetKeyFields(tableName
,colInf
,noCols
);
2392 } // wxDb::GetColumns()
2395 #else // New GetColumns
2400 These are tentative new GetColumns members which should be more database
2401 independant and which always returns the columns in the order they were
2404 - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const
2405 wxChar* userID)) calls the second implementation for each separate table
2406 before merging the results. This makes the code easier to maintain as
2407 only one member (the second) makes the real work
2408 - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const
2409 wxChar *userID) is a little bit improved
2410 - It doesn't anymore rely on the type-name to find out which database-type
2412 - It ends by sorting the columns, so that they are returned in the same
2413 order they were created
2423 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2426 // The last array element of the tableName[] argument must be zero (null).
2427 // This is how the end of the array is detected.
2431 // How many tables ?
2433 for (tbl
= 0 ; tableName
[tbl
]; tbl
++);
2435 // Create a table to maintain the columns for each separate table
2436 _TableColumns
*TableColumns
= new _TableColumns
[tbl
];
2439 for (i
= 0 ; i
< tbl
; i
++)
2442 TableColumns
[i
].colInf
= GetColumns(tableName
[i
], &TableColumns
[i
].noCols
, userID
);
2443 if (TableColumns
[i
].colInf
== NULL
)
2445 noCols
+= TableColumns
[i
].noCols
;
2448 // Now merge all the separate table infos
2449 wxDbColInf
*colInf
= new wxDbColInf
[noCols
+1];
2451 // Mark the end of the array
2452 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2453 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2454 colInf
[noCols
].sqlDataType
= 0;
2459 for (i
= 0 ; i
< tbl
; i
++)
2461 for (j
= 0 ; j
< TableColumns
[i
].noCols
; j
++)
2463 colInf
[offset
++] = TableColumns
[i
].colInf
[j
];
2467 delete [] TableColumns
;
2470 } // wxDb::GetColumns() -- NEW
2473 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, int *numCols
, const wxChar
*userID
)
2475 // Same as the above GetColumns() function except this one gets columns
2476 // only for a single table, and if 'numCols' is not NULL, the number of
2477 // columns stored in the returned wxDbColInf is set in '*numCols'
2479 // userID is evaluated in the following manner:
2480 // userID == NULL ... UserID is ignored
2481 // userID == "" ... UserID set equal to 'this->uid'
2482 // userID != "" ... UserID set equal to 'userID'
2484 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2485 // by this function. This function should use its own wxDb instance
2486 // to avoid undesired unbinding of columns.
2490 wxDbColInf
*colInf
= 0;
2498 convertUserID(userID
,UserID
);
2500 // Pass 1 - Determine how many columns there are.
2501 // Pass 2 - Allocate the wxDbColInf array and fill in
2502 // the array with the column information.
2504 for (pass
= 1; pass
<= 2; pass
++)
2508 if (noCols
== 0) // Probably a bogus table name(s)
2510 // Allocate n wxDbColInf objects to hold the column information
2511 colInf
= new wxDbColInf
[noCols
+1];
2514 // Mark the end of the array
2515 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2516 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2517 colInf
[noCols
].sqlDataType
= 0;
2520 TableName
= tableName
;
2521 // Oracle and Interbase table names are uppercase only, so force
2522 // the name to uppercase just in case programmer forgot to do this
2523 if ((Dbms() == dbmsORACLE
) ||
2524 (Dbms() == dbmsINTERBASE
))
2525 TableName
= TableName
.Upper();
2527 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2529 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2530 // use the call below that leaves out the user name
2531 if (!UserID
.IsEmpty() &&
2532 Dbms() != dbmsMY_SQL
&&
2533 Dbms() != dbmsACCESS
&&
2534 Dbms() != dbmsMS_SQL_SERVER
)
2536 retcode
= SQLColumns(hstmt
,
2537 NULL
, 0, // All qualifiers
2538 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2539 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2540 NULL
, 0); // All columns
2544 retcode
= SQLColumns(hstmt
,
2545 NULL
, 0, // All qualifiers
2547 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2548 NULL
, 0); // All columns
2550 if (retcode
!= SQL_SUCCESS
)
2551 { // Error occured, abort
2552 DispAllErrors(henv
, hdbc
, hstmt
);
2555 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2561 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2563 if (pass
== 1) // First pass, just add up the number of columns
2565 else // Pass 2; Fill in the array of structures
2567 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2569 // NOTE: Only the ODBC 1.x fields are retrieved
2570 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2571 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2572 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2573 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2574 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2575 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2576 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2577 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2578 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2579 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2580 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2581 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2582 // Start Values for Primary/Foriegn Key (=No)
2583 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2584 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2585 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2586 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
2589 // IODBC does not return a correct columnSize, so we set
2590 // columnSize = bufferLength if no column size was returned
2591 // IODBC returns the columnSize in bufferLength.. (bug)
2592 if (colInf
[colNo
].columnSize
< 1)
2594 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2598 // Determine the wxDb data type that is used to represent the native data type of this data source
2599 colInf
[colNo
].dbDataType
= 0;
2600 // Get the intern datatype
2601 switch (colInf
[colNo
].sqlDataType
)
2605 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2611 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2618 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2621 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2626 errMsg
.Printf(wxT("SQL Data type %d currently not supported by wxWindows"), colInf
[colNo
].sqlDataType
);
2627 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
2634 if (retcode
!= SQL_NO_DATA_FOUND
)
2635 { // Error occured, abort
2636 DispAllErrors(henv
, hdbc
, hstmt
);
2639 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2646 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2648 // Store Primary and Foreign Keys
2649 GetKeyFields(tableName
,colInf
,noCols
);
2651 ///////////////////////////////////////////////////////////////////////////
2652 // Now sort the the columns in order to make them appear in the right order
2653 ///////////////////////////////////////////////////////////////////////////
2655 // Build a generic SELECT statement which returns 0 rows
2658 Stmt
.Printf(wxT("select * from %s where 0=1"), tableName
);
2661 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) Stmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
2663 DispAllErrors(henv
, hdbc
, hstmt
);
2667 // Get the number of result columns
2668 if (SQLNumResultCols (hstmt
, &noCols
) != SQL_SUCCESS
)
2670 DispAllErrors(henv
, hdbc
, hstmt
);
2674 if (noCols
== 0) // Probably a bogus table name
2683 for (colNum
= 0; colNum
< noCols
; colNum
++)
2685 if (SQLColAttributes(hstmt
,colNum
+1, SQL_COLUMN_NAME
,
2687 &Sword
, &Sdword
) != SQL_SUCCESS
)
2689 DispAllErrors(henv
, hdbc
, hstmt
);
2693 wxString Name1
= name
;
2694 Name1
= Name1
.Upper();
2696 // Where is this name in the array ?
2697 for (i
= colNum
; i
< noCols
; i
++)
2699 wxString Name2
= colInf
[i
].colName
;
2700 Name2
= Name2
.Upper();
2703 if (colNum
!= i
) // swap to sort
2705 wxDbColInf tmpColInf
= colInf
[colNum
];
2706 colInf
[colNum
] = colInf
[i
];
2707 colInf
[i
] = tmpColInf
;
2713 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2715 ///////////////////////////////////////////////////////////////////////////
2717 ///////////////////////////////////////////////////////////////////////////
2723 } // wxDb::GetColumns()
2726 #endif // #else OLD_GETCOLUMNS
2729 /********** wxDb::GetColumnCount() **********/
2730 int wxDb::GetColumnCount(const wxString
&tableName
, const wxChar
*userID
)
2732 * Returns a count of how many columns are in a table.
2733 * If an error occurs in computing the number of columns
2734 * this function will return a -1 for the count
2736 * userID is evaluated in the following manner:
2737 * userID == NULL ... UserID is ignored
2738 * userID == "" ... UserID set equal to 'this->uid'
2739 * userID != "" ... UserID set equal to 'userID'
2741 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2742 * by this function. This function should use its own wxDb instance
2743 * to avoid undesired unbinding of columns.
2753 convertUserID(userID
,UserID
);
2755 TableName
= tableName
;
2756 // Oracle and Interbase table names are uppercase only, so force
2757 // the name to uppercase just in case programmer forgot to do this
2758 if ((Dbms() == dbmsORACLE
) ||
2759 (Dbms() == dbmsINTERBASE
))
2760 TableName
= TableName
.Upper();
2762 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2764 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2765 // use the call below that leaves out the user name
2766 if (!UserID
.IsEmpty() &&
2767 Dbms() != dbmsMY_SQL
&&
2768 Dbms() != dbmsACCESS
&&
2769 Dbms() != dbmsMS_SQL_SERVER
)
2771 retcode
= SQLColumns(hstmt
,
2772 NULL
, 0, // All qualifiers
2773 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2774 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2775 NULL
, 0); // All columns
2779 retcode
= SQLColumns(hstmt
,
2780 NULL
, 0, // All qualifiers
2782 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2783 NULL
, 0); // All columns
2785 if (retcode
!= SQL_SUCCESS
)
2786 { // Error occured, abort
2787 DispAllErrors(henv
, hdbc
, hstmt
);
2788 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2792 // Count the columns
2793 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2796 if (retcode
!= SQL_NO_DATA_FOUND
)
2797 { // Error occured, abort
2798 DispAllErrors(henv
, hdbc
, hstmt
);
2799 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2803 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2806 } // wxDb::GetColumnCount()
2809 /********** wxDb::GetCatalog() *******/
2810 wxDbInf
*wxDb::GetCatalog(const wxChar
*userID
)
2812 * ---------------------------------------------------------------------
2813 * -- 19991203 : mj10777 : Create ------
2814 * -- : Creates a wxDbInf with Tables / Cols Array ------
2815 * -- : uses SQLTables and fills pTableInf; ------
2816 * -- : pColInf is set to NULL and numCols to 0; ------
2817 * -- : returns pDbInf (wxDbInf) ------
2818 * -- - if unsuccesfull (pDbInf == NULL) ------
2819 * -- : pColInf can be filled with GetColumns(..); ------
2820 * -- : numCols can be filled with GetColumnCount(..); ------
2821 * ---------------------------------------------------------------------
2823 * userID is evaluated in the following manner:
2824 * userID == NULL ... UserID is ignored
2825 * userID == "" ... UserID set equal to 'this->uid'
2826 * userID != "" ... UserID set equal to 'userID'
2828 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2829 * by this function. This function should use its own wxDb instance
2830 * to avoid undesired unbinding of columns.
2833 wxDbInf
*pDbInf
= NULL
; // Array of catalog entries
2834 int noTab
= 0; // Counter while filling table entries
2838 wxString tblNameSave
;
2841 convertUserID(userID
,UserID
);
2843 //-------------------------------------------------------------
2844 pDbInf
= new wxDbInf
; // Create the Database Array
2845 //-------------------------------------------------------------
2846 // Table Information
2847 // Pass 1 - Determine how many Tables there are.
2848 // Pass 2 - Create the Table array and fill it
2849 // - Create the Cols array = NULL
2850 //-------------------------------------------------------------
2852 for (pass
= 1; pass
<= 2; pass
++)
2854 SQLFreeStmt(hstmt
, SQL_CLOSE
); // Close if Open
2855 tblNameSave
.Empty();
2857 if (!UserID
.IsEmpty() &&
2858 Dbms() != dbmsMY_SQL
&&
2859 Dbms() != dbmsACCESS
&&
2860 Dbms() != dbmsMS_SQL_SERVER
)
2862 retcode
= SQLTables(hstmt
,
2863 NULL
, 0, // All qualifiers
2864 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
2865 NULL
, 0, // All tables
2866 NULL
, 0); // All columns
2870 retcode
= SQLTables(hstmt
,
2871 NULL
, 0, // All qualifiers
2872 NULL
, 0, // User specified
2873 NULL
, 0, // All tables
2874 NULL
, 0); // All columns
2877 if (retcode
!= SQL_SUCCESS
)
2879 DispAllErrors(henv
, hdbc
, hstmt
);
2881 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2885 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
) // Table Information
2887 if (pass
== 1) // First pass, just count the Tables
2889 if (pDbInf
->numTables
== 0)
2891 GetData( 1, SQL_C_CHAR
, (UCHAR
*) pDbInf
->catalog
, 128+1, &cb
);
2892 GetData( 2, SQL_C_CHAR
, (UCHAR
*) pDbInf
->schema
, 128+1, &cb
);
2894 pDbInf
->numTables
++; // Counter for Tables
2896 if (pass
== 2) // Create and fill the Table entries
2898 if (pDbInf
->pTableInf
== NULL
) // Has the Table Array been created
2899 { // no, then create the Array
2900 pDbInf
->pTableInf
= new wxDbTableInf
[pDbInf
->numTables
];
2902 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
2904 GetData( 3, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2905 GetData( 4, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableType
, 30+1, &cb
);
2906 GetData( 5, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableRemarks
, 254+1, &cb
);
2912 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2914 // Query how many columns are in each table
2915 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
2917 (pDbInf
->pTableInf
+noTab
)->numCols
= GetColumnCount((pDbInf
->pTableInf
+noTab
)->tableName
,UserID
);
2922 } // wxDb::GetCatalog()
2925 /********** wxDb::Catalog() **********/
2926 bool wxDb::Catalog(const wxChar
*userID
, const wxString
&fileName
)
2928 * Creates the text file specified in 'filename' which will contain
2929 * a minimal data dictionary of all tables accessible by the user specified
2932 * userID is evaluated in the following manner:
2933 * userID == NULL ... UserID is ignored
2934 * userID == "" ... UserID set equal to 'this->uid'
2935 * userID != "" ... UserID set equal to 'userID'
2937 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2938 * by this function. This function should use its own wxDb instance
2939 * to avoid undesired unbinding of columns.
2942 wxASSERT(fileName
.Length());
2946 wxChar tblName
[DB_MAX_TABLE_NAME_LEN
+1];
2947 wxString tblNameSave
;
2948 wxChar colName
[DB_MAX_COLUMN_NAME_LEN
+1];
2950 wxChar typeName
[30+1];
2951 SWORD precision
, length
;
2953 FILE *fp
= fopen(fileName
.c_str(),wxT("wt"));
2957 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2960 convertUserID(userID
,UserID
);
2962 if (!UserID
.IsEmpty() &&
2963 Dbms() != dbmsMY_SQL
&&
2964 Dbms() != dbmsACCESS
&&
2965 Dbms() != dbmsMS_SQL_SERVER
)
2967 retcode
= SQLColumns(hstmt
,
2968 NULL
, 0, // All qualifiers
2969 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
2970 NULL
, 0, // All tables
2971 NULL
, 0); // All columns
2975 retcode
= SQLColumns(hstmt
,
2976 NULL
, 0, // All qualifiers
2977 NULL
, 0, // User specified
2978 NULL
, 0, // All tables
2979 NULL
, 0); // All columns
2981 if (retcode
!= SQL_SUCCESS
)
2983 DispAllErrors(henv
, hdbc
, hstmt
);
2989 tblNameSave
.Empty();
2992 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2994 if (wxStrcmp(tblName
, tblNameSave
.c_str()))
2997 fputs(wxT("\n"), fp
);
2998 fputs(wxT("================================ "), fp
);
2999 fputs(wxT("================================ "), fp
);
3000 fputs(wxT("===================== "), fp
);
3001 fputs(wxT("========= "), fp
);
3002 fputs(wxT("=========\n"), fp
);
3003 outStr
.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
3004 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
3005 fputs(outStr
.c_str(), fp
);
3006 fputs(wxT("================================ "), fp
);
3007 fputs(wxT("================================ "), fp
);
3008 fputs(wxT("===================== "), fp
);
3009 fputs(wxT("========= "), fp
);
3010 fputs(wxT("=========\n"), fp
);
3011 tblNameSave
= tblName
;
3014 GetData(3,SQL_C_CHAR
, (UCHAR
*)tblName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
3015 GetData(4,SQL_C_CHAR
, (UCHAR
*)colName
, DB_MAX_COLUMN_NAME_LEN
+1,&cb
);
3016 GetData(5,SQL_C_SSHORT
,(UCHAR
*)&sqlDataType
,0, &cb
);
3017 GetData(6,SQL_C_CHAR
, (UCHAR
*)typeName
, sizeof(typeName
), &cb
);
3018 GetData(7,SQL_C_SSHORT
,(UCHAR
*)&precision
, 0, &cb
);
3019 GetData(8,SQL_C_SSHORT
,(UCHAR
*)&length
, 0, &cb
);
3021 outStr
.Printf(wxT("%-32s %-32s (%04d)%-15s %9d %9d\n"),
3022 tblName
, colName
, sqlDataType
, typeName
, precision
, length
);
3023 if (fputs(outStr
.c_str(), fp
) == EOF
)
3025 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3032 if (retcode
!= SQL_NO_DATA_FOUND
)
3033 DispAllErrors(henv
, hdbc
, hstmt
);
3035 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3038 return(retcode
== SQL_NO_DATA_FOUND
);
3040 } // wxDb::Catalog()
3043 bool wxDb::TableExists(const wxString
&tableName
, const wxChar
*userID
, const wxString
&tablePath
)
3045 * Table name can refer to a table, view, alias or synonym. Returns true
3046 * if the object exists in the database. This function does not indicate
3047 * whether or not the user has privleges to query or perform other functions
3050 * userID is evaluated in the following manner:
3051 * userID == NULL ... UserID is ignored
3052 * userID == "" ... UserID set equal to 'this->uid'
3053 * userID != "" ... UserID set equal to 'userID'
3056 wxASSERT(tableName
.Length());
3060 if (Dbms() == dbmsDBASE
)
3063 if (tablePath
.Length())
3064 dbName
.Printf(wxT("%s/%s.dbf"), tablePath
.c_str(), tableName
.c_str());
3066 dbName
.Printf(wxT("%s.dbf"), tableName
.c_str());
3069 exists
= wxFileExists(dbName
);
3074 convertUserID(userID
,UserID
);
3076 TableName
= tableName
;
3077 // Oracle and Interbase table names are uppercase only, so force
3078 // the name to uppercase just in case programmer forgot to do this
3079 if ((Dbms() == dbmsORACLE
) ||
3080 (Dbms() == dbmsINTERBASE
))
3081 TableName
= TableName
.Upper();
3083 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3086 // Some databases cannot accept a user name when looking up table names,
3087 // so we use the call below that leaves out the user name
3088 if (!UserID
.IsEmpty() &&
3089 Dbms() != dbmsMY_SQL
&&
3090 Dbms() != dbmsACCESS
&&
3091 Dbms() != dbmsMS_SQL_SERVER
)
3093 retcode
= SQLTables(hstmt
,
3094 NULL
, 0, // All qualifiers
3095 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Only tables owned by this user
3096 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3097 NULL
, 0); // All table types
3101 retcode
= SQLTables(hstmt
,
3102 NULL
, 0, // All qualifiers
3103 NULL
, 0, // All owners
3104 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3105 NULL
, 0); // All table types
3107 if (retcode
!= SQL_SUCCESS
)
3108 return(DispAllErrors(henv
, hdbc
, hstmt
));
3110 retcode
= SQLFetch(hstmt
);
3111 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
3113 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3114 return(DispAllErrors(henv
, hdbc
, hstmt
));
3117 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3121 } // wxDb::TableExists()
3124 /********** wxDb::TablePrivileges() **********/
3125 bool wxDb::TablePrivileges(const wxString
&tableName
, const wxString
&priv
, const wxChar
*userID
,
3126 const wxChar
*schema
, const wxString
&tablePath
)
3128 wxASSERT(tableName
.Length());
3130 wxDbTablePrivilegeInfo result
;
3134 // We probably need to be able to dynamically set this based on
3135 // the driver type, and state.
3136 wxChar curRole
[]=wxT("public");
3141 convertUserID(userID
,UserID
);
3143 TableName
= tableName
;
3144 // Oracle and Interbase table names are uppercase only, so force
3145 // the name to uppercase just in case programmer forgot to do this
3146 if ((Dbms() == dbmsORACLE
) ||
3147 (Dbms() == dbmsINTERBASE
))
3148 TableName
= TableName
.Upper();
3150 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3154 retcode
= SQLTablePrivileges(hstmt
,
3157 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3161 retcode
= SQLTablePrivileges(hstmt
,
3163 (UCHAR FAR
*)schema
, SQL_NTS
, // Schema
3164 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3167 #ifdef DBDEBUG_CONSOLE
3168 fprintf(stderr
,wxT("SQLTablePrivileges() returned %i \n"),retcode
);
3171 if ((retcode
!= SQL_SUCCESS
) && (retcode
!= SQL_SUCCESS_WITH_INFO
))
3172 return(DispAllErrors(henv
, hdbc
, hstmt
));
3174 retcode
= SQLFetch(hstmt
);
3175 while (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
3177 if (SQLGetData(hstmt
, 1, SQL_C_CHAR
, (UCHAR
*) result
.tableQual
, sizeof(result
.tableQual
), &cbRetVal
) != SQL_SUCCESS
)
3178 return(DispAllErrors(henv
, hdbc
, hstmt
));
3180 if (SQLGetData(hstmt
, 2, SQL_C_CHAR
, (UCHAR
*) result
.tableOwner
, sizeof(result
.tableOwner
), &cbRetVal
) != SQL_SUCCESS
)
3181 return(DispAllErrors(henv
, hdbc
, hstmt
));
3183 if (SQLGetData(hstmt
, 3, SQL_C_CHAR
, (UCHAR
*) result
.tableName
, sizeof(result
.tableName
), &cbRetVal
) != SQL_SUCCESS
)
3184 return(DispAllErrors(henv
, hdbc
, hstmt
));
3186 if (SQLGetData(hstmt
, 4, SQL_C_CHAR
, (UCHAR
*) result
.grantor
, sizeof(result
.grantor
), &cbRetVal
) != SQL_SUCCESS
)
3187 return(DispAllErrors(henv
, hdbc
, hstmt
));
3189 if (SQLGetData(hstmt
, 5, SQL_C_CHAR
, (UCHAR
*) result
.grantee
, sizeof(result
.grantee
), &cbRetVal
) != SQL_SUCCESS
)
3190 return(DispAllErrors(henv
, hdbc
, hstmt
));
3192 if (SQLGetData(hstmt
, 6, SQL_C_CHAR
, (UCHAR
*) result
.privilege
, sizeof(result
.privilege
), &cbRetVal
) != SQL_SUCCESS
)
3193 return(DispAllErrors(henv
, hdbc
, hstmt
));
3195 if (SQLGetData(hstmt
, 7, SQL_C_CHAR
, (UCHAR
*) result
.grantable
, sizeof(result
.grantable
), &cbRetVal
) != SQL_SUCCESS
)
3196 return(DispAllErrors(henv
, hdbc
, hstmt
));
3198 #ifdef DBDEBUG_CONSOLE
3199 fprintf(stderr
,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
3200 result
.privilege
,result
.tableOwner
,result
.tableName
,
3201 result
.grantor
, result
.grantee
);
3204 if (UserID
.IsSameAs(result
.tableOwner
,FALSE
))
3206 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3210 if (UserID
.IsSameAs(result
.grantee
,FALSE
) &&
3211 !wxStrcmp(result
.privilege
,priv
))
3213 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3217 if (!wxStrcmp(result
.grantee
,curRole
) &&
3218 !wxStrcmp(result
.privilege
,priv
))
3220 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3224 retcode
= SQLFetch(hstmt
);
3227 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3230 } // wxDb::TablePrivileges
3233 /********** wxDb::SetSqlLogging() **********/
3234 bool wxDb::SetSqlLogging(wxDbSqlLogState state
, const wxString
&filename
, bool append
)
3236 wxASSERT(state
== sqlLogON
|| state
== sqlLogOFF
);
3237 wxASSERT(state
== sqlLogOFF
|| filename
.Length());
3239 if (state
== sqlLogON
)
3243 fpSqlLog
= fopen(filename
, (append
? wxT("at") : wxT("wt")));
3244 if (fpSqlLog
== NULL
)
3252 if (fclose(fpSqlLog
))
3258 sqlLogState
= state
;
3261 } // wxDb::SetSqlLogging()
3264 /********** wxDb::WriteSqlLog() **********/
3265 bool wxDb::WriteSqlLog(const wxString
&logMsg
)
3267 wxASSERT(logMsg
.Length());
3269 if (fpSqlLog
== 0 || sqlLogState
== sqlLogOFF
)
3272 if (fputs(wxT("\n"), fpSqlLog
) == EOF
)
3274 if (fputs(logMsg
, fpSqlLog
) == EOF
)
3276 if (fputs(wxT("\n"), fpSqlLog
) == EOF
)
3281 } // wxDb::WriteSqlLog()
3284 /********** wxDb::Dbms() **********/
3285 wxDBMS
wxDb::Dbms(void)
3287 * Be aware that not all database engines use the exact same syntax, and not
3288 * every ODBC compliant database is compliant to the same level of compliancy.
3289 * Some manufacturers support the minimum Level 1 compliancy, and others up
3290 * through Level 3. Others support subsets of features for levels above 1.
3292 * If you find an inconsistency between the wxDb class and a specific database
3293 * engine, and an identifier to this section, and special handle the database in
3294 * the area where behavior is non-conforming with the other databases.
3297 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3298 * ---------------------------------------------------
3301 * - Currently the only database supported by the class to support VIEWS
3304 * - Does not support the SQL_TIMESTAMP structure
3305 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
3306 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
3307 * is TRUE. The user must create ALL indexes from their program.
3308 * - Table names can only be 8 characters long
3309 * - Column names can only be 10 characters long
3312 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3313 * after every table name involved in the query/join if that tables matching record(s)
3315 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
3317 * SYBASE (Enterprise)
3318 * - If a column is part of the Primary Key, the column cannot be NULL
3319 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
3322 * - If a column is part of the Primary Key, the column cannot be NULL
3323 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3324 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3325 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3326 * column definition if it is not defined correctly, but it is experimental
3327 * - Does not support sub-queries in SQL statements
3330 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3331 * - Does not support sub-queries in SQL statements
3334 * - Primary keys must be declared as NOT NULL
3338 // Should only need to do this once for each new database connection
3339 // so return the value we already determined it to be to save time
3340 // and lots of string comparisons
3341 if (dbmsType
!= dbmsUNIDENTIFIED
)
3344 wxChar baseName
[25+1];
3345 wxStrncpy(baseName
,dbInf
.dbmsName
,25);
3348 // RGG 20001025 : add support for Interbase
3349 // GT : Integrated to base classes on 20001121
3350 if (!wxStricmp(dbInf
.dbmsName
,wxT("Interbase")))
3351 return((wxDBMS
)(dbmsType
= dbmsINTERBASE
));
3353 // BJO 20000428 : add support for Virtuoso
3354 if (!wxStricmp(dbInf
.dbmsName
,wxT("OpenLink Virtuoso VDBMS")))
3355 return((wxDBMS
)(dbmsType
= dbmsVIRTUOSO
));
3357 if (!wxStricmp(dbInf
.dbmsName
,wxT("Adaptive Server Anywhere")))
3358 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASA
));
3360 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3361 // connected through an OpenLink driver.
3362 // Is it also returned by Sybase Adapatitve server?
3363 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
3364 if (!wxStricmp(dbInf
.dbmsName
,wxT("SQL Server")))
3366 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
3367 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
3368 return ((wxDBMS
)(dbmsMS_SQL_SERVER
));
3370 return ((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3373 if (!wxStricmp(dbInf
.dbmsName
,wxT("Microsoft SQL Server")))
3374 return((wxDBMS
)(dbmsType
= dbmsMS_SQL_SERVER
));
3375 if (!wxStricmp(dbInf
.dbmsName
,wxT("MySQL")))
3376 return((wxDBMS
)(dbmsType
= dbmsMY_SQL
));
3377 if (!wxStricmp(dbInf
.dbmsName
,wxT("PostgreSQL"))) // v6.5.0
3378 return((wxDBMS
)(dbmsType
= dbmsPOSTGRES
));
3381 if (!wxStricmp(baseName
,wxT("Informix")))
3382 return((wxDBMS
)(dbmsType
= dbmsINFORMIX
));
3385 if (!wxStricmp(baseName
,wxT("Oracle")))
3386 return((wxDBMS
)(dbmsType
= dbmsORACLE
));
3387 if (!wxStricmp(dbInf
.dbmsName
,wxT("ACCESS")))
3388 return((wxDBMS
)(dbmsType
= dbmsACCESS
));
3389 if (!wxStricmp(dbInf
.dbmsName
,wxT("MySQL")))
3390 return((wxDBMS
)(dbmsType
= dbmsMY_SQL
));
3391 if (!wxStricmp(baseName
,wxT("Sybase")))
3392 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3395 if (!wxStricmp(baseName
,wxT("DBASE")))
3396 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3399 if (!wxStricmp(baseName
,wxT("DB2")))
3400 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3402 return((wxDBMS
)(dbmsType
= dbmsUNIDENTIFIED
));
3407 bool wxDb::ModifyColumn(const wxString
&tableName
, const wxString
&columnName
,
3408 int dataType
, ULONG columnLength
,
3409 const wxString
&optionalParam
)
3411 wxASSERT(tableName
.Length());
3412 wxASSERT(columnName
.Length());
3413 wxASSERT((dataType
== DB_DATA_TYPE_VARCHAR
&& columnLength
> 0) ||
3414 dataType
!= DB_DATA_TYPE_VARCHAR
);
3416 // Must specify a columnLength if modifying a VARCHAR type column
3417 if (dataType
== DB_DATA_TYPE_VARCHAR
&& !columnLength
)
3420 wxString dataTypeName
;
3422 wxString alterSlashModify
;
3426 case DB_DATA_TYPE_VARCHAR
:
3427 dataTypeName
= typeInfVarchar
.TypeName
;
3429 case DB_DATA_TYPE_INTEGER
:
3430 dataTypeName
= typeInfInteger
.TypeName
;
3432 case DB_DATA_TYPE_FLOAT
:
3433 dataTypeName
= typeInfFloat
.TypeName
;
3435 case DB_DATA_TYPE_DATE
:
3436 dataTypeName
= typeInfDate
.TypeName
;
3442 // Set the modify or alter syntax depending on the type of database connected to
3446 alterSlashModify
= "MODIFY";
3448 case dbmsMS_SQL_SERVER
:
3449 alterSlashModify
= "ALTER COLUMN";
3451 case dbmsUNIDENTIFIED
:
3453 case dbmsSYBASE_ASA
:
3454 case dbmsSYBASE_ASE
:
3460 alterSlashModify
= "MODIFY";
3464 // create the SQL statement
3465 sqlStmt
.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName
.c_str(), alterSlashModify
.c_str(),
3466 columnName
.c_str(), dataTypeName
.c_str());
3468 // For varchars only, append the size of the column
3469 if (dataType
== DB_DATA_TYPE_VARCHAR
)
3472 s
.Printf(wxT("(%d)"), columnLength
);
3476 // for passing things like "NOT NULL"
3477 if (optionalParam
.Length())
3479 sqlStmt
+= wxT(" ");
3480 sqlStmt
+= optionalParam
;
3483 return ExecSql(sqlStmt
);
3485 } // wxDb::ModifyColumn()
3488 /********** wxDbGetConnection() **********/
3489 wxDb WXDLLEXPORT
*wxDbGetConnection(wxDbConnectInf
*pDbConfig
, bool FwdOnlyCursors
)
3493 // Used to keep a pointer to a DB connection that matches the requested
3494 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
3495 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
3496 // rather than having to re-query the datasource to get all the values
3497 // using the wxDb::Open(Dsn,Uid,AuthStr) function
3498 wxDb
*matchingDbConnection
= NULL
;
3500 // Scan the linked list searching for an available database connection
3501 // that's already been opened but is currently not in use.
3502 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3504 // The database connection must be for the same datasource
3505 // name and must currently not be in use.
3507 (pList
->PtrDb
->FwdOnlyCursors() == FwdOnlyCursors
) &&
3508 (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
))) // Found a free connection
3510 pList
->Free
= FALSE
;
3511 return(pList
->PtrDb
);
3514 if (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
) &&
3515 !wxStrcmp(pDbConfig
->GetUserID(), pList
->Uid
) &&
3516 !wxStrcmp(pDbConfig
->GetPassword(), pList
->AuthStr
))
3517 matchingDbConnection
= pList
->PtrDb
;
3520 // No available connections. A new connection must be made and
3521 // appended to the end of the linked list.
3524 // Find the end of the list
3525 for (pList
= PtrBegDbList
; pList
->PtrNext
; pList
= pList
->PtrNext
);
3526 // Append a new list item
3527 pList
->PtrNext
= new wxDbList
;
3528 pList
->PtrNext
->PtrPrev
= pList
;
3529 pList
= pList
->PtrNext
;
3533 // Create the first node on the list
3534 pList
= PtrBegDbList
= new wxDbList
;
3538 // Initialize new node in the linked list
3540 pList
->Free
= FALSE
;
3541 pList
->Dsn
= pDbConfig
->GetDsn(); //glt - will this assignment work?
3542 pList
->Uid
= pDbConfig
->GetUserID();
3543 pList
->AuthStr
= pDbConfig
->GetPassword();
3545 pList
->PtrDb
= new wxDb(pDbConfig
->GetHenv(), FwdOnlyCursors
);
3547 bool opened
= FALSE
;
3549 if (!matchingDbConnection
)
3550 opened
= pList
->PtrDb
->Open(pDbConfig
->GetDsn(), pDbConfig
->GetUserID(), pDbConfig
->GetPassword());
3552 opened
= pList
->PtrDb
->Open(matchingDbConnection
);
3554 // Connect to the datasource
3557 pList
->PtrDb
->SetSqlLogging(SQLLOGstate
,SQLLOGfn
,TRUE
);
3558 return(pList
->PtrDb
);
3560 else // Unable to connect, destroy list item
3563 pList
->PtrPrev
->PtrNext
= 0;
3565 PtrBegDbList
= 0; // Empty list again
3566 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
3567 pList
->PtrDb
->Close(); // Close the wxDb object
3568 delete pList
->PtrDb
; // Deletes the wxDb object
3569 delete pList
; // Deletes the linked list object
3573 } // wxDbGetConnection()
3576 /********** wxDbFreeConnection() **********/
3577 bool WXDLLEXPORT
wxDbFreeConnection(wxDb
*pDb
)
3581 // Scan the linked list searching for the database connection
3582 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3584 if (pList
->PtrDb
== pDb
) // Found it, now free it!!!
3585 return (pList
->Free
= TRUE
);
3588 // Never found the database object, return failure
3591 } // wxDbFreeConnection()
3594 /********** wxDbCloseConnections() **********/
3595 void WXDLLEXPORT
wxDbCloseConnections(void)
3597 wxDbList
*pList
, *pNext
;
3599 // Traverse the linked list closing database connections and freeing memory as I go.
3600 for (pList
= PtrBegDbList
; pList
; pList
= pNext
)
3602 pNext
= pList
->PtrNext
; // Save the pointer to next
3603 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
3604 pList
->PtrDb
->Close(); // Close the wxDb object
3605 delete pList
->PtrDb
; // Deletes the wxDb object
3606 delete pList
; // Deletes the linked list object
3609 // Mark the list as empty
3612 } // wxDbCloseConnections()
3615 /********** wxDbConnectionsInUse() **********/
3616 int WXDLLEXPORT
wxDbConnectionsInUse(void)
3621 // Scan the linked list counting db connections that are currently in use
3622 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3624 if (pList
->Free
== FALSE
)
3630 } // wxDbConnectionsInUse()
3633 /********** wxDbSqlLog() **********/
3634 bool wxDbSqlLog(wxDbSqlLogState state
, const wxChar
*filename
)
3636 bool append
= FALSE
;
3639 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3641 if (!pList
->PtrDb
->SetSqlLogging(state
,filename
,append
))
3646 SQLLOGstate
= state
;
3647 SQLLOGfn
= filename
;
3655 /********** wxDbCreateDataSource() **********/
3656 int wxDbCreateDataSource(const wxString
&driverName
, const wxString
&dsn
, const wxString
&description
,
3657 bool sysDSN
, const wxString
&defDir
, wxWindow
*parent
)
3659 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3660 * Very rudimentary creation of an ODBC data source.
3662 * ODBC driver must be ODBC 3.0 compliant to use this function
3667 //!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3673 dsnLocation
= ODBC_ADD_SYS_DSN
;
3675 dsnLocation
= ODBC_ADD_DSN
;
3677 // NOTE: The decimal 2 is an invalid character in all keyword pairs
3678 // so that is why I used it, as wxString does not deal well with
3679 // embedded nulls in strings
3680 setupStr
.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn
,2,description
,2,defDir
,2);
3682 // Replace the separator from above with the '\0' seperator needed
3683 // by the SQLConfigDataSource() function
3687 k
= setupStr
.Find((wxChar
)2,TRUE
);
3688 if (k
!= wxNOT_FOUND
)
3689 setupStr
[(UINT
)k
] = wxT('\0');
3691 while (k
!= wxNOT_FOUND
);
3693 result
= SQLConfigDataSource((HWND
)parent
->GetHWND(), dsnLocation
,
3694 driverName
, setupStr
.c_str());
3696 if ((result
!= SQL_SUCCESS
) && (result
!= SQL_SUCCESS_WITH_INFO
))
3698 // check for errors caused by ConfigDSN based functions
3701 wxChar errMsg
[SQL_MAX_MESSAGE_LENGTH
];
3702 errMsg
[0] = wxT('\0');
3704 // This function is only supported in ODBC drivers v3.0 compliant and above
3705 SQLInstallerError(1,&retcode
,errMsg
,SQL_MAX_MESSAGE_LENGTH
-1,&cb
);
3708 #ifdef DBDEBUG_CONSOLE
3709 // When run in console mode, use standard out to display errors.
3710 cout
<< errMsg
<< endl
;
3711 cout
<< wxT("Press any key to continue...") << endl
;
3713 #endif // DBDEBUG_CONSOLE
3716 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
3717 #endif // __WXDEBUG__
3723 // Using iODBC/unixODBC or some other compiler which does not support the APIs
3724 // necessary to use this function, so this function is not supported
3726 wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
3729 #endif // __VISUALC__
3733 } // wxDbCreateDataSource()
3737 /********** wxDbGetDataSource() **********/
3738 bool wxDbGetDataSource(HENV henv
, wxChar
*Dsn
, SWORD DsnMax
, wxChar
*DsDesc
,
3739 SWORD DsDescMax
, UWORD direction
)
3741 * Dsn and DsDesc will contain the data source name and data source
3742 * description upon return
3747 if (SQLDataSources(henv
, direction
, (UCHAR FAR
*) Dsn
, DsnMax
, &cb1
,
3748 (UCHAR FAR
*) DsDesc
, DsDescMax
, &cb2
) == SQL_SUCCESS
)
3753 } // wxDbGetDataSource()
3756 // Change this to 0 to remove use of all deprecated functions
3757 #if wxODBC_BACKWARD_COMPATABILITY
3758 /********************************************************************
3759 ********************************************************************
3761 * The following functions are all DEPRECATED and are included for
3762 * backward compatability reasons only
3764 ********************************************************************
3765 ********************************************************************/
3766 bool SqlLog(sqlLog state
, const wxChar
*filename
)
3768 return wxDbSqlLog((enum wxDbSqlLogState
)state
, filename
);
3770 /***** DEPRECATED: use wxGetDataSource() *****/
3771 bool GetDataSource(HENV henv
, char *Dsn
, SWORD DsnMax
, char *DsDesc
, SWORD DsDescMax
,
3774 return wxDbGetDataSource(henv
, Dsn
, DsnMax
, DsDesc
, DsDescMax
, direction
);
3776 /***** DEPRECATED: use wxDbGetConnection() *****/
3777 wxDb WXDLLEXPORT
*GetDbConnection(DbStuff
*pDbStuff
, bool FwdOnlyCursors
)
3779 return wxDbGetConnection((wxDbConnectInf
*)pDbStuff
, FwdOnlyCursors
);
3781 /***** DEPRECATED: use wxDbFreeConnection() *****/
3782 bool WXDLLEXPORT
FreeDbConnection(wxDb
*pDb
)
3784 return wxDbFreeConnection(pDb
);
3786 /***** DEPRECATED: use wxDbCloseConnections() *****/
3787 void WXDLLEXPORT
CloseDbConnections(void)
3789 wxDbCloseConnections();
3791 /***** DEPRECATED: use wxDbConnectionsInUse() *****/
3792 int WXDLLEXPORT
NumberDbConnectionsInUse(void)
3794 return wxDbConnectionsInUse();