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()
263 i_Nation
= 0; // 0=EU, 1=UK, 2=International, 3=US
266 Format(1,DB_DATA_TYPE_VARCHAR
,0,0,0); // the Function that does the work
267 } // wxDbColFor::wxDbColFor()
270 wxDbColFor::~wxDbColFor()
272 } // wxDbColFor::~wxDbColFor()
275 /********** wxDbColFor::Format() **********/
276 int wxDbColFor::Format(int Nation
, int dbDataType
, SWORD sqlDataType
,
277 short columnSize
, short decimalDigits
)
279 // ----------------------------------------------------------------------------------------
280 // -- 19991224 : mj10777 : Create
281 // There is still a lot of work to do here, but it is a start
282 // It handles all the basic data-types that I have run into up to now
283 // The main work will have be with Dates and float Formatting
284 // (US 1,000.00 ; EU 1.000,00)
285 // There are wxWindow plans for locale support and the new wxDateTime. If
286 // they define some constants (wxEUROPEAN) that can be gloably used,
287 // they should be used here.
288 // ----------------------------------------------------------------------------------------
289 // There should also be a function to scan in a string to fill the variable
290 // ----------------------------------------------------------------------------------------
292 i_Nation
= Nation
; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
293 i_dbDataType
= dbDataType
;
294 i_sqlDataType
= sqlDataType
;
295 s_Field
.Printf(wxT("%s%d"),s_Amount
[1].c_str(),i_Amount
[1]); // OK for VARCHAR, INTEGER and FLOAT
297 if (i_dbDataType
== 0) // Filter unsupported dbDataTypes
299 if ((i_sqlDataType
== SQL_VARCHAR
) || (i_sqlDataType
== SQL_LONGVARCHAR
))
300 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
301 if ((i_sqlDataType
== SQL_C_DATE
) || (i_sqlDataType
== SQL_C_TIMESTAMP
))
302 i_dbDataType
= DB_DATA_TYPE_DATE
;
303 if (i_sqlDataType
== SQL_C_BIT
)
304 i_dbDataType
= DB_DATA_TYPE_INTEGER
;
305 if (i_sqlDataType
== SQL_NUMERIC
)
306 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
307 if (i_sqlDataType
== SQL_REAL
)
308 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
311 if ((i_dbDataType
== DB_DATA_TYPE_INTEGER
) && (i_sqlDataType
== SQL_C_DOUBLE
))
313 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
316 switch(i_dbDataType
) // TBD: Still a lot of proper formatting to do
318 case DB_DATA_TYPE_VARCHAR
:
321 case DB_DATA_TYPE_INTEGER
:
324 case DB_DATA_TYPE_FLOAT
:
325 if (decimalDigits
== 0)
328 tempStr
.Printf(wxT("%s%d.%d"),tempStr
.c_str(),columnSize
,decimalDigits
);
329 s_Field
.Printf(wxT("%sf"),tempStr
.c_str());
331 case DB_DATA_TYPE_DATE
:
332 if (i_Nation
== 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
334 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
336 if (i_Nation
== 1) // European DD.MM.YYYY HH:MM:SS.SSS
338 s_Field
= wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d");
340 if (i_Nation
== 2) // UK DD/MM/YYYY HH:MM:SS.SSS
342 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
344 if (i_Nation
== 3) // International YYYY-MM-DD HH:MM:SS.SSS
346 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
348 if (i_Nation
== 4) // US MM/DD/YYYY HH:MM:SS.SSS
350 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
354 s_Field
.Printf(wxT("Unknown Format(%d)-SQL(%d)"),dbDataType
,sqlDataType
); //
358 } // wxDbColFor::Format()
361 /********** wxDbColInf Constructor **********/
362 wxDbColInf::wxDbColInf()
382 } // wxDbColInf::wxDbColInf()
385 /********** wxDbColInf Destructor ********/
386 wxDbColInf::~wxDbColInf()
391 } // wxDbColInf::~wxDbColInf()
394 /********** wxDbTableInf Constructor ********/
395 wxDbTableInf::wxDbTableInf()
402 } // wxDbTableInf::wxDbTableInf()
405 /********** wxDbTableInf Constructor ********/
406 wxDbTableInf::~wxDbTableInf()
411 } // wxDbTableInf::~wxDbTableInf()
414 /********** wxDbInf Constructor *************/
421 } // wxDbInf::wxDbFor()
424 /********** wxDbInf Destructor *************/
430 } // wxDbInf::~wxDbInf()
433 /********** wxDb Constructors **********/
434 wxDb::wxDb(HENV
&aHenv
, bool FwdOnlyCursors
)
436 // Copy the HENV into the db class
438 fwdOnlyCursors
= FwdOnlyCursors
;
443 /********** wxDb::Initialize() **********/
444 void wxDb::Initialize()
446 * Private member function that sets all wxDb member variables to
447 * known values at creation of the wxDb
452 fpSqlLog
= 0; // Sql Log file pointer
453 sqlLogState
= sqlLogOFF
; // By default, logging is turned off
455 dbmsType
= dbmsUNIDENTIFIED
;
457 wxStrcpy(sqlState
,wxT(""));
458 wxStrcpy(errorMsg
,wxT(""));
459 nativeError
= cbErrorMsg
= 0;
460 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
461 wxStrcpy(errorList
[i
], wxT(""));
463 // Init typeInf structures
464 typeInfVarchar
.TypeName
.Empty();
465 typeInfVarchar
.FsqlType
= 0;
466 typeInfVarchar
.Precision
= 0;
467 typeInfVarchar
.CaseSensitive
= 0;
468 typeInfVarchar
.MaximumScale
= 0;
470 typeInfInteger
.TypeName
.Empty();
471 typeInfInteger
.FsqlType
= 0;
472 typeInfInteger
.Precision
= 0;
473 typeInfInteger
.CaseSensitive
= 0;
474 typeInfInteger
.MaximumScale
= 0;
476 typeInfFloat
.TypeName
.Empty();
477 typeInfFloat
.FsqlType
= 0;
478 typeInfFloat
.Precision
= 0;
479 typeInfFloat
.CaseSensitive
= 0;
480 typeInfFloat
.MaximumScale
= 0;
482 typeInfDate
.TypeName
.Empty();
483 typeInfDate
.FsqlType
= 0;
484 typeInfDate
.Precision
= 0;
485 typeInfDate
.CaseSensitive
= 0;
486 typeInfDate
.MaximumScale
= 0;
488 // Error reporting is turned OFF by default
491 // Allocate a data source connection handle
492 if (SQLAllocConnect(henv
, &hdbc
) != SQL_SUCCESS
)
495 // Initialize the db status flag
498 // Mark database as not open as of yet
500 } // wxDb::Initialize()
503 /********** PRIVATE! wxDb::convertUserID PRIVATE! **********/
505 // NOTE: Return value from this function MUST be copied
506 // immediately, as the value is not good after
507 // this function has left scope.
509 const wxChar
*wxDb::convertUserID(const wxChar
*userID
, wxString
&UserID
)
513 if (!wxStrlen(userID
))
521 // dBase does not use user names, and some drivers fail if you try to pass one
522 if (Dbms() == dbmsDBASE
)
525 // Oracle user names may only be in uppercase, so force
526 // the name to uppercase
527 if (Dbms() == dbmsORACLE
)
528 UserID
= UserID
.Upper();
530 return UserID
.c_str();
531 } // wxDb::convertUserID()
534 /********** wxDb::Open() **********/
535 bool wxDb::Open(const wxString
&Dsn
, const wxString
&Uid
, const wxString
&AuthStr
)
537 wxASSERT(Dsn
.Length());
544 if (!FwdOnlyCursors())
546 // Specify that the ODBC cursor library be used, if needed. This must be
547 // specified before the connection is made.
548 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
550 #ifdef DBDEBUG_CONSOLE
551 if (retcode
== SQL_SUCCESS
)
552 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
554 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
558 // Connect to the data source
559 retcode
= SQLConnect(hdbc
, (UCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
560 (UCHAR FAR
*) uid
.c_str(), SQL_NTS
,
561 (UCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
564 if (retcode == SQL_SUCCESS_WITH_INFO)
565 DispAllErrors(henv, hdbc);
566 else if (retcode != SQL_SUCCESS)
567 return(DispAllErrors(henv, hdbc));
569 if (retcode == SQL_ERROR)
570 return(DispAllErrors(henv, hdbc));
572 if ((retcode
!= SQL_SUCCESS
) &&
573 (retcode
!= SQL_SUCCESS_WITH_INFO
))
574 return(DispAllErrors(henv
, hdbc
));
577 If using Intersolv branded ODBC drivers, this is the place where you would substitute
578 your branded driver license information
580 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxT(""));
581 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxT(""));
584 // Mark database as open
587 // Allocate a statement handle for the database connection
588 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
589 return(DispAllErrors(henv
, hdbc
));
591 // Set Connection Options
592 if (!setConnectionOptions())
595 // Query the data source for inf. about itself
599 // Query the data source regarding data type information
602 // The way I determined which SQL data types to use was by calling SQLGetInfo
603 // for all of the possible SQL data types to see which ones were supported. If
604 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
605 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
606 // types I've selected below will not alway's be what we want. These are just
607 // what happened to work against an Oracle 7/Intersolv combination. The following is
608 // a complete list of the results I got back against the Oracle 7 database:
610 // SQL_BIGINT SQL_NO_DATA_FOUND
611 // SQL_BINARY SQL_NO_DATA_FOUND
612 // SQL_BIT SQL_NO_DATA_FOUND
613 // SQL_CHAR type name = 'CHAR', Precision = 255
614 // SQL_DATE SQL_NO_DATA_FOUND
615 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
616 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
617 // SQL_FLOAT SQL_NO_DATA_FOUND
618 // SQL_INTEGER SQL_NO_DATA_FOUND
619 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
620 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
621 // SQL_NUMERIC SQL_NO_DATA_FOUND
622 // SQL_REAL SQL_NO_DATA_FOUND
623 // SQL_SMALLINT SQL_NO_DATA_FOUND
624 // SQL_TIME SQL_NO_DATA_FOUND
625 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
626 // SQL_VARBINARY type name = 'RAW', Precision = 255
627 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
628 // =====================================================================
629 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
631 // SQL_VARCHAR type name = 'TEXT', Precision = 255
632 // SQL_TIMESTAMP type name = 'DATETIME'
633 // SQL_DECIMAL SQL_NO_DATA_FOUND
634 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
635 // SQL_FLOAT SQL_NO_DATA_FOUND
636 // SQL_REAL type name = 'SINGLE', Precision = 7
637 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
638 // SQL_INTEGER type name = 'LONG', Precision = 10
640 // VARCHAR = Variable length character string
641 if (!getDataTypeInfo(SQL_VARCHAR
, typeInfVarchar
))
642 if (!getDataTypeInfo(SQL_CHAR
, typeInfVarchar
))
645 typeInfVarchar
.FsqlType
= SQL_CHAR
;
647 typeInfVarchar
.FsqlType
= SQL_VARCHAR
;
650 if (!getDataTypeInfo(SQL_DOUBLE
,typeInfFloat
))
652 if (!getDataTypeInfo(SQL_REAL
,typeInfFloat
))
653 if (!getDataTypeInfo(SQL_FLOAT
,typeInfFloat
))
654 if (!getDataTypeInfo(SQL_DECIMAL
,typeInfFloat
))
655 if (!getDataTypeInfo(SQL_NUMERIC
,typeInfFloat
))
658 typeInfFloat
.FsqlType
= SQL_NUMERIC
;
660 typeInfFloat
.FsqlType
= SQL_DECIMAL
;
662 typeInfFloat
.FsqlType
= SQL_FLOAT
;
664 typeInfFloat
.FsqlType
= SQL_REAL
;
666 typeInfFloat
.FsqlType
= SQL_DOUBLE
;
669 if (!getDataTypeInfo(SQL_INTEGER
, typeInfInteger
))
671 // If SQL_INTEGER is not supported, use the floating point
672 // data type to store integers as well as floats
673 if (!getDataTypeInfo(typeInfFloat
.FsqlType
, typeInfInteger
))
676 typeInfInteger
.FsqlType
= typeInfFloat
.FsqlType
;
679 typeInfInteger
.FsqlType
= SQL_INTEGER
;
682 if (Dbms() != dbmsDBASE
)
684 if (! getDataTypeInfo(SQL_TIMESTAMP
,typeInfDate
))
687 typeInfDate
.FsqlType
= SQL_TIMESTAMP
;
691 if (!getDataTypeInfo(SQL_DATE
,typeInfDate
))
694 typeInfDate
.FsqlType
= SQL_DATE
;
697 #ifdef DBDEBUG_CONSOLE
698 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
699 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
700 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
701 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
705 // Completed Successfully
711 bool wxDb::Open(wxDb
*copyDb
)
713 dsn
= copyDb
->GetDatasourceName();
714 uid
= copyDb
->GetUsername();
715 authStr
= copyDb
->GetPassword();
719 if (!FwdOnlyCursors())
721 // Specify that the ODBC cursor library be used, if needed. This must be
722 // specified before the connection is made.
723 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
725 #ifdef DBDEBUG_CONSOLE
726 if (retcode
== SQL_SUCCESS
)
727 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
729 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
733 // Connect to the data source
734 retcode
= SQLConnect(hdbc
, (UCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
735 (UCHAR FAR
*) uid
.c_str(), SQL_NTS
,
736 (UCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
738 if (retcode
== SQL_ERROR
)
739 return(DispAllErrors(henv
, hdbc
));
742 If using Intersolv branded ODBC drivers, this is the place where you would substitute
743 your branded driver license information
745 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxT(""));
746 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxT(""));
749 // Mark database as open
752 // Allocate a statement handle for the database connection
753 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
754 return(DispAllErrors(henv
, hdbc
));
756 // Set Connection Options
757 if (!setConnectionOptions())
760 // Instead of Querying the data source for info about itself, it can just be copied
761 // from the wxDb instance that was passed in (copyDb).
762 wxStrcpy(dbInf
.serverName
,copyDb
->dbInf
.serverName
);
763 wxStrcpy(dbInf
.databaseName
,copyDb
->dbInf
.databaseName
);
764 wxStrcpy(dbInf
.dbmsName
,copyDb
->dbInf
.dbmsName
);
765 wxStrcpy(dbInf
.dbmsVer
,copyDb
->dbInf
.dbmsVer
);
766 dbInf
.maxConnections
= copyDb
->dbInf
.maxConnections
;
767 dbInf
.maxStmts
= copyDb
->dbInf
.maxStmts
;
768 wxStrcpy(dbInf
.driverName
,copyDb
->dbInf
.driverName
);
769 wxStrcpy(dbInf
.odbcVer
,copyDb
->dbInf
.odbcVer
);
770 wxStrcpy(dbInf
.drvMgrOdbcVer
,copyDb
->dbInf
.drvMgrOdbcVer
);
771 wxStrcpy(dbInf
.driverVer
,copyDb
->dbInf
.driverVer
);
772 dbInf
.apiConfLvl
= copyDb
->dbInf
.apiConfLvl
;
773 dbInf
.cliConfLvl
= copyDb
->dbInf
.cliConfLvl
;
774 dbInf
.sqlConfLvl
= copyDb
->dbInf
.sqlConfLvl
;
775 wxStrcpy(dbInf
.outerJoins
,copyDb
->dbInf
.outerJoins
);
776 wxStrcpy(dbInf
.procedureSupport
,copyDb
->dbInf
.procedureSupport
);
777 wxStrcpy(dbInf
.accessibleTables
,copyDb
->dbInf
.accessibleTables
);
778 dbInf
.cursorCommitBehavior
= copyDb
->dbInf
.cursorCommitBehavior
;
779 dbInf
.cursorRollbackBehavior
= copyDb
->dbInf
.cursorRollbackBehavior
;
780 dbInf
.supportNotNullClause
= copyDb
->dbInf
.supportNotNullClause
;
781 wxStrcpy(dbInf
.supportIEF
,copyDb
->dbInf
.supportIEF
);
782 dbInf
.txnIsolation
= copyDb
->dbInf
.txnIsolation
;
783 dbInf
.txnIsolationOptions
= copyDb
->dbInf
.txnIsolationOptions
;
784 dbInf
.fetchDirections
= copyDb
->dbInf
.fetchDirections
;
785 dbInf
.lockTypes
= copyDb
->dbInf
.lockTypes
;
786 dbInf
.posOperations
= copyDb
->dbInf
.posOperations
;
787 dbInf
.posStmts
= copyDb
->dbInf
.posStmts
;
788 dbInf
.scrollConcurrency
= copyDb
->dbInf
.scrollConcurrency
;
789 dbInf
.scrollOptions
= copyDb
->dbInf
.scrollOptions
;
790 dbInf
.staticSensitivity
= copyDb
->dbInf
.staticSensitivity
;
791 dbInf
.txnCapable
= copyDb
->dbInf
.txnCapable
;
792 dbInf
.loginTimeout
= copyDb
->dbInf
.loginTimeout
;
794 // VARCHAR = Variable length character string
795 typeInfVarchar
.FsqlType
= copyDb
->typeInfVarchar
.FsqlType
;
796 typeInfVarchar
.TypeName
= copyDb
->typeInfVarchar
.TypeName
;
797 typeInfVarchar
.Precision
= copyDb
->typeInfVarchar
.Precision
;
798 typeInfVarchar
.CaseSensitive
= copyDb
->typeInfVarchar
.CaseSensitive
;
799 typeInfVarchar
.MaximumScale
= copyDb
->typeInfVarchar
.MaximumScale
;
802 typeInfFloat
.FsqlType
= copyDb
->typeInfFloat
.FsqlType
;
803 typeInfFloat
.TypeName
= copyDb
->typeInfFloat
.TypeName
;
804 typeInfFloat
.Precision
= copyDb
->typeInfFloat
.Precision
;
805 typeInfFloat
.CaseSensitive
= copyDb
->typeInfFloat
.CaseSensitive
;
806 typeInfFloat
.MaximumScale
= copyDb
->typeInfFloat
.MaximumScale
;
809 typeInfInteger
.FsqlType
= copyDb
->typeInfInteger
.FsqlType
;
810 typeInfInteger
.TypeName
= copyDb
->typeInfInteger
.TypeName
;
811 typeInfInteger
.Precision
= copyDb
->typeInfInteger
.Precision
;
812 typeInfInteger
.CaseSensitive
= copyDb
->typeInfInteger
.CaseSensitive
;
813 typeInfInteger
.MaximumScale
= copyDb
->typeInfInteger
.MaximumScale
;
816 typeInfDate
.FsqlType
= copyDb
->typeInfDate
.FsqlType
;
817 typeInfDate
.TypeName
= copyDb
->typeInfDate
.TypeName
;
818 typeInfDate
.Precision
= copyDb
->typeInfDate
.Precision
;
819 typeInfDate
.CaseSensitive
= copyDb
->typeInfDate
.CaseSensitive
;
820 typeInfDate
.MaximumScale
= copyDb
->typeInfDate
.MaximumScale
;
822 #ifdef DBDEBUG_CONSOLE
823 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
824 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
825 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
826 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
830 // Completed Successfully
835 /********** wxDb::setConnectionOptions() **********/
836 bool wxDb::setConnectionOptions(void)
838 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
843 // I need to get the DBMS name here, because some of the connection options
844 // are database specific and need to call the Dbms() function.
845 if (SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, 40, &cb
) != SQL_SUCCESS
)
846 return(DispAllErrors(henv
, hdbc
));
848 SQLSetConnectOption(hdbc
, SQL_AUTOCOMMIT
, SQL_AUTOCOMMIT_OFF
);
849 SQLSetConnectOption(hdbc
, SQL_OPT_TRACE
, SQL_OPT_TRACE_OFF
);
850 // SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads
852 // By default, MS Sql Server closes cursors on commit and rollback. The following
853 // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors
854 // after a transaction. This is a driver specific option and is not part of the
855 // ODBC standard. Note: this behavior is specific to the ODBC interface to SQL Server.
856 // The database settings don't have any effect one way or the other.
857 if (Dbms() == dbmsMS_SQL_SERVER
)
859 const long SQL_PRESERVE_CURSORS
= 1204L;
860 const long SQL_PC_ON
= 1L;
861 SQLSetConnectOption(hdbc
, SQL_PRESERVE_CURSORS
, SQL_PC_ON
);
864 // Display the connection options to verify them
865 #ifdef DBDEBUG_CONSOLE
867 cout
<< wxT("****** CONNECTION OPTIONS ******") << endl
;
869 if (SQLGetConnectOption(hdbc
, SQL_AUTOCOMMIT
, &l
) != SQL_SUCCESS
)
870 return(DispAllErrors(henv
, hdbc
));
871 cout
<< wxT("AUTOCOMMIT: ") << (l
== SQL_AUTOCOMMIT_OFF
? "OFF" : "ON") << endl
;
873 if (SQLGetConnectOption(hdbc
, SQL_ODBC_CURSORS
, &l
) != SQL_SUCCESS
)
874 return(DispAllErrors(henv
, hdbc
));
875 cout
<< wxT("ODBC CURSORS: ");
878 case(SQL_CUR_USE_IF_NEEDED
):
879 cout
<< wxT("SQL_CUR_USE_IF_NEEDED");
881 case(SQL_CUR_USE_ODBC
):
882 cout
<< wxT("SQL_CUR_USE_ODBC");
884 case(SQL_CUR_USE_DRIVER
):
885 cout
<< wxT("SQL_CUR_USE_DRIVER");
890 if (SQLGetConnectOption(hdbc
, SQL_OPT_TRACE
, &l
) != SQL_SUCCESS
)
891 return(DispAllErrors(henv
, hdbc
));
892 cout
<< wxT("TRACING: ") << (l
== SQL_OPT_TRACE_OFF
? wxT("OFF") : wxT("ON")) << endl
;
897 // Completed Successfully
900 } // wxDb::setConnectionOptions()
903 /********** wxDb::getDbInfo() **********/
904 bool wxDb::getDbInfo(void)
909 if (SQLGetInfo(hdbc
, SQL_SERVER_NAME
, (UCHAR
*) dbInf
.serverName
, 80, &cb
) != SQL_SUCCESS
)
910 return(DispAllErrors(henv
, hdbc
));
912 if (SQLGetInfo(hdbc
, SQL_DATABASE_NAME
, (UCHAR
*) dbInf
.databaseName
, 128, &cb
) != SQL_SUCCESS
)
913 return(DispAllErrors(henv
, hdbc
));
915 if (SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, 40, &cb
) != SQL_SUCCESS
)
916 return(DispAllErrors(henv
, hdbc
));
919 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
920 // causing database connectivity to fail in some cases.
921 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_VER
, (UCHAR
*) dbInf
.dbmsVer
, 64, &cb
);
923 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
924 return(DispAllErrors(henv
, hdbc
));
926 if (SQLGetInfo(hdbc
, SQL_ACTIVE_CONNECTIONS
, (UCHAR
*) &dbInf
.maxConnections
, sizeof(dbInf
.maxConnections
), &cb
) != SQL_SUCCESS
)
927 return(DispAllErrors(henv
, hdbc
));
929 if (SQLGetInfo(hdbc
, SQL_ACTIVE_STATEMENTS
, (UCHAR
*) &dbInf
.maxStmts
, sizeof(dbInf
.maxStmts
), &cb
) != SQL_SUCCESS
)
930 return(DispAllErrors(henv
, hdbc
));
932 if (SQLGetInfo(hdbc
, SQL_DRIVER_NAME
, (UCHAR
*) dbInf
.driverName
, 40, &cb
) != SQL_SUCCESS
)
933 return(DispAllErrors(henv
, hdbc
));
935 if (SQLGetInfo(hdbc
, SQL_DRIVER_ODBC_VER
, (UCHAR
*) dbInf
.odbcVer
, 60, &cb
) == SQL_ERROR
)
936 return(DispAllErrors(henv
, hdbc
));
938 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_VER
, (UCHAR
*) dbInf
.drvMgrOdbcVer
, 60, &cb
);
939 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
940 return(DispAllErrors(henv
, hdbc
));
942 if (SQLGetInfo(hdbc
, SQL_DRIVER_VER
, (UCHAR
*) dbInf
.driverVer
, 60, &cb
) == SQL_ERROR
)
943 return(DispAllErrors(henv
, hdbc
));
945 if (SQLGetInfo(hdbc
, SQL_ODBC_API_CONFORMANCE
, (UCHAR
*) &dbInf
.apiConfLvl
, sizeof(dbInf
.apiConfLvl
), &cb
) != SQL_SUCCESS
)
946 return(DispAllErrors(henv
, hdbc
));
948 if (SQLGetInfo(hdbc
, SQL_ODBC_SAG_CLI_CONFORMANCE
, (UCHAR
*) &dbInf
.cliConfLvl
, sizeof(dbInf
.cliConfLvl
), &cb
) != SQL_SUCCESS
)
949 // return(DispAllErrors(henv, hdbc));
951 // Not all drivers support this call - Nick Gorham(unixODBC)
952 dbInf
.cliConfLvl
= 0;
955 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_CONFORMANCE
, (UCHAR
*) &dbInf
.sqlConfLvl
, sizeof(dbInf
.sqlConfLvl
), &cb
) != SQL_SUCCESS
)
956 return(DispAllErrors(henv
, hdbc
));
958 if (SQLGetInfo(hdbc
, SQL_OUTER_JOINS
, (UCHAR
*) dbInf
.outerJoins
, 2, &cb
) != SQL_SUCCESS
)
959 return(DispAllErrors(henv
, hdbc
));
961 if (SQLGetInfo(hdbc
, SQL_PROCEDURES
, (UCHAR
*) dbInf
.procedureSupport
, 2, &cb
) != SQL_SUCCESS
)
962 return(DispAllErrors(henv
, hdbc
));
964 if (SQLGetInfo(hdbc
, SQL_ACCESSIBLE_TABLES
, (UCHAR
*) dbInf
.accessibleTables
, 2, &cb
) != SQL_SUCCESS
)
965 return(DispAllErrors(henv
, hdbc
));
967 if (SQLGetInfo(hdbc
, SQL_CURSOR_COMMIT_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorCommitBehavior
, sizeof(dbInf
.cursorCommitBehavior
), &cb
) != SQL_SUCCESS
)
968 return(DispAllErrors(henv
, hdbc
));
970 if (SQLGetInfo(hdbc
, SQL_CURSOR_ROLLBACK_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorRollbackBehavior
, sizeof(dbInf
.cursorRollbackBehavior
), &cb
) != SQL_SUCCESS
)
971 return(DispAllErrors(henv
, hdbc
));
973 if (SQLGetInfo(hdbc
, SQL_NON_NULLABLE_COLUMNS
, (UCHAR
*) &dbInf
.supportNotNullClause
, sizeof(dbInf
.supportNotNullClause
), &cb
) != SQL_SUCCESS
)
974 return(DispAllErrors(henv
, hdbc
));
976 if (SQLGetInfo(hdbc
, SQL_ODBC_SQL_OPT_IEF
, (UCHAR
*) dbInf
.supportIEF
, 2, &cb
) != SQL_SUCCESS
)
977 return(DispAllErrors(henv
, hdbc
));
979 if (SQLGetInfo(hdbc
, SQL_DEFAULT_TXN_ISOLATION
, (UCHAR
*) &dbInf
.txnIsolation
, sizeof(dbInf
.txnIsolation
), &cb
) != SQL_SUCCESS
)
980 return(DispAllErrors(henv
, hdbc
));
982 if (SQLGetInfo(hdbc
, SQL_TXN_ISOLATION_OPTION
, (UCHAR
*) &dbInf
.txnIsolationOptions
, sizeof(dbInf
.txnIsolationOptions
), &cb
) != SQL_SUCCESS
)
983 return(DispAllErrors(henv
, hdbc
));
985 if (SQLGetInfo(hdbc
, SQL_FETCH_DIRECTION
, (UCHAR
*) &dbInf
.fetchDirections
, sizeof(dbInf
.fetchDirections
), &cb
) != SQL_SUCCESS
)
986 return(DispAllErrors(henv
, hdbc
));
988 if (SQLGetInfo(hdbc
, SQL_LOCK_TYPES
, (UCHAR
*) &dbInf
.lockTypes
, sizeof(dbInf
.lockTypes
), &cb
) != SQL_SUCCESS
)
989 return(DispAllErrors(henv
, hdbc
));
991 if (SQLGetInfo(hdbc
, SQL_POS_OPERATIONS
, (UCHAR
*) &dbInf
.posOperations
, sizeof(dbInf
.posOperations
), &cb
) != SQL_SUCCESS
)
992 return(DispAllErrors(henv
, hdbc
));
994 if (SQLGetInfo(hdbc
, SQL_POSITIONED_STATEMENTS
, (UCHAR
*) &dbInf
.posStmts
, sizeof(dbInf
.posStmts
), &cb
) != SQL_SUCCESS
)
995 return(DispAllErrors(henv
, hdbc
));
997 if (SQLGetInfo(hdbc
, SQL_SCROLL_CONCURRENCY
, (UCHAR
*) &dbInf
.scrollConcurrency
, sizeof(dbInf
.scrollConcurrency
), &cb
) != SQL_SUCCESS
)
998 return(DispAllErrors(henv
, hdbc
));
1000 if (SQLGetInfo(hdbc
, SQL_SCROLL_OPTIONS
, (UCHAR
*) &dbInf
.scrollOptions
, sizeof(dbInf
.scrollOptions
), &cb
) != SQL_SUCCESS
)
1001 return(DispAllErrors(henv
, hdbc
));
1003 if (SQLGetInfo(hdbc
, SQL_STATIC_SENSITIVITY
, (UCHAR
*) &dbInf
.staticSensitivity
, sizeof(dbInf
.staticSensitivity
), &cb
) != SQL_SUCCESS
)
1004 return(DispAllErrors(henv
, hdbc
));
1006 if (SQLGetInfo(hdbc
, SQL_TXN_CAPABLE
, (UCHAR
*) &dbInf
.txnCapable
, sizeof(dbInf
.txnCapable
), &cb
) != SQL_SUCCESS
)
1007 return(DispAllErrors(henv
, hdbc
));
1009 if (SQLGetInfo(hdbc
, SQL_LOGIN_TIMEOUT
, (UCHAR
*) &dbInf
.loginTimeout
, sizeof(dbInf
.loginTimeout
), &cb
) != SQL_SUCCESS
)
1010 return(DispAllErrors(henv
, hdbc
));
1012 #ifdef DBDEBUG_CONSOLE
1013 cout
<< wxT("***** DATA SOURCE INFORMATION *****") << endl
;
1014 cout
<< wxT(wxT("SERVER Name: ") << dbInf
.serverName
<< endl
;
1015 cout
<< wxT("DBMS Name: ") << dbInf
.dbmsName
<< wxT("; DBMS Version: ") << dbInf
.dbmsVer
<< endl
;
1016 cout
<< wxT("ODBC Version: ") << dbInf
.odbcVer
<< wxT("; Driver Version: ") << dbInf
.driverVer
<< endl
;
1018 cout
<< wxT("API Conf. Level: ");
1019 switch(dbInf
.apiConfLvl
)
1021 case SQL_OAC_NONE
: cout
<< wxT("None"); break;
1022 case SQL_OAC_LEVEL1
: cout
<< wxT("Level 1"); break;
1023 case SQL_OAC_LEVEL2
: cout
<< wxT("Level 2"); break;
1027 cout
<< wxT("SAG CLI Conf. Level: ");
1028 switch(dbInf
.cliConfLvl
)
1030 case SQL_OSCC_NOT_COMPLIANT
: cout
<< wxT("Not Compliant"); break;
1031 case SQL_OSCC_COMPLIANT
: cout
<< wxT("Compliant"); break;
1035 cout
<< wxT("SQL Conf. Level: ");
1036 switch(dbInf
.sqlConfLvl
)
1038 case SQL_OSC_MINIMUM
: cout
<< wxT("Minimum Grammar"); break;
1039 case SQL_OSC_CORE
: cout
<< wxT("Core Grammar"); break;
1040 case SQL_OSC_EXTENDED
: cout
<< wxT("Extended Grammar"); break;
1044 cout
<< wxT("Max. Connections: ") << dbInf
.maxConnections
<< endl
;
1045 cout
<< wxT("Outer Joins: ") << dbInf
.outerJoins
<< endl
;
1046 cout
<< wxT("Support for Procedures: ") << dbInf
.procedureSupport
<< endl
;
1047 cout
<< wxT("All tables accessible : ") << dbInf
.accessibleTables
<< endl
;
1048 cout
<< wxT("Cursor COMMIT Behavior: ");
1049 switch(dbInf
.cursorCommitBehavior
)
1051 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1052 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1053 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1057 cout
<< wxT("Cursor ROLLBACK Behavior: ");
1058 switch(dbInf
.cursorRollbackBehavior
)
1060 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1061 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1062 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1066 cout
<< wxT("Support NOT NULL clause: ");
1067 switch(dbInf
.supportNotNullClause
)
1069 case SQL_NNC_NULL
: cout
<< wxT("No"); break;
1070 case SQL_NNC_NON_NULL
: cout
<< wxT("Yes"); break;
1074 cout
<< wxT("Support IEF (Ref. Integrity): ") << dbInf
.supportIEF
<< endl
;
1075 cout
<< wxT("Login Timeout: ") << dbInf
.loginTimeout
<< endl
;
1077 cout
<< endl
<< endl
<< wxT("more ...") << endl
;
1080 cout
<< wxT("Default Transaction Isolation: ";
1081 switch(dbInf
.txnIsolation
)
1083 case SQL_TXN_READ_UNCOMMITTED
: cout
<< wxT("Read Uncommitted"); break;
1084 case SQL_TXN_READ_COMMITTED
: cout
<< wxT("Read Committed"); break;
1085 case SQL_TXN_REPEATABLE_READ
: cout
<< wxT("Repeatable Read"); break;
1086 case SQL_TXN_SERIALIZABLE
: cout
<< wxT("Serializable"); break;
1088 case SQL_TXN_VERSIONING
: cout
<< wxT("Versioning"); break;
1093 cout
<< wxT("Transaction Isolation Options: ");
1094 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_UNCOMMITTED
)
1095 cout
<< wxT("Read Uncommitted, ");
1096 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_COMMITTED
)
1097 cout
<< wxT("Read Committed, ");
1098 if (dbInf
.txnIsolationOptions
& SQL_TXN_REPEATABLE_READ
)
1099 cout
<< wxT("Repeatable Read, ");
1100 if (dbInf
.txnIsolationOptions
& SQL_TXN_SERIALIZABLE
)
1101 cout
<< wxT("Serializable, ");
1103 if (dbInf
.txnIsolationOptions
& SQL_TXN_VERSIONING
)
1104 cout
<< wxT("Versioning");
1108 cout
<< wxT("Fetch Directions Supported:") << endl
<< wxT(" ");
1109 if (dbInf
.fetchDirections
& SQL_FD_FETCH_NEXT
)
1110 cout
<< wxT("Next, ");
1111 if (dbInf
.fetchDirections
& SQL_FD_FETCH_PRIOR
)
1112 cout
<< wxT("Prev, ");
1113 if (dbInf
.fetchDirections
& SQL_FD_FETCH_FIRST
)
1114 cout
<< wxT("First, ");
1115 if (dbInf
.fetchDirections
& SQL_FD_FETCH_LAST
)
1116 cout
<< wxT("Last, ");
1117 if (dbInf
.fetchDirections
& SQL_FD_FETCH_ABSOLUTE
)
1118 cout
<< wxT("Absolute, ");
1119 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RELATIVE
)
1120 cout
<< wxT("Relative, ");
1122 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RESUME
)
1123 cout
<< wxT("Resume, ");
1125 if (dbInf
.fetchDirections
& SQL_FD_FETCH_BOOKMARK
)
1126 cout
<< wxT("Bookmark");
1129 cout
<< wxT("Lock Types Supported (SQLSetPos): ");
1130 if (dbInf
.lockTypes
& SQL_LCK_NO_CHANGE
)
1131 cout
<< wxT("No Change, ");
1132 if (dbInf
.lockTypes
& SQL_LCK_EXCLUSIVE
)
1133 cout
<< wxT("Exclusive, ");
1134 if (dbInf
.lockTypes
& SQL_LCK_UNLOCK
)
1135 cout
<< wxT("UnLock");
1138 cout
<< wxT("Position Operations Supported (SQLSetPos): ");
1139 if (dbInf
.posOperations
& SQL_POS_POSITION
)
1140 cout
<< wxT("Position, ");
1141 if (dbInf
.posOperations
& SQL_POS_REFRESH
)
1142 cout
<< wxT("Refresh, ");
1143 if (dbInf
.posOperations
& SQL_POS_UPDATE
)
1144 cout
<< wxT("Upd, "));
1145 if (dbInf
.posOperations
& SQL_POS_DELETE
)
1146 cout
<< wxT("Del, ");
1147 if (dbInf
.posOperations
& SQL_POS_ADD
)
1151 cout
<< wxT("Positioned Statements Supported: ");
1152 if (dbInf
.posStmts
& SQL_PS_POSITIONED_DELETE
)
1153 cout
<< wxT("Pos delete, ");
1154 if (dbInf
.posStmts
& SQL_PS_POSITIONED_UPDATE
)
1155 cout
<< wxT("Pos update, ");
1156 if (dbInf
.posStmts
& SQL_PS_SELECT_FOR_UPDATE
)
1157 cout
<< wxT("Select for update");
1160 cout
<< wxT("Scroll Concurrency: ");
1161 if (dbInf
.scrollConcurrency
& SQL_SCCO_READ_ONLY
)
1162 cout
<< wxT("Read Only, ");
1163 if (dbInf
.scrollConcurrency
& SQL_SCCO_LOCK
)
1164 cout
<< wxT("Lock, ");
1165 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_ROWVER
)
1166 cout
<< wxT("Opt. Rowver, ");
1167 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_VALUES
)
1168 cout
<< wxT("Opt. Values");
1171 cout
<< wxT("Scroll Options: ");
1172 if (dbInf
.scrollOptions
& SQL_SO_FORWARD_ONLY
)
1173 cout
<< wxT("Fwd Only, ");
1174 if (dbInf
.scrollOptions
& SQL_SO_STATIC
)
1175 cout
<< wxT("Static, ");
1176 if (dbInf
.scrollOptions
& SQL_SO_KEYSET_DRIVEN
)
1177 cout
<< wxT("Keyset Driven, ");
1178 if (dbInf
.scrollOptions
& SQL_SO_DYNAMIC
)
1179 cout
<< wxT("Dynamic, ");
1180 if (dbInf
.scrollOptions
& SQL_SO_MIXED
)
1181 cout
<< wxT("Mixed");
1184 cout
<< wxT("Static Sensitivity: ");
1185 if (dbInf
.staticSensitivity
& SQL_SS_ADDITIONS
)
1186 cout
<< wxT("Additions, ");
1187 if (dbInf
.staticSensitivity
& SQL_SS_DELETIONS
)
1188 cout
<< wxT("Deletions, ");
1189 if (dbInf
.staticSensitivity
& SQL_SS_UPDATES
)
1190 cout
<< wxT("Updates");
1193 cout
<< wxT("Transaction Capable?: ");
1194 switch(dbInf
.txnCapable
)
1196 case SQL_TC_NONE
: cout
<< wxT("No"); break;
1197 case SQL_TC_DML
: cout
<< wxT("DML Only"); break;
1198 case SQL_TC_DDL_COMMIT
: cout
<< wxT("DDL Commit"); break;
1199 case SQL_TC_DDL_IGNORE
: cout
<< wxT("DDL Ignore"); break;
1200 case SQL_TC_ALL
: cout
<< wxT("DDL & DML"); break;
1207 // Completed Successfully
1210 } // wxDb::getDbInfo()
1213 /********** wxDb::getDataTypeInfo() **********/
1214 bool wxDb::getDataTypeInfo(SWORD fSqlType
, wxDbSqlTypeInfo
&structSQLTypeInfo
)
1217 * fSqlType will be something like SQL_VARCHAR. This parameter determines
1218 * the data type inf. is gathered for.
1220 * wxDbSqlTypeInfo is a structure that is filled in with data type information,
1225 // Get information about the data type specified
1226 if (SQLGetTypeInfo(hstmt
, fSqlType
) != SQL_SUCCESS
)
1227 return(DispAllErrors(henv
, hdbc
, hstmt
));
1229 if ((retcode
= SQLFetch(hstmt
)) != SQL_SUCCESS
)
1231 #ifdef DBDEBUG_CONSOLE
1232 if (retcode
== SQL_NO_DATA_FOUND
)
1233 cout
<< wxT("SQL_NO_DATA_FOUND fetching inf. about data type.") << endl
;
1235 DispAllErrors(henv
, hdbc
, hstmt
);
1236 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1240 wxChar typeName
[DB_TYPE_NAME_LEN
+1];
1241 // Obtain columns from the record
1242 if (SQLGetData(hstmt
, 1, SQL_C_CHAR
, (UCHAR
*) typeName
, DB_TYPE_NAME_LEN
, &cbRet
) != SQL_SUCCESS
)
1243 return(DispAllErrors(henv
, hdbc
, hstmt
));
1245 structSQLTypeInfo
.TypeName
= typeName
;
1247 // BJO 20000503: no more needed with new GetColumns...
1250 if (Dbms() == dbmsMY_SQL
)
1252 if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1253 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1254 else if (structSQLTypeInfo
.TypeName
== wxT("middleint unsigned"))
1255 structSQLTypeInfo
.TypeName
= wxT("mediumint unsigned");
1256 else if (structSQLTypeInfo
.TypeName
== wxT("integer"))
1257 structSQLTypeInfo
.TypeName
= wxT("int");
1258 else if (structSQLTypeInfo
.TypeName
== wxT("integer unsigned"))
1259 structSQLTypeInfo
.TypeName
= wxT("int unsigned");
1260 else if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1261 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1262 else if (structSQLTypeInfo
.TypeName
== wxT("varchar"))
1263 structSQLTypeInfo
.TypeName
= wxT("char");
1266 // BJO 20000427 : OpenLink driver
1267 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
1268 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
1270 if (structSQLTypeInfo
.TypeName
== wxT("double precision"))
1271 structSQLTypeInfo
.TypeName
= wxT("real");
1275 if (SQLGetData(hstmt
, 3, SQL_C_LONG
, (UCHAR
*) &structSQLTypeInfo
.Precision
, 0, &cbRet
) != SQL_SUCCESS
)
1276 return(DispAllErrors(henv
, hdbc
, hstmt
));
1277 if (SQLGetData(hstmt
, 8, SQL_C_SHORT
, (UCHAR
*) &structSQLTypeInfo
.CaseSensitive
, 0, &cbRet
) != SQL_SUCCESS
)
1278 return(DispAllErrors(henv
, hdbc
, hstmt
));
1279 // if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
1280 // return(DispAllErrors(henv, hdbc, hstmt));
1282 if (SQLGetData(hstmt
, 15, SQL_C_SHORT
,(UCHAR
*) &structSQLTypeInfo
.MaximumScale
, 0, &cbRet
) != SQL_SUCCESS
)
1283 return(DispAllErrors(henv
, hdbc
, hstmt
));
1285 if (structSQLTypeInfo
.MaximumScale
< 0)
1286 structSQLTypeInfo
.MaximumScale
= 0;
1288 // Close the statement handle which closes open cursors
1289 if (SQLFreeStmt(hstmt
, SQL_CLOSE
) != SQL_SUCCESS
)
1290 return(DispAllErrors(henv
, hdbc
, hstmt
));
1292 // Completed Successfully
1295 } // wxDb::getDataTypeInfo()
1298 /********** wxDb::Close() **********/
1299 void wxDb::Close(void)
1301 // Close the Sql Log file
1308 // Free statement handle
1311 if (SQLFreeStmt(hstmt
, SQL_DROP
) != SQL_SUCCESS
)
1312 DispAllErrors(henv
, hdbc
);
1315 // Disconnect from the datasource
1316 if (SQLDisconnect(hdbc
) != SQL_SUCCESS
)
1317 DispAllErrors(henv
, hdbc
);
1319 // Free the connection to the datasource
1320 if (SQLFreeConnect(hdbc
) != SQL_SUCCESS
)
1321 DispAllErrors(henv
, hdbc
);
1323 // There should be zero Ctable objects still connected to this db object
1324 wxASSERT(nTables
== 0);
1329 pNode
= TablesInUse
.First();
1333 tiu
= (wxTablesInUse
*)pNode
->Data();
1334 if (tiu
->pDb
== this)
1336 s
.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu
->tableName
,tiu
->tableID
,tiu
->pDb
);
1337 s2
.Printf(wxT("Orphaned found using pDb:[%p]"),this);
1340 pNode
= pNode
->Next();
1344 // Copy the error messages to a global variable
1346 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1347 wxStrcpy(DBerrorList
[i
], errorList
[i
]);
1349 dbmsType
= dbmsUNIDENTIFIED
;
1355 /********** wxDb::CommitTrans() **********/
1356 bool wxDb::CommitTrans(void)
1360 // Commit the transaction
1361 if (SQLTransact(henv
, hdbc
, SQL_COMMIT
) != SQL_SUCCESS
)
1362 return(DispAllErrors(henv
, hdbc
));
1365 // Completed successfully
1368 } // wxDb::CommitTrans()
1371 /********** wxDb::RollbackTrans() **********/
1372 bool wxDb::RollbackTrans(void)
1374 // Rollback the transaction
1375 if (SQLTransact(henv
, hdbc
, SQL_ROLLBACK
) != SQL_SUCCESS
)
1376 return(DispAllErrors(henv
, hdbc
));
1378 // Completed successfully
1381 } // wxDb::RollbackTrans()
1384 /********** wxDb::DispAllErrors() **********/
1385 bool wxDb::DispAllErrors(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1387 * This function is called internally whenever an error condition prevents the user's
1388 * request from being executed. This function will query the datasource as to the
1389 * actual error(s) that just occured on the previous request of the datasource.
1391 * The function will retrieve each error condition from the datasource and
1392 * Printf the codes/text values into a string which it then logs via logError().
1393 * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
1394 * window and program execution will be paused until the user presses a key.
1396 * This function always returns a FALSE, so that functions which call this function
1397 * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure
1398 * of the users request, so that the calling code can then process the error msg log
1401 wxString odbcErrMsg
;
1403 while (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1405 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1406 logError(odbcErrMsg
, sqlState
);
1409 #ifdef DBDEBUG_CONSOLE
1410 // When run in console mode, use standard out to display errors.
1411 cout
<< odbcErrMsg
.c_str() << endl
;
1412 cout
<< wxT("Press any key to continue...") << endl
;
1417 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
1422 return(FALSE
); // This function always returns false.
1424 } // wxDb::DispAllErrors()
1427 /********** wxDb::GetNextError() **********/
1428 bool wxDb::GetNextError(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1430 if (SQLError(aHenv
, aHdbc
, aHstmt
, (UCHAR FAR
*) sqlState
, &nativeError
, (UCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1435 } // wxDb::GetNextError()
1438 /********** wxDb::DispNextError() **********/
1439 void wxDb::DispNextError(void)
1441 wxString odbcErrMsg
;
1443 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1444 logError(odbcErrMsg
, sqlState
);
1449 #ifdef DBDEBUG_CONSOLE
1450 // When run in console mode, use standard out to display errors.
1451 cout
<< odbcErrMsg
.c_str() << endl
;
1452 cout
<< wxT("Press any key to continue...") << endl
;
1457 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE"));
1458 #endif // __WXDEBUG__
1460 } // wxDb::DispNextError()
1463 /********** wxDb::logError() **********/
1464 void wxDb::logError(const wxString
&errMsg
, const wxString
&SQLState
)
1466 wxASSERT(errMsg
.Length());
1468 static int pLast
= -1;
1471 if (++pLast
== DB_MAX_ERROR_HISTORY
)
1474 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1475 wxStrcpy(errorList
[i
], errorList
[i
+1]);
1479 wxStrcpy(errorList
[pLast
], errMsg
);
1481 if (SQLState
.Length())
1482 if ((dbStatus
= TranslateSqlState(SQLState
)) != DB_ERR_FUNCTION_SEQUENCE_ERROR
)
1483 DB_STATUS
= dbStatus
;
1485 // Add the errmsg to the sql log
1486 WriteSqlLog(errMsg
);
1488 } // wxDb::logError()
1491 /**********wxDb::TranslateSqlState() **********/
1492 int wxDb::TranslateSqlState(const wxString
&SQLState
)
1494 if (!wxStrcmp(SQLState
, wxT("01000")))
1495 return(DB_ERR_GENERAL_WARNING
);
1496 if (!wxStrcmp(SQLState
, wxT("01002")))
1497 return(DB_ERR_DISCONNECT_ERROR
);
1498 if (!wxStrcmp(SQLState
, wxT("01004")))
1499 return(DB_ERR_DATA_TRUNCATED
);
1500 if (!wxStrcmp(SQLState
, wxT("01006")))
1501 return(DB_ERR_PRIV_NOT_REVOKED
);
1502 if (!wxStrcmp(SQLState
, wxT("01S00")))
1503 return(DB_ERR_INVALID_CONN_STR_ATTR
);
1504 if (!wxStrcmp(SQLState
, wxT("01S01")))
1505 return(DB_ERR_ERROR_IN_ROW
);
1506 if (!wxStrcmp(SQLState
, wxT("01S02")))
1507 return(DB_ERR_OPTION_VALUE_CHANGED
);
1508 if (!wxStrcmp(SQLState
, wxT("01S03")))
1509 return(DB_ERR_NO_ROWS_UPD_OR_DEL
);
1510 if (!wxStrcmp(SQLState
, wxT("01S04")))
1511 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL
);
1512 if (!wxStrcmp(SQLState
, wxT("07001")))
1513 return(DB_ERR_WRONG_NO_OF_PARAMS
);
1514 if (!wxStrcmp(SQLState
, wxT("07006")))
1515 return(DB_ERR_DATA_TYPE_ATTR_VIOL
);
1516 if (!wxStrcmp(SQLState
, wxT("08001")))
1517 return(DB_ERR_UNABLE_TO_CONNECT
);
1518 if (!wxStrcmp(SQLState
, wxT("08002")))
1519 return(DB_ERR_CONNECTION_IN_USE
);
1520 if (!wxStrcmp(SQLState
, wxT("08003")))
1521 return(DB_ERR_CONNECTION_NOT_OPEN
);
1522 if (!wxStrcmp(SQLState
, wxT("08004")))
1523 return(DB_ERR_REJECTED_CONNECTION
);
1524 if (!wxStrcmp(SQLState
, wxT("08007")))
1525 return(DB_ERR_CONN_FAIL_IN_TRANS
);
1526 if (!wxStrcmp(SQLState
, wxT("08S01")))
1527 return(DB_ERR_COMM_LINK_FAILURE
);
1528 if (!wxStrcmp(SQLState
, wxT("21S01")))
1529 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH
);
1530 if (!wxStrcmp(SQLState
, wxT("21S02")))
1531 return(DB_ERR_DERIVED_TABLE_MISMATCH
);
1532 if (!wxStrcmp(SQLState
, wxT("22001")))
1533 return(DB_ERR_STRING_RIGHT_TRUNC
);
1534 if (!wxStrcmp(SQLState
, wxT("22003")))
1535 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG
);
1536 if (!wxStrcmp(SQLState
, wxT("22005")))
1537 return(DB_ERR_ERROR_IN_ASSIGNMENT
);
1538 if (!wxStrcmp(SQLState
, wxT("22008")))
1539 return(DB_ERR_DATETIME_FLD_OVERFLOW
);
1540 if (!wxStrcmp(SQLState
, wxT("22012")))
1541 return(DB_ERR_DIVIDE_BY_ZERO
);
1542 if (!wxStrcmp(SQLState
, wxT("22026")))
1543 return(DB_ERR_STR_DATA_LENGTH_MISMATCH
);
1544 if (!wxStrcmp(SQLState
, wxT("23000")))
1545 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL
);
1546 if (!wxStrcmp(SQLState
, wxT("24000")))
1547 return(DB_ERR_INVALID_CURSOR_STATE
);
1548 if (!wxStrcmp(SQLState
, wxT("25000")))
1549 return(DB_ERR_INVALID_TRANS_STATE
);
1550 if (!wxStrcmp(SQLState
, wxT("28000")))
1551 return(DB_ERR_INVALID_AUTH_SPEC
);
1552 if (!wxStrcmp(SQLState
, wxT("34000")))
1553 return(DB_ERR_INVALID_CURSOR_NAME
);
1554 if (!wxStrcmp(SQLState
, wxT("37000")))
1555 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL
);
1556 if (!wxStrcmp(SQLState
, wxT("3C000")))
1557 return(DB_ERR_DUPLICATE_CURSOR_NAME
);
1558 if (!wxStrcmp(SQLState
, wxT("40001")))
1559 return(DB_ERR_SERIALIZATION_FAILURE
);
1560 if (!wxStrcmp(SQLState
, wxT("42000")))
1561 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2
);
1562 if (!wxStrcmp(SQLState
, wxT("70100")))
1563 return(DB_ERR_OPERATION_ABORTED
);
1564 if (!wxStrcmp(SQLState
, wxT("IM001")))
1565 return(DB_ERR_UNSUPPORTED_FUNCTION
);
1566 if (!wxStrcmp(SQLState
, wxT("IM002")))
1567 return(DB_ERR_NO_DATA_SOURCE
);
1568 if (!wxStrcmp(SQLState
, wxT("IM003")))
1569 return(DB_ERR_DRIVER_LOAD_ERROR
);
1570 if (!wxStrcmp(SQLState
, wxT("IM004")))
1571 return(DB_ERR_SQLALLOCENV_FAILED
);
1572 if (!wxStrcmp(SQLState
, wxT("IM005")))
1573 return(DB_ERR_SQLALLOCCONNECT_FAILED
);
1574 if (!wxStrcmp(SQLState
, wxT("IM006")))
1575 return(DB_ERR_SQLSETCONNECTOPTION_FAILED
);
1576 if (!wxStrcmp(SQLState
, wxT("IM007")))
1577 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB
);
1578 if (!wxStrcmp(SQLState
, wxT("IM008")))
1579 return(DB_ERR_DIALOG_FAILED
);
1580 if (!wxStrcmp(SQLState
, wxT("IM009")))
1581 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL
);
1582 if (!wxStrcmp(SQLState
, wxT("IM010")))
1583 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG
);
1584 if (!wxStrcmp(SQLState
, wxT("IM011")))
1585 return(DB_ERR_DRIVER_NAME_TOO_LONG
);
1586 if (!wxStrcmp(SQLState
, wxT("IM012")))
1587 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR
);
1588 if (!wxStrcmp(SQLState
, wxT("IM013")))
1589 return(DB_ERR_TRACE_FILE_ERROR
);
1590 if (!wxStrcmp(SQLState
, wxT("S0001")))
1591 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS
);
1592 if (!wxStrcmp(SQLState
, wxT("S0002")))
1593 return(DB_ERR_TABLE_NOT_FOUND
);
1594 if (!wxStrcmp(SQLState
, wxT("S0011")))
1595 return(DB_ERR_INDEX_ALREADY_EXISTS
);
1596 if (!wxStrcmp(SQLState
, wxT("S0012")))
1597 return(DB_ERR_INDEX_NOT_FOUND
);
1598 if (!wxStrcmp(SQLState
, wxT("S0021")))
1599 return(DB_ERR_COLUMN_ALREADY_EXISTS
);
1600 if (!wxStrcmp(SQLState
, wxT("S0022")))
1601 return(DB_ERR_COLUMN_NOT_FOUND
);
1602 if (!wxStrcmp(SQLState
, wxT("S0023")))
1603 return(DB_ERR_NO_DEFAULT_FOR_COLUMN
);
1604 if (!wxStrcmp(SQLState
, wxT("S1000")))
1605 return(DB_ERR_GENERAL_ERROR
);
1606 if (!wxStrcmp(SQLState
, wxT("S1001")))
1607 return(DB_ERR_MEMORY_ALLOCATION_FAILURE
);
1608 if (!wxStrcmp(SQLState
, wxT("S1002")))
1609 return(DB_ERR_INVALID_COLUMN_NUMBER
);
1610 if (!wxStrcmp(SQLState
, wxT("S1003")))
1611 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE
);
1612 if (!wxStrcmp(SQLState
, wxT("S1004")))
1613 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE
);
1614 if (!wxStrcmp(SQLState
, wxT("S1008")))
1615 return(DB_ERR_OPERATION_CANCELLED
);
1616 if (!wxStrcmp(SQLState
, wxT("S1009")))
1617 return(DB_ERR_INVALID_ARGUMENT_VALUE
);
1618 if (!wxStrcmp(SQLState
, wxT("S1010")))
1619 return(DB_ERR_FUNCTION_SEQUENCE_ERROR
);
1620 if (!wxStrcmp(SQLState
, wxT("S1011")))
1621 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME
);
1622 if (!wxStrcmp(SQLState
, wxT("S1012")))
1623 return(DB_ERR_INVALID_TRANS_OPERATION_CODE
);
1624 if (!wxStrcmp(SQLState
, wxT("S1015")))
1625 return(DB_ERR_NO_CURSOR_NAME_AVAIL
);
1626 if (!wxStrcmp(SQLState
, wxT("S1090")))
1627 return(DB_ERR_INVALID_STR_OR_BUF_LEN
);
1628 if (!wxStrcmp(SQLState
, wxT("S1091")))
1629 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE
);
1630 if (!wxStrcmp(SQLState
, wxT("S1092")))
1631 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE
);
1632 if (!wxStrcmp(SQLState
, wxT("S1093")))
1633 return(DB_ERR_INVALID_PARAM_NO
);
1634 if (!wxStrcmp(SQLState
, wxT("S1094")))
1635 return(DB_ERR_INVALID_SCALE_VALUE
);
1636 if (!wxStrcmp(SQLState
, wxT("S1095")))
1637 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE
);
1638 if (!wxStrcmp(SQLState
, wxT("S1096")))
1639 return(DB_ERR_INF_TYPE_OUT_OF_RANGE
);
1640 if (!wxStrcmp(SQLState
, wxT("S1097")))
1641 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE
);
1642 if (!wxStrcmp(SQLState
, wxT("S1098")))
1643 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE
);
1644 if (!wxStrcmp(SQLState
, wxT("S1099")))
1645 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE
);
1646 if (!wxStrcmp(SQLState
, wxT("S1100")))
1647 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE
);
1648 if (!wxStrcmp(SQLState
, wxT("S1101")))
1649 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE
);
1650 if (!wxStrcmp(SQLState
, wxT("S1103")))
1651 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE
);
1652 if (!wxStrcmp(SQLState
, wxT("S1104")))
1653 return(DB_ERR_INVALID_PRECISION_VALUE
);
1654 if (!wxStrcmp(SQLState
, wxT("S1105")))
1655 return(DB_ERR_INVALID_PARAM_TYPE
);
1656 if (!wxStrcmp(SQLState
, wxT("S1106")))
1657 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE
);
1658 if (!wxStrcmp(SQLState
, wxT("S1107")))
1659 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE
);
1660 if (!wxStrcmp(SQLState
, wxT("S1108")))
1661 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE
);
1662 if (!wxStrcmp(SQLState
, wxT("S1109")))
1663 return(DB_ERR_INVALID_CURSOR_POSITION
);
1664 if (!wxStrcmp(SQLState
, wxT("S1110")))
1665 return(DB_ERR_INVALID_DRIVER_COMPLETION
);
1666 if (!wxStrcmp(SQLState
, wxT("S1111")))
1667 return(DB_ERR_INVALID_BOOKMARK_VALUE
);
1668 if (!wxStrcmp(SQLState
, wxT("S1C00")))
1669 return(DB_ERR_DRIVER_NOT_CAPABLE
);
1670 if (!wxStrcmp(SQLState
, wxT("S1T00")))
1671 return(DB_ERR_TIMEOUT_EXPIRED
);
1676 } // wxDb::TranslateSqlState()
1679 /********** wxDb::Grant() **********/
1680 bool wxDb::Grant(int privileges
, const wxString
&tableName
, const wxString
&userList
)
1684 // Build the grant statement
1685 sqlStmt
= wxT("GRANT ");
1686 if (privileges
== DB_GRANT_ALL
)
1687 sqlStmt
+= wxT("ALL");
1691 if (privileges
& DB_GRANT_SELECT
)
1693 sqlStmt
+= wxT("SELECT");
1696 if (privileges
& DB_GRANT_INSERT
)
1699 sqlStmt
+= wxT(", ");
1700 sqlStmt
+= wxT("INSERT");
1702 if (privileges
& DB_GRANT_UPDATE
)
1705 sqlStmt
+= wxT(", ");
1706 sqlStmt
+= wxT("UPDATE");
1708 if (privileges
& DB_GRANT_DELETE
)
1711 sqlStmt
+= wxT(", ");
1712 sqlStmt
+= wxT("DELETE");
1716 sqlStmt
+= wxT(" ON ");
1717 sqlStmt
+= tableName
;
1718 sqlStmt
+= wxT(" TO ");
1719 sqlStmt
+= userList
;
1721 #ifdef DBDEBUG_CONSOLE
1722 cout
<< endl
<< sqlStmt
.c_str() << endl
;
1725 WriteSqlLog(sqlStmt
);
1727 return(ExecSql(sqlStmt
));
1732 /********** wxDb::CreateView() **********/
1733 bool wxDb::CreateView(const wxString
&viewName
, const wxString
&colList
,
1734 const wxString
&pSqlStmt
, bool attemptDrop
)
1738 // Drop the view first
1739 if (attemptDrop
&& !DropView(viewName
))
1742 // Build the create view statement
1743 sqlStmt
= wxT("CREATE VIEW ");
1744 sqlStmt
+= viewName
;
1746 if (colList
.Length())
1748 sqlStmt
+= wxT(" (");
1750 sqlStmt
+= wxT(")");
1753 sqlStmt
+= wxT(" AS ");
1754 sqlStmt
+= pSqlStmt
;
1756 WriteSqlLog(sqlStmt
);
1758 #ifdef DBDEBUG_CONSOLE
1759 cout
<< sqlStmt
.c_str() << endl
;
1762 return(ExecSql(sqlStmt
));
1764 } // wxDb::CreateView()
1767 /********** wxDb::DropView() **********/
1768 bool wxDb::DropView(const wxString
&viewName
)
1771 * NOTE: This function returns TRUE if the View does not exist, but
1772 * only for identified databases. Code will need to be added
1773 * below for any other databases when those databases are defined
1774 * to handle this situation consistently
1778 sqlStmt
.Printf(wxT("DROP VIEW %s"), viewName
.c_str());
1780 WriteSqlLog(sqlStmt
);
1782 #ifdef DBDEBUG_CONSOLE
1783 cout
<< endl
<< sqlStmt
.c_str() << endl
;
1786 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) sqlStmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
1788 // Check for "Base table not found" error and ignore
1789 GetNextError(henv
, hdbc
, hstmt
);
1790 if (wxStrcmp(sqlState
,wxT("S0002"))) // "Base table not found"
1792 // Check for product specific error codes
1793 if (!((Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(sqlState
,wxT("42000"))))) // 5.x (and lower?)
1796 DispAllErrors(henv
, hdbc
, hstmt
);
1803 // Commit the transaction
1804 if (! CommitTrans())
1809 } // wxDb::DropView()
1812 /********** wxDb::ExecSql() **********/
1813 bool wxDb::ExecSql(const wxString
&pSqlStmt
)
1815 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1816 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) pSqlStmt
.c_str(), SQL_NTS
) == SQL_SUCCESS
)
1820 DispAllErrors(henv
, hdbc
, hstmt
);
1824 } // wxDb::ExecSql()
1827 /********** wxDb::GetNext() **********/
1828 bool wxDb::GetNext(void)
1830 if (SQLFetch(hstmt
) == SQL_SUCCESS
)
1834 DispAllErrors(henv
, hdbc
, hstmt
);
1838 } // wxDb::GetNext()
1841 /********** wxDb::GetData() **********/
1842 bool wxDb::GetData(UWORD colNo
, SWORD cType
, PTR pData
, SDWORD maxLen
, SDWORD FAR
*cbReturned
)
1845 wxASSERT(cbReturned
);
1847 if (SQLGetData(hstmt
, colNo
, cType
, pData
, maxLen
, cbReturned
) == SQL_SUCCESS
)
1851 DispAllErrors(henv
, hdbc
, hstmt
);
1855 } // wxDb::GetData()
1858 /********** wxDb::GetKeyFields() **********/
1859 int wxDb::GetKeyFields(const wxString
&tableName
, wxDbColInf
* colInf
, int noCols
)
1861 wxChar szPkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Primary key table name */
1862 wxChar szFkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Foreign key table name */
1864 // SQLSMALLINT iKeySeq;
1865 wxChar szPkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Primary key column */
1866 wxChar szFkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Foreign key column */
1872 * -----------------------------------------------------------------------
1873 * -- 19991224 : mj10777 : Create ------
1874 * -- : Three things are done and stored here : ------
1875 * -- : 1) which Column(s) is/are Primary Key(s) ------
1876 * -- : 2) which tables use this Key as a Foreign Key ------
1877 * -- : 3) which columns are Foreign Key and the name ------
1878 * -- : of the Table where the Key is the Primary Key -----
1879 * -- : Called from GetColumns(const wxString &tableName, ------
1880 * -- int *numCols,const wxChar *userID ) ------
1881 * -----------------------------------------------------------------------
1884 /*---------------------------------------------------------------------*/
1885 /* Get the names of the columns in the primary key. */
1886 /*---------------------------------------------------------------------*/
1887 retcode
= SQLPrimaryKeys(hstmt
,
1888 NULL
, 0, /* Catalog name */
1889 NULL
, 0, /* Schema name */
1890 (UCHAR FAR
*) tableName
.c_str(), SQL_NTS
); /* Table name */
1892 /*---------------------------------------------------------------------*/
1893 /* Fetch and display the result set. This will be a list of the */
1894 /* columns in the primary key of the tableName table. */
1895 /*---------------------------------------------------------------------*/
1896 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1898 retcode
= SQLFetch(hstmt
);
1899 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1901 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1902 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1904 for (i
=0;i
<noCols
;i
++) // Find the Column name
1905 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column
1906 colInf
[i
].PkCol
= iKeySeq
; // Which Primary Key is this (first, second usw.) ?
1909 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1911 /*---------------------------------------------------------------------*/
1912 /* Get all the foreign keys that refer to tableName primary key. */
1913 /*---------------------------------------------------------------------*/
1914 retcode
= SQLForeignKeys(hstmt
,
1915 NULL
, 0, /* Primary catalog */
1916 NULL
, 0, /* Primary schema */
1917 (UCHAR FAR
*)tableName
.c_str(), SQL_NTS
,/* Primary table */
1918 NULL
, 0, /* Foreign catalog */
1919 NULL
, 0, /* Foreign schema */
1920 NULL
, 0); /* Foreign table */
1922 /*---------------------------------------------------------------------*/
1923 /* Fetch and display the result set. This will be all of the foreign */
1924 /* keys in other tables that refer to the tableName primary key. */
1925 /*---------------------------------------------------------------------*/
1928 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1930 retcode
= SQLFetch(hstmt
);
1931 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1933 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1934 GetData( 4, SQL_C_CHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1935 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1936 GetData( 7, SQL_C_CHAR
, szFkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1937 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1938 tempStr
.Printf(wxT("%s[%s] "),tempStr
.c_str(),szFkTable
); // [ ] in case there is a blank in the Table name
1942 tempStr
.Trim(); // Get rid of any unneeded blanks
1943 if (!tempStr
.IsEmpty())
1945 for (i
=0; i
<noCols
; i
++)
1946 { // Find the Column name
1947 if (!wxStrcmp(colInf
[i
].colName
, szPkCol
)) // We have found the Column, store the Information
1948 wxStrcpy(colInf
[i
].PkTableName
, tempStr
.c_str()); // Name of the Tables where this Primary Key is used as a Foreign Key
1952 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1954 /*---------------------------------------------------------------------*/
1955 /* Get all the foreign keys in the tablename table. */
1956 /*---------------------------------------------------------------------*/
1957 retcode
= SQLForeignKeys(hstmt
,
1958 NULL
, 0, /* Primary catalog */
1959 NULL
, 0, /* Primary schema */
1960 NULL
, 0, /* Primary table */
1961 NULL
, 0, /* Foreign catalog */
1962 NULL
, 0, /* Foreign schema */
1963 (UCHAR
*)tableName
.c_str(), SQL_NTS
);/* Foreign table */
1965 /*---------------------------------------------------------------------*/
1966 /* Fetch and display the result set. This will be all of the */
1967 /* primary keys in other tables that are referred to by foreign */
1968 /* keys in the tableName table. */
1969 /*---------------------------------------------------------------------*/
1971 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
1973 retcode
= SQLFetch(hstmt
);
1974 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
1976 GetData( 3, SQL_C_CHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
1977 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
1978 GetData( 8, SQL_C_CHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
1980 for (i
=0; i
<noCols
; i
++) // Find the Column name
1982 if (!wxStrcmp(colInf
[i
].colName
,szFkCol
)) // We have found the (Foreign Key) Column
1984 colInf
[i
].FkCol
= iKeySeq
; // Which Foreign Key is this (first, second usw.) ?
1985 wxStrcpy(colInf
[i
].FkTableName
,szPkTable
); // Name of the Table where this Foriegn is the Primary Key
1990 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
1994 } // wxDb::GetKeyFields()
1998 /********** wxDb::GetColumns() **********/
1999 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2001 * 1) The last array element of the tableName[] argument must be zero (null).
2002 * This is how the end of the array is detected.
2003 * 2) This function returns an array of wxDbColInf structures. If no columns
2004 * were found, or an error occured, this pointer will be zero (null). THE
2005 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
2006 * IS FINISHED WITH IT. i.e.
2008 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
2011 * // Use the column inf
2013 * // Destroy the memory
2017 * userID is evaluated in the following manner:
2018 * userID == NULL ... UserID is ignored
2019 * userID == "" ... UserID set equal to 'this->uid'
2020 * userID != "" ... UserID set equal to 'userID'
2022 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2023 * by this function. This function should use its own wxDb instance
2024 * to avoid undesired unbinding of columns.
2029 wxDbColInf
*colInf
= 0;
2037 convertUserID(userID
,UserID
);
2039 // Pass 1 - Determine how many columns there are.
2040 // Pass 2 - Allocate the wxDbColInf array and fill in
2041 // the array with the column information.
2043 for (pass
= 1; pass
<= 2; pass
++)
2047 if (noCols
== 0) // Probably a bogus table name(s)
2049 // Allocate n wxDbColInf objects to hold the column information
2050 colInf
= new wxDbColInf
[noCols
+1];
2053 // Mark the end of the array
2054 wxStrcpy(colInf
[noCols
].tableName
,wxT(""));
2055 wxStrcpy(colInf
[noCols
].colName
,wxT(""));
2056 colInf
[noCols
].sqlDataType
= 0;
2058 // Loop through each table name
2060 for (tbl
= 0; tableName
[tbl
]; tbl
++)
2062 TableName
= tableName
[tbl
];
2063 // Oracle and Interbase table names are uppercase only, so force
2064 // the name to uppercase just in case programmer forgot to do this
2065 if ((Dbms() == dbmsORACLE
) ||
2066 (Dbms() == dbmsINTERBASE
))
2067 TableName
= TableName
.Upper();
2069 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2071 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2072 // use the call below that leaves out the user name
2073 if (!UserID
.IsEmpty() &&
2074 Dbms() != dbmsMY_SQL
&&
2075 Dbms() != dbmsACCESS
&&
2076 Dbms() != dbmsMS_SQL_SERVER
)
2078 retcode
= SQLColumns(hstmt
,
2079 NULL
, 0, // All qualifiers
2080 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2081 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2082 NULL
, 0); // All columns
2086 retcode
= SQLColumns(hstmt
,
2087 NULL
, 0, // All qualifiers
2089 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2090 NULL
, 0); // All columns
2092 if (retcode
!= SQL_SUCCESS
)
2093 { // Error occured, abort
2094 DispAllErrors(henv
, hdbc
, hstmt
);
2097 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2101 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2103 if (pass
== 1) // First pass, just add up the number of columns
2105 else // Pass 2; Fill in the array of structures
2107 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2109 // NOTE: Only the ODBC 1.x fields are retrieved
2110 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2111 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2112 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2113 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2114 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2115 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2116 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2117 GetData( 8, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2118 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2119 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2120 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2121 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2123 // Determine the wxDb data type that is used to represent the native data type of this data source
2124 colInf
[colNo
].dbDataType
= 0;
2125 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
2128 // IODBC does not return a correct columnSize, so we set
2129 // columnSize = bufferLength if no column size was returned
2130 // IODBC returns the columnSize in bufferLength.. (bug)
2131 if (colInf
[colNo
].columnSize
< 1)
2133 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2136 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2138 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
2139 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2140 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
2141 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2142 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
2143 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2149 if (retcode
!= SQL_NO_DATA_FOUND
)
2150 { // Error occured, abort
2151 DispAllErrors(henv
, hdbc
, hstmt
);
2154 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2160 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2163 } // wxDb::GetColumns()
2166 /********** wxDb::GetColumns() **********/
2168 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, int *numCols
, const wxChar
*userID
)
2170 // Same as the above GetColumns() function except this one gets columns
2171 // only for a single table, and if 'numCols' is not NULL, the number of
2172 // columns stored in the returned wxDbColInf is set in '*numCols'
2174 // userID is evaluated in the following manner:
2175 // userID == NULL ... UserID is ignored
2176 // userID == "" ... UserID set equal to 'this->uid'
2177 // userID != "" ... UserID set equal to 'userID'
2179 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2180 // by this function. This function should use its own wxDb instance
2181 // to avoid undesired unbinding of columns.
2186 wxDbColInf
*colInf
= 0;
2194 convertUserID(userID
,UserID
);
2196 // Pass 1 - Determine how many columns there are.
2197 // Pass 2 - Allocate the wxDbColInf array and fill in
2198 // the array with the column information.
2200 for (pass
= 1; pass
<= 2; pass
++)
2204 if (noCols
== 0) // Probably a bogus table name(s)
2206 // Allocate n wxDbColInf objects to hold the column information
2207 colInf
= new wxDbColInf
[noCols
+1];
2210 // Mark the end of the array
2211 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
2212 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
2213 colInf
[noCols
].sqlDataType
= 0;
2216 TableName
= tableName
;
2217 // Oracle and Interbase table names are uppercase only, so force
2218 // the name to uppercase just in case programmer forgot to do this
2219 if ((Dbms() == dbmsORACLE
) ||
2220 (Dbms() == dbmsINTERBASE
))
2221 TableName
= TableName
.Upper();
2223 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2225 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2226 // use the call below that leaves out the user name
2227 if (!UserID
.IsEmpty() &&
2228 Dbms() != dbmsMY_SQL
&&
2229 Dbms() != dbmsACCESS
&&
2230 Dbms() != dbmsMS_SQL_SERVER
)
2232 retcode
= SQLColumns(hstmt
,
2233 NULL
, 0, // All qualifiers
2234 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2235 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2236 NULL
, 0); // All columns
2240 retcode
= SQLColumns(hstmt
,
2241 NULL
, 0, // All qualifiers
2243 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2244 NULL
, 0); // All columns
2246 if (retcode
!= SQL_SUCCESS
)
2247 { // Error occured, abort
2248 DispAllErrors(henv
, hdbc
, hstmt
);
2251 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2257 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2259 if (pass
== 1) // First pass, just add up the number of columns
2261 else // Pass 2; Fill in the array of structures
2263 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2265 // NOTE: Only the ODBC 1.x fields are retrieved
2266 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2267 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2268 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2269 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2270 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2271 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2272 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2273 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
2274 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2275 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2276 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2277 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2278 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2279 // Start Values for Primary/Foriegn Key (=No)
2280 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2281 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2282 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2283 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
2285 // BJO 20000428 : Virtuoso returns type names with upper cases!
2286 if (Dbms() == dbmsVIRTUOSO
)
2288 wxString s
= colInf
[colNo
].typeName
;
2290 wxStrcmp(colInf
[colNo
].typeName
, s
.c_str());
2293 // Determine the wxDb data type that is used to represent the native data type of this data source
2294 colInf
[colNo
].dbDataType
= 0;
2295 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
2298 // IODBC does not return a correct columnSize, so we set
2299 // columnSize = bufferLength if no column size was returned
2300 // IODBC returns the columnSize in bufferLength.. (bug)
2301 if (colInf
[colNo
].columnSize
< 1)
2303 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2307 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2309 else if (!wxStricmp(typeInfInteger
.TypeName
,colInf
[colNo
].typeName
))
2310 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2311 else if (!wxStricmp(typeInfFloat
.TypeName
,colInf
[colNo
].typeName
))
2312 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2313 else if (!wxStricmp(typeInfDate
.TypeName
,colInf
[colNo
].typeName
))
2314 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2320 if (retcode
!= SQL_NO_DATA_FOUND
)
2321 { // Error occured, abort
2322 DispAllErrors(henv
, hdbc
, hstmt
);
2325 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2332 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2334 // Store Primary and Foriegn Keys
2335 GetKeyFields(tableName
,colInf
,noCols
);
2341 } // wxDb::GetColumns()
2344 #else // New GetColumns
2349 These are tentative new GetColumns members which should be more database
2350 independant and which always returns the columns in the order they were
2353 - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const
2354 wxChar* userID)) calls the second implementation for each separate table
2355 before merging the results. This makes the code easier to maintain as
2356 only one member (the second) makes the real work
2357 - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const
2358 wxChar *userID) is a little bit improved
2359 - It doesn't anymore rely on the type-name to find out which database-type
2361 - It ends by sorting the columns, so that they are returned in the same
2362 order they were created
2372 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2375 // The last array element of the tableName[] argument must be zero (null).
2376 // This is how the end of the array is detected.
2380 // How many tables ?
2382 for (tbl
= 0 ; tableName
[tbl
]; tbl
++);
2384 // Create a table to maintain the columns for each separate table
2385 _TableColumns
*TableColumns
= new _TableColumns
[tbl
];
2388 for (i
= 0 ; i
< tbl
; i
++)
2391 TableColumns
[i
].colInf
= GetColumns(tableName
[i
], &TableColumns
[i
].noCols
, userID
);
2392 if (TableColumns
[i
].colInf
== NULL
)
2394 noCols
+= TableColumns
[i
].noCols
;
2397 // Now merge all the separate table infos
2398 wxDbColInf
*colInf
= new wxDbColInf
[noCols
+1];
2400 // Mark the end of the array
2401 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
2402 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
2403 colInf
[noCols
].sqlDataType
= 0;
2408 for (i
= 0 ; i
< tbl
; i
++)
2410 for (j
= 0 ; j
< TableColumns
[i
].noCols
; j
++)
2412 colInf
[offset
++] = TableColumns
[i
].colInf
[j
];
2416 delete [] TableColumns
;
2419 } // wxDb::GetColumns() -- NEW
2422 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, int *numCols
, const wxChar
*userID
)
2424 // Same as the above GetColumns() function except this one gets columns
2425 // only for a single table, and if 'numCols' is not NULL, the number of
2426 // columns stored in the returned wxDbColInf is set in '*numCols'
2428 // userID is evaluated in the following manner:
2429 // userID == NULL ... UserID is ignored
2430 // userID == "" ... UserID set equal to 'this->uid'
2431 // userID != "" ... UserID set equal to 'userID'
2433 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2434 // by this function. This function should use its own wxDb instance
2435 // to avoid undesired unbinding of columns.
2439 wxDbColInf
*colInf
= 0;
2447 convertUserID(userID
,UserID
);
2449 // Pass 1 - Determine how many columns there are.
2450 // Pass 2 - Allocate the wxDbColInf array and fill in
2451 // the array with the column information.
2453 for (pass
= 1; pass
<= 2; pass
++)
2457 if (noCols
== 0) // Probably a bogus table name(s)
2459 // Allocate n wxDbColInf objects to hold the column information
2460 colInf
= new wxDbColInf
[noCols
+1];
2463 // Mark the end of the array
2464 wxStrcpy(colInf
[noCols
].tableName
, wxT(""));
2465 wxStrcpy(colInf
[noCols
].colName
, wxT(""));
2466 colInf
[noCols
].sqlDataType
= 0;
2469 TableName
= tableName
;
2470 // Oracle and Interbase table names are uppercase only, so force
2471 // the name to uppercase just in case programmer forgot to do this
2472 if ((Dbms() == dbmsORACLE
) ||
2473 (Dbms() == dbmsINTERBASE
))
2474 TableName
= TableName
.Upper();
2476 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2478 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2479 // use the call below that leaves out the user name
2480 if (!UserID
.IsEmpty() &&
2481 Dbms() != dbmsMY_SQL
&&
2482 Dbms() != dbmsACCESS
&&
2483 Dbms() != dbmsMS_SQL_SERVER
)
2485 retcode
= SQLColumns(hstmt
,
2486 NULL
, 0, // All qualifiers
2487 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2488 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2489 NULL
, 0); // All columns
2493 retcode
= SQLColumns(hstmt
,
2494 NULL
, 0, // All qualifiers
2496 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2497 NULL
, 0); // All columns
2499 if (retcode
!= SQL_SUCCESS
)
2500 { // Error occured, abort
2501 DispAllErrors(henv
, hdbc
, hstmt
);
2504 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2510 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2512 if (pass
== 1) // First pass, just add up the number of columns
2514 else // Pass 2; Fill in the array of structures
2516 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2518 // NOTE: Only the ODBC 1.x fields are retrieved
2519 GetData( 1, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2520 GetData( 2, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2521 GetData( 3, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2522 GetData( 4, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2523 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2524 GetData( 6, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2525 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnSize
, 0, &cb
);
2526 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferLength
, 0, &cb
);
2527 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2528 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2529 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2530 GetData(12, SQL_C_CHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2531 // Start Values for Primary/Foriegn Key (=No)
2532 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2533 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2534 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2535 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
2538 // IODBC does not return a correct columnSize, so we set
2539 // columnSize = bufferLength if no column size was returned
2540 // IODBC returns the columnSize in bufferLength.. (bug)
2541 if (colInf
[colNo
].columnSize
< 1)
2543 colInf
[colNo
].columnSize
= colInf
[colNo
].bufferLength
;
2547 // Determine the wxDb data type that is used to represent the native data type of this data source
2548 colInf
[colNo
].dbDataType
= 0;
2549 // Get the intern datatype
2550 switch (colInf
[colNo
].sqlDataType
)
2554 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2560 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2567 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2570 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2575 errMsg
.Printf(wxT("SQL Data type %d currently not supported by wxWindows"), colInf
[colNo
].sqlDataType
);
2576 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
2583 if (retcode
!= SQL_NO_DATA_FOUND
)
2584 { // Error occured, abort
2585 DispAllErrors(henv
, hdbc
, hstmt
);
2588 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2595 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2597 // Store Primary and Foreign Keys
2598 GetKeyFields(tableName
,colInf
,noCols
);
2600 ///////////////////////////////////////////////////////////////////////////
2601 // Now sort the the columns in order to make them appear in the right order
2602 ///////////////////////////////////////////////////////////////////////////
2604 // Build a generic SELECT statement which returns 0 rows
2607 Stmt
.Printf(wxT("select * from %s where 0=1"), tableName
);
2610 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) Stmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
2612 DispAllErrors(henv
, hdbc
, hstmt
);
2616 // Get the number of result columns
2617 if (SQLNumResultCols (hstmt
, &noCols
) != SQL_SUCCESS
)
2619 DispAllErrors(henv
, hdbc
, hstmt
);
2623 if (noCols
== 0) // Probably a bogus table name
2632 for (colNum
= 0; colNum
< noCols
; colNum
++)
2634 if (SQLColAttributes(hstmt
,colNum
+1, SQL_COLUMN_NAME
,
2636 &Sword
, &Sdword
) != SQL_SUCCESS
)
2638 DispAllErrors(henv
, hdbc
, hstmt
);
2642 wxString Name1
= name
;
2643 Name1
= Name1
.Upper();
2645 // Where is this name in the array ?
2646 for (i
= colNum
; i
< noCols
; i
++)
2648 wxString Name2
= colInf
[i
].colName
;
2649 Name2
= Name2
.Upper();
2652 if (colNum
!= i
) // swap to sort
2654 wxDbColInf tmpColInf
= colInf
[colNum
];
2655 colInf
[colNum
] = colInf
[i
];
2656 colInf
[i
] = tmpColInf
;
2662 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2664 ///////////////////////////////////////////////////////////////////////////
2666 ///////////////////////////////////////////////////////////////////////////
2672 } // wxDb::GetColumns()
2675 #endif // #else OLD_GETCOLUMNS
2678 /********** wxDb::GetColumnCount() **********/
2679 int wxDb::GetColumnCount(const wxString
&tableName
, const wxChar
*userID
)
2681 * Returns a count of how many columns are in a table.
2682 * If an error occurs in computing the number of columns
2683 * this function will return a -1 for the count
2685 * userID is evaluated in the following manner:
2686 * userID == NULL ... UserID is ignored
2687 * userID == "" ... UserID set equal to 'this->uid'
2688 * userID != "" ... UserID set equal to 'userID'
2690 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2691 * by this function. This function should use its own wxDb instance
2692 * to avoid undesired unbinding of columns.
2702 convertUserID(userID
,UserID
);
2704 TableName
= tableName
;
2705 // Oracle and Interbase table names are uppercase only, so force
2706 // the name to uppercase just in case programmer forgot to do this
2707 if ((Dbms() == dbmsORACLE
) ||
2708 (Dbms() == dbmsINTERBASE
))
2709 TableName
= TableName
.Upper();
2711 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2713 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2714 // use the call below that leaves out the user name
2715 if (!UserID
.IsEmpty() &&
2716 Dbms() != dbmsMY_SQL
&&
2717 Dbms() != dbmsACCESS
&&
2718 Dbms() != dbmsMS_SQL_SERVER
)
2720 retcode
= SQLColumns(hstmt
,
2721 NULL
, 0, // All qualifiers
2722 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2723 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2724 NULL
, 0); // All columns
2728 retcode
= SQLColumns(hstmt
,
2729 NULL
, 0, // All qualifiers
2731 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2732 NULL
, 0); // All columns
2734 if (retcode
!= SQL_SUCCESS
)
2735 { // Error occured, abort
2736 DispAllErrors(henv
, hdbc
, hstmt
);
2737 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2741 // Count the columns
2742 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2745 if (retcode
!= SQL_NO_DATA_FOUND
)
2746 { // Error occured, abort
2747 DispAllErrors(henv
, hdbc
, hstmt
);
2748 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2752 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2755 } // wxDb::GetColumnCount()
2758 /********** wxDb::GetCatalog() *******/
2759 wxDbInf
*wxDb::GetCatalog(const wxChar
*userID
)
2761 * ---------------------------------------------------------------------
2762 * -- 19991203 : mj10777 : Create ------
2763 * -- : Creates a wxDbInf with Tables / Cols Array ------
2764 * -- : uses SQLTables and fills pTableInf; ------
2765 * -- : pColInf is set to NULL and numCols to 0; ------
2766 * -- : returns pDbInf (wxDbInf) ------
2767 * -- - if unsuccesfull (pDbInf == NULL) ------
2768 * -- : pColInf can be filled with GetColumns(..); ------
2769 * -- : numCols can be filled with GetColumnCount(..); ------
2770 * ---------------------------------------------------------------------
2772 * userID is evaluated in the following manner:
2773 * userID == NULL ... UserID is ignored
2774 * userID == "" ... UserID set equal to 'this->uid'
2775 * userID != "" ... UserID set equal to 'userID'
2777 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2778 * by this function. This function should use its own wxDb instance
2779 * to avoid undesired unbinding of columns.
2782 wxDbInf
*pDbInf
= NULL
; // Array of catalog entries
2783 int noTab
= 0; // Counter while filling table entries
2787 wxString tblNameSave
;
2790 convertUserID(userID
,UserID
);
2792 //-------------------------------------------------------------
2793 pDbInf
= new wxDbInf
; // Create the Database Array
2794 //-------------------------------------------------------------
2795 // Table Information
2796 // Pass 1 - Determine how many Tables there are.
2797 // Pass 2 - Create the Table array and fill it
2798 // - Create the Cols array = NULL
2799 //-------------------------------------------------------------
2801 for (pass
= 1; pass
<= 2; pass
++)
2803 SQLFreeStmt(hstmt
, SQL_CLOSE
); // Close if Open
2804 tblNameSave
.Empty();
2806 if (!UserID
.IsEmpty() &&
2807 Dbms() != dbmsMY_SQL
&&
2808 Dbms() != dbmsACCESS
&&
2809 Dbms() != dbmsMS_SQL_SERVER
)
2811 retcode
= SQLTables(hstmt
,
2812 NULL
, 0, // All qualifiers
2813 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
2814 NULL
, 0, // All tables
2815 NULL
, 0); // All columns
2819 retcode
= SQLTables(hstmt
,
2820 NULL
, 0, // All qualifiers
2821 NULL
, 0, // User specified
2822 NULL
, 0, // All tables
2823 NULL
, 0); // All columns
2826 if (retcode
!= SQL_SUCCESS
)
2828 DispAllErrors(henv
, hdbc
, hstmt
);
2830 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2834 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
) // Table Information
2836 if (pass
== 1) // First pass, just count the Tables
2838 if (pDbInf
->numTables
== 0)
2840 GetData( 1, SQL_C_CHAR
, (UCHAR
*) pDbInf
->catalog
, 128+1, &cb
);
2841 GetData( 2, SQL_C_CHAR
, (UCHAR
*) pDbInf
->schema
, 128+1, &cb
);
2843 pDbInf
->numTables
++; // Counter for Tables
2845 if (pass
== 2) // Create and fill the Table entries
2847 if (pDbInf
->pTableInf
== NULL
) // Has the Table Array been created
2848 { // no, then create the Array
2849 pDbInf
->pTableInf
= new wxDbTableInf
[pDbInf
->numTables
];
2851 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
2853 GetData( 3, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2854 GetData( 4, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableType
, 30+1, &cb
);
2855 GetData( 5, SQL_C_CHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableRemarks
, 254+1, &cb
);
2861 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2863 // Query how many columns are in each table
2864 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
2866 (pDbInf
->pTableInf
+noTab
)->numCols
= GetColumnCount((pDbInf
->pTableInf
+noTab
)->tableName
,UserID
);
2871 } // wxDb::GetCatalog()
2874 /********** wxDb::Catalog() **********/
2875 bool wxDb::Catalog(const wxChar
*userID
, const wxString
&fileName
)
2877 * Creates the text file specified in 'filename' which will contain
2878 * a minimal data dictionary of all tables accessible by the user specified
2881 * userID is evaluated in the following manner:
2882 * userID == NULL ... UserID is ignored
2883 * userID == "" ... UserID set equal to 'this->uid'
2884 * userID != "" ... UserID set equal to 'userID'
2886 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2887 * by this function. This function should use its own wxDb instance
2888 * to avoid undesired unbinding of columns.
2891 wxASSERT(fileName
.Length());
2895 wxChar tblName
[DB_MAX_TABLE_NAME_LEN
+1];
2896 wxString tblNameSave
;
2897 wxChar colName
[DB_MAX_COLUMN_NAME_LEN
+1];
2899 wxChar typeName
[30+1];
2900 SWORD precision
, length
;
2902 FILE *fp
= fopen(fileName
.c_str(),wxT("wt"));
2906 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2909 convertUserID(userID
,UserID
);
2911 if (!UserID
.IsEmpty() &&
2912 Dbms() != dbmsMY_SQL
&&
2913 Dbms() != dbmsACCESS
&&
2914 Dbms() != dbmsMS_SQL_SERVER
)
2916 retcode
= SQLColumns(hstmt
,
2917 NULL
, 0, // All qualifiers
2918 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
2919 NULL
, 0, // All tables
2920 NULL
, 0); // All columns
2924 retcode
= SQLColumns(hstmt
,
2925 NULL
, 0, // All qualifiers
2926 NULL
, 0, // User specified
2927 NULL
, 0, // All tables
2928 NULL
, 0); // All columns
2930 if (retcode
!= SQL_SUCCESS
)
2932 DispAllErrors(henv
, hdbc
, hstmt
);
2938 tblNameSave
.Empty();
2941 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2943 if (wxStrcmp(tblName
, tblNameSave
.c_str()))
2946 fputs(wxT("\n"), fp
);
2947 fputs(wxT("================================ "), fp
);
2948 fputs(wxT("================================ "), fp
);
2949 fputs(wxT("===================== "), fp
);
2950 fputs(wxT("========= "), fp
);
2951 fputs(wxT("=========\n"), fp
);
2952 outStr
.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
2953 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
2954 fputs(outStr
.c_str(), fp
);
2955 fputs(wxT("================================ "), fp
);
2956 fputs(wxT("================================ "), fp
);
2957 fputs(wxT("===================== "), fp
);
2958 fputs(wxT("========= "), fp
);
2959 fputs(wxT("=========\n"), fp
);
2960 tblNameSave
= tblName
;
2963 GetData(3,SQL_C_CHAR
, (UCHAR
*)tblName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2964 GetData(4,SQL_C_CHAR
, (UCHAR
*)colName
, DB_MAX_COLUMN_NAME_LEN
+1,&cb
);
2965 GetData(5,SQL_C_SSHORT
,(UCHAR
*)&sqlDataType
,0, &cb
);
2966 GetData(6,SQL_C_CHAR
, (UCHAR
*)typeName
, sizeof(typeName
), &cb
);
2967 GetData(7,SQL_C_SSHORT
,(UCHAR
*)&precision
, 0, &cb
);
2968 GetData(8,SQL_C_SSHORT
,(UCHAR
*)&length
, 0, &cb
);
2970 outStr
.Printf(wxT("%-32s %-32s (%04d)%-15s %9d %9d\n"),
2971 tblName
, colName
, sqlDataType
, typeName
, precision
, length
);
2972 if (fputs(outStr
.c_str(), fp
) == EOF
)
2974 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2981 if (retcode
!= SQL_NO_DATA_FOUND
)
2982 DispAllErrors(henv
, hdbc
, hstmt
);
2984 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2987 return(retcode
== SQL_NO_DATA_FOUND
);
2989 } // wxDb::Catalog()
2992 bool wxDb::TableExists(const wxString
&tableName
, const wxChar
*userID
, const wxString
&tablePath
)
2994 * Table name can refer to a table, view, alias or synonym. Returns true
2995 * if the object exists in the database. This function does not indicate
2996 * whether or not the user has privleges to query or perform other functions
2999 * userID is evaluated in the following manner:
3000 * userID == NULL ... UserID is ignored
3001 * userID == "" ... UserID set equal to 'this->uid'
3002 * userID != "" ... UserID set equal to 'userID'
3005 wxASSERT(tableName
.Length());
3009 if (Dbms() == dbmsDBASE
)
3012 if (tablePath
.Length())
3013 dbName
.Printf(wxT("%s/%s.dbf"), tablePath
.c_str(), tableName
.c_str());
3015 dbName
.Printf(wxT("%s.dbf"), tableName
.c_str());
3018 exists
= wxFileExists(dbName
);
3023 convertUserID(userID
,UserID
);
3025 TableName
= tableName
;
3026 // Oracle and Interbase table names are uppercase only, so force
3027 // the name to uppercase just in case programmer forgot to do this
3028 if ((Dbms() == dbmsORACLE
) ||
3029 (Dbms() == dbmsINTERBASE
))
3030 TableName
= TableName
.Upper();
3032 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3035 // Some databases cannot accept a user name when looking up table names,
3036 // so we use the call below that leaves out the user name
3037 if (!UserID
.IsEmpty() &&
3038 Dbms() != dbmsMY_SQL
&&
3039 Dbms() != dbmsACCESS
&&
3040 Dbms() != dbmsMS_SQL_SERVER
)
3042 retcode
= SQLTables(hstmt
,
3043 NULL
, 0, // All qualifiers
3044 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Only tables owned by this user
3045 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3046 NULL
, 0); // All table types
3050 retcode
= SQLTables(hstmt
,
3051 NULL
, 0, // All qualifiers
3052 NULL
, 0, // All owners
3053 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3054 NULL
, 0); // All table types
3056 if (retcode
!= SQL_SUCCESS
)
3057 return(DispAllErrors(henv
, hdbc
, hstmt
));
3059 retcode
= SQLFetch(hstmt
);
3060 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
3062 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3063 return(DispAllErrors(henv
, hdbc
, hstmt
));
3066 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3070 } // wxDb::TableExists()
3073 /********** wxDb::TablePrivileges() **********/
3074 bool wxDb::TablePrivileges(const wxString
&tableName
, const wxString
&priv
, const wxChar
*userID
,
3075 const wxChar
*schema
, const wxString
&tablePath
)
3077 wxASSERT(tableName
.Length());
3079 wxDbTablePrivilegeInfo result
;
3083 // We probably need to be able to dynamically set this based on
3084 // the driver type, and state.
3085 wxChar curRole
[]=wxT("public");
3090 convertUserID(userID
,UserID
);
3092 TableName
= tableName
;
3093 // Oracle and Interbase table names are uppercase only, so force
3094 // the name to uppercase just in case programmer forgot to do this
3095 if ((Dbms() == dbmsORACLE
) ||
3096 (Dbms() == dbmsINTERBASE
))
3097 TableName
= TableName
.Upper();
3099 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3103 retcode
= SQLTablePrivileges(hstmt
,
3106 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3110 retcode
= SQLTablePrivileges(hstmt
,
3112 (UCHAR FAR
*)schema
, SQL_NTS
, // Schema
3113 (UCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3116 #ifdef DBDEBUG_CONSOLE
3117 fprintf(stderr
,wxT("SQLTablePrivileges() returned %i \n"),retcode
);
3120 if ((retcode
!= SQL_SUCCESS
) && (retcode
!= SQL_SUCCESS_WITH_INFO
))
3121 return(DispAllErrors(henv
, hdbc
, hstmt
));
3123 retcode
= SQLFetch(hstmt
);
3124 while (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
3126 if (SQLGetData(hstmt
, 1, SQL_C_CHAR
, (UCHAR
*) result
.tableQual
, sizeof(result
.tableQual
), &cbRetVal
) != SQL_SUCCESS
)
3127 return(DispAllErrors(henv
, hdbc
, hstmt
));
3129 if (SQLGetData(hstmt
, 2, SQL_C_CHAR
, (UCHAR
*) result
.tableOwner
, sizeof(result
.tableOwner
), &cbRetVal
) != SQL_SUCCESS
)
3130 return(DispAllErrors(henv
, hdbc
, hstmt
));
3132 if (SQLGetData(hstmt
, 3, SQL_C_CHAR
, (UCHAR
*) result
.tableName
, sizeof(result
.tableName
), &cbRetVal
) != SQL_SUCCESS
)
3133 return(DispAllErrors(henv
, hdbc
, hstmt
));
3135 if (SQLGetData(hstmt
, 4, SQL_C_CHAR
, (UCHAR
*) result
.grantor
, sizeof(result
.grantor
), &cbRetVal
) != SQL_SUCCESS
)
3136 return(DispAllErrors(henv
, hdbc
, hstmt
));
3138 if (SQLGetData(hstmt
, 5, SQL_C_CHAR
, (UCHAR
*) result
.grantee
, sizeof(result
.grantee
), &cbRetVal
) != SQL_SUCCESS
)
3139 return(DispAllErrors(henv
, hdbc
, hstmt
));
3141 if (SQLGetData(hstmt
, 6, SQL_C_CHAR
, (UCHAR
*) result
.privilege
, sizeof(result
.privilege
), &cbRetVal
) != SQL_SUCCESS
)
3142 return(DispAllErrors(henv
, hdbc
, hstmt
));
3144 if (SQLGetData(hstmt
, 7, SQL_C_CHAR
, (UCHAR
*) result
.grantable
, sizeof(result
.grantable
), &cbRetVal
) != SQL_SUCCESS
)
3145 return(DispAllErrors(henv
, hdbc
, hstmt
));
3147 #ifdef DBDEBUG_CONSOLE
3148 fprintf(stderr
,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
3149 result
.privilege
,result
.tableOwner
,result
.tableName
,
3150 result
.grantor
, result
.grantee
);
3153 if (UserID
.IsSameAs(result
.tableOwner
,FALSE
))
3155 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3159 if (UserID
.IsSameAs(result
.grantee
,FALSE
) &&
3160 !wxStrcmp(result
.privilege
,priv
))
3162 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3166 if (!wxStrcmp(result
.grantee
,curRole
) &&
3167 !wxStrcmp(result
.privilege
,priv
))
3169 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3173 retcode
= SQLFetch(hstmt
);
3176 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3179 } // wxDb::TablePrivileges
3182 /********** wxDb::SetSqlLogging() **********/
3183 bool wxDb::SetSqlLogging(wxDbSqlLogState state
, const wxString
&filename
, bool append
)
3185 wxASSERT(state
== sqlLogON
|| state
== sqlLogOFF
);
3186 wxASSERT(state
== sqlLogOFF
|| filename
.Length());
3188 if (state
== sqlLogON
)
3192 fpSqlLog
= fopen(filename
, (append
? wxT("at") : wxT("wt")));
3193 if (fpSqlLog
== NULL
)
3201 if (fclose(fpSqlLog
))
3207 sqlLogState
= state
;
3210 } // wxDb::SetSqlLogging()
3213 /********** wxDb::WriteSqlLog() **********/
3214 bool wxDb::WriteSqlLog(const wxString
&logMsg
)
3216 wxASSERT(logMsg
.Length());
3218 if (fpSqlLog
== 0 || sqlLogState
== sqlLogOFF
)
3221 if (fputs(wxT("\n"), fpSqlLog
) == EOF
)
3223 if (fputs(logMsg
, fpSqlLog
) == EOF
)
3225 if (fputs(wxT("\n"), fpSqlLog
) == EOF
)
3230 } // wxDb::WriteSqlLog()
3233 /********** wxDb::Dbms() **********/
3234 wxDBMS
wxDb::Dbms(void)
3236 * Be aware that not all database engines use the exact same syntax, and not
3237 * every ODBC compliant database is compliant to the same level of compliancy.
3238 * Some manufacturers support the minimum Level 1 compliancy, and others up
3239 * through Level 3. Others support subsets of features for levels above 1.
3241 * If you find an inconsistency between the wxDb class and a specific database
3242 * engine, and an identifier to this section, and special handle the database in
3243 * the area where behavior is non-conforming with the other databases.
3246 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3247 * ---------------------------------------------------
3250 * - Currently the only database supported by the class to support VIEWS
3253 * - Does not support the SQL_TIMESTAMP structure
3254 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
3255 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
3256 * is TRUE. The user must create ALL indexes from their program.
3257 * - Table names can only be 8 characters long
3258 * - Column names can only be 10 characters long
3261 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3262 * after every table name involved in the query/join if that tables matching record(s)
3264 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
3266 * SYBASE (Enterprise)
3267 * - If a column is part of the Primary Key, the column cannot be NULL
3268 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
3271 * - If a column is part of the Primary Key, the column cannot be NULL
3272 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3273 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3274 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3275 * column definition if it is not defined correctly, but it is experimental
3276 * - Does not support sub-queries in SQL statements
3279 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3280 * - Does not support sub-queries in SQL statements
3283 * - Primary keys must be declared as NOT NULL
3287 // Should only need to do this once for each new database connection
3288 // so return the value we already determined it to be to save time
3289 // and lots of string comparisons
3290 if (dbmsType
!= dbmsUNIDENTIFIED
)
3293 wxChar baseName
[25+1];
3294 wxStrncpy(baseName
,dbInf
.dbmsName
,25);
3297 // RGG 20001025 : add support for Interbase
3298 // GT : Integrated to base classes on 20001121
3299 if (!wxStricmp(dbInf
.dbmsName
,wxT("Interbase")))
3300 return((wxDBMS
)(dbmsType
= dbmsINTERBASE
));
3302 // BJO 20000428 : add support for Virtuoso
3303 if (!wxStricmp(dbInf
.dbmsName
,wxT("OpenLink Virtuoso VDBMS")))
3304 return((wxDBMS
)(dbmsType
= dbmsVIRTUOSO
));
3306 if (!wxStricmp(dbInf
.dbmsName
,wxT("Adaptive Server Anywhere")))
3307 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASA
));
3309 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3310 // connected through an OpenLink driver.
3311 // Is it also returned by Sybase Adapatitve server?
3312 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
3313 if (!wxStricmp(dbInf
.dbmsName
,wxT("SQL Server")))
3315 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
3316 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
3317 return ((wxDBMS
)(dbmsMS_SQL_SERVER
));
3319 return ((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3322 if (!wxStricmp(dbInf
.dbmsName
,wxT("Microsoft SQL Server")))
3323 return((wxDBMS
)(dbmsType
= dbmsMS_SQL_SERVER
));
3324 if (!wxStricmp(dbInf
.dbmsName
,wxT("MySQL")))
3325 return((wxDBMS
)(dbmsType
= dbmsMY_SQL
));
3326 if (!wxStricmp(dbInf
.dbmsName
,wxT("PostgreSQL"))) // v6.5.0
3327 return((wxDBMS
)(dbmsType
= dbmsPOSTGRES
));
3330 if (!wxStricmp(baseName
,wxT("Informix")))
3331 return((wxDBMS
)(dbmsType
= dbmsINFORMIX
));
3334 if (!wxStricmp(baseName
,wxT("Oracle")))
3335 return((wxDBMS
)(dbmsType
= dbmsORACLE
));
3336 if (!wxStricmp(dbInf
.dbmsName
,wxT("ACCESS")))
3337 return((wxDBMS
)(dbmsType
= dbmsACCESS
));
3338 if (!wxStricmp(dbInf
.dbmsName
,wxT("MySQL")))
3339 return((wxDBMS
)(dbmsType
= dbmsMY_SQL
));
3340 if (!wxStricmp(baseName
,wxT("Sybase")))
3341 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3344 if (!wxStricmp(baseName
,wxT("DBASE")))
3345 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3348 if (!wxStricmp(baseName
,wxT("DB2")))
3349 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3351 return((wxDBMS
)(dbmsType
= dbmsUNIDENTIFIED
));
3356 bool wxDb::ModifyColumn(const wxString
&tableName
, const wxString
&columnName
,
3357 int dataType
, ULONG columnLength
,
3358 const wxString
&optionalParam
)
3360 wxASSERT(tableName
.Length());
3361 wxASSERT(columnName
.Length());
3362 wxASSERT((dataType
== DB_DATA_TYPE_VARCHAR
&& columnLength
> 0) ||
3363 dataType
!= DB_DATA_TYPE_VARCHAR
);
3365 // Must specify a columnLength if modifying a VARCHAR type column
3366 if (dataType
== DB_DATA_TYPE_VARCHAR
&& !columnLength
)
3369 wxString dataTypeName
;
3371 wxString alterSlashModify
;
3375 case DB_DATA_TYPE_VARCHAR
:
3376 dataTypeName
= typeInfVarchar
.TypeName
;
3378 case DB_DATA_TYPE_INTEGER
:
3379 dataTypeName
= typeInfInteger
.TypeName
;
3381 case DB_DATA_TYPE_FLOAT
:
3382 dataTypeName
= typeInfFloat
.TypeName
;
3384 case DB_DATA_TYPE_DATE
:
3385 dataTypeName
= typeInfDate
.TypeName
;
3391 // Set the modify or alter syntax depending on the type of database connected to
3395 alterSlashModify
= "MODIFY";
3397 case dbmsMS_SQL_SERVER
:
3398 alterSlashModify
= "ALTER COLUMN";
3400 case dbmsUNIDENTIFIED
:
3402 case dbmsSYBASE_ASA
:
3403 case dbmsSYBASE_ASE
:
3409 alterSlashModify
= "MODIFY";
3413 // create the SQL statement
3414 sqlStmt
.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName
.c_str(), alterSlashModify
.c_str(),
3415 columnName
.c_str(), dataTypeName
.c_str());
3417 // For varchars only, append the size of the column
3418 if (dataType
== DB_DATA_TYPE_VARCHAR
)
3421 s
.Printf(wxT("(%d)"), columnLength
);
3425 // for passing things like "NOT NULL"
3426 if (optionalParam
.Length())
3428 sqlStmt
+= wxT(" ");
3429 sqlStmt
+= optionalParam
;
3432 return ExecSql(sqlStmt
);
3434 } // wxDb::ModifyColumn()
3437 /********** wxDbGetConnection() **********/
3438 wxDb WXDLLEXPORT
*wxDbGetConnection(wxDbConnectInf
*pDbConfig
, bool FwdOnlyCursors
)
3442 // Used to keep a pointer to a DB connection that matches the requested
3443 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
3444 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
3445 // rather than having to re-query the datasource to get all the values
3446 // using the wxDb::Open(Dsn,Uid,AuthStr) function
3447 wxDb
*matchingDbConnection
= NULL
;
3449 // Scan the linked list searching for an available database connection
3450 // that's already been opened but is currently not in use.
3451 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3453 // The database connection must be for the same datasource
3454 // name and must currently not be in use.
3456 (pList
->PtrDb
->FwdOnlyCursors() == FwdOnlyCursors
) &&
3457 (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
))) // Found a free connection
3459 pList
->Free
= FALSE
;
3460 return(pList
->PtrDb
);
3463 if (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
) &&
3464 !wxStrcmp(pDbConfig
->GetUserID(), pList
->Uid
) &&
3465 !wxStrcmp(pDbConfig
->GetPassword(), pList
->AuthStr
))
3466 matchingDbConnection
= pList
->PtrDb
;
3469 // No available connections. A new connection must be made and
3470 // appended to the end of the linked list.
3473 // Find the end of the list
3474 for (pList
= PtrBegDbList
; pList
->PtrNext
; pList
= pList
->PtrNext
);
3475 // Append a new list item
3476 pList
->PtrNext
= new wxDbList
;
3477 pList
->PtrNext
->PtrPrev
= pList
;
3478 pList
= pList
->PtrNext
;
3482 // Create the first node on the list
3483 pList
= PtrBegDbList
= new wxDbList
;
3487 // Initialize new node in the linked list
3489 pList
->Free
= FALSE
;
3490 pList
->Dsn
= pDbConfig
->GetDsn(); //glt - will this assignment work?
3491 pList
->Uid
= pDbConfig
->GetUserID();
3492 pList
->AuthStr
= pDbConfig
->GetPassword();
3494 pList
->PtrDb
= new wxDb((HENV
)pDbConfig
->GetHenvAddress(),FwdOnlyCursors
);
3496 bool opened
= FALSE
;
3498 if (!matchingDbConnection
)
3499 opened
= pList
->PtrDb
->Open(pDbConfig
->GetDsn(), pDbConfig
->GetUserID(), pDbConfig
->GetPassword());
3501 opened
= pList
->PtrDb
->Open(matchingDbConnection
);
3503 // Connect to the datasource
3506 pList
->PtrDb
->SetSqlLogging(SQLLOGstate
,SQLLOGfn
,TRUE
);
3507 return(pList
->PtrDb
);
3509 else // Unable to connect, destroy list item
3512 pList
->PtrPrev
->PtrNext
= 0;
3514 PtrBegDbList
= 0; // Empty list again
3515 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
3516 pList
->PtrDb
->Close(); // Close the wxDb object
3517 delete pList
->PtrDb
; // Deletes the wxDb object
3518 delete pList
; // Deletes the linked list object
3522 } // wxDbGetConnection()
3525 /********** wxDbFreeConnection() **********/
3526 bool WXDLLEXPORT
wxDbFreeConnection(wxDb
*pDb
)
3530 // Scan the linked list searching for the database connection
3531 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3533 if (pList
->PtrDb
== pDb
) // Found it, now free it!!!
3534 return (pList
->Free
= TRUE
);
3537 // Never found the database object, return failure
3540 } // wxDbFreeConnection()
3543 /********** wxDbCloseConnections() **********/
3544 void WXDLLEXPORT
wxDbCloseConnections(void)
3546 wxDbList
*pList
, *pNext
;
3548 // Traverse the linked list closing database connections and freeing memory as I go.
3549 for (pList
= PtrBegDbList
; pList
; pList
= pNext
)
3551 pNext
= pList
->PtrNext
; // Save the pointer to next
3552 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
3553 pList
->PtrDb
->Close(); // Close the wxDb object
3554 delete pList
->PtrDb
; // Deletes the wxDb object
3555 delete pList
; // Deletes the linked list object
3558 // Mark the list as empty
3561 } // wxDbCloseConnections()
3564 /********** wxDbConnectionsInUse() **********/
3565 int WXDLLEXPORT
wxDbConnectionsInUse(void)
3570 // Scan the linked list counting db connections that are currently in use
3571 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3573 if (pList
->Free
== FALSE
)
3579 } // wxDbConnectionsInUse()
3582 /********** wxDbSqlLog() **********/
3583 bool wxDbSqlLog(wxDbSqlLogState state
, const wxChar
*filename
)
3585 bool append
= FALSE
;
3588 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
3590 if (!pList
->PtrDb
->SetSqlLogging(state
,filename
,append
))
3595 SQLLOGstate
= state
;
3596 SQLLOGfn
= filename
;
3604 /********** wxDbCreateDataSource() **********/
3605 int wxDbCreateDataSource(const wxString
&driverName
, const wxString
&dsn
, const wxString
&description
,
3606 bool sysDSN
, const wxString
&defDir
, wxWindow
*parent
)
3608 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3609 * Very rudimentary creation of an ODBC data source.
3611 * ODBC driver must be ODBC 3.0 compliant to use this function
3616 //!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3622 dsnLocation
= ODBC_ADD_SYS_DSN
;
3624 dsnLocation
= ODBC_ADD_DSN
;
3626 // NOTE: The decimal 2 is an invalid character in all keyword pairs
3627 // so that is why I used it, as wxString does not deal well with
3628 // embedded nulls in strings
3629 setupStr
.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn
,2,description
,2,defDir
,2);
3631 // Replace the separator from above with the '\0' seperator needed
3632 // by the SQLConfigDataSource() function
3636 k
= setupStr
.Find((wxChar
)2,TRUE
);
3637 if (k
!= wxNOT_FOUND
)
3638 setupStr
[(UINT
)k
] = wxT('\0');
3640 while (k
!= wxNOT_FOUND
);
3642 result
= SQLConfigDataSource((HWND
)parent
->GetHWND(), dsnLocation
,
3643 driverName
, setupStr
.c_str());
3645 if ((result
!= SQL_SUCCESS
) && (result
!= SQL_SUCCESS_WITH_INFO
))
3647 // check for errors caused by ConfigDSN based functions
3650 wxChar errMsg
[SQL_MAX_MESSAGE_LENGTH
];
3651 errMsg
[0] = wxT('\0');
3653 // This function is only supported in ODBC drivers v3.0 compliant and above
3654 SQLInstallerError(1,&retcode
,errMsg
,SQL_MAX_MESSAGE_LENGTH
-1,&cb
);
3657 #ifdef DBDEBUG_CONSOLE
3658 // When run in console mode, use standard out to display errors.
3659 cout
<< errMsg
<< endl
;
3660 cout
<< wxT("Press any key to continue...") << endl
;
3662 #endif // DBDEBUG_CONSOLE
3665 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
3666 #endif // __WXDEBUG__
3672 // Using iODBC/unixODBC or some other compiler which does not support the APIs
3673 // necessary to use this function, so this function is not supported
3675 wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
3678 #endif // __VISUALC__
3682 } // wxDbCreateDataSource()
3686 /********** wxDbGetDataSource() **********/
3687 bool wxDbGetDataSource(HENV henv
, wxChar
*Dsn
, SWORD DsnMax
, wxChar
*DsDesc
,
3688 SWORD DsDescMax
, UWORD direction
)
3690 * Dsn and DsDesc will contain the data source name and data source
3691 * description upon return
3696 if (SQLDataSources(henv
, direction
, (UCHAR FAR
*) Dsn
, DsnMax
, &cb1
,
3697 (UCHAR FAR
*) DsDesc
, DsDescMax
, &cb2
) == SQL_SUCCESS
)
3702 } // wxDbGetDataSource()
3705 // Change this to 0 to remove use of all deprecated functions
3706 #if wxODBC_BACKWARD_COMPATABILITY
3707 /********************************************************************
3708 ********************************************************************
3710 * The following functions are all DEPRECATED and are included for
3711 * backward compatability reasons only
3713 ********************************************************************
3714 ********************************************************************/
3715 bool SqlLog(sqlLog state
, const wxChar
*filename
)
3717 return wxDbSqlLog((enum wxDbSqlLogState
)state
, filename
);
3719 /***** DEPRECATED: use wxGetDataSource() *****/
3720 bool GetDataSource(HENV henv
, char *Dsn
, SWORD DsnMax
, char *DsDesc
, SWORD DsDescMax
,
3723 return wxDbGetDataSource(henv
, Dsn
, DsnMax
, DsDesc
, DsDescMax
, direction
);
3725 /***** DEPRECATED: use wxDbGetConnection() *****/
3726 wxDb WXDLLEXPORT
*GetDbConnection(DbStuff
*pDbStuff
, bool FwdOnlyCursors
)
3728 return wxDbGetConnection((wxDbConnectInf
*)pDbStuff
, FwdOnlyCursors
);
3730 /***** DEPRECATED: use wxDbFreeConnection() *****/
3731 bool WXDLLEXPORT
FreeDbConnection(wxDb
*pDb
)
3733 return wxDbFreeConnection(pDb
);
3735 /***** DEPRECATED: use wxDbCloseConnections() *****/
3736 void WXDLLEXPORT
CloseDbConnections(void)
3738 wxDbCloseConnections();
3740 /***** DEPRECATED: use wxDbConnectionsInUse() *****/
3741 int WXDLLEXPORT
NumberDbConnectionsInUse(void)
3743 return wxDbConnectionsInUse();