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()
145 /********** wxDbConnectInf Constructor - form 2 **********/
146 wxDbConnectInf::wxDbConnectInf(HENV Henv
, const wxString
&Dsn
, const wxString
&UserID
,
147 const wxString
&Password
, const wxString
&DefaultDir
,
148 const wxString
&FileType
, const wxString
&Description
)
150 wxASSERT(Dsn
.Length());
161 SetPassword(Password
);
162 SetDescription(Description
);
163 SetFileType(FileType
);
164 SetDefaultDir(DefaultDir
);
165 } // wxDbConnectInf Constructor
168 wxDbConnectInf::~wxDbConnectInf()
170 if (freeHenvOnDestroy
)
174 } // wxDbConnectInf Destructor
178 /********** wxDbConnectInf::Initialize() **********/
179 bool wxDbConnectInf::Initialize()
181 freeHenvOnDestroy
= FALSE
;
192 } // wxDbConnectInf::Initialize()
195 /********** wxDbConnectInf::AllocHenv() **********/
196 bool wxDbConnectInf::AllocHenv()
198 // This is here to help trap if you are getting a new henv
199 // without releasing an existing henv
202 // Initialize the ODBC Environment for Database Operations
203 if (SQLAllocEnv(&Henv
) != SQL_SUCCESS
)
205 wxLogDebug(wxT("A problem occured while trying to get a connection to the data source"));
209 freeHenvOnDestroy
= TRUE
;
212 } // wxDbConnectInf::AllocHenv()
215 void wxDbConnectInf::FreeHenv()
223 freeHenvOnDestroy
= FALSE
;
225 } // wxDbConnectInf::FreeHenv()
228 void wxDbConnectInf::SetDsn(const wxString
&dsn
)
230 wxASSERT(dsn
.Length() < sizeof(Dsn
));
233 } // wxDbConnectInf::SetDsn()
236 void wxDbConnectInf::SetUserID(const wxString
&uid
)
238 wxASSERT(uid
.Length() < sizeof(Uid
));
240 } // wxDbConnectInf::SetUserID()
243 void wxDbConnectInf::SetPassword(const wxString
&password
)
245 wxASSERT(password
.Length() < sizeof(AuthStr
));
247 wxStrcpy(AuthStr
,password
);
248 } // wxDbConnectInf::SetPassword()
252 /********** wxDbColFor Constructor **********/
253 wxDbColFor::wxDbColFor()
256 } // wxDbColFor::wxDbColFor()
259 wxDbColFor::~wxDbColFor()
261 } // wxDbColFor::~wxDbColFor()
264 /********** wxDbColFor::Initialize() **********/
265 void wxDbColFor::Initialize()
275 i_Nation
= 0; // 0=EU, 1=UK, 2=International, 3=US
278 Format(1,DB_DATA_TYPE_VARCHAR
,0,0,0); // the Function that does the work
279 } // wxDbColFor::Initialize()
282 /********** wxDbColFor::Format() **********/
283 int wxDbColFor::Format(int Nation
, int dbDataType
, SWORD sqlDataType
,
284 short columnSize
, short decimalDigits
)
286 // ----------------------------------------------------------------------------------------
287 // -- 19991224 : mj10777 : Create
288 // There is still a lot of work to do here, but it is a start
289 // It handles all the basic data-types that I have run into up to now
290 // The main work will have be with Dates and float Formatting
291 // (US 1,000.00 ; EU 1.000,00)
292 // There are wxWindow plans for locale support and the new wxDateTime. If
293 // they define some constants (wxEUROPEAN) that can be gloably used,
294 // they should be used here.
295 // ----------------------------------------------------------------------------------------
296 // There should also be a function to scan in a string to fill the variable
297 // ----------------------------------------------------------------------------------------
299 i_Nation
= Nation
; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
300 i_dbDataType
= dbDataType
;
301 i_sqlDataType
= sqlDataType
;
302 s_Field
.Printf(wxT("%s%d"),s_Amount
[1].c_str(),i_Amount
[1]); // OK for VARCHAR, INTEGER and FLOAT
304 if (i_dbDataType
== 0) // Filter unsupported dbDataTypes
306 if ((i_sqlDataType
== SQL_VARCHAR
) || (i_sqlDataType
== SQL_LONGVARCHAR
))
307 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
308 if ((i_sqlDataType
== SQL_C_DATE
) || (i_sqlDataType
== SQL_C_TIMESTAMP
))
309 i_dbDataType
= DB_DATA_TYPE_DATE
;
310 if (i_sqlDataType
== SQL_C_BIT
)
311 i_dbDataType
= DB_DATA_TYPE_INTEGER
;
312 if (i_sqlDataType
== SQL_NUMERIC
)
313 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
314 if (i_sqlDataType
== SQL_REAL
)
315 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
318 if ((i_dbDataType
== DB_DATA_TYPE_INTEGER
) && (i_sqlDataType
== SQL_C_DOUBLE
))
320 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
323 switch(i_dbDataType
) // TBD: Still a lot of proper formatting to do
325 case DB_DATA_TYPE_VARCHAR
:
328 case DB_DATA_TYPE_INTEGER
:
331 case DB_DATA_TYPE_FLOAT
:
332 if (decimalDigits
== 0)
335 tempStr
.Printf(wxT("%s%d.%d"),tempStr
.c_str(),columnSize
,decimalDigits
);
336 s_Field
.Printf(wxT("%sf"),tempStr
.c_str());
338 case DB_DATA_TYPE_DATE
:
339 if (i_Nation
== 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
341 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
343 if (i_Nation
== 1) // European DD.MM.YYYY HH:MM:SS.SSS
345 s_Field
= wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d");
347 if (i_Nation
== 2) // UK DD/MM/YYYY HH:MM:SS.SSS
349 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
351 if (i_Nation
== 3) // International YYYY-MM-DD HH:MM:SS.SSS
353 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
355 if (i_Nation
== 4) // US MM/DD/YYYY HH:MM:SS.SSS
357 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
361 s_Field
.Printf(wxT("Unknown Format(%d)-SQL(%d)"),dbDataType
,sqlDataType
); //
365 } // wxDbColFor::Format()
369 /********** wxDbColInf Constructor **********/
370 wxDbColInf::wxDbColInf()
390 } // wxDbColInf::wxDbColInf()
393 /********** wxDbColInf Destructor ********/
394 wxDbColInf::~wxDbColInf()
399 } // wxDbColInf::~wxDbColInf()
402 /********** wxDbTableInf Constructor ********/
403 wxDbTableInf::wxDbTableInf()
410 } // wxDbTableInf::wxDbTableInf()
413 /********** wxDbTableInf Constructor ********/
414 wxDbTableInf::~wxDbTableInf()
419 } // wxDbTableInf::~wxDbTableInf()
422 /********** wxDbInf Constructor *************/
426 } // wxDbInf::wxDbInf()
429 /********** wxDbInf Destructor *************/
435 } // wxDbInf::~wxDbInf()
438 /********** wxDbInf::Initialize() *************/
439 void wxDbInf::Initialize()
445 } // wxDbInf::Initialize()
448 /********** wxDb Constructors **********/
449 wxDb::wxDb(const HENV
&aHenv
, bool FwdOnlyCursors
)
451 // Copy the HENV into the db class
453 fwdOnlyCursors
= FwdOnlyCursors
;
458 /********** wxDb::Initialize() **********/
459 void wxDb::Initialize()
461 * Private member function that sets all wxDb member variables to
462 * known values at creation of the wxDb
467 fpSqlLog
= 0; // Sql Log file pointer
468 sqlLogState
= sqlLogOFF
; // By default, logging is turned off
470 dbmsType
= dbmsUNIDENTIFIED
;
472 wxStrcpy(sqlState
,wxT(""));
473 wxStrcpy(errorMsg
,wxT(""));
474 nativeError
= cbErrorMsg
= 0;
475 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
476 wxStrcpy(errorList
[i
], wxT(""));
478 // Init typeInf structures
479 typeInfVarchar
.TypeName
.Empty();
480 typeInfVarchar
.FsqlType
= 0;
481 typeInfVarchar
.Precision
= 0;
482 typeInfVarchar
.CaseSensitive
= 0;
483 typeInfVarchar
.MaximumScale
= 0;
485 typeInfInteger
.TypeName
.Empty();
486 typeInfInteger
.FsqlType
= 0;
487 typeInfInteger
.Precision
= 0;
488 typeInfInteger
.CaseSensitive
= 0;
489 typeInfInteger
.MaximumScale
= 0;
491 typeInfFloat
.TypeName
.Empty();
492 typeInfFloat
.FsqlType
= 0;
493 typeInfFloat
.Precision
= 0;
494 typeInfFloat
.CaseSensitive
= 0;
495 typeInfFloat
.MaximumScale
= 0;
497 typeInfDate
.TypeName
.Empty();
498 typeInfDate
.FsqlType
= 0;
499 typeInfDate
.Precision
= 0;
500 typeInfDate
.CaseSensitive
= 0;
501 typeInfDate
.MaximumScale
= 0;
503 // Error reporting is turned OFF by default
506 // Allocate a data source connection handle
507 if (SQLAllocConnect(henv
, &hdbc
) != SQL_SUCCESS
)
510 // Initialize the db status flag
513 // Mark database as not open as of yet
515 } // wxDb::Initialize()
518 /********** PRIVATE! wxDb::convertUserID PRIVATE! **********/
520 // NOTE: Return value from this function MUST be copied
521 // immediately, as the value is not good after
522 // this function has left scope.
524 const wxChar
*wxDb::convertUserID(const wxChar
*userID
, wxString
&UserID
)
528 if (!wxStrlen(userID
))
536 // dBase does not use user names, and some drivers fail if you try to pass one
537 if (Dbms() == dbmsDBASE
)
540 // Oracle user names may only be in uppercase, so force
541 // the name to uppercase
542 if (Dbms() == dbmsORACLE
)
543 UserID
= UserID
.Upper();
545 return UserID
.c_str();
546 } // wxDb::convertUserID()
549 /********** wxDb::Open() **********/
550 bool wxDb::Open(const wxString
&Dsn
, const wxString
&Uid
, const wxString
&AuthStr
)
552 wxASSERT(Dsn
.Length());
559 if (!FwdOnlyCursors())
561 // Specify that the ODBC cursor library be used, if needed. This must be
562 // specified before the connection is made.
563 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
565 #ifdef DBDEBUG_CONSOLE
566 if (retcode
== SQL_SUCCESS
)
567 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
569 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
573 // Connect to the data source
574 retcode
= SQLConnect(hdbc
, (UCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
575 (UCHAR FAR
*) uid
.c_str(), SQL_NTS
,
576 (UCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
579 if (retcode == SQL_SUCCESS_WITH_INFO)
580 DispAllErrors(henv, hdbc);
581 else if (retcode != SQL_SUCCESS)
582 return(DispAllErrors(henv, hdbc));
584 if (retcode == SQL_ERROR)
585 return(DispAllErrors(henv, hdbc));
587 if ((retcode
!= SQL_SUCCESS
) &&
588 (retcode
!= SQL_SUCCESS_WITH_INFO
))
589 return(DispAllErrors(henv
, hdbc
));
592 If using Intersolv branded ODBC drivers, this is the place where you would substitute
593 your branded driver license information
595 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxT(""));
596 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxT(""));
599 // Mark database as open
602 // Allocate a statement handle for the database connection
603 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
604 return(DispAllErrors(henv
, hdbc
));
606 // Set Connection Options
607 if (!setConnectionOptions())
610 // Query the data source for inf. about itself
614 // Query the data source regarding data type information
617 // The way I determined which SQL data types to use was by calling SQLGetInfo
618 // for all of the possible SQL data types to see which ones were supported. If
619 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
620 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
621 // types I've selected below will not alway's be what we want. These are just
622 // what happened to work against an Oracle 7/Intersolv combination. The following is
623 // a complete list of the results I got back against the Oracle 7 database:
625 // SQL_BIGINT SQL_NO_DATA_FOUND
626 // SQL_BINARY SQL_NO_DATA_FOUND
627 // SQL_BIT SQL_NO_DATA_FOUND
628 // SQL_CHAR type name = 'CHAR', Precision = 255
629 // SQL_DATE SQL_NO_DATA_FOUND
630 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
631 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
632 // SQL_FLOAT SQL_NO_DATA_FOUND
633 // SQL_INTEGER SQL_NO_DATA_FOUND
634 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
635 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
636 // SQL_NUMERIC SQL_NO_DATA_FOUND
637 // SQL_REAL SQL_NO_DATA_FOUND
638 // SQL_SMALLINT SQL_NO_DATA_FOUND
639 // SQL_TIME SQL_NO_DATA_FOUND
640 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
641 // SQL_VARBINARY type name = 'RAW', Precision = 255
642 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
643 // =====================================================================
644 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
646 // SQL_VARCHAR type name = 'TEXT', Precision = 255
647 // SQL_TIMESTAMP type name = 'DATETIME'
648 // SQL_DECIMAL SQL_NO_DATA_FOUND
649 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
650 // SQL_FLOAT SQL_NO_DATA_FOUND
651 // SQL_REAL type name = 'SINGLE', Precision = 7
652 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
653 // SQL_INTEGER type name = 'LONG', Precision = 10
655 // VARCHAR = Variable length character string
656 if (!getDataTypeInfo(SQL_VARCHAR
, typeInfVarchar
))
657 if (!getDataTypeInfo(SQL_CHAR
, typeInfVarchar
))
660 typeInfVarchar
.FsqlType
= SQL_CHAR
;
662 typeInfVarchar
.FsqlType
= SQL_VARCHAR
;
665 if (!getDataTypeInfo(SQL_DOUBLE
,typeInfFloat
))
667 if (!getDataTypeInfo(SQL_REAL
,typeInfFloat
))
668 if (!getDataTypeInfo(SQL_FLOAT
,typeInfFloat
))
669 if (!getDataTypeInfo(SQL_DECIMAL
,typeInfFloat
))
670 if (!getDataTypeInfo(SQL_NUMERIC
,typeInfFloat
))
673 typeInfFloat
.FsqlType
= SQL_NUMERIC
;
675 typeInfFloat
.FsqlType
= SQL_DECIMAL
;
677 typeInfFloat
.FsqlType
= SQL_FLOAT
;
679 typeInfFloat
.FsqlType
= SQL_REAL
;
681 typeInfFloat
.FsqlType
= SQL_DOUBLE
;
684 if (!getDataTypeInfo(SQL_INTEGER
, typeInfInteger
))
686 // If SQL_INTEGER is not supported, use the floating point
687 // data type to store integers as well as floats
688 if (!getDataTypeInfo(typeInfFloat
.FsqlType
, typeInfInteger
))
691 typeInfInteger
.FsqlType
= typeInfFloat
.FsqlType
;
694 typeInfInteger
.FsqlType
= SQL_INTEGER
;
697 if (Dbms() != dbmsDBASE
)
699 if (! getDataTypeInfo(SQL_TIMESTAMP
,typeInfDate
))
702 typeInfDate
.FsqlType
= SQL_TIMESTAMP
;
706 if (!getDataTypeInfo(SQL_DATE
,typeInfDate
))
709 typeInfDate
.FsqlType
= SQL_DATE
;
712 #ifdef DBDEBUG_CONSOLE
713 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
714 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
715 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
716 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
720 // Completed Successfully
726 bool wxDb::Open(wxDbConnectInf
*dbConnectInf
)
728 return Open(dbConnectInf
->GetDsn(), dbConnectInf
->GetUserID(),
729 dbConnectInf
->GetPassword());
733 bool wxDb::Open(wxDb
*copyDb
)
735 dsn
= copyDb
->GetDatasourceName();
736 uid
= copyDb
->GetUsername();
737 authStr
= copyDb
->GetPassword();
741 if (!FwdOnlyCursors())
743 // Specify that the ODBC cursor library be used, if needed. This must be
744 // specified before the connection is made.
745 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
747 #ifdef DBDEBUG_CONSOLE
748 if (retcode
== SQL_SUCCESS
)
749 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
751 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
755 // Connect to the data source
756 retcode
= SQLConnect(hdbc
, (UCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
757 (UCHAR FAR
*) uid
.c_str(), SQL_NTS
,
758 (UCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
760 if (retcode
== SQL_ERROR
)
761 return(DispAllErrors(henv
, hdbc
));
764 If using Intersolv branded ODBC drivers, this is the place where you would substitute
765 your branded driver license information
767 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxT(""));
768 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxT(""));
771 // Mark database as open
774 // Allocate a statement handle for the database connection
775 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
776 return(DispAllErrors(henv
, hdbc
));
778 // Set Connection Options
779 if (!setConnectionOptions())
782 // Instead of Querying the data source for info about itself, it can just be copied
783 // from the wxDb instance that was passed in (copyDb).
784 wxStrcpy(dbInf
.serverName
,copyDb
->dbInf
.serverName
);
785 wxStrcpy(dbInf
.databaseName
,copyDb
->dbInf
.databaseName
);
786 wxStrcpy(dbInf
.dbmsName
,copyDb
->dbInf
.dbmsName
);
787 wxStrcpy(dbInf
.dbmsVer
,copyDb
->dbInf
.dbmsVer
);
788 dbInf
.maxConnections
= copyDb
->dbInf
.maxConnections
;
789 dbInf
.maxStmts
= copyDb
->dbInf
.maxStmts
;
790 wxStrcpy(dbInf
.driverName
,copyDb
->dbInf
.driverName
);
791 wxStrcpy(dbInf
.odbcVer
,copyDb
->dbInf
.odbcVer
);
792 wxStrcpy(dbInf
.drvMgrOdbcVer
,copyDb
->dbInf
.drvMgrOdbcVer
);
793 wxStrcpy(dbInf
.driverVer
,copyDb
->dbInf
.driverVer
);
794 dbInf
.apiConfLvl
= copyDb
->dbInf
.apiConfLvl
;
795 dbInf
.cliConfLvl
= copyDb
->dbInf
.cliConfLvl
;
796 dbInf
.sqlConfLvl
= copyDb
->dbInf
.sqlConfLvl
;
797 wxStrcpy(dbInf
.outerJoins
,copyDb
->dbInf
.outerJoins
);
798 wxStrcpy(dbInf
.procedureSupport
,copyDb
->dbInf
.procedureSupport
);
799 wxStrcpy(dbInf
.accessibleTables
,copyDb
->dbInf
.accessibleTables
);
800 dbInf
.cursorCommitBehavior
= copyDb
->dbInf
.cursorCommitBehavior
;
801 dbInf
.cursorRollbackBehavior
= copyDb
->dbInf
.cursorRollbackBehavior
;
802 dbInf
.supportNotNullClause
= copyDb
->dbInf
.supportNotNullClause
;
803 wxStrcpy(dbInf
.supportIEF
,copyDb
->dbInf
.supportIEF
);
804 dbInf
.txnIsolation
= copyDb
->dbInf
.txnIsolation
;
805 dbInf
.txnIsolationOptions
= copyDb
->dbInf
.txnIsolationOptions
;
806 dbInf
.fetchDirections
= copyDb
->dbInf
.fetchDirections
;
807 dbInf
.lockTypes
= copyDb
->dbInf
.lockTypes
;
808 dbInf
.posOperations
= copyDb
->dbInf
.posOperations
;
809 dbInf
.posStmts
= copyDb
->dbInf
.posStmts
;
810 dbInf
.scrollConcurrency
= copyDb
->dbInf
.scrollConcurrency
;
811 dbInf
.scrollOptions
= copyDb
->dbInf
.scrollOptions
;
812 dbInf
.staticSensitivity
= copyDb
->dbInf
.staticSensitivity
;
813 dbInf
.txnCapable
= copyDb
->dbInf
.txnCapable
;
814 dbInf
.loginTimeout
= copyDb
->dbInf
.loginTimeout
;
816 // VARCHAR = Variable length character string
817 typeInfVarchar
.FsqlType
= copyDb
->typeInfVarchar
.FsqlType
;
818 typeInfVarchar
.TypeName
= copyDb
->typeInfVarchar
.TypeName
;
819 typeInfVarchar
.Precision
= copyDb
->typeInfVarchar
.Precision
;
820 typeInfVarchar
.CaseSensitive
= copyDb
->typeInfVarchar
.CaseSensitive
;
821 typeInfVarchar
.MaximumScale
= copyDb
->typeInfVarchar
.MaximumScale
;
824 typeInfFloat
.FsqlType
= copyDb
->typeInfFloat
.FsqlType
;
825 typeInfFloat
.TypeName
= copyDb
->typeInfFloat
.TypeName
;
826 typeInfFloat
.Precision
= copyDb
->typeInfFloat
.Precision
;
827 typeInfFloat
.CaseSensitive
= copyDb
->typeInfFloat
.CaseSensitive
;
828 typeInfFloat
.MaximumScale
= copyDb
->typeInfFloat
.MaximumScale
;
831 typeInfInteger
.FsqlType
= copyDb
->typeInfInteger
.FsqlType
;
832 typeInfInteger
.TypeName
= copyDb
->typeInfInteger
.TypeName
;
833 typeInfInteger
.Precision
= copyDb
->typeInfInteger
.Precision
;
834 typeInfInteger
.CaseSensitive
= copyDb
->typeInfInteger
.CaseSensitive
;
835 typeInfInteger
.MaximumScale
= copyDb
->typeInfInteger
.MaximumScale
;
838 typeInfDate
.FsqlType
= copyDb
->typeInfDate
.FsqlType
;
839 typeInfDate
.TypeName
= copyDb
->typeInfDate
.TypeName
;
840 typeInfDate
.Precision
= copyDb
->typeInfDate
.Precision
;
841 typeInfDate
.CaseSensitive
= copyDb
->typeInfDate
.CaseSensitive
;
842 typeInfDate
.MaximumScale
= copyDb
->typeInfDate
.MaximumScale
;
844 #ifdef DBDEBUG_CONSOLE
845 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
846 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
847 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
848 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
852 // Completed Successfully
857 /********** wxDb::setConnectionOptions() **********/
858 bool wxDb::setConnectionOptions(void)
860 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
865 // I need to get the DBMS name here, because some of the connection options
866 // are database specific and need to call the Dbms() function.
867 if (SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, 40, &cb
) != SQL_SUCCESS
)
868 return(DispAllErrors(henv
, hdbc
));
870 SQLSetConnectOption(hdbc
, SQL_AUTOCOMMIT
, SQL_AUTOCOMMIT_OFF
);
871 SQLSetConnectOption(hdbc
, SQL_OPT_TRACE
, SQL_OPT_TRACE_OFF
);
872 // SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads
874 // By default, MS Sql Server closes cursors on commit and rollback. The following
875 // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors
876 // after a transaction. This is a driver specific option and is not part of the
877 // ODBC standard. Note: this behavior is specific to the ODBC interface to SQL Server.
878 // The database settings don't have any effect one way or the other.
879 if (Dbms() == dbmsMS_SQL_SERVER
)
881 const long SQL_PRESERVE_CURSORS
= 1204L;
882 const long SQL_PC_ON
= 1L;
883 SQLSetConnectOption(hdbc
, SQL_PRESERVE_CURSORS
, SQL_PC_ON
);
886 // Display the connection options to verify them
887 #ifdef DBDEBUG_CONSOLE
889 cout
<< wxT("****** CONNECTION OPTIONS ******") << endl
;
891 if (SQLGetConnectOption(hdbc
, SQL_AUTOCOMMIT
, &l
) != SQL_SUCCESS
)
892 return(DispAllErrors(henv
, hdbc
));
893 cout
<< wxT("AUTOCOMMIT: ") << (l
== SQL_AUTOCOMMIT_OFF
? "OFF" : "ON") << endl
;
895 if (SQLGetConnectOption(hdbc
, SQL_ODBC_CURSORS
, &l
) != SQL_SUCCESS
)
896 return(DispAllErrors(henv
, hdbc
));
897 cout
<< wxT("ODBC CURSORS: ");
900 case(SQL_CUR_USE_IF_NEEDED
):
901 cout
<< wxT("SQL_CUR_USE_IF_NEEDED");
903 case(SQL_CUR_USE_ODBC
):
904 cout
<< wxT("SQL_CUR_USE_ODBC");
906 case(SQL_CUR_USE_DRIVER
):
907 cout
<< wxT("SQL_CUR_USE_DRIVER");
912 if (SQLGetConnectOption(hdbc
, SQL_OPT_TRACE
, &l
) != SQL_SUCCESS
)
913 return(DispAllErrors(henv
, hdbc
));
914 cout
<< wxT("TRACING: ") << (l
== SQL_OPT_TRACE_OFF
? wxT("OFF") : wxT("ON")) << endl
;
919 // Completed Successfully
922 } // wxDb::setConnectionOptions()
925 /********** wxDb::getDbInfo() **********/
926 bool wxDb::getDbInfo(void)
931 if (SQLGetInfo(hdbc
, SQL_SERVER_NAME
, (UCHAR
*) dbInf
.serverName
, 80, &cb
) != SQL_SUCCESS
)
932 return(DispAllErrors(henv
, hdbc
));
934 if (SQLGetInfo(hdbc
, SQL_DATABASE_NAME
, (UCHAR
*) dbInf
.databaseName
, 128, &cb
) != SQL_SUCCESS
)
935 return(DispAllErrors(henv
, hdbc
));
937 if (SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, 40, &cb
) != SQL_SUCCESS
)
938 return(DispAllErrors(henv
, hdbc
));
941 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
942 // causing database connectivity to fail in some cases.
943 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_VER
, (UCHAR
*) dbInf
.dbmsVer
, 64, &cb
);
945 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
946 return(DispAllErrors(henv
, hdbc
));
948 if (SQLGetInfo(hdbc
, SQL_ACTIVE_CONNECTIONS
, (UCHAR
*) &dbInf
.maxConnections
, sizeof(dbInf
.maxConnections
), &cb
) != SQL_SUCCESS
)
949 return(DispAllErrors(henv
, hdbc
));
951 if (SQLGetInfo(hdbc
, SQL_ACTIVE_STATEMENTS
, (UCHAR
*) &dbInf
.maxStmts
, sizeof(dbInf
.maxStmts
), &cb
) != SQL_SUCCESS
)
952 return(DispAllErrors(henv
, hdbc
));
954 if (SQLGetInfo(hdbc
, SQL_DRIVER_NAME
, (UCHAR
*) dbInf
.driverName
, 40, &cb
) != SQL_SUCCESS
)
955 return(DispAllErrors(henv
, hdbc
));
957 if (SQLGetInfo(hdbc
, SQL_DRIVER_ODBC_VER
, (UCHAR
*) dbInf
.odbcVer
, 60, &cb
) == SQL_ERROR
)
958 return(DispAllErrors(henv
, hdbc
));
960 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_VER
, (UCHAR
*) dbInf
.drvMgrOdbcVer
, 60, &cb
);
961 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
962 return(DispAllErrors(henv
, hdbc
));
964 if (SQLGetInfo(hdbc
, SQL_DRIVER_VER
, (UCHAR
*) dbInf
.driverVer
, 60, &cb
) == SQL_ERROR
)
965 return(DispAllErrors(henv
, hdbc
));
967 if (SQLGetInfo(hdbc
, SQL_ODBC_API_CONFORMANCE
, (UCHAR
*) &dbInf
.apiConfLvl
, sizeof(dbInf
.apiConfLvl
), &cb
) != SQL_SUCCESS
)
968 return(DispAllErrors(henv
, hdbc
));
970 if (SQLGetInfo(hdbc
, SQL_ODBC_SAG_CLI_CONFORMANCE
, (UCHAR
*) &dbInf
.cliConfLvl
, sizeof(dbInf
.cliConfLvl
), &cb
) != SQL_SUCCESS
)
971 // return(DispAllErrors(henv, hdbc));
973 // Not all drivers support this call - Nick Gorham(unixODBC)
974 dbInf
.cliConfLvl
= 0;
977 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_CONFORMANCE
, (UCHAR
*) &dbInf
.sqlConfLvl
, sizeof(dbInf
.sqlConfLvl
), &cb
) != SQL_SUCCESS
)
978 return(DispAllErrors(henv
, hdbc
));
980 if (SQLGetInfo(hdbc
, SQL_OUTER_JOINS
, (UCHAR
*) dbInf
.outerJoins
, 2, &cb
) != SQL_SUCCESS
)
981 return(DispAllErrors(henv
, hdbc
));
983 if (SQLGetInfo(hdbc
, SQL_PROCEDURES
, (UCHAR
*) dbInf
.procedureSupport
, 2, &cb
) != SQL_SUCCESS
)
984 return(DispAllErrors(henv
, hdbc
));
986 if (SQLGetInfo(hdbc
, SQL_ACCESSIBLE_TABLES
, (UCHAR
*) dbInf
.accessibleTables
, 2, &cb
) != SQL_SUCCESS
)
987 return(DispAllErrors(henv
, hdbc
));
989 if (SQLGetInfo(hdbc
, SQL_CURSOR_COMMIT_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorCommitBehavior
, sizeof(dbInf
.cursorCommitBehavior
), &cb
) != SQL_SUCCESS
)
990 return(DispAllErrors(henv
, hdbc
));
992 if (SQLGetInfo(hdbc
, SQL_CURSOR_ROLLBACK_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorRollbackBehavior
, sizeof(dbInf
.cursorRollbackBehavior
), &cb
) != SQL_SUCCESS
)
993 return(DispAllErrors(henv
, hdbc
));
995 if (SQLGetInfo(hdbc
, SQL_NON_NULLABLE_COLUMNS
, (UCHAR
*) &dbInf
.supportNotNullClause
, sizeof(dbInf
.supportNotNullClause
), &cb
) != SQL_SUCCESS
)
996 return(DispAllErrors(henv
, hdbc
));
998 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_OPT_IEF
, (UCHAR
*) dbInf
.supportIEF
, 2, &cb
) != SQL_SUCCESS
)
999 return(DispAllErrors(henv
, hdbc
));
1001 if (SQLGetInfo(hdbc
, SQL_DEFAULT_TXN_ISOLATION
, (UCHAR
*) &dbInf
.txnIsolation
, sizeof(dbInf
.txnIsolation
), &cb
) != SQL_SUCCESS
)
1002 return(DispAllErrors(henv
, hdbc
));
1004 if (SQLGetInfo(hdbc
, SQL_TXN_ISOLATION_OPTION
, (UCHAR
*) &dbInf
.txnIsolationOptions
, sizeof(dbInf
.txnIsolationOptions
), &cb
) != SQL_SUCCESS
)
1005 return(DispAllErrors(henv
, hdbc
));
1007 if (SQLGetInfo(hdbc
, SQL_FETCH_DIRECTION
, (UCHAR
*) &dbInf
.fetchDirections
, sizeof(dbInf
.fetchDirections
), &cb
) != SQL_SUCCESS
)
1008 return(DispAllErrors(henv
, hdbc
));
1010 if (SQLGetInfo(hdbc
, SQL_LOCK_TYPES
, (UCHAR
*) &dbInf
.lockTypes
, sizeof(dbInf
.lockTypes
), &cb
) != SQL_SUCCESS
)
1011 return(DispAllErrors(henv
, hdbc
));
1013 if (SQLGetInfo(hdbc
, SQL_POS_OPERATIONS
, (UCHAR
*) &dbInf
.posOperations
, sizeof(dbInf
.posOperations
), &cb
) != SQL_SUCCESS
)
1014 return(DispAllErrors(henv
, hdbc
));
1016 if (SQLGetInfo(hdbc
, SQL_POSITIONED_STATEMENTS
, (UCHAR
*) &dbInf
.posStmts
, sizeof(dbInf
.posStmts
), &cb
) != SQL_SUCCESS
)
1017 return(DispAllErrors(henv
, hdbc
));
1019 if (SQLGetInfo(hdbc
, SQL_SCROLL_CONCURRENCY
, (UCHAR
*) &dbInf
.scrollConcurrency
, sizeof(dbInf
.scrollConcurrency
), &cb
) != SQL_SUCCESS
)
1020 return(DispAllErrors(henv
, hdbc
));
1022 if (SQLGetInfo(hdbc
, SQL_SCROLL_OPTIONS
, (UCHAR
*) &dbInf
.scrollOptions
, sizeof(dbInf
.scrollOptions
), &cb
) != SQL_SUCCESS
)
1023 return(DispAllErrors(henv
, hdbc
));
1025 if (SQLGetInfo(hdbc
, SQL_STATIC_SENSITIVITY
, (UCHAR
*) &dbInf
.staticSensitivity
, sizeof(dbInf
.staticSensitivity
), &cb
) != SQL_SUCCESS
)
1026 return(DispAllErrors(henv
, hdbc
));
1028 if (SQLGetInfo(hdbc
, SQL_TXN_CAPABLE
, (UCHAR
*) &dbInf
.txnCapable
, sizeof(dbInf
.txnCapable
), &cb
) != SQL_SUCCESS
)
1029 return(DispAllErrors(henv
, hdbc
));
1031 if (SQLGetInfo(hdbc
, SQL_LOGIN_TIMEOUT
, (UCHAR
*) &dbInf
.loginTimeout
, sizeof(dbInf
.loginTimeout
), &cb
) != SQL_SUCCESS
)
1032 return(DispAllErrors(henv
, hdbc
));
1034 #ifdef DBDEBUG_CONSOLE
1035 cout
<< wxT("***** DATA SOURCE INFORMATION *****") << endl
;
1036 cout
<< wxT(wxT("SERVER Name: ") << dbInf
.serverName
<< endl
;
1037 cout
<< wxT("DBMS Name: ") << dbInf
.dbmsName
<< wxT("; DBMS Version: ") << dbInf
.dbmsVer
<< endl
;
1038 cout
<< wxT("ODBC Version: ") << dbInf
.odbcVer
<< wxT("; Driver Version: ") << dbInf
.driverVer
<< endl
;
1040 cout
<< wxT("API Conf. Level: ");
1041 switch(dbInf
.apiConfLvl
)
1043 case SQL_OAC_NONE
: cout
<< wxT("None"); break;
1044 case SQL_OAC_LEVEL1
: cout
<< wxT("Level 1"); break;
1045 case SQL_OAC_LEVEL2
: cout
<< wxT("Level 2"); break;
1049 cout
<< wxT("SAG CLI Conf. Level: ");
1050 switch(dbInf
.cliConfLvl
)
1052 case SQL_OSCC_NOT_COMPLIANT
: cout
<< wxT("Not Compliant"); break;
1053 case SQL_OSCC_COMPLIANT
: cout
<< wxT("Compliant"); break;
1057 cout
<< wxT("SQL Conf. Level: ");
1058 switch(dbInf
.sqlConfLvl
)
1060 case SQL_OSC_MINIMUM
: cout
<< wxT("Minimum Grammar"); break;
1061 case SQL_OSC_CORE
: cout
<< wxT("Core Grammar"); break;
1062 case SQL_OSC_EXTENDED
: cout
<< wxT("Extended Grammar"); break;
1066 cout
<< wxT("Max. Connections: ") << dbInf
.maxConnections
<< endl
;
1067 cout
<< wxT("Outer Joins: ") << dbInf
.outerJoins
<< endl
;
1068 cout
<< wxT("Support for Procedures: ") << dbInf
.procedureSupport
<< endl
;
1069 cout
<< wxT("All tables accessible : ") << dbInf
.accessibleTables
<< endl
;
1070 cout
<< wxT("Cursor COMMIT Behavior: ");
1071 switch(dbInf
.cursorCommitBehavior
)
1073 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1074 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1075 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1079 cout
<< wxT("Cursor ROLLBACK Behavior: ");
1080 switch(dbInf
.cursorRollbackBehavior
)
1082 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1083 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1084 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1088 cout
<< wxT("Support NOT NULL clause: ");
1089 switch(dbInf
.supportNotNullClause
)
1091 case SQL_NNC_NULL
: cout
<< wxT("No"); break;
1092 case SQL_NNC_NON_NULL
: cout
<< wxT("Yes"); break;
1096 cout
<< wxT("Support IEF (Ref. Integrity): ") << dbInf
.supportIEF
<< endl
;
1097 cout
<< wxT("Login Timeout: ") << dbInf
.loginTimeout
<< endl
;
1099 cout
<< endl
<< endl
<< wxT("more ...") << endl
;
1102 cout
<< wxT("Default Transaction Isolation: ";
1103 switch(dbInf
.txnIsolation
)
1105 case SQL_TXN_READ_UNCOMMITTED
: cout
<< wxT("Read Uncommitted"); break;
1106 case SQL_TXN_READ_COMMITTED
: cout
<< wxT("Read Committed"); break;
1107 case SQL_TXN_REPEATABLE_READ
: cout
<< wxT("Repeatable Read"); break;
1108 case SQL_TXN_SERIALIZABLE
: cout
<< wxT("Serializable"); break;
1110 case SQL_TXN_VERSIONING
: cout
<< wxT("Versioning"); break;
1115 cout
<< wxT("Transaction Isolation Options: ");
1116 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_UNCOMMITTED
)
1117 cout
<< wxT("Read Uncommitted, ");
1118 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_COMMITTED
)
1119 cout
<< wxT("Read Committed, ");
1120 if (dbInf
.txnIsolationOptions
& SQL_TXN_REPEATABLE_READ
)
1121 cout
<< wxT("Repeatable Read, ");
1122 if (dbInf
.txnIsolationOptions
& SQL_TXN_SERIALIZABLE
)
1123 cout
<< wxT("Serializable, ");
1125 if (dbInf
.txnIsolationOptions
& SQL_TXN_VERSIONING
)
1126 cout
<< wxT("Versioning");
1130 cout
<< wxT("Fetch Directions Supported:") << endl
<< wxT(" ");
1131 if (dbInf
.fetchDirections
& SQL_FD_FETCH_NEXT
)
1132 cout
<< wxT("Next, ");
1133 if (dbInf
.fetchDirections
& SQL_FD_FETCH_PRIOR
)
1134 cout
<< wxT("Prev, ");
1135 if (dbInf
.fetchDirections
& SQL_FD_FETCH_FIRST
)
1136 cout
<< wxT("First, ");
1137 if (dbInf
.fetchDirections
& SQL_FD_FETCH_LAST
)
1138 cout
<< wxT("Last, ");
1139 if (dbInf
.fetchDirections
& SQL_FD_FETCH_ABSOLUTE
)
1140 cout
<< wxT("Absolute, ");
1141 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RELATIVE
)
1142 cout
<< wxT("Relative, ");
1144 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RESUME
)
1145 cout
<< wxT("Resume, ");
1147 if (dbInf
.fetchDirections
& SQL_FD_FETCH_BOOKMARK
)
1148 cout
<< wxT("Bookmark");
1151 cout
<< wxT("Lock Types Supported (SQLSetPos): ");
1152 if (dbInf
.lockTypes
& SQL_LCK_NO_CHANGE
)
1153 cout
<< wxT("No Change, ");
1154 if (dbInf
.lockTypes
& SQL_LCK_EXCLUSIVE
)
1155 cout
<< wxT("Exclusive, ");
1156 if (dbInf
.lockTypes
& SQL_LCK_UNLOCK
)
1157 cout
<< wxT("UnLock");
1160 cout
<< wxT("Position Operations Supported (SQLSetPos): ");
1161 if (dbInf
.posOperations
& SQL_POS_POSITION
)
1162 cout
<< wxT("Position, ");
1163 if (dbInf
.posOperations
& SQL_POS_REFRESH
)
1164 cout
<< wxT("Refresh, ");
1165 if (dbInf
.posOperations
& SQL_POS_UPDATE
)
1166 cout
<< wxT("Upd, "));
1167 if (dbInf
.posOperations
& SQL_POS_DELETE
)
1168 cout
<< wxT("Del, ");
1169 if (dbInf
.posOperations
& SQL_POS_ADD
)
1173 cout
<< wxT("Positioned Statements Supported: ");
1174 if (dbInf
.posStmts
& SQL_PS_POSITIONED_DELETE
)
1175 cout
<< wxT("Pos delete, ");
1176 if (dbInf
.posStmts
& SQL_PS_POSITIONED_UPDATE
)
1177 cout
<< wxT("Pos update, ");
1178 if (dbInf
.posStmts
& SQL_PS_SELECT_FOR_UPDATE
)
1179 cout
<< wxT("Select for update");
1182 cout
<< wxT("Scroll Concurrency: ");
1183 if (dbInf
.scrollConcurrency
& SQL_SCCO_READ_ONLY
)
1184 cout
<< wxT("Read Only, ");
1185 if (dbInf
.scrollConcurrency
& SQL_SCCO_LOCK
)
1186 cout
<< wxT("Lock, ");
1187 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_ROWVER
)
1188 cout
<< wxT("Opt. Rowver, ");
1189 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_VALUES
)
1190 cout
<< wxT("Opt. Values");
1193 cout
<< wxT("Scroll Options: ");
1194 if (dbInf
.scrollOptions
& SQL_SO_FORWARD_ONLY
)
1195 cout
<< wxT("Fwd Only, ");
1196 if (dbInf
.scrollOptions
& SQL_SO_STATIC
)
1197 cout
<< wxT("Static, ");
1198 if (dbInf
.scrollOptions
& SQL_SO_KEYSET_DRIVEN
)
1199 cout
<< wxT("Keyset Driven, ");
1200 if (dbInf
.scrollOptions
& SQL_SO_DYNAMIC
)
1201 cout
<< wxT("Dynamic, ");
1202 if (dbInf
.scrollOptions
& SQL_SO_MIXED
)
1203 cout
<< wxT("Mixed");
1206 cout
<< wxT("Static Sensitivity: ");
1207 if (dbInf
.staticSensitivity
& SQL_SS_ADDITIONS
)
1208 cout
<< wxT("Additions, ");
1209 if (dbInf
.staticSensitivity
& SQL_SS_DELETIONS
)
1210 cout
<< wxT("Deletions, ");
1211 if (dbInf
.staticSensitivity
& SQL_SS_UPDATES
)
1212 cout
<< wxT("Updates");
1215 cout
<< wxT("Transaction Capable?: ");
1216 switch(dbInf
.txnCapable
)
1218 case SQL_TC_NONE
: cout
<< wxT("No"); break;
1219 case SQL_TC_DML
: cout
<< wxT("DML Only"); break;
1220 case SQL_TC_DDL_COMMIT
: cout
<< wxT("DDL Commit"); break;
1221 case SQL_TC_DDL_IGNORE
: cout
<< wxT("DDL Ignore"); break;
1222 case SQL_TC_ALL
: cout
<< wxT("DDL & DML"); break;
1229 // Completed Successfully
1232 } // wxDb::getDbInfo()
1235 /********** wxDb::getDataTypeInfo() **********/
1236 bool wxDb::getDataTypeInfo(SWORD fSqlType
, wxDbSqlTypeInfo
&structSQLTypeInfo
)
1239 * fSqlType will be something like SQL_VARCHAR. This parameter determines
1240 * the data type inf. is gathered for.
1242 * wxDbSqlTypeInfo is a structure that is filled in with data type information,
1247 // Get information about the data type specified
1248 if (SQLGetTypeInfo(hstmt
, fSqlType
) != SQL_SUCCESS
)
1249 return(DispAllErrors(henv
, hdbc
, hstmt
));
1251 if ((retcode
= SQLFetch(hstmt
)) != SQL_SUCCESS
)
1253 #ifdef DBDEBUG_CONSOLE
1254 if (retcode
== SQL_NO_DATA_FOUND
)
1255 cout
<< wxT("SQL_NO_DATA_FOUND fetching inf. about data type.") << endl
;
1257 DispAllErrors(henv
, hdbc
, hstmt
);
1258 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1262 wxChar typeName
[DB_TYPE_NAME_LEN
+1];
1263 // Obtain columns from the record
1264 if (SQLGetData(hstmt
, 1, SQL_C_CHAR
, (UCHAR
*) typeName
, DB_TYPE_NAME_LEN
, &cbRet
) != SQL_SUCCESS
)
1265 return(DispAllErrors(henv
, hdbc
, hstmt
));
1267 structSQLTypeInfo
.TypeName
= typeName
;
1269 // BJO 20000503: no more needed with new GetColumns...
1272 if (Dbms() == dbmsMY_SQL
)
1274 if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1275 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1276 else if (structSQLTypeInfo
.TypeName
== wxT("middleint unsigned"))
1277 structSQLTypeInfo
.TypeName
= wxT("mediumint unsigned");
1278 else if (structSQLTypeInfo
.TypeName
== wxT("integer"))
1279 structSQLTypeInfo
.TypeName
= wxT("int");
1280 else if (structSQLTypeInfo
.TypeName
== wxT("integer unsigned"))
1281 structSQLTypeInfo
.TypeName
= wxT("int unsigned");
1282 else if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1283 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1284 else if (structSQLTypeInfo
.TypeName
== wxT("varchar"))
1285 structSQLTypeInfo
.TypeName
= wxT("char");
1288 // BJO 20000427 : OpenLink driver
1289 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
1290 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
1292 if (structSQLTypeInfo
.TypeName
== wxT("double precision"))
1293 structSQLTypeInfo
.TypeName
= wxT("real");
1297 if (SQLGetData(hstmt
, 3, SQL_C_LONG
, (UCHAR
*) &structSQLTypeInfo
.Precision
, 0, &cbRet
) != SQL_SUCCESS
)
1298 return(DispAllErrors(henv
, hdbc
, hstmt
));
1299 if (SQLGetData(hstmt
, 8, SQL_C_SHORT
, (UCHAR
*) &structSQLTypeInfo
.CaseSensitive
, 0, &cbRet
) != SQL_SUCCESS
)
1300 return(DispAllErrors(henv
, hdbc
, hstmt
));
1301 // if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
1302 // return(DispAllErrors(henv, hdbc, hstmt));
1304 if (SQLGetData(hstmt
, 15, SQL_C_SHORT
,(UCHAR
*) &structSQLTypeInfo
.MaximumScale
, 0, &cbRet
) != SQL_SUCCESS
)
1305 return(DispAllErrors(henv
, hdbc
, hstmt
));
1307 if (structSQLTypeInfo
.MaximumScale
< 0)
1308 structSQLTypeInfo
.MaximumScale
= 0;
1310 // Close the statement handle which closes open cursors
1311 if (SQLFreeStmt(hstmt
, SQL_CLOSE
) != SQL_SUCCESS
)
1312 return(DispAllErrors(henv
, hdbc
, hstmt
));
1314 // Completed Successfully
1317 } // wxDb::getDataTypeInfo()
1320 /********** wxDb::Close() **********/
1321 void wxDb::Close(void)
1323 // Close the Sql Log file
1330 // Free statement handle
1333 if (SQLFreeStmt(hstmt
, SQL_DROP
) != SQL_SUCCESS
)
1334 DispAllErrors(henv
, hdbc
);
1337 // Disconnect from the datasource
1338 if (SQLDisconnect(hdbc
) != SQL_SUCCESS
)
1339 DispAllErrors(henv
, hdbc
);
1341 // Free the connection to the datasource
1342 if (SQLFreeConnect(hdbc
) != SQL_SUCCESS
)
1343 DispAllErrors(henv
, hdbc
);
1345 // There should be zero Ctable objects still connected to this db object
1346 wxASSERT(nTables
== 0);
1351 pNode
= TablesInUse
.First();
1355 tiu
= (wxTablesInUse
*)pNode
->Data();
1356 if (tiu
->pDb
== this)
1358 s
.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu
->tableName
,tiu
->tableID
,tiu
->pDb
);
1359 s2
.Printf(wxT("Orphaned found using pDb:[%p]"),this);
1362 pNode
= pNode
->Next();
1366 // Copy the error messages to a global variable
1368 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1369 wxStrcpy(DBerrorList
[i
], errorList
[i
]);
1371 dbmsType
= dbmsUNIDENTIFIED
;
1377 /********** wxDb::CommitTrans() **********/
1378 bool wxDb::CommitTrans(void)
1382 // Commit the transaction
1383 if (SQLTransact(henv
, hdbc
, SQL_COMMIT
) != SQL_SUCCESS
)
1384 return(DispAllErrors(henv
, hdbc
));
1387 // Completed successfully
1390 } // wxDb::CommitTrans()
1393 /********** wxDb::RollbackTrans() **********/
1394 bool wxDb::RollbackTrans(void)
1396 // Rollback the transaction
1397 if (SQLTransact(henv
, hdbc
, SQL_ROLLBACK
) != SQL_SUCCESS
)
1398 return(DispAllErrors(henv
, hdbc
));
1400 // Completed successfully
1403 } // wxDb::RollbackTrans()
1406 /********** wxDb::DispAllErrors() **********/
1407 bool wxDb::DispAllErrors(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1409 * This function is called internally whenever an error condition prevents the user's
1410 * request from being executed. This function will query the datasource as to the
1411 * actual error(s) that just occured on the previous request of the datasource.
1413 * The function will retrieve each error condition from the datasource and
1414 * Printf the codes/text values into a string which it then logs via logError().
1415 * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
1416 * window and program execution will be paused until the user presses a key.
1418 * This function always returns a FALSE, so that functions which call this function
1419 * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure
1420 * of the users request, so that the calling code can then process the error msg log
1423 wxString odbcErrMsg
;
1425 while (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1427 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1428 logError(odbcErrMsg
, sqlState
);
1431 #ifdef DBDEBUG_CONSOLE
1432 // When run in console mode, use standard out to display errors.
1433 cout
<< odbcErrMsg
.c_str() << endl
;
1434 cout
<< wxT("Press any key to continue...") << endl
;
1439 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
1444 return(FALSE
); // This function always returns false.
1446 } // wxDb::DispAllErrors()
1449 /********** wxDb::GetNextError() **********/
1450 bool wxDb::GetNextError(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1452 if (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1457 } // wxDb::GetNextError()
1460 /********** wxDb::DispNextError() **********/
1461 void wxDb::DispNextError(void)
1463 wxString odbcErrMsg
;
1465 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1466 logError(odbcErrMsg
, sqlState
);
1471 #ifdef DBDEBUG_CONSOLE
1472 // When run in console mode, use standard out to display errors.
1473 cout
<< odbcErrMsg
.c_str() << endl
;
1474 cout
<< wxT("Press any key to continue...") << endl
;
1479 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE"));
1480 #endif // __WXDEBUG__
1482 } // wxDb::DispNextError()
1485 /********** wxDb::logError() **********/
1486 void wxDb::logError(const wxString
&errMsg
, const wxString
&SQLState
)
1488 wxASSERT(errMsg
.Length());
1490 static int pLast
= -1;
1493 if (++pLast
== DB_MAX_ERROR_HISTORY
)
1496 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1497 wxStrcpy(errorList
[i
], errorList
[i
+1]);
1501 wxStrcpy(errorList
[pLast
], errMsg
);
1503 if (SQLState
.Length())
1504 if ((dbStatus
= TranslateSqlState(SQLState
)) != DB_ERR_FUNCTION_SEQUENCE_ERROR
)
1505 DB_STATUS
= dbStatus
;
1507 // Add the errmsg to the sql log
1508 WriteSqlLog(errMsg
);
1510 } // wxDb::logError()
1513 /**********wxDb::TranslateSqlState() **********/
1514 int wxDb::TranslateSqlState(const wxString
&SQLState
)
1516 if (!wxStrcmp(SQLState
, wxT("01000")))
1517 return(DB_ERR_GENERAL_WARNING
);
1518 if (!wxStrcmp(SQLState
, wxT("01002")))
1519 return(DB_ERR_DISCONNECT_ERROR
);
1520 if (!wxStrcmp(SQLState
, wxT("01004")))
1521 return(DB_ERR_DATA_TRUNCATED
);
1522 if (!wxStrcmp(SQLState
, wxT("01006")))
1523 return(DB_ERR_PRIV_NOT_REVOKED
);
1524 if (!wxStrcmp(SQLState
, wxT("01S00")))
1525 return(DB_ERR_INVALID_CONN_STR_ATTR
);
1526 if (!wxStrcmp(SQLState
, wxT("01S01")))
1527 return(DB_ERR_ERROR_IN_ROW
);
1528 if (!wxStrcmp(SQLState
, wxT("01S02")))
1529 return(DB_ERR_OPTION_VALUE_CHANGED
);
1530 if (!wxStrcmp(SQLState
, wxT("01S03")))
1531 return(DB_ERR_NO_ROWS_UPD_OR_DEL
);
1532 if (!wxStrcmp(SQLState
, wxT("01S04")))
1533 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL
);
1534 if (!wxStrcmp(SQLState
, wxT("07001")))
1535 return(DB_ERR_WRONG_NO_OF_PARAMS
);
1536 if (!wxStrcmp(SQLState
, wxT("07006")))
1537 return(DB_ERR_DATA_TYPE_ATTR_VIOL
);
1538 if (!wxStrcmp(SQLState
, wxT("08001")))
1539 return(DB_ERR_UNABLE_TO_CONNECT
);
1540 if (!wxStrcmp(SQLState
, wxT("08002")))
1541 return(DB_ERR_CONNECTION_IN_USE
);
1542 if (!wxStrcmp(SQLState
, wxT("08003")))
1543 return(DB_ERR_CONNECTION_NOT_OPEN
);
1544 if (!wxStrcmp(SQLState
, wxT("08004")))
1545 return(DB_ERR_REJECTED_CONNECTION
);
1546 if (!wxStrcmp(SQLState
, wxT("08007")))
1547 return(DB_ERR_CONN_FAIL_IN_TRANS
);
1548 if (!wxStrcmp(SQLState
, wxT("08S01")))
1549 return(DB_ERR_COMM_LINK_FAILURE
);
1550 if (!wxStrcmp(SQLState
, wxT("21S01")))
1551 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH
);
1552 if (!wxStrcmp(SQLState
, wxT("21S02")))
1553 return(DB_ERR_DERIVED_TABLE_MISMATCH
);
1554 if (!wxStrcmp(SQLState
, wxT("22001")))
1555 return(DB_ERR_STRING_RIGHT_TRUNC
);
1556 if (!wxStrcmp(SQLState
, wxT("22003")))
1557 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG
);
1558 if (!wxStrcmp(SQLState
, wxT("22005")))
1559 return(DB_ERR_ERROR_IN_ASSIGNMENT
);
1560 if (!wxStrcmp(SQLState
, wxT("22008")))
1561 return(DB_ERR_DATETIME_FLD_OVERFLOW
);
1562 if (!wxStrcmp(SQLState
, wxT("22012")))
1563 return(DB_ERR_DIVIDE_BY_ZERO
);
1564 if (!wxStrcmp(SQLState
, wxT("22026")))
1565 return(DB_ERR_STR_DATA_LENGTH_MISMATCH
);
1566 if (!wxStrcmp(SQLState
, wxT("23000")))
1567 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL
);
1568 if (!wxStrcmp(SQLState
, wxT("24000")))
1569 return(DB_ERR_INVALID_CURSOR_STATE
);
1570 if (!wxStrcmp(SQLState
, wxT("25000")))
1571 return(DB_ERR_INVALID_TRANS_STATE
);
1572 if (!wxStrcmp(SQLState
, wxT("28000")))
1573 return(DB_ERR_INVALID_AUTH_SPEC
);
1574 if (!wxStrcmp(SQLState
, wxT("34000")))
1575 return(DB_ERR_INVALID_CURSOR_NAME
);
1576 if (!wxStrcmp(SQLState
, wxT("37000")))
1577 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL
);
1578 if (!wxStrcmp(SQLState
, wxT("3C000")))
1579 return(DB_ERR_DUPLICATE_CURSOR_NAME
);
1580 if (!wxStrcmp(SQLState
, wxT("40001")))
1581 return(DB_ERR_SERIALIZATION_FAILURE
);
1582 if (!wxStrcmp(SQLState
, wxT("42000")))
1583 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2
);
1584 if (!wxStrcmp(SQLState
, wxT("70100")))
1585 return(DB_ERR_OPERATION_ABORTED
);
1586 if (!wxStrcmp(SQLState
, wxT("IM001")))
1587 return(DB_ERR_UNSUPPORTED_FUNCTION
);
1588 if (!wxStrcmp(SQLState
, wxT("IM002")))
1589 return(DB_ERR_NO_DATA_SOURCE
);
1590 if (!wxStrcmp(SQLState
, wxT("IM003")))
1591 return(DB_ERR_DRIVER_LOAD_ERROR
);
1592 if (!wxStrcmp(SQLState
, wxT("IM004")))
1593 return(DB_ERR_SQLALLOCENV_FAILED
);
1594 if (!wxStrcmp(SQLState
, wxT("IM005")))
1595 return(DB_ERR_SQLALLOCCONNECT_FAILED
);
1596 if (!wxStrcmp(SQLState
, wxT("IM006")))
1597 return(DB_ERR_SQLSETCONNECTOPTION_FAILED
);
1598 if (!wxStrcmp(SQLState
, wxT("IM007")))
1599 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB
);
1600 if (!wxStrcmp(SQLState
, wxT("IM008")))
1601 return(DB_ERR_DIALOG_FAILED
);
1602 if (!wxStrcmp(SQLState
, wxT("IM009")))
1603 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL
);
1604 if (!wxStrcmp(SQLState
, wxT("IM010")))
1605 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG
);
1606 if (!wxStrcmp(SQLState
, wxT("IM011")))
1607 return(DB_ERR_DRIVER_NAME_TOO_LONG
);
1608 if (!wxStrcmp(SQLState
, wxT("IM012")))
1609 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR
);
1610 if (!wxStrcmp(SQLState
, wxT("IM013")))
1611 return(DB_ERR_TRACE_FILE_ERROR
);
1612 if (!wxStrcmp(SQLState
, wxT("S0001")))
1613 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS
);
1614 if (!wxStrcmp(SQLState
, wxT("S0002")))
1615 return(DB_ERR_TABLE_NOT_FOUND
);
1616 if (!wxStrcmp(SQLState
, wxT("S0011")))
1617 return(DB_ERR_INDEX_ALREADY_EXISTS
);
1618 if (!wxStrcmp(SQLState
, wxT("S0012")))
1619 return(DB_ERR_INDEX_NOT_FOUND
);
1620 if (!wxStrcmp(SQLState
, wxT("S0021")))
1621 return(DB_ERR_COLUMN_ALREADY_EXISTS
);
1622 if (!wxStrcmp(SQLState
, wxT("S0022")))
1623 return(DB_ERR_COLUMN_NOT_FOUND
);
1624 if (!wxStrcmp(SQLState
, wxT("S0023")))
1625 return(DB_ERR_NO_DEFAULT_FOR_COLUMN
);
1626 if (!wxStrcmp(SQLState
, wxT("S1000")))
1627 return(DB_ERR_GENERAL_ERROR
);
1628 if (!wxStrcmp(SQLState
, wxT("S1001")))
1629 return(DB_ERR_MEMORY_ALLOCATION_FAILURE
);
1630 if (!wxStrcmp(SQLState
, wxT("S1002")))
1631 return(DB_ERR_INVALID_COLUMN_NUMBER
);
1632 if (!wxStrcmp(SQLState
, wxT("S1003")))
1633 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE
);
1634 if (!wxStrcmp(SQLState
, wxT("S1004")))
1635 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE
);
1636 if (!wxStrcmp(SQLState
, wxT("S1008")))
1637 return(DB_ERR_OPERATION_CANCELLED
);
1638 if (!wxStrcmp(SQLState
, wxT("S1009")))
1639 return(DB_ERR_INVALID_ARGUMENT_VALUE
);
1640 if (!wxStrcmp(SQLState
, wxT("S1010")))
1641 return(DB_ERR_FUNCTION_SEQUENCE_ERROR
);
1642 if (!wxStrcmp(SQLState
, wxT("S1011")))
1643 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME
);
1644 if (!wxStrcmp(SQLState
, wxT("S1012")))
1645 return(DB_ERR_INVALID_TRANS_OPERATION_CODE
);
1646 if (!wxStrcmp(SQLState
, wxT("S1015")))
1647 return(DB_ERR_NO_CURSOR_NAME_AVAIL
);
1648 if (!wxStrcmp(SQLState
, wxT("S1090")))
1649 return(DB_ERR_INVALID_STR_OR_BUF_LEN
);
1650 if (!wxStrcmp(SQLState
, wxT("S1091")))
1651 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE
);
1652 if (!wxStrcmp(SQLState
, wxT("S1092")))
1653 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE
);
1654 if (!wxStrcmp(SQLState
, wxT("S1093")))
1655 return(DB_ERR_INVALID_PARAM_NO
);
1656 if (!wxStrcmp(SQLState
, wxT("S1094")))
1657 return(DB_ERR_INVALID_SCALE_VALUE
);
1658 if (!wxStrcmp(SQLState
, wxT("S1095")))
1659 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE
);
1660 if (!wxStrcmp(SQLState
, wxT("S1096")))
1661 return(DB_ERR_INF_TYPE_OUT_OF_RANGE
);
1662 if (!wxStrcmp(SQLState
, wxT("S1097")))
1663 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE
);
1664 if (!wxStrcmp(SQLState
, wxT("S1098")))
1665 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE
);
1666 if (!wxStrcmp(SQLState
, wxT("S1099")))
1667 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE
);
1668 if (!wxStrcmp(SQLState
, wxT("S1100")))
1669 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE
);
1670 if (!wxStrcmp(SQLState
, wxT("S1101")))
1671 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE
);
1672 if (!wxStrcmp(SQLState
, wxT("S1103")))
1673 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE
);
1674 if (!wxStrcmp(SQLState
, wxT("S1104")))
1675 return(DB_ERR_INVALID_PRECISION_VALUE
);
1676 if (!wxStrcmp(SQLState
, wxT("S1105")))
1677 return(DB_ERR_INVALID_PARAM_TYPE
);
1678 if (!wxStrcmp(SQLState
, wxT("S1106")))
1679 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE
);
1680 if (!wxStrcmp(SQLState
, wxT("S1107")))
1681 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE
);
1682 if (!wxStrcmp(SQLState
, wxT("S1108")))
1683 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE
);
1684 if (!wxStrcmp(SQLState
, wxT("S1109")))
1685 return(DB_ERR_INVALID_CURSOR_POSITION
);
1686 if (!wxStrcmp(SQLState
, wxT("S1110")))
1687 return(DB_ERR_INVALID_DRIVER_COMPLETION
);
1688 if (!wxStrcmp(SQLState
, wxT("S1111")))
1689 return(DB_ERR_INVALID_BOOKMARK_VALUE
);
1690 if (!wxStrcmp(SQLState
, wxT("S1C00")))
1691 return(DB_ERR_DRIVER_NOT_CAPABLE
);
1692 if (!wxStrcmp(SQLState
, wxT("S1T00")))
1693 return(DB_ERR_TIMEOUT_EXPIRED
);
1698 } // wxDb::TranslateSqlState()
1701 /********** wxDb::Grant() **********/
1702 bool wxDb::Grant(int privileges
, const wxString
&tableName
, const wxString
&userList
)
1706 // Build the grant statement
1707 sqlStmt
= wxT("GRANT ");
1708 if (privileges
== DB_GRANT_ALL
)
1709 sqlStmt
+= wxT("ALL");
1713 if (privileges
& DB_GRANT_SELECT
)
1715 sqlStmt
+= wxT("SELECT");
1718 if (privileges
& DB_GRANT_INSERT
)
1721 sqlStmt
+= wxT(", ");
1722 sqlStmt
+= wxT("INSERT");
1724 if (privileges
& DB_GRANT_UPDATE
)
1727 sqlStmt
+= wxT(", ");
1728 sqlStmt
+= wxT("UPDATE");
1730 if (privileges
& DB_GRANT_DELETE
)
1733 sqlStmt
+= wxT(", ");
1734 sqlStmt
+= wxT("DELETE");
1738 sqlStmt
+= wxT(" ON ");
1739 sqlStmt
+= tableName
;
1740 sqlStmt
+= wxT(" TO ");
1741 sqlStmt
+= userList
;
1743 #ifdef DBDEBUG_CONSOLE
1744 cout
<< endl
<< sqlStmt
.c_str() << endl
;
1747 WriteSqlLog(sqlStmt
);
1749 return(ExecSql(sqlStmt
));
1754 /********** wxDb::CreateView() **********/
1755 bool wxDb::CreateView(const wxString
&viewName
, const wxString
&colList
,
1756 const wxString
&pSqlStmt
, bool attemptDrop
)
1760 // Drop the view first
1761 if (attemptDrop
&& !DropView(viewName
))
1764 // Build the create view statement
1765 sqlStmt
= wxT("CREATE VIEW ");
1766 sqlStmt
+= viewName
;
1768 if (colList
.Length())
1770 sqlStmt
+= wxT(" (");
1772 sqlStmt
+= wxT(")");
1775 sqlStmt
+= wxT(" AS ");
1776 sqlStmt
+= pSqlStmt
;
1778 WriteSqlLog(sqlStmt
);
1780 #ifdef DBDEBUG_CONSOLE
1781 cout
<< sqlStmt
.c_str() << endl
;
1784 return(ExecSql(sqlStmt
));
1786 } // wxDb::CreateView()
1789 /********** wxDb::DropView() **********/
1790 bool wxDb::DropView(const wxString
&viewName
)
1793 * NOTE: This function returns TRUE if the View does not exist, but
1794 * only for identified databases. Code will need to be added
1795 * below for any other databases when those databases are defined
1796 * to handle this situation consistently
1800 sqlStmt
.Printf(wxT("DROP VIEW %s"), viewName
.c_str());
1802 WriteSqlLog(sqlStmt
);
1804 #ifdef DBDEBUG_CONSOLE
1805 cout
<< endl
<< sqlStmt
.c_str() << endl
;
1808 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
1810 // Check for "Base table not found" error and ignore
1811 GetNextError(henv
, hdbc
, hstmt
);
1812 if (wxStrcmp(sqlState
,wxT("S0002"))) // "Base table not found"
1814 // Check for product specific error codes
1815 if (!((Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(sqlState
,wxT("42000"))))) // 5.x (and lower?)
1818 DispAllErrors(henv
, hdbc
, hstmt
);
1825 // Commit the transaction
1826 if (! CommitTrans())
1831 } // wxDb::DropView()
1834 /********** wxDb::ExecSql() **********/
1835 bool wxDb::ExecSql(const wxString
&pSqlStmt
)
1837 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1838 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) pSqlStmt
.c_str(), SQL_NTS
) == SQL_SUCCESS
)
1842 DispAllErrors(henv
, hdbc
, hstmt
);
1846 } // wxDb::ExecSql()
1849 /********** wxDb::GetNext() **********/
1850 bool wxDb::GetNext(void)
1852 if (SQLFetch(hstmt
) == SQL_SUCCESS
)
1856 DispAllErrors(henv
, hdbc
, hstmt
);
1860 } // wxDb::GetNext()
1863 /********** wxDb::GetData() **********/
1864 bool wxDb::GetData(UWORD colNo
, SWORD cType
, PTR pData
, SDWORD maxLen
, SDWORD FAR
*cbReturned
)
1867 wxASSERT(cbReturned
);
1869 if (SQLGetData(hstmt
, colNo
, cType
, pData
, maxLen
, cbReturned
) == SQL_SUCCESS
)
1873 DispAllErrors(henv
, hdbc
, hstmt
);
1877 } // wxDb::GetData()
1880 /********** wxDb::GetKeyFields() **********/
1881 int wxDb::GetKeyFields(const wxString
&tableName
, wxDbColInf
* colInf
, int noCols
)
1883 wxChar szPkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Primary key table name */
1884 wxChar szFkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Foreign key table name */
1886 // SQLSMALLINT iKeySeq;
1887 wxChar szPkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Primary key column */
1888 wxChar szFkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Foreign key column */
1894 * -----------------------------------------------------------------------
1895 * -- 19991224 : mj10777 : Create ------
1896 * -- : Three things are done and stored here : ------
1897 * -- : 1) which Column(s) is/are Primary Key(s) ------
1898 * -- : 2) which tables use this Key as a Foreign Key ------
1899 * -- : 3) which columns are Foreign Key and the name ------
1900 * -- : of the Table where the Key is the Primary Key -----
1901 * -- : Called from GetColumns(const wxString &tableName, ------
1902 * -- int *numCols,const wxChar *userID ) ------
1903 * -----------------------------------------------------------------------
1906 /*---------------------------------------------------------------------*/
1907 /* Get the names of the columns in the primary key. */
1908 /*---------------------------------------------------------------------*/
1909 retcode
= SQLPrimaryKeys(hstmt
,
1910 NULL
, 0, /* Catalog name */
1911 NULL
, 0, /* Schema name */
1912 (UCHAR FAR
*) tableName
.c_str(), SQL_NTS
); /* Table name */
1914 /*---------------------------------------------------------------------*/
1915 /* Fetch and display the result set. This will be a list of the */
1916 /* columns in the primary key of the tableName table. */
1917 /*---------------------------------------------------------------------*/
1918 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1920 retcode
= SQLFetch(hstmt
);
1921 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1923 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1924 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1926 for (i
=0;i
<noCols
;i
++) // Find the Column name
1927 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column
1928 colInf
[i
].PkCol
= iKeySeq
; // Which Primary Key is this (first, second usw.) ?
1931 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1933 /*---------------------------------------------------------------------*/
1934 /* Get all the foreign keys that refer to tableName primary key. */
1935 /*---------------------------------------------------------------------*/
1936 retcode
= SQLForeignKeys(hstmt
,
1937 NULL
, 0, /* Primary catalog */
1938 NULL
, 0, /* Primary schema */
1939 (UCHAR FAR
*)tableName
.c_str(), SQL_NTS
,/* Primary table */
1940 NULL
, 0, /* Foreign catalog */
1941 NULL
, 0, /* Foreign schema */
1942 NULL
, 0); /* Foreign table */
1944 /*---------------------------------------------------------------------*/
1945 /* Fetch and display the result set. This will be all of the foreign */
1946 /* keys in other tables that refer to the tableName primary key. */
1947 /*---------------------------------------------------------------------*/
1950 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1952 retcode
= SQLFetch(hstmt
);
1953 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1955 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1956 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1957 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1958 GetData( 7, SQL_C_CHAR
, szFkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1959 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1960 tempStr
.Printf(wxT("%s[%s] "),tempStr
.c_str(),szFkTable
); // [ ] in case there is a blank in the Table name
1964 tempStr
.Trim(); // Get rid of any unneeded blanks
1965 if (!tempStr
.IsEmpty())
1967 for (i
=0; i
<noCols
; i
++)
1968 { // Find the Column name
1969 if (!wxStrcmp(colInf
[i
].colName
, szPkCol
)) // We have found the Column, store the Information
1970 wxStrcpy(colInf
[i
].PkTableName
, tempStr
.c_str()); // Name of the Tables where this Primary Key is used as a Foreign Key
1974 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1976 /*---------------------------------------------------------------------*/
1977 /* Get all the foreign keys in the tablename table. */
1978 /*---------------------------------------------------------------------*/
1979 retcode
= SQLForeignKeys(hstmt
,
1980 NULL
, 0, /* Primary catalog */
1981 NULL
, 0, /* Primary schema */
1982 NULL
, 0, /* Primary table */
1983 NULL
, 0, /* Foreign catalog */
1984 NULL
, 0, /* Foreign schema */
1985 (UCHAR
*)tableName
.c_str(), SQL_NTS
);/* Foreign table */
1987 /*---------------------------------------------------------------------*/
1988 /* Fetch and display the result set. This will be all of the */
1989 /* primary keys in other tables that are referred to by foreign */
1990 /* keys in the tableName table. */
1991 /*---------------------------------------------------------------------*/
1993 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1995 retcode
= SQLFetch(hstmt
);
1996 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1998 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1999 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
2000 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2002 for (i
=0; i
<noCols
; i
++) // Find the Column name
2004 if (!wxStrcmp(colInf
[i
].colName
,szFkCol
)) // We have found the (Foreign Key) Column
2006 colInf
[i
].FkCol
= iKeySeq
; // Which Foreign Key is this (first, second usw.) ?
2007 wxStrcpy(colInf
[i
].FkTableName
,szPkTable
); // Name of the Table where this Foriegn is the Primary Key
2012 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
2016 } // wxDb::GetKeyFields()
2020 /********** wxDb::GetColumns() **********/
2021 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2023 * 1) The last array element of the tableName[] argument must be zero (null).
2024 * This is how the end of the array is detected.
2025 * 2) This function returns an array of wxDbColInf structures. If no columns
2026 * were found, or an error occured, this pointer will be zero (null). THE
2027 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
2028 * IS FINISHED WITH IT. i.e.
2030 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
2033 * // Use the column inf
2035 * // Destroy the memory
2039 * userID is evaluated in the following manner:
2040 * userID == NULL ... UserID is ignored
2041 * userID == "" ... UserID set equal to 'this->uid'
2042 * userID != "" ... UserID set equal to 'userID'
2044 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2045 * by this function. This function should use its own wxDb instance
2046 * to avoid undesired unbinding of columns.
2051 wxDbColInf
*colInf
= 0;
2059 convertUserID(userID
,UserID
);
2061 // Pass 1 - Determine how many columns there are.
2062 // Pass 2 - Allocate the wxDbColInf array and fill in
2063 // the array with the column information.
2065 for (pass
= 1; pass
<= 2; pass
++)
2069 if (noCols
== 0) // Probably a bogus table name(s)
2071 // Allocate n wxDbColInf objects to hold the column information
2072 colInf
= new wxDbColInf
[noCols
+1];
2075 // Mark the end of the array
2076 wxStrcpy(colInf
[noCols
].tableName
,wxT(""));
2077 wxStrcpy(colInf
[noCols
].colName
,wxT(""));
2078 colInf
[noCols
].sqlDataType
= 0;
2080 // Loop through each table name
2082 for (tbl
= 0; tableName
[tbl
]; tbl
++)
2084 TableName
= tableName
[tbl
];
2085 // Oracle and Interbase table names are uppercase only, so force
2086 // the name to uppercase just in case programmer forgot to do this
2087 if ((Dbms() == dbmsORACLE
) ||
2088 (Dbms() == dbmsINTERBASE
))
2089 TableName
= TableName
.Upper();
2091 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2093 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2094 // use the call below that leaves out the user name
2095 if (!UserID
.IsEmpty() &&
2096 Dbms() != dbmsMY_SQL
&&
2097 Dbms() != dbmsACCESS
&&
2098 Dbms() != dbmsMS_SQL_SERVER
)
2100 retcode
= SQLColumns(hstmt
,
2101 NULL
, 0, // All qualifiers
2102 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2103 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2104 NULL
, 0); // All columns
2108 retcode
= SQLColumns(hstmt
,
2109 NULL
, 0, // All qualifiers
2111 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2112 NULL
, 0); // All columns
2114 if (retcode
!= SQL_SUCCESS
)
2115 { // Error occured, abort
2116 DispAllErrors(henv
, hdbc
, hstmt
);
2119 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2123 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2125 if (pass
== 1) // First pass, just add up the number of columns
2127 else // Pass 2; Fill in the array of structures
2129 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2131 // NOTE: Only the ODBC 1.x fields are retrieved
2132 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2133 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2134 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2135 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2136 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2137 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2138 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2139 GetData( 8, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2140 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2141 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2142 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2143 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2145 // Determine the wxDb data type that is used to represent the native data type of this data source
2146 colInf
[colNo
].dbDataType
= 0;
2147 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
2150 // IODBC does not return a correct columnSize, so we set
2151 // columnSize = bufferLength if no column size was returned
2152 // IODBC returns the columnSize in bufferLength.. (bug)
2153 if (colInf
[colNo
].columnSize
< 1)
2155 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2158 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2160 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
2161 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2162 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
2163 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2164 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
2165 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2171 if (retcode
!= SQL_NO_DATA_FOUND
)
2172 { // Error occured, abort
2173 DispAllErrors(henv
, hdbc
, hstmt
);
2176 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2182 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2185 } // wxDb::GetColumns()
2188 /********** wxDb::GetColumns() **********/
2190 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, int *numCols
, const wxChar
*userID
)
2192 // Same as the above GetColumns() function except this one gets columns
2193 // only for a single table, and if 'numCols' is not NULL, the number of
2194 // columns stored in the returned wxDbColInf is set in '*numCols'
2196 // userID is evaluated in the following manner:
2197 // userID == NULL ... UserID is ignored
2198 // userID == "" ... UserID set equal to 'this->uid'
2199 // userID != "" ... UserID set equal to 'userID'
2201 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2202 // by this function. This function should use its own wxDb instance
2203 // to avoid undesired unbinding of columns.
2208 wxDbColInf
*colInf
= 0;
2216 convertUserID(userID
,UserID
);
2218 // Pass 1 - Determine how many columns there are.
2219 // Pass 2 - Allocate the wxDbColInf array and fill in
2220 // the array with the column information.
2222 for (pass
= 1; pass
<= 2; pass
++)
2226 if (noCols
== 0) // Probably a bogus table name(s)
2228 // Allocate n wxDbColInf objects to hold the column information
2229 colInf
= new wxDbColInf
[noCols
+1];
2232 // Mark the end of the array
2233 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
2234 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
2235 colInf
[noCols
].sqlDataType
= 0;
2238 TableName
= tableName
;
2239 // Oracle and Interbase table names are uppercase only, so force
2240 // the name to uppercase just in case programmer forgot to do this
2241 if ((Dbms() == dbmsORACLE
) ||
2242 (Dbms() == dbmsINTERBASE
))
2243 TableName
= TableName
.Upper();
2245 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2247 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2248 // use the call below that leaves out the user name
2249 if (!UserID
.IsEmpty() &&
2250 Dbms() != dbmsMY_SQL
&&
2251 Dbms() != dbmsACCESS
&&
2252 Dbms() != dbmsMS_SQL_SERVER
)
2254 retcode
= SQLColumns(hstmt
,
2255 NULL
, 0, // All qualifiers
2256 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2257 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2258 NULL
, 0); // All columns
2262 retcode
= SQLColumns(hstmt
,
2263 NULL
, 0, // All qualifiers
2265 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2266 NULL
, 0); // All columns
2268 if (retcode
!= SQL_SUCCESS
)
2269 { // Error occured, abort
2270 DispAllErrors(henv
, hdbc
, hstmt
);
2273 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2279 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2281 if (pass
== 1) // First pass, just add up the number of columns
2283 else // Pass 2; Fill in the array of structures
2285 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2287 // NOTE: Only the ODBC 1.x fields are retrieved
2288 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2289 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2290 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2291 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2292 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2293 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2294 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2295 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
2296 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2297 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2298 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2299 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2300 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2301 // Start Values for Primary/Foriegn Key (=No)
2302 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2303 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2304 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2305 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
2307 // BJO 20000428 : Virtuoso returns type names with upper cases!
2308 if (Dbms() == dbmsVIRTUOSO
)
2310 wxString s
= colInf
[colNo
].typeName
;
2312 wxStrcmp(colInf
[colNo
].typeName
, s
.c_str());
2315 // Determine the wxDb data type that is used to represent the native data type of this data source
2316 colInf
[colNo
].dbDataType
= 0;
2317 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
2320 // IODBC does not return a correct columnSize, so we set
2321 // columnSize = bufferLength if no column size was returned
2322 // IODBC returns the columnSize in bufferLength.. (bug)
2323 if (colInf
[colNo
].columnSize
< 1)
2325 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2329 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2331 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
2332 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2333 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
2334 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2335 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
2336 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2342 if (retcode
!= SQL_NO_DATA_FOUND
)
2343 { // Error occured, abort
2344 DispAllErrors(henv
, hdbc
, hstmt
);
2347 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2354 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2356 // Store Primary and Foriegn Keys
2357 GetKeyFields(tableName
,colInf
,noCols
);
2363 } // wxDb::GetColumns()
2366 #else // New GetColumns
2371 These are tentative new GetColumns members which should be more database
2372 independant and which always returns the columns in the order they were
2375 - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const
2376 wxChar* userID)) calls the second implementation for each separate table
2377 before merging the results. This makes the code easier to maintain as
2378 only one member (the second) makes the real work
2379 - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const
2380 wxChar *userID) is a little bit improved
2381 - It doesn't anymore rely on the type-name to find out which database-type
2383 - It ends by sorting the columns, so that they are returned in the same
2384 order they were created
2394 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2397 // The last array element of the tableName[] argument must be zero (null).
2398 // This is how the end of the array is detected.
2402 // How many tables ?
2404 for (tbl
= 0 ; tableName
[tbl
]; tbl
++);
2406 // Create a table to maintain the columns for each separate table
2407 _TableColumns
*TableColumns
= new _TableColumns
[tbl
];
2410 for (i
= 0 ; i
< tbl
; i
++)
2413 TableColumns
[i
].colInf
= GetColumns(tableName
[i
], &TableColumns
[i
].noCols
, userID
);
2414 if (TableColumns
[i
].colInf
== NULL
)
2416 noCols
+= TableColumns
[i
].noCols
;
2419 // Now merge all the separate table infos
2420 wxDbColInf
*colInf
= new wxDbColInf
[noCols
+1];
2422 // Mark the end of the array
2423 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
2424 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
2425 colInf
[noCols
].sqlDataType
= 0;
2430 for (i
= 0 ; i
< tbl
; i
++)
2432 for (j
= 0 ; j
< TableColumns
[i
].noCols
; j
++)
2434 colInf
[offset
++] = TableColumns
[i
].colInf
[j
];
2438 delete [] TableColumns
;
2441 } // wxDb::GetColumns() -- NEW
2444 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, int *numCols
, const wxChar
*userID
)
2446 // Same as the above GetColumns() function except this one gets columns
2447 // only for a single table, and if 'numCols' is not NULL, the number of
2448 // columns stored in the returned wxDbColInf is set in '*numCols'
2450 // userID is evaluated in the following manner:
2451 // userID == NULL ... UserID is ignored
2452 // userID == "" ... UserID set equal to 'this->uid'
2453 // userID != "" ... UserID set equal to 'userID'
2455 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2456 // by this function. This function should use its own wxDb instance
2457 // to avoid undesired unbinding of columns.
2461 wxDbColInf
*colInf
= 0;
2469 convertUserID(userID
,UserID
);
2471 // Pass 1 - Determine how many columns there are.
2472 // Pass 2 - Allocate the wxDbColInf array and fill in
2473 // the array with the column information.
2475 for (pass
= 1; pass
<= 2; pass
++)
2479 if (noCols
== 0) // Probably a bogus table name(s)
2481 // Allocate n wxDbColInf objects to hold the column information
2482 colInf
= new wxDbColInf
[noCols
+1];
2485 // Mark the end of the array
2486 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
2487 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
2488 colInf
[noCols
].sqlDataType
= 0;
2491 TableName
= tableName
;
2492 // Oracle and Interbase table names are uppercase only, so force
2493 // the name to uppercase just in case programmer forgot to do this
2494 if ((Dbms() == dbmsORACLE
) ||
2495 (Dbms() == dbmsINTERBASE
))
2496 TableName
= TableName
.Upper();
2498 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2500 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2501 // use the call below that leaves out the user name
2502 if (!UserID
.IsEmpty() &&
2503 Dbms() != dbmsMY_SQL
&&
2504 Dbms() != dbmsACCESS
&&
2505 Dbms() != dbmsMS_SQL_SERVER
)
2507 retcode
= SQLColumns(hstmt
,
2508 NULL
, 0, // All qualifiers
2509 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2510 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2511 NULL
, 0); // All columns
2515 retcode
= SQLColumns(hstmt
,
2516 NULL
, 0, // All qualifiers
2518 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2519 NULL
, 0); // All columns
2521 if (retcode
!= SQL_SUCCESS
)
2522 { // Error occured, abort
2523 DispAllErrors(henv
, hdbc
, hstmt
);
2526 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2532 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2534 if (pass
== 1) // First pass, just add up the number of columns
2536 else // Pass 2; Fill in the array of structures
2538 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2540 // NOTE: Only the ODBC 1.x fields are retrieved
2541 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2542 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2543 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2544 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2545 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2546 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2547 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2548 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2549 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2550 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2551 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2552 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2553 // Start Values for Primary/Foriegn Key (=No)
2554 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2555 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2556 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2557 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
2560 // IODBC does not return a correct columnSize, so we set
2561 // columnSize = bufferLength if no column size was returned
2562 // IODBC returns the columnSize in bufferLength.. (bug)
2563 if (colInf
[colNo
].columnSize
< 1)
2565 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2569 // Determine the wxDb data type that is used to represent the native data type of this data source
2570 colInf
[colNo
].dbDataType
= 0;
2571 // Get the intern datatype
2572 switch (colInf
[colNo
].sqlDataType
)
2576 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2582 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2589 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2592 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2597 errMsg
.Printf(wxT("SQL Data type %d currently not supported by wxWindows"), colInf
[colNo
].sqlDataType
);
2598 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
2605 if (retcode
!= SQL_NO_DATA_FOUND
)
2606 { // Error occured, abort
2607 DispAllErrors(henv
, hdbc
, hstmt
);
2610 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2617 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2619 // Store Primary and Foreign Keys
2620 GetKeyFields(tableName
,colInf
,noCols
);
2622 ///////////////////////////////////////////////////////////////////////////
2623 // Now sort the the columns in order to make them appear in the right order
2624 ///////////////////////////////////////////////////////////////////////////
2626 // Build a generic SELECT statement which returns 0 rows
2629 Stmt
.Printf(wxT("select * from %s where 0=1"), tableName
);
2632 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) Stmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
2634 DispAllErrors(henv
, hdbc
, hstmt
);
2638 // Get the number of result columns
2639 if (SQLNumResultCols (hstmt
, &noCols
) != SQL_SUCCESS
)
2641 DispAllErrors(henv
, hdbc
, hstmt
);
2645 if (noCols
== 0) // Probably a bogus table name
2654 for (colNum
= 0; colNum
< noCols
; colNum
++)
2656 if (SQLColAttributes(hstmt
,colNum
+1, SQL_COLUMN_NAME
,
2658 &Sword
, &Sdword
) != SQL_SUCCESS
)
2660 DispAllErrors(henv
, hdbc
, hstmt
);
2664 wxString Name1
= name
;
2665 Name1
= Name1
.Upper();
2667 // Where is this name in the array ?
2668 for (i
= colNum
; i
< noCols
; i
++)
2670 wxString Name2
= colInf
[i
].colName
;
2671 Name2
= Name2
.Upper();
2674 if (colNum
!= i
) // swap to sort
2676 wxDbColInf tmpColInf
= colInf
[colNum
];
2677 colInf
[colNum
] = colInf
[i
];
2678 colInf
[i
] = tmpColInf
;
2684 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2686 ///////////////////////////////////////////////////////////////////////////
2688 ///////////////////////////////////////////////////////////////////////////
2694 } // wxDb::GetColumns()
2697 #endif // #else OLD_GETCOLUMNS
2700 /********** wxDb::GetColumnCount() **********/
2701 int wxDb::GetColumnCount(const wxString
&tableName
, const wxChar
*userID
)
2703 * Returns a count of how many columns are in a table.
2704 * If an error occurs in computing the number of columns
2705 * this function will return a -1 for the count
2707 * userID is evaluated in the following manner:
2708 * userID == NULL ... UserID is ignored
2709 * userID == "" ... UserID set equal to 'this->uid'
2710 * userID != "" ... UserID set equal to 'userID'
2712 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2713 * by this function. This function should use its own wxDb instance
2714 * to avoid undesired unbinding of columns.
2724 convertUserID(userID
,UserID
);
2726 TableName
= tableName
;
2727 // Oracle and Interbase table names are uppercase only, so force
2728 // the name to uppercase just in case programmer forgot to do this
2729 if ((Dbms() == dbmsORACLE
) ||
2730 (Dbms() == dbmsINTERBASE
))
2731 TableName
= TableName
.Upper();
2733 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2735 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2736 // use the call below that leaves out the user name
2737 if (!UserID
.IsEmpty() &&
2738 Dbms() != dbmsMY_SQL
&&
2739 Dbms() != dbmsACCESS
&&
2740 Dbms() != dbmsMS_SQL_SERVER
)
2742 retcode
= SQLColumns(hstmt
,
2743 NULL
, 0, // All qualifiers
2744 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2745 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2746 NULL
, 0); // All columns
2750 retcode
= SQLColumns(hstmt
,
2751 NULL
, 0, // All qualifiers
2753 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2754 NULL
, 0); // All columns
2756 if (retcode
!= SQL_SUCCESS
)
2757 { // Error occured, abort
2758 DispAllErrors(henv
, hdbc
, hstmt
);
2759 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2763 // Count the columns
2764 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2767 if (retcode
!= SQL_NO_DATA_FOUND
)
2768 { // Error occured, abort
2769 DispAllErrors(henv
, hdbc
, hstmt
);
2770 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2774 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2777 } // wxDb::GetColumnCount()
2780 /********** wxDb::GetCatalog() *******/
2781 wxDbInf
*wxDb::GetCatalog(const wxChar
*userID
)
2783 * ---------------------------------------------------------------------
2784 * -- 19991203 : mj10777 : Create ------
2785 * -- : Creates a wxDbInf with Tables / Cols Array ------
2786 * -- : uses SQLTables and fills pTableInf; ------
2787 * -- : pColInf is set to NULL and numCols to 0; ------
2788 * -- : returns pDbInf (wxDbInf) ------
2789 * -- - if unsuccesfull (pDbInf == NULL) ------
2790 * -- : pColInf can be filled with GetColumns(..); ------
2791 * -- : numCols can be filled with GetColumnCount(..); ------
2792 * ---------------------------------------------------------------------
2794 * userID is evaluated in the following manner:
2795 * userID == NULL ... UserID is ignored
2796 * userID == "" ... UserID set equal to 'this->uid'
2797 * userID != "" ... UserID set equal to 'userID'
2799 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2800 * by this function. This function should use its own wxDb instance
2801 * to avoid undesired unbinding of columns.
2804 wxDbInf
*pDbInf
= NULL
; // Array of catalog entries
2805 int noTab
= 0; // Counter while filling table entries
2809 wxString tblNameSave
;
2812 convertUserID(userID
,UserID
);
2814 //-------------------------------------------------------------
2815 pDbInf
= new wxDbInf
; // Create the Database Array
2816 //-------------------------------------------------------------
2817 // Table Information
2818 // Pass 1 - Determine how many Tables there are.
2819 // Pass 2 - Create the Table array and fill it
2820 // - Create the Cols array = NULL
2821 //-------------------------------------------------------------
2823 for (pass
= 1; pass
<= 2; pass
++)
2825 SQLFreeStmt(hstmt
, SQL_CLOSE
); // Close if Open
2826 tblNameSave
.Empty();
2828 if (!UserID
.IsEmpty() &&
2829 Dbms() != dbmsMY_SQL
&&
2830 Dbms() != dbmsACCESS
&&
2831 Dbms() != dbmsMS_SQL_SERVER
)
2833 retcode
= SQLTables(hstmt
,
2834 NULL
, 0, // All qualifiers
2835 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
2836 NULL
, 0, // All tables
2837 NULL
, 0); // All columns
2841 retcode
= SQLTables(hstmt
,
2842 NULL
, 0, // All qualifiers
2843 NULL
, 0, // User specified
2844 NULL
, 0, // All tables
2845 NULL
, 0); // All columns
2848 if (retcode
!= SQL_SUCCESS
)
2850 DispAllErrors(henv
, hdbc
, hstmt
);
2852 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2856 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
) // Table Information
2858 if (pass
== 1) // First pass, just count the Tables
2860 if (pDbInf
->numTables
== 0)
2862 GetData( 1, SQL_C_CHAR
, (UCHAR
*) pDbInf
->catalog
, 128+1, &cb
);
2863 GetData( 2, SQL_C_CHAR
, (UCHAR
*) pDbInf
->schema
, 128+1, &cb
);
2865 pDbInf
->numTables
++; // Counter for Tables
2867 if (pass
== 2) // Create and fill the Table entries
2869 if (pDbInf
->pTableInf
== NULL
) // Has the Table Array been created
2870 { // no, then create the Array
2871 pDbInf
->pTableInf
= new wxDbTableInf
[pDbInf
->numTables
];
2873 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
2875 GetData( 3, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2876 GetData( 4, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableType
, 30+1, &cb
);
2877 GetData( 5, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableRemarks
, 254+1, &cb
);
2883 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2885 // Query how many columns are in each table
2886 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
2888 (pDbInf
->pTableInf
+noTab
)->numCols
= GetColumnCount((pDbInf
->pTableInf
+noTab
)->tableName
,UserID
);
2893 } // wxDb::GetCatalog()
2896 /********** wxDb::Catalog() **********/
2897 bool wxDb::Catalog(const wxChar
*userID
, const wxString
&fileName
)
2899 * Creates the text file specified in 'filename' which will contain
2900 * a minimal data dictionary of all tables accessible by the user specified
2903 * userID is evaluated in the following manner:
2904 * userID == NULL ... UserID is ignored
2905 * userID == "" ... UserID set equal to 'this->uid'
2906 * userID != "" ... UserID set equal to 'userID'
2908 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2909 * by this function. This function should use its own wxDb instance
2910 * to avoid undesired unbinding of columns.
2913 wxASSERT(fileName
.Length());
2917 wxChar tblName
[DB_MAX_TABLE_NAME_LEN
+1];
2918 wxString tblNameSave
;
2919 wxChar colName
[DB_MAX_COLUMN_NAME_LEN
+1];
2921 wxChar typeName
[30+1];
2922 SWORD precision
, length
;
2924 FILE *fp
= fopen(fileName
.c_str(),wxT("wt"));
2928 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2931 convertUserID(userID
,UserID
);
2933 if (!UserID
.IsEmpty() &&
2934 Dbms() != dbmsMY_SQL
&&
2935 Dbms() != dbmsACCESS
&&
2936 Dbms() != dbmsMS_SQL_SERVER
)
2938 retcode
= SQLColumns(hstmt
,
2939 NULL
, 0, // All qualifiers
2940 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
2941 NULL
, 0, // All tables
2942 NULL
, 0); // All columns
2946 retcode
= SQLColumns(hstmt
,
2947 NULL
, 0, // All qualifiers
2948 NULL
, 0, // User specified
2949 NULL
, 0, // All tables
2950 NULL
, 0); // All columns
2952 if (retcode
!= SQL_SUCCESS
)
2954 DispAllErrors(henv
, hdbc
, hstmt
);
2960 tblNameSave
.Empty();
2963 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2965 if (wxStrcmp(tblName
, tblNameSave
.c_str()))
2968 fputs(wxT("\n"), fp
);
2969 fputs(wxT("================================ "), fp
);
2970 fputs(wxT("================================ "), fp
);
2971 fputs(wxT("===================== "), fp
);
2972 fputs(wxT("========= "), fp
);
2973 fputs(wxT("=========\n"), fp
);
2974 outStr
.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
2975 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
2976 fputs(outStr
.c_str(), fp
);
2977 fputs(wxT("================================ "), fp
);
2978 fputs(wxT("================================ "), fp
);
2979 fputs(wxT("===================== "), fp
);
2980 fputs(wxT("========= "), fp
);
2981 fputs(wxT("=========\n"), fp
);
2982 tblNameSave
= tblName
;
2985 GetData(3,SQL_C_CHAR
, (UCHAR
*)tblName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2986 GetData(4,SQL_C_CHAR
, (UCHAR
*)colName
, DB_MAX_COLUMN_NAME_LEN
+1,&cb
);
2987 GetData(5,SQL_C_SSHORT
,(UCHAR
*)&sqlDataType
,0, &cb
);
2988 GetData(6,SQL_C_CHAR
, (UCHAR
*)typeName
, sizeof(typeName
), &cb
);
2989 GetData(7,SQL_C_SSHORT
,(UCHAR
*)&precision
, 0, &cb
);
2990 GetData(8,SQL_C_SSHORT
,(UCHAR
*)&length
, 0, &cb
);
2992 outStr
.Printf(wxT("%-32s %-32s (%04d)%-15s %9d %9d\n"),
2993 tblName
, colName
, sqlDataType
, typeName
, precision
, length
);
2994 if (fputs(outStr
.c_str(), fp
) == EOF
)
2996 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3003 if (retcode
!= SQL_NO_DATA_FOUND
)
3004 DispAllErrors(henv
, hdbc
, hstmt
);
3006 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3009 return(retcode
== SQL_NO_DATA_FOUND
);
3011 } // wxDb::Catalog()
3014 bool wxDb::TableExists(const wxString
&tableName
, const wxChar
*userID
, const wxString
&tablePath
)
3016 * Table name can refer to a table, view, alias or synonym. Returns true
3017 * if the object exists in the database. This function does not indicate
3018 * whether or not the user has privleges to query or perform other functions
3021 * userID is evaluated in the following manner:
3022 * userID == NULL ... UserID is ignored
3023 * userID == "" ... UserID set equal to 'this->uid'
3024 * userID != "" ... UserID set equal to 'userID'
3027 wxASSERT(tableName
.Length());
3031 if (Dbms() == dbmsDBASE
)
3034 if (tablePath
.Length())
3035 dbName
.Printf(wxT("%s/%s.dbf"), tablePath
.c_str(), tableName
.c_str());
3037 dbName
.Printf(wxT("%s.dbf"), tableName
.c_str());
3040 exists
= wxFileExists(dbName
);
3045 convertUserID(userID
,UserID
);
3047 TableName
= tableName
;
3048 // Oracle and Interbase table names are uppercase only, so force
3049 // the name to uppercase just in case programmer forgot to do this
3050 if ((Dbms() == dbmsORACLE
) ||
3051 (Dbms() == dbmsINTERBASE
))
3052 TableName
= TableName
.Upper();
3054 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3057 // Some databases cannot accept a user name when looking up table names,
3058 // so we use the call below that leaves out the user name
3059 if (!UserID
.IsEmpty() &&
3060 Dbms() != dbmsMY_SQL
&&
3061 Dbms() != dbmsACCESS
&&
3062 Dbms() != dbmsMS_SQL_SERVER
)
3064 retcode
= SQLTables(hstmt
,
3065 NULL
, 0, // All qualifiers
3066 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Only tables owned by this user
3067 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3068 NULL
, 0); // All table types
3072 retcode
= SQLTables(hstmt
,
3073 NULL
, 0, // All qualifiers
3074 NULL
, 0, // All owners
3075 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3076 NULL
, 0); // All table types
3078 if (retcode
!= SQL_SUCCESS
)
3079 return(DispAllErrors(henv
, hdbc
, hstmt
));
3081 retcode
= SQLFetch(hstmt
);
3082 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
3084 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3085 return(DispAllErrors(henv
, hdbc
, hstmt
));
3088 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3092 } // wxDb::TableExists()
3095 /********** wxDb::TablePrivileges() **********/
3096 bool wxDb::TablePrivileges(const wxString
&tableName
, const wxString
&priv
, const wxChar
*userID
,
3097 const wxChar
*schema
, const wxString
&tablePath
)
3099 wxASSERT(tableName
.Length());
3101 wxDbTablePrivilegeInfo result
;
3105 // We probably need to be able to dynamically set this based on
3106 // the driver type, and state.
3107 wxChar curRole
[]=wxT("public");
3112 convertUserID(userID
,UserID
);
3114 TableName
= tableName
;
3115 // Oracle and Interbase table names are uppercase only, so force
3116 // the name to uppercase just in case programmer forgot to do this
3117 if ((Dbms() == dbmsORACLE
) ||
3118 (Dbms() == dbmsINTERBASE
))
3119 TableName
= TableName
.Upper();
3121 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3125 retcode
= SQLTablePrivileges(hstmt
,
3128 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3132 retcode
= SQLTablePrivileges(hstmt
,
3134 (UCHAR FAR
*)schema
, SQL_NTS
, // Schema
3135 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3138 #ifdef DBDEBUG_CONSOLE
3139 fprintf(stderr
,wxT("SQLTablePrivileges() returned %i \n"),retcode
);
3142 if ((retcode
!= SQL_SUCCESS
) && (retcode
!= SQL_SUCCESS_WITH_INFO
))
3143 return(DispAllErrors(henv
, hdbc
, hstmt
));
3145 retcode
= SQLFetch(hstmt
);
3146 while (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
3148 if (SQLGetData(hstmt
, 1, SQL_C_CHAR
, (UCHAR
*) result
.tableQual
, sizeof(result
.tableQual
), &cbRetVal
) != SQL_SUCCESS
)
3149 return(DispAllErrors(henv
, hdbc
, hstmt
));
3151 if (SQLGetData(hstmt
, 2, SQL_C_CHAR
, (UCHAR
*) result
.tableOwner
, sizeof(result
.tableOwner
), &cbRetVal
) != SQL_SUCCESS
)
3152 return(DispAllErrors(henv
, hdbc
, hstmt
));
3154 if (SQLGetData(hstmt
, 3, SQL_C_CHAR
, (UCHAR
*) result
.tableName
, sizeof(result
.tableName
), &cbRetVal
) != SQL_SUCCESS
)
3155 return(DispAllErrors(henv
, hdbc
, hstmt
));
3157 if (SQLGetData(hstmt
, 4, SQL_C_CHAR
, (UCHAR
*) result
.grantor
, sizeof(result
.grantor
), &cbRetVal
) != SQL_SUCCESS
)
3158 return(DispAllErrors(henv
, hdbc
, hstmt
));
3160 if (SQLGetData(hstmt
, 5, SQL_C_CHAR
, (UCHAR
*) result
.grantee
, sizeof(result
.grantee
), &cbRetVal
) != SQL_SUCCESS
)
3161 return(DispAllErrors(henv
, hdbc
, hstmt
));
3163 if (SQLGetData(hstmt
, 6, SQL_C_CHAR
, (UCHAR
*) result
.privilege
, sizeof(result
.privilege
), &cbRetVal
) != SQL_SUCCESS
)
3164 return(DispAllErrors(henv
, hdbc
, hstmt
));
3166 if (SQLGetData(hstmt
, 7, SQL_C_CHAR
, (UCHAR
*) result
.grantable
, sizeof(result
.grantable
), &cbRetVal
) != SQL_SUCCESS
)
3167 return(DispAllErrors(henv
, hdbc
, hstmt
));
3169 #ifdef DBDEBUG_CONSOLE
3170 fprintf(stderr
,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
3171 result
.privilege
,result
.tableOwner
,result
.tableName
,
3172 result
.grantor
, result
.grantee
);
3175 if (UserID
.IsSameAs(result
.tableOwner
,FALSE
))
3177 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3181 if (UserID
.IsSameAs(result
.grantee
,FALSE
) &&
3182 !wxStrcmp(result
.privilege
,priv
))
3184 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3188 if (!wxStrcmp(result
.grantee
,curRole
) &&
3189 !wxStrcmp(result
.privilege
,priv
))
3191 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3195 retcode
= SQLFetch(hstmt
);
3198 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3201 } // wxDb::TablePrivileges
3204 /********** wxDb::SetSqlLogging() **********/
3205 bool wxDb::SetSqlLogging(wxDbSqlLogState state
, const wxString
&filename
, bool append
)
3207 wxASSERT(state
== sqlLogON
|| state
== sqlLogOFF
);
3208 wxASSERT(state
== sqlLogOFF
|| filename
.Length());
3210 if (state
== sqlLogON
)
3214 fpSqlLog
= fopen(filename
, (append
? wxT("at") : wxT("wt")));
3215 if (fpSqlLog
== NULL
)
3223 if (fclose(fpSqlLog
))
3229 sqlLogState
= state
;
3232 } // wxDb::SetSqlLogging()
3235 /********** wxDb::WriteSqlLog() **********/
3236 bool wxDb::WriteSqlLog(const wxString
&logMsg
)
3238 wxASSERT(logMsg
.Length());
3240 if (fpSqlLog
== 0 || sqlLogState
== sqlLogOFF
)
3243 if (fputs(wxT("\n"), fpSqlLog
) == EOF
)
3245 if (fputs(logMsg
, fpSqlLog
) == EOF
)
3247 if (fputs(wxT("\n"), fpSqlLog
) == EOF
)
3252 } // wxDb::WriteSqlLog()
3255 /********** wxDb::Dbms() **********/
3256 wxDBMS
wxDb::Dbms(void)
3258 * Be aware that not all database engines use the exact same syntax, and not
3259 * every ODBC compliant database is compliant to the same level of compliancy.
3260 * Some manufacturers support the minimum Level 1 compliancy, and others up
3261 * through Level 3. Others support subsets of features for levels above 1.
3263 * If you find an inconsistency between the wxDb class and a specific database
3264 * engine, and an identifier to this section, and special handle the database in
3265 * the area where behavior is non-conforming with the other databases.
3268 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3269 * ---------------------------------------------------
3272 * - Currently the only database supported by the class to support VIEWS
3275 * - Does not support the SQL_TIMESTAMP structure
3276 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
3277 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
3278 * is TRUE. The user must create ALL indexes from their program.
3279 * - Table names can only be 8 characters long
3280 * - Column names can only be 10 characters long
3283 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3284 * after every table name involved in the query/join if that tables matching record(s)
3286 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
3288 * SYBASE (Enterprise)
3289 * - If a column is part of the Primary Key, the column cannot be NULL
3290 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
3293 * - If a column is part of the Primary Key, the column cannot be NULL
3294 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3295 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3296 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3297 * column definition if it is not defined correctly, but it is experimental
3298 * - Does not support sub-queries in SQL statements
3301 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3302 * - Does not support sub-queries in SQL statements
3305 * - Primary keys must be declared as NOT NULL
3309 // Should only need to do this once for each new database connection
3310 // so return the value we already determined it to be to save time
3311 // and lots of string comparisons
3312 if (dbmsType
!= dbmsUNIDENTIFIED
)
3315 wxChar baseName
[25+1];
3316 wxStrncpy(baseName
,dbInf
.dbmsName
,25);
3319 // RGG 20001025 : add support for Interbase
3320 // GT : Integrated to base classes on 20001121
3321 if (!wxStricmp(dbInf
.dbmsName
,wxT("Interbase")))
3322 return((wxDBMS
)(dbmsType
= dbmsINTERBASE
));
3324 // BJO 20000428 : add support for Virtuoso
3325 if (!wxStricmp(dbInf
.dbmsName
,wxT("OpenLink Virtuoso VDBMS")))
3326 return((wxDBMS
)(dbmsType
= dbmsVIRTUOSO
));
3328 if (!wxStricmp(dbInf
.dbmsName
,wxT("Adaptive Server Anywhere")))
3329 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASA
));
3331 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3332 // connected through an OpenLink driver.
3333 // Is it also returned by Sybase Adapatitve server?
3334 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
3335 if (!wxStricmp(dbInf
.dbmsName
,wxT("SQL Server")))
3337 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
3338 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
3339 return ((wxDBMS
)(dbmsMS_SQL_SERVER
));
3341 return ((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3344 if (!wxStricmp(dbInf
.dbmsName
,wxT("Microsoft SQL Server")))
3345 return((wxDBMS
)(dbmsType
= dbmsMS_SQL_SERVER
));
3346 if (!wxStricmp(dbInf
.dbmsName
,wxT("MySQL")))
3347 return((wxDBMS
)(dbmsType
= dbmsMY_SQL
));
3348 if (!wxStricmp(dbInf
.dbmsName
,wxT("PostgreSQL"))) // v6.5.0
3349 return((wxDBMS
)(dbmsType
= dbmsPOSTGRES
));
3352 if (!wxStricmp(baseName
,wxT("Informix")))
3353 return((wxDBMS
)(dbmsType
= dbmsINFORMIX
));
3356 if (!wxStricmp(baseName
,wxT("Oracle")))
3357 return((wxDBMS
)(dbmsType
= dbmsORACLE
));
3358 if (!wxStricmp(dbInf
.dbmsName
,wxT("ACCESS")))
3359 return((wxDBMS
)(dbmsType
= dbmsACCESS
));
3360 if (!wxStricmp(dbInf
.dbmsName
,wxT("MySQL")))
3361 return((wxDBMS
)(dbmsType
= dbmsMY_SQL
));
3362 if (!wxStricmp(baseName
,wxT("Sybase")))
3363 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3366 if (!wxStricmp(baseName
,wxT("DBASE")))
3367 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3370 if (!wxStricmp(baseName
,wxT("DB2")))
3371 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3373 return((wxDBMS
)(dbmsType
= dbmsUNIDENTIFIED
));
3378 bool wxDb::ModifyColumn(const wxString
&tableName
, const wxString
&columnName
,
3379 int dataType
, ULONG columnLength
,
3380 const wxString
&optionalParam
)
3382 wxASSERT(tableName
.Length());
3383 wxASSERT(columnName
.Length());
3384 wxASSERT((dataType
== DB_DATA_TYPE_VARCHAR
&& columnLength
> 0) ||
3385 dataType
!= DB_DATA_TYPE_VARCHAR
);
3387 // Must specify a columnLength if modifying a VARCHAR type column
3388 if (dataType
== DB_DATA_TYPE_VARCHAR
&& !columnLength
)
3391 wxString dataTypeName
;
3393 wxString alterSlashModify
;
3397 case DB_DATA_TYPE_VARCHAR
:
3398 dataTypeName
= typeInfVarchar
.TypeName
;
3400 case DB_DATA_TYPE_INTEGER
:
3401 dataTypeName
= typeInfInteger
.TypeName
;
3403 case DB_DATA_TYPE_FLOAT
:
3404 dataTypeName
= typeInfFloat
.TypeName
;
3406 case DB_DATA_TYPE_DATE
:
3407 dataTypeName
= typeInfDate
.TypeName
;
3413 // Set the modify or alter syntax depending on the type of database connected to
3417 alterSlashModify
= "MODIFY";
3419 case dbmsMS_SQL_SERVER
:
3420 alterSlashModify
= "ALTER COLUMN";
3422 case dbmsUNIDENTIFIED
:
3424 case dbmsSYBASE_ASA
:
3425 case dbmsSYBASE_ASE
:
3431 alterSlashModify
= "MODIFY";
3435 // create the SQL statement
3436 sqlStmt
.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName
.c_str(), alterSlashModify
.c_str(),
3437 columnName
.c_str(), dataTypeName
.c_str());
3439 // For varchars only, append the size of the column
3440 if (dataType
== DB_DATA_TYPE_VARCHAR
)
3443 s
.Printf(wxT("(%d)"), columnLength
);
3447 // for passing things like "NOT NULL"
3448 if (optionalParam
.Length())
3450 sqlStmt
+= wxT(" ");
3451 sqlStmt
+= optionalParam
;
3454 return ExecSql(sqlStmt
);
3456 } // wxDb::ModifyColumn()
3459 /********** wxDbGetConnection() **********/
3460 wxDb WXDLLEXPORT
*wxDbGetConnection(wxDbConnectInf
*pDbConfig
, bool FwdOnlyCursors
)
3464 // Used to keep a pointer to a DB connection that matches the requested
3465 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
3466 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
3467 // rather than having to re-query the datasource to get all the values
3468 // using the wxDb::Open(Dsn,Uid,AuthStr) function
3469 wxDb
*matchingDbConnection
= NULL
;
3471 // Scan the linked list searching for an available database connection
3472 // that's already been opened but is currently not in use.
3473 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3475 // The database connection must be for the same datasource
3476 // name and must currently not be in use.
3478 (pList
->PtrDb
->FwdOnlyCursors() == FwdOnlyCursors
) &&
3479 (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
))) // Found a free connection
3481 pList
->Free
= FALSE
;
3482 return(pList
->PtrDb
);
3485 if (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
) &&
3486 !wxStrcmp(pDbConfig
->GetUserID(), pList
->Uid
) &&
3487 !wxStrcmp(pDbConfig
->GetPassword(), pList
->AuthStr
))
3488 matchingDbConnection
= pList
->PtrDb
;
3491 // No available connections. A new connection must be made and
3492 // appended to the end of the linked list.
3495 // Find the end of the list
3496 for (pList
= PtrBegDbList
; pList
->PtrNext
; pList
= pList
->PtrNext
);
3497 // Append a new list item
3498 pList
->PtrNext
= new wxDbList
;
3499 pList
->PtrNext
->PtrPrev
= pList
;
3500 pList
= pList
->PtrNext
;
3504 // Create the first node on the list
3505 pList
= PtrBegDbList
= new wxDbList
;
3509 // Initialize new node in the linked list
3511 pList
->Free
= FALSE
;
3512 pList
->Dsn
= pDbConfig
->GetDsn(); //glt - will this assignment work?
3513 pList
->Uid
= pDbConfig
->GetUserID();
3514 pList
->AuthStr
= pDbConfig
->GetPassword();
3516 pList
->PtrDb
= new wxDb(pDbConfig
->GetHenv(), FwdOnlyCursors
);
3518 bool opened
= FALSE
;
3520 if (!matchingDbConnection
)
3521 opened
= pList
->PtrDb
->Open(pDbConfig
->GetDsn(), pDbConfig
->GetUserID(), pDbConfig
->GetPassword());
3523 opened
= pList
->PtrDb
->Open(matchingDbConnection
);
3525 // Connect to the datasource
3528 pList
->PtrDb
->SetSqlLogging(SQLLOGstate
,SQLLOGfn
,TRUE
);
3529 return(pList
->PtrDb
);
3531 else // Unable to connect, destroy list item
3534 pList
->PtrPrev
->PtrNext
= 0;
3536 PtrBegDbList
= 0; // Empty list again
3537 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
3538 pList
->PtrDb
->Close(); // Close the wxDb object
3539 delete pList
->PtrDb
; // Deletes the wxDb object
3540 delete pList
; // Deletes the linked list object
3544 } // wxDbGetConnection()
3547 /********** wxDbFreeConnection() **********/
3548 bool WXDLLEXPORT
wxDbFreeConnection(wxDb
*pDb
)
3552 // Scan the linked list searching for the database connection
3553 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3555 if (pList
->PtrDb
== pDb
) // Found it, now free it!!!
3556 return (pList
->Free
= TRUE
);
3559 // Never found the database object, return failure
3562 } // wxDbFreeConnection()
3565 /********** wxDbCloseConnections() **********/
3566 void WXDLLEXPORT
wxDbCloseConnections(void)
3568 wxDbList
*pList
, *pNext
;
3570 // Traverse the linked list closing database connections and freeing memory as I go.
3571 for (pList
= PtrBegDbList
; pList
; pList
= pNext
)
3573 pNext
= pList
->PtrNext
; // Save the pointer to next
3574 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
3575 pList
->PtrDb
->Close(); // Close the wxDb object
3576 delete pList
->PtrDb
; // Deletes the wxDb object
3577 delete pList
; // Deletes the linked list object
3580 // Mark the list as empty
3583 } // wxDbCloseConnections()
3586 /********** wxDbConnectionsInUse() **********/
3587 int WXDLLEXPORT
wxDbConnectionsInUse(void)
3592 // Scan the linked list counting db connections that are currently in use
3593 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3595 if (pList
->Free
== FALSE
)
3601 } // wxDbConnectionsInUse()
3604 /********** wxDbSqlLog() **********/
3605 bool wxDbSqlLog(wxDbSqlLogState state
, const wxChar
*filename
)
3607 bool append
= FALSE
;
3610 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3612 if (!pList
->PtrDb
->SetSqlLogging(state
,filename
,append
))
3617 SQLLOGstate
= state
;
3618 SQLLOGfn
= filename
;
3626 /********** wxDbCreateDataSource() **********/
3627 int wxDbCreateDataSource(const wxString
&driverName
, const wxString
&dsn
, const wxString
&description
,
3628 bool sysDSN
, const wxString
&defDir
, wxWindow
*parent
)
3630 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3631 * Very rudimentary creation of an ODBC data source.
3633 * ODBC driver must be ODBC 3.0 compliant to use this function
3638 //!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3644 dsnLocation
= ODBC_ADD_SYS_DSN
;
3646 dsnLocation
= ODBC_ADD_DSN
;
3648 // NOTE: The decimal 2 is an invalid character in all keyword pairs
3649 // so that is why I used it, as wxString does not deal well with
3650 // embedded nulls in strings
3651 setupStr
.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn
,2,description
,2,defDir
,2);
3653 // Replace the separator from above with the '\0' seperator needed
3654 // by the SQLConfigDataSource() function
3658 k
= setupStr
.Find((wxChar
)2,TRUE
);
3659 if (k
!= wxNOT_FOUND
)
3660 setupStr
[(UINT
)k
] = wxT('\0');
3662 while (k
!= wxNOT_FOUND
);
3664 result
= SQLConfigDataSource((HWND
)parent
->GetHWND(), dsnLocation
,
3665 driverName
, setupStr
.c_str());
3667 if ((result
!= SQL_SUCCESS
) && (result
!= SQL_SUCCESS_WITH_INFO
))
3669 // check for errors caused by ConfigDSN based functions
3672 wxChar errMsg
[SQL_MAX_MESSAGE_LENGTH
];
3673 errMsg
[0] = wxT('\0');
3675 // This function is only supported in ODBC drivers v3.0 compliant and above
3676 SQLInstallerError(1,&retcode
,errMsg
,SQL_MAX_MESSAGE_LENGTH
-1,&cb
);
3679 #ifdef DBDEBUG_CONSOLE
3680 // When run in console mode, use standard out to display errors.
3681 cout
<< errMsg
<< endl
;
3682 cout
<< wxT("Press any key to continue...") << endl
;
3684 #endif // DBDEBUG_CONSOLE
3687 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
3688 #endif // __WXDEBUG__
3694 // Using iODBC/unixODBC or some other compiler which does not support the APIs
3695 // necessary to use this function, so this function is not supported
3697 wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
3700 #endif // __VISUALC__
3704 } // wxDbCreateDataSource()
3708 /********** wxDbGetDataSource() **********/
3709 bool wxDbGetDataSource(HENV henv
, wxChar
*Dsn
, SWORD DsnMax
, wxChar
*DsDesc
,
3710 SWORD DsDescMax
, UWORD direction
)
3712 * Dsn and DsDesc will contain the data source name and data source
3713 * description upon return
3718 if (SQLDataSources(henv
, direction
, (UCHAR FAR
*) Dsn
, DsnMax
, &cb1
,
3719 (UCHAR FAR
*) DsDesc
, DsDescMax
, &cb2
) == SQL_SUCCESS
)
3724 } // wxDbGetDataSource()
3727 // Change this to 0 to remove use of all deprecated functions
3728 #if wxODBC_BACKWARD_COMPATABILITY
3729 /********************************************************************
3730 ********************************************************************
3732 * The following functions are all DEPRECATED and are included for
3733 * backward compatability reasons only
3735 ********************************************************************
3736 ********************************************************************/
3737 bool SqlLog(sqlLog state
, const wxChar
*filename
)
3739 return wxDbSqlLog((enum wxDbSqlLogState
)state
, filename
);
3741 /***** DEPRECATED: use wxGetDataSource() *****/
3742 bool GetDataSource(HENV henv
, char *Dsn
, SWORD DsnMax
, char *DsDesc
, SWORD DsDescMax
,
3745 return wxDbGetDataSource(henv
, Dsn
, DsnMax
, DsDesc
, DsDescMax
, direction
);
3747 /***** DEPRECATED: use wxDbGetConnection() *****/
3748 wxDb WXDLLEXPORT
*GetDbConnection(DbStuff
*pDbStuff
, bool FwdOnlyCursors
)
3750 return wxDbGetConnection((wxDbConnectInf
*)pDbStuff
, FwdOnlyCursors
);
3752 /***** DEPRECATED: use wxDbFreeConnection() *****/
3753 bool WXDLLEXPORT
FreeDbConnection(wxDb
*pDb
)
3755 return wxDbFreeConnection(pDb
);
3757 /***** DEPRECATED: use wxDbCloseConnections() *****/
3758 void WXDLLEXPORT
CloseDbConnections(void)
3760 wxDbCloseConnections();
3762 /***** DEPRECATED: use wxDbConnectionsInUse() *****/
3763 int WXDLLEXPORT
NumberDbConnectionsInUse(void)
3765 return wxDbConnectionsInUse();