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
22 ///////////////////////////////////////////////////////////////////////////////
29 #include "wx/wxprec.h"
35 #ifdef DBDEBUG_CONSOLE
36 #include "wx/ioswrap.h"
40 #include "wx/string.h"
41 #include "wx/object.h"
46 #include "wx/filefn.h"
47 #include "wx/wxchar.h"
59 // DLL options compatibility check:
61 WX_CHECK_BUILD_OPTIONS("wxODBC")
63 WXDLLIMPEXP_DATA_ODBC(wxDbList
*) PtrBegDbList
= 0;
65 wxChar
const *SQL_LOG_FILENAME
= wxT("sqllog.txt");
66 wxChar
const *SQL_CATALOG_FILENAME
= wxT("catalog.txt");
69 extern wxList TablesInUse
;
72 // SQL Log defaults to be used by GetDbConnection
73 wxDbSqlLogState SQLLOGstate
= sqlLogOFF
;
75 static wxString SQLLOGfn
= SQL_LOG_FILENAME
;
77 // The wxDb::errorList is copied to this variable when the wxDb object
78 // is closed. This way, the error list is still available after the
79 // database object is closed. This is necessary if the database
80 // connection fails so the calling application can show the operator
81 // why the connection failed. Note: as each wxDb object is closed, it
82 // will overwrite the errors of the previously destroyed wxDb object in
83 // this variable. NOTE: This occurs during a CLOSE, not a FREEing of the
85 wxChar DBerrorList
[DB_MAX_ERROR_HISTORY
][DB_MAX_ERROR_MSG_LEN
+1];
88 // This type defines the return row-struct form
89 // SQLTablePrivileges, and is used by wxDB::TablePrivileges.
92 wxChar tableQual
[128+1];
93 wxChar tableOwner
[128+1];
94 wxChar tableName
[128+1];
95 wxChar grantor
[128+1];
96 wxChar grantee
[128+1];
97 wxChar privilege
[128+1];
98 wxChar grantable
[3+1];
99 } wxDbTablePrivilegeInfo
;
102 /********** wxDbConnectInf Constructor - form 1 **********/
103 wxDbConnectInf::wxDbConnectInf()
106 freeHenvOnDestroy
= false;
112 /********** wxDbConnectInf Constructor - form 2 **********/
113 wxDbConnectInf::wxDbConnectInf(HENV henv
, const wxString
&dsn
, const wxString
&userID
,
114 const wxString
&password
, const wxString
&defaultDir
,
115 const wxString
&fileType
, const wxString
&description
)
118 freeHenvOnDestroy
= false;
129 SetPassword(password
);
130 SetDescription(description
);
131 SetFileType(fileType
);
132 SetDefaultDir(defaultDir
);
133 } // wxDbConnectInf Constructor
136 wxDbConnectInf::~wxDbConnectInf()
138 if (freeHenvOnDestroy
)
142 } // wxDbConnectInf Destructor
146 /********** wxDbConnectInf::Initialize() **********/
147 bool wxDbConnectInf::Initialize()
149 freeHenvOnDestroy
= false;
151 if (freeHenvOnDestroy
&& Henv
)
158 ConnectionStr
[0] = 0;
163 useConnectionStr
= false;
166 } // wxDbConnectInf::Initialize()
169 /********** wxDbConnectInf::AllocHenv() **********/
170 bool wxDbConnectInf::AllocHenv()
172 // This is here to help trap if you are getting a new henv
173 // without releasing an existing henv
176 // Initialize the ODBC Environment for Database Operations
177 if (SQLAllocEnv(&Henv
) != SQL_SUCCESS
)
179 wxLogDebug(wxT("A problem occurred while trying to get a connection to the data source"));
183 freeHenvOnDestroy
= true;
186 } // wxDbConnectInf::AllocHenv()
189 void wxDbConnectInf::FreeHenv()
197 freeHenvOnDestroy
= false;
199 } // wxDbConnectInf::FreeHenv()
202 void wxDbConnectInf::SetDsn(const wxString
&dsn
)
204 wxASSERT(dsn
.Length() < sizeof(Dsn
));
206 wxStrncpy(Dsn
, dsn
, sizeof(Dsn
)-1);
207 Dsn
[sizeof(Dsn
)-1] = 0; // Prevent buffer overrun
208 } // wxDbConnectInf::SetDsn()
211 void wxDbConnectInf::SetUserID(const wxString
&uid
)
213 wxASSERT(uid
.Length() < sizeof(Uid
));
214 wxStrncpy(Uid
, uid
, sizeof(Uid
)-1);
215 Uid
[sizeof(Uid
)-1] = 0; // Prevent buffer overrun
216 } // wxDbConnectInf::SetUserID()
219 void wxDbConnectInf::SetPassword(const wxString
&password
)
221 wxASSERT(password
.Length() < sizeof(AuthStr
));
223 wxStrncpy(AuthStr
, password
, sizeof(AuthStr
)-1);
224 AuthStr
[sizeof(AuthStr
)-1] = 0; // Prevent buffer overrun
225 } // wxDbConnectInf::SetPassword()
227 void wxDbConnectInf::SetConnectionStr(const wxString
&connectStr
)
229 wxASSERT(connectStr
.Length() < sizeof(ConnectionStr
));
231 useConnectionStr
= wxStrlen(connectStr
) > 0;
233 wxStrncpy(ConnectionStr
, connectStr
, sizeof(ConnectionStr
)-1);
234 ConnectionStr
[sizeof(ConnectionStr
)-1] = 0; // Prevent buffer overrun
235 } // wxDbConnectInf::SetConnectionStr()
238 /********** wxDbColFor Constructor **********/
239 wxDbColFor::wxDbColFor()
242 } // wxDbColFor::wxDbColFor()
245 /********** wxDbColFor::Initialize() **********/
246 void wxDbColFor::Initialize()
256 i_Nation
= 0; // 0=EU, 1=UK, 2=International, 3=US
259 Format(1,DB_DATA_TYPE_VARCHAR
,0,0,0); // the Function that does the work
260 } // wxDbColFor::Initialize()
263 /********** wxDbColFor::Format() **********/
264 int wxDbColFor::Format(int Nation
, int dbDataType
, SWORD sqlDataType
,
265 short columnLength
, short decimalDigits
)
267 // ----------------------------------------------------------------------------------------
268 // -- 19991224 : mj10777 : Create
269 // There is still a lot of work to do here, but it is a start
270 // It handles all the basic data-types that I have run into up to now
271 // The main work will have be with Dates and float Formatting
272 // (US 1,000.00 ; EU 1.000,00)
273 // There are wxWindow plans for locale support and the new wxDateTime. If
274 // they define some constants (wxEUROPEAN) that can be gloably used,
275 // they should be used here.
276 // ----------------------------------------------------------------------------------------
277 // There should also be a function to scan in a string to fill the variable
278 // ----------------------------------------------------------------------------------------
280 i_Nation
= Nation
; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
281 i_dbDataType
= dbDataType
;
282 i_sqlDataType
= sqlDataType
;
283 s_Field
.Printf(wxT("%s%d"),s_Amount
[1].c_str(),i_Amount
[1]); // OK for VARCHAR, INTEGER and FLOAT
285 if (i_dbDataType
== 0) // Filter unsupported dbDataTypes
287 if ((i_sqlDataType
== SQL_VARCHAR
)
289 #if defined(SQL_WCHAR)
290 || (i_sqlDataType
== SQL_WCHAR
)
292 #if defined(SQL_WVARCHAR)
293 || (i_sqlDataType
== SQL_WVARCHAR
)
296 || (i_sqlDataType
== SQL_LONGVARCHAR
))
297 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
298 if ((i_sqlDataType
== SQL_C_DATE
) || (i_sqlDataType
== SQL_C_TIMESTAMP
))
299 i_dbDataType
= DB_DATA_TYPE_DATE
;
300 if (i_sqlDataType
== SQL_C_BIT
)
301 i_dbDataType
= DB_DATA_TYPE_INTEGER
;
302 if (i_sqlDataType
== SQL_NUMERIC
)
303 i_dbDataType
= DB_DATA_TYPE_VARCHAR
; // glt - ??? is this right?
304 if (i_sqlDataType
== SQL_REAL
)
305 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
306 if (i_sqlDataType
== SQL_C_BINARY
)
307 i_dbDataType
= DB_DATA_TYPE_BLOB
;
310 if ((i_dbDataType
== DB_DATA_TYPE_INTEGER
) && (i_sqlDataType
== SQL_C_DOUBLE
))
312 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
315 switch(i_dbDataType
) // TBD: Still a lot of proper formatting to do
317 case DB_DATA_TYPE_VARCHAR
:
320 case DB_DATA_TYPE_INTEGER
:
323 case DB_DATA_TYPE_FLOAT
:
324 if (decimalDigits
== 0)
326 tempStr
.Printf(wxT("%%%d.%d"), columnLength
, decimalDigits
);
327 s_Field
.Printf(wxT("%sf"), tempStr
.c_str());
329 case DB_DATA_TYPE_DATE
:
330 if (i_Nation
== 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
332 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
334 if (i_Nation
== 1) // European DD.MM.YYYY HH:MM:SS.SSS
336 s_Field
= wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d");
338 if (i_Nation
== 2) // UK DD/MM/YYYY HH:MM:SS.SSS
340 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
342 if (i_Nation
== 3) // International YYYY-MM-DD HH:MM:SS.SSS
344 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
346 if (i_Nation
== 4) // US MM/DD/YYYY HH:MM:SS.SSS
348 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
351 case DB_DATA_TYPE_BLOB
:
352 s_Field
.Printf(wxT("Unable to format(%d)-SQL(%d)"), dbDataType
,sqlDataType
); //
355 s_Field
.Printf(wxT("Unknown Format(%d)-SQL(%d)"), dbDataType
,sqlDataType
); //
359 } // wxDbColFor::Format()
362 /********** wxDbColInf Constructor **********/
363 wxDbColInf::wxDbColInf()
366 } // wxDbColInf::wxDbColInf()
369 /********** wxDbColInf Destructor ********/
370 wxDbColInf::~wxDbColInf()
375 } // wxDbColInf::~wxDbColInf()
378 bool wxDbColInf::Initialize()
400 } // wxDbColInf::Initialize()
403 /********** wxDbTableInf Constructor ********/
404 wxDbTableInf::wxDbTableInf()
407 } // wxDbTableInf::wxDbTableInf()
410 /********** wxDbTableInf Constructor ********/
411 wxDbTableInf::~wxDbTableInf()
416 } // wxDbTableInf::~wxDbTableInf()
419 bool wxDbTableInf::Initialize()
428 } // wxDbTableInf::Initialize()
431 /********** wxDbInf Constructor *************/
435 } // wxDbInf::wxDbInf()
438 /********** wxDbInf Destructor *************/
444 } // wxDbInf::~wxDbInf()
447 /********** wxDbInf::Initialize() *************/
448 bool wxDbInf::Initialize()
456 } // wxDbInf::Initialize()
459 /********** wxDb Constructor **********/
460 wxDb::wxDb(const HENV
&aHenv
, bool FwdOnlyCursors
)
462 // Copy the HENV into the db class
464 fwdOnlyCursors
= FwdOnlyCursors
;
470 /********** wxDb Destructor **********/
473 wxASSERT_MSG(!IsCached(),wxT("Cached connections must not be manually deleted, use\nwxDbFreeConnection() or wxDbCloseConnections()."));
483 /********** PRIVATE! wxDb::initialize PRIVATE! **********/
484 /********** wxDb::initialize() **********/
485 void wxDb::initialize()
487 * Private member function that sets all wxDb member variables to
488 * known values at creation of the wxDb
493 fpSqlLog
= 0; // Sql Log file pointer
494 sqlLogState
= sqlLogOFF
; // By default, logging is turned off
496 dbmsType
= dbmsUNIDENTIFIED
;
498 wxStrcpy(sqlState
,wxEmptyString
);
499 wxStrcpy(errorMsg
,wxEmptyString
);
500 nativeError
= cbErrorMsg
= 0;
501 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
502 wxStrcpy(errorList
[i
], wxEmptyString
);
504 // Init typeInf structures
505 typeInfVarchar
.TypeName
.Empty();
506 typeInfVarchar
.FsqlType
= 0;
507 typeInfVarchar
.Precision
= 0;
508 typeInfVarchar
.CaseSensitive
= 0;
509 typeInfVarchar
.MaximumScale
= 0;
511 typeInfInteger
.TypeName
.Empty();
512 typeInfInteger
.FsqlType
= 0;
513 typeInfInteger
.Precision
= 0;
514 typeInfInteger
.CaseSensitive
= 0;
515 typeInfInteger
.MaximumScale
= 0;
517 typeInfFloat
.TypeName
.Empty();
518 typeInfFloat
.FsqlType
= 0;
519 typeInfFloat
.Precision
= 0;
520 typeInfFloat
.CaseSensitive
= 0;
521 typeInfFloat
.MaximumScale
= 0;
523 typeInfDate
.TypeName
.Empty();
524 typeInfDate
.FsqlType
= 0;
525 typeInfDate
.Precision
= 0;
526 typeInfDate
.CaseSensitive
= 0;
527 typeInfDate
.MaximumScale
= 0;
529 typeInfBlob
.TypeName
.Empty();
530 typeInfBlob
.FsqlType
= 0;
531 typeInfBlob
.Precision
= 0;
532 typeInfBlob
.CaseSensitive
= 0;
533 typeInfBlob
.MaximumScale
= 0;
535 // Error reporting is turned OFF by default
538 // Allocate a data source connection handle
539 if (SQLAllocConnect(henv
, &hdbc
) != SQL_SUCCESS
)
542 // Initialize the db status flag
545 // Mark database as not open as of yet
548 dbOpenedWithConnectionString
= false;
549 } // wxDb::initialize()
552 /********** PRIVATE! wxDb::convertUserID PRIVATE! **********/
554 // NOTE: Return value from this function MUST be copied
555 // immediately, as the value is not good after
556 // this function has left scope.
558 const wxChar
*wxDb::convertUserID(const wxChar
*userID
, wxString
&UserID
)
562 if (!wxStrlen(userID
))
570 // dBase does not use user names, and some drivers fail if you try to pass one
571 if ( Dbms() == dbmsDBASE
572 || Dbms() == dbmsXBASE_SEQUITER
)
575 // Some databases require user names to be specified in uppercase,
576 // so force the name to uppercase
577 if ((Dbms() == dbmsORACLE
) ||
578 (Dbms() == dbmsMAXDB
))
579 UserID
= UserID
.Upper();
581 return UserID
.c_str();
582 } // wxDb::convertUserID()
585 bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported
)
589 // These are the possible SQL types we check for use against the datasource we are connected
590 // to for the purpose of determining which data type to use for the basic character strings
593 // NOTE: The first type in this enumeration that is determined to be supported by the
594 // datasource/driver is the one that will be used.
595 SWORD PossibleSqlCharTypes
[] = {
596 #if wxUSE_UNICODE && defined(SQL_WVARCHAR)
600 #if wxUSE_UNICODE && defined(SQL_WVARCHAR)
606 // These are the possible SQL types we check for use against the datasource we are connected
607 // to for the purpose of determining which data type to use for the basic non-floating point
610 // NOTE: The first type in this enumeration that is determined to be supported by the
611 // datasource/driver is the one that will be used.
612 SWORD PossibleSqlIntegerTypes
[] = {
616 // These are the possible SQL types we check for use against the datasource we are connected
617 // to for the purpose of determining which data type to use for the basic floating point number
620 // NOTE: The first type in this enumeration that is determined to be supported by the
621 // datasource/driver is the one that will be used.
622 SWORD PossibleSqlFloatTypes
[] = {
630 // These are the possible SQL types we check for use agains the datasource we are connected
631 // to for the purpose of determining which data type to use for the date/time column types
633 // NOTE: The first type in this enumeration that is determined to be supported by the
634 // datasource/driver is the one that will be used.
635 SWORD PossibleSqlDateTypes
[] = {
643 // These are the possible SQL types we check for use agains the datasource we are connected
644 // to for the purpose of determining which data type to use for the BLOB column types.
646 // NOTE: The first type in this enumeration that is determined to be supported by the
647 // datasource/driver is the one that will be used.
648 SWORD PossibleSqlBlobTypes
[] = {
654 // Query the data source regarding data type information
657 // The way it was determined which SQL data types to use was by calling SQLGetInfo
658 // for all of the possible SQL data types to see which ones were supported. If
659 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
660 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
661 // types I've selected below will not always be what we want. These are just
662 // what happened to work against an Oracle 7/Intersolv combination. The following is
663 // a complete list of the results I got back against the Oracle 7 database:
665 // SQL_BIGINT SQL_NO_DATA_FOUND
666 // SQL_BINARY SQL_NO_DATA_FOUND
667 // SQL_BIT SQL_NO_DATA_FOUND
668 // SQL_CHAR type name = 'CHAR', Precision = 255
669 // SQL_DATE SQL_NO_DATA_FOUND
670 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
671 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
672 // SQL_FLOAT SQL_NO_DATA_FOUND
673 // SQL_INTEGER SQL_NO_DATA_FOUND
674 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
675 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
676 // SQL_NUMERIC SQL_NO_DATA_FOUND
677 // SQL_REAL SQL_NO_DATA_FOUND
678 // SQL_SMALLINT SQL_NO_DATA_FOUND
679 // SQL_TIME SQL_NO_DATA_FOUND
680 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
681 // SQL_VARBINARY type name = 'RAW', Precision = 255
682 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
683 // =====================================================================
684 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
686 // SQL_VARCHAR type name = 'TEXT', Precision = 255
687 // SQL_TIMESTAMP type name = 'DATETIME'
688 // SQL_DECIMAL SQL_NO_DATA_FOUND
689 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
690 // SQL_FLOAT SQL_NO_DATA_FOUND
691 // SQL_REAL type name = 'SINGLE', Precision = 7
692 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
693 // SQL_INTEGER type name = 'LONG', Precision = 10
695 // Query the data source for info about itself
696 if (!getDbInfo(failOnDataTypeUnsupported
))
699 // --------------- Varchar - (Variable length character string) ---------------
700 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlCharTypes
) &&
701 !getDataTypeInfo(PossibleSqlCharTypes
[iIndex
], typeInfVarchar
); ++iIndex
)
704 if (iIndex
< WXSIZEOF(PossibleSqlCharTypes
))
705 typeInfVarchar
.FsqlType
= PossibleSqlCharTypes
[iIndex
];
706 else if (failOnDataTypeUnsupported
)
709 // --------------- Float ---------------
710 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlFloatTypes
) &&
711 !getDataTypeInfo(PossibleSqlFloatTypes
[iIndex
], typeInfFloat
); ++iIndex
)
714 if (iIndex
< WXSIZEOF(PossibleSqlFloatTypes
))
715 typeInfFloat
.FsqlType
= PossibleSqlFloatTypes
[iIndex
];
716 else if (failOnDataTypeUnsupported
)
719 // --------------- Integer -------------
720 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlIntegerTypes
) &&
721 !getDataTypeInfo(PossibleSqlIntegerTypes
[iIndex
], typeInfInteger
); ++iIndex
)
724 if (iIndex
< WXSIZEOF(PossibleSqlIntegerTypes
))
725 typeInfInteger
.FsqlType
= PossibleSqlIntegerTypes
[iIndex
];
726 else if (failOnDataTypeUnsupported
)
728 // If no non-floating point data types are supported, we'll
729 // use the type assigned for floats to store integers as well
730 if (!getDataTypeInfo(typeInfFloat
.FsqlType
, typeInfInteger
))
732 if (failOnDataTypeUnsupported
)
736 typeInfInteger
.FsqlType
= typeInfFloat
.FsqlType
;
739 // --------------- Date/Time ---------------
740 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlDateTypes
) &&
741 !getDataTypeInfo(PossibleSqlDateTypes
[iIndex
], typeInfDate
); ++iIndex
)
744 if (iIndex
< WXSIZEOF(PossibleSqlDateTypes
))
745 typeInfDate
.FsqlType
= PossibleSqlDateTypes
[iIndex
];
746 else if (failOnDataTypeUnsupported
)
749 // --------------- BLOB ---------------
750 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlBlobTypes
) &&
751 !getDataTypeInfo(PossibleSqlBlobTypes
[iIndex
], typeInfBlob
); ++iIndex
)
754 if (iIndex
< WXSIZEOF(PossibleSqlBlobTypes
))
755 typeInfBlob
.FsqlType
= PossibleSqlBlobTypes
[iIndex
];
756 else if (failOnDataTypeUnsupported
)
760 } // wxDb::determineDataTypes
763 bool wxDb::open(bool failOnDataTypeUnsupported
)
766 If using Intersolv branded ODBC drivers, this is the place where you would substitute
767 your branded driver license information
769 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
770 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
773 // Mark database as open
776 // Allocate a statement handle for the database connection
777 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
778 return(DispAllErrors(henv
, hdbc
));
780 // Set Connection Options
781 if (!setConnectionOptions())
784 if (!determineDataTypes(failOnDataTypeUnsupported
))
787 #ifdef DBDEBUG_CONSOLE
788 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
789 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
790 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
791 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
792 cout
<< wxT("BLOB DATA TYPE: ") << typeInfBlob
.TypeName
<< endl
;
796 // Completed Successfully
800 bool wxDb::Open(const wxString
& inConnectStr
, bool failOnDataTypeUnsupported
)
802 wxASSERT(inConnectStr
.Length());
803 return Open(inConnectStr
, NULL
, failOnDataTypeUnsupported
);
806 bool wxDb::Open(const wxString
& inConnectStr
, SQLHWND parentWnd
, bool failOnDataTypeUnsupported
)
814 if (!FwdOnlyCursors())
816 // Specify that the ODBC cursor library be used, if needed. This must be
817 // specified before the connection is made.
818 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
820 #ifdef DBDEBUG_CONSOLE
821 if (retcode
== SQL_SUCCESS
)
822 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
824 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
826 wxUnusedVar(retcode
);
830 // Connect to the data source
831 SQLTCHAR outConnectBuffer
[SQL_MAX_CONNECTSTR_LEN
+1]; // MS recommends at least 1k buffer
832 short outConnectBufferLen
;
834 inConnectionStr
= inConnectStr
;
836 retcode
= SQLDriverConnect(hdbc
, parentWnd
, (SQLTCHAR FAR
*)inConnectionStr
.c_str(),
837 (SWORD
)inConnectionStr
.Length(), (SQLTCHAR FAR
*)outConnectBuffer
,
838 sizeof(outConnectBuffer
), &outConnectBufferLen
, SQL_DRIVER_COMPLETE
);
840 if ((retcode
!= SQL_SUCCESS
) &&
841 (retcode
!= SQL_SUCCESS_WITH_INFO
))
842 return(DispAllErrors(henv
, hdbc
));
844 outConnectBuffer
[outConnectBufferLen
] = 0;
845 outConnectionStr
= outConnectBuffer
;
846 dbOpenedWithConnectionString
= true;
848 return open(failOnDataTypeUnsupported
);
851 /********** wxDb::Open() **********/
852 bool wxDb::Open(const wxString
&Dsn
, const wxString
&Uid
, const wxString
&AuthStr
, bool failOnDataTypeUnsupported
)
854 wxASSERT(Dsn
.Length());
859 inConnectionStr
= wxT("");
860 outConnectionStr
= wxT("");
864 if (!FwdOnlyCursors())
866 // Specify that the ODBC cursor library be used, if needed. This must be
867 // specified before the connection is made.
868 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
870 #ifdef DBDEBUG_CONSOLE
871 if (retcode
== SQL_SUCCESS
)
872 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
874 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
876 wxUnusedVar( retcode
);
880 // Connect to the data source
881 retcode
= SQLConnect(hdbc
, (SQLTCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
882 (SQLTCHAR FAR
*) uid
.c_str(), SQL_NTS
,
883 (SQLTCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
885 if ((retcode
!= SQL_SUCCESS
) &&
886 (retcode
!= SQL_SUCCESS_WITH_INFO
))
887 return(DispAllErrors(henv
, hdbc
));
889 return open(failOnDataTypeUnsupported
);
894 bool wxDb::Open(wxDbConnectInf
*dbConnectInf
, bool failOnDataTypeUnsupported
)
896 wxASSERT(dbConnectInf
);
898 // Use the connection string if one is present
899 if (dbConnectInf
->UseConnectionStr())
900 return Open(GetConnectionInStr(), failOnDataTypeUnsupported
);
902 return Open(dbConnectInf
->GetDsn(), dbConnectInf
->GetUserID(),
903 dbConnectInf
->GetPassword(), failOnDataTypeUnsupported
);
907 bool wxDb::Open(wxDb
*copyDb
)
909 dsn
= copyDb
->GetDatasourceName();
910 uid
= copyDb
->GetUsername();
911 authStr
= copyDb
->GetPassword();
912 inConnectionStr
= copyDb
->GetConnectionInStr();
913 outConnectionStr
= copyDb
->GetConnectionOutStr();
917 if (!FwdOnlyCursors())
919 // Specify that the ODBC cursor library be used, if needed. This must be
920 // specified before the connection is made.
921 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
923 #ifdef DBDEBUG_CONSOLE
924 if (retcode
== SQL_SUCCESS
)
925 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
927 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
929 wxUnusedVar( retcode
);
933 if (copyDb
->OpenedWithConnectionString())
935 // Connect to the data source
936 SQLTCHAR outConnectBuffer
[SQL_MAX_CONNECTSTR_LEN
+1];
937 short outConnectBufferLen
;
939 inConnectionStr
= copyDb
->GetConnectionInStr();
941 retcode
= SQLDriverConnect(hdbc
, NULL
, (SQLTCHAR FAR
*)inConnectionStr
.c_str(),
942 (SWORD
)inConnectionStr
.Length(), (SQLTCHAR FAR
*)outConnectBuffer
,
943 sizeof(outConnectBuffer
), &outConnectBufferLen
, SQL_DRIVER_COMPLETE
);
945 if ((retcode
!= SQL_SUCCESS
) &&
946 (retcode
!= SQL_SUCCESS_WITH_INFO
))
947 return(DispAllErrors(henv
, hdbc
));
949 outConnectBuffer
[outConnectBufferLen
] = 0;
950 outConnectionStr
= outConnectBuffer
;
951 dbOpenedWithConnectionString
= true;
955 // Connect to the data source
956 retcode
= SQLConnect(hdbc
, (SQLTCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
957 (SQLTCHAR FAR
*) uid
.c_str(), SQL_NTS
,
958 (SQLTCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
961 if ((retcode
!= SQL_SUCCESS
) &&
962 (retcode
!= SQL_SUCCESS_WITH_INFO
))
963 return(DispAllErrors(henv
, hdbc
));
966 If using Intersolv branded ODBC drivers, this is the place where you would substitute
967 your branded driver license information
969 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
970 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
973 // Mark database as open
976 // Allocate a statement handle for the database connection
977 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
978 return(DispAllErrors(henv
, hdbc
));
980 // Set Connection Options
981 if (!setConnectionOptions())
984 // Instead of Querying the data source for info about itself, it can just be copied
985 // from the wxDb instance that was passed in (copyDb).
986 wxStrcpy(dbInf
.serverName
,copyDb
->dbInf
.serverName
);
987 wxStrcpy(dbInf
.databaseName
,copyDb
->dbInf
.databaseName
);
988 wxStrcpy(dbInf
.dbmsName
,copyDb
->dbInf
.dbmsName
);
989 wxStrcpy(dbInf
.dbmsVer
,copyDb
->dbInf
.dbmsVer
);
990 dbInf
.maxConnections
= copyDb
->dbInf
.maxConnections
;
991 dbInf
.maxStmts
= copyDb
->dbInf
.maxStmts
;
992 wxStrcpy(dbInf
.driverName
,copyDb
->dbInf
.driverName
);
993 wxStrcpy(dbInf
.odbcVer
,copyDb
->dbInf
.odbcVer
);
994 wxStrcpy(dbInf
.drvMgrOdbcVer
,copyDb
->dbInf
.drvMgrOdbcVer
);
995 wxStrcpy(dbInf
.driverVer
,copyDb
->dbInf
.driverVer
);
996 dbInf
.apiConfLvl
= copyDb
->dbInf
.apiConfLvl
;
997 dbInf
.cliConfLvl
= copyDb
->dbInf
.cliConfLvl
;
998 dbInf
.sqlConfLvl
= copyDb
->dbInf
.sqlConfLvl
;
999 wxStrcpy(dbInf
.outerJoins
,copyDb
->dbInf
.outerJoins
);
1000 wxStrcpy(dbInf
.procedureSupport
,copyDb
->dbInf
.procedureSupport
);
1001 wxStrcpy(dbInf
.accessibleTables
,copyDb
->dbInf
.accessibleTables
);
1002 dbInf
.cursorCommitBehavior
= copyDb
->dbInf
.cursorCommitBehavior
;
1003 dbInf
.cursorRollbackBehavior
= copyDb
->dbInf
.cursorRollbackBehavior
;
1004 dbInf
.supportNotNullClause
= copyDb
->dbInf
.supportNotNullClause
;
1005 wxStrcpy(dbInf
.supportIEF
,copyDb
->dbInf
.supportIEF
);
1006 dbInf
.txnIsolation
= copyDb
->dbInf
.txnIsolation
;
1007 dbInf
.txnIsolationOptions
= copyDb
->dbInf
.txnIsolationOptions
;
1008 dbInf
.fetchDirections
= copyDb
->dbInf
.fetchDirections
;
1009 dbInf
.lockTypes
= copyDb
->dbInf
.lockTypes
;
1010 dbInf
.posOperations
= copyDb
->dbInf
.posOperations
;
1011 dbInf
.posStmts
= copyDb
->dbInf
.posStmts
;
1012 dbInf
.scrollConcurrency
= copyDb
->dbInf
.scrollConcurrency
;
1013 dbInf
.scrollOptions
= copyDb
->dbInf
.scrollOptions
;
1014 dbInf
.staticSensitivity
= copyDb
->dbInf
.staticSensitivity
;
1015 dbInf
.txnCapable
= copyDb
->dbInf
.txnCapable
;
1016 dbInf
.loginTimeout
= copyDb
->dbInf
.loginTimeout
;
1018 // VARCHAR = Variable length character string
1019 typeInfVarchar
.FsqlType
= copyDb
->typeInfVarchar
.FsqlType
;
1020 typeInfVarchar
.TypeName
= copyDb
->typeInfVarchar
.TypeName
;
1021 typeInfVarchar
.Precision
= copyDb
->typeInfVarchar
.Precision
;
1022 typeInfVarchar
.CaseSensitive
= copyDb
->typeInfVarchar
.CaseSensitive
;
1023 typeInfVarchar
.MaximumScale
= copyDb
->typeInfVarchar
.MaximumScale
;
1026 typeInfFloat
.FsqlType
= copyDb
->typeInfFloat
.FsqlType
;
1027 typeInfFloat
.TypeName
= copyDb
->typeInfFloat
.TypeName
;
1028 typeInfFloat
.Precision
= copyDb
->typeInfFloat
.Precision
;
1029 typeInfFloat
.CaseSensitive
= copyDb
->typeInfFloat
.CaseSensitive
;
1030 typeInfFloat
.MaximumScale
= copyDb
->typeInfFloat
.MaximumScale
;
1033 typeInfInteger
.FsqlType
= copyDb
->typeInfInteger
.FsqlType
;
1034 typeInfInteger
.TypeName
= copyDb
->typeInfInteger
.TypeName
;
1035 typeInfInteger
.Precision
= copyDb
->typeInfInteger
.Precision
;
1036 typeInfInteger
.CaseSensitive
= copyDb
->typeInfInteger
.CaseSensitive
;
1037 typeInfInteger
.MaximumScale
= copyDb
->typeInfInteger
.MaximumScale
;
1040 typeInfDate
.FsqlType
= copyDb
->typeInfDate
.FsqlType
;
1041 typeInfDate
.TypeName
= copyDb
->typeInfDate
.TypeName
;
1042 typeInfDate
.Precision
= copyDb
->typeInfDate
.Precision
;
1043 typeInfDate
.CaseSensitive
= copyDb
->typeInfDate
.CaseSensitive
;
1044 typeInfDate
.MaximumScale
= copyDb
->typeInfDate
.MaximumScale
;
1047 typeInfBlob
.FsqlType
= copyDb
->typeInfBlob
.FsqlType
;
1048 typeInfBlob
.TypeName
= copyDb
->typeInfBlob
.TypeName
;
1049 typeInfBlob
.Precision
= copyDb
->typeInfBlob
.Precision
;
1050 typeInfBlob
.CaseSensitive
= copyDb
->typeInfBlob
.CaseSensitive
;
1051 typeInfBlob
.MaximumScale
= copyDb
->typeInfBlob
.MaximumScale
;
1053 #ifdef DBDEBUG_CONSOLE
1054 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
1055 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
1056 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
1057 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
1058 cout
<< wxT("BLOB DATA TYPE: ") << typeInfBlob
.TypeName
<< endl
;
1062 // Completed Successfully
1067 /********** wxDb::setConnectionOptions() **********/
1068 bool wxDb::setConnectionOptions(void)
1070 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
1075 // I need to get the DBMS name here, because some of the connection options
1076 // are database specific and need to call the Dbms() function.
1079 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, sizeof(dbInf
.dbmsName
), &cb
);
1080 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1081 return(DispAllErrors(henv
, hdbc
));
1083 /* retcode = */ SQLSetConnectOption(hdbc
, SQL_AUTOCOMMIT
, SQL_AUTOCOMMIT_OFF
);
1084 /* retcode = */ SQLSetConnectOption(hdbc
, SQL_OPT_TRACE
, SQL_OPT_TRACE_OFF
);
1085 // SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads
1087 // By default, MS Sql Server closes cursors on commit and rollback. The following
1088 // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors
1089 // after a transaction. This is a driver specific option and is not part of the
1090 // ODBC standard. Note: this behavior is specific to the ODBC interface to SQL Server.
1091 // The database settings don't have any effect one way or the other.
1092 if (Dbms() == dbmsMS_SQL_SERVER
)
1094 const long SQL_PRESERVE_CURSORS
= 1204L;
1095 const long SQL_PC_ON
= 1L;
1096 /* retcode = */ SQLSetConnectOption(hdbc
, SQL_PRESERVE_CURSORS
, SQL_PC_ON
);
1099 // Display the connection options to verify them
1100 #ifdef DBDEBUG_CONSOLE
1102 cout
<< wxT("****** CONNECTION OPTIONS ******") << endl
;
1104 retcode
= SQLGetConnectOption(hdbc
, SQL_AUTOCOMMIT
, &l
);
1105 if (retcode
!= SQL_SUCCESS
)
1106 return(DispAllErrors(henv
, hdbc
));
1107 cout
<< wxT("AUTOCOMMIT: ") << (l
== SQL_AUTOCOMMIT_OFF
? "OFF" : "ON") << endl
;
1109 retcode
= SQLGetConnectOption(hdbc
, SQL_ODBC_CURSORS
, &l
);
1110 if (retcode
!= SQL_SUCCESS
)
1111 return(DispAllErrors(henv
, hdbc
));
1112 cout
<< wxT("ODBC CURSORS: ");
1115 case(SQL_CUR_USE_IF_NEEDED
):
1116 cout
<< wxT("SQL_CUR_USE_IF_NEEDED");
1118 case(SQL_CUR_USE_ODBC
):
1119 cout
<< wxT("SQL_CUR_USE_ODBC");
1121 case(SQL_CUR_USE_DRIVER
):
1122 cout
<< wxT("SQL_CUR_USE_DRIVER");
1127 retcode
= SQLGetConnectOption(hdbc
, SQL_OPT_TRACE
, &l
)
1128 if (retcode
!= SQL_SUCCESS
)
1129 return(DispAllErrors(henv
, hdbc
));
1130 cout
<< wxT("TRACING: ") << (l
== SQL_OPT_TRACE_OFF
? wxT("OFF") : wxT("ON")) << endl
;
1135 // Completed Successfully
1138 } // wxDb::setConnectionOptions()
1141 /********** wxDb::getDbInfo() **********/
1142 bool wxDb::getDbInfo(bool failOnDataTypeUnsupported
)
1147 retcode
= SQLGetInfo(hdbc
, SQL_SERVER_NAME
, (UCHAR
*) dbInf
.serverName
, sizeof(dbInf
.serverName
), &cb
);
1148 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1150 DispAllErrors(henv
, hdbc
);
1151 if (failOnDataTypeUnsupported
)
1155 retcode
= SQLGetInfo(hdbc
, SQL_DATABASE_NAME
, (UCHAR
*) dbInf
.databaseName
, sizeof(dbInf
.databaseName
), &cb
);
1156 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1158 DispAllErrors(henv
, hdbc
);
1159 if (failOnDataTypeUnsupported
)
1163 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, sizeof(dbInf
.dbmsName
), &cb
);
1164 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1166 DispAllErrors(henv
, hdbc
);
1167 if (failOnDataTypeUnsupported
)
1172 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
1173 // causing database connectivity to fail in some cases.
1174 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_VER
, (UCHAR
*) dbInf
.dbmsVer
, sizeof(dbInf
.dbmsVer
), &cb
);
1175 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1177 DispAllErrors(henv
, hdbc
);
1178 if (failOnDataTypeUnsupported
)
1182 retcode
= SQLGetInfo(hdbc
, SQL_ACTIVE_CONNECTIONS
, (UCHAR
*) &dbInf
.maxConnections
, sizeof(dbInf
.maxConnections
), &cb
);
1183 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1185 DispAllErrors(henv
, hdbc
);
1186 if (failOnDataTypeUnsupported
)
1190 retcode
= SQLGetInfo(hdbc
, SQL_ACTIVE_STATEMENTS
, (UCHAR
*) &dbInf
.maxStmts
, sizeof(dbInf
.maxStmts
), &cb
);
1191 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1193 DispAllErrors(henv
, hdbc
);
1194 if (failOnDataTypeUnsupported
)
1198 retcode
= SQLGetInfo(hdbc
, SQL_DRIVER_NAME
, (UCHAR
*) dbInf
.driverName
, sizeof(dbInf
.driverName
), &cb
);
1199 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1201 DispAllErrors(henv
, hdbc
);
1202 if (failOnDataTypeUnsupported
)
1206 retcode
= SQLGetInfo(hdbc
, SQL_DRIVER_ODBC_VER
, (UCHAR
*) dbInf
.odbcVer
, sizeof(dbInf
.odbcVer
), &cb
);
1207 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1209 DispAllErrors(henv
, hdbc
);
1210 if (failOnDataTypeUnsupported
)
1214 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_VER
, (UCHAR
*) dbInf
.drvMgrOdbcVer
, sizeof(dbInf
.drvMgrOdbcVer
), &cb
);
1215 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1217 DispAllErrors(henv
, hdbc
);
1218 if (failOnDataTypeUnsupported
)
1222 retcode
= SQLGetInfo(hdbc
, SQL_DRIVER_VER
, (UCHAR
*) dbInf
.driverVer
, sizeof(dbInf
.driverVer
), &cb
);
1223 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1225 DispAllErrors(henv
, hdbc
);
1226 if (failOnDataTypeUnsupported
)
1230 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_API_CONFORMANCE
, (UCHAR
*) &dbInf
.apiConfLvl
, sizeof(dbInf
.apiConfLvl
), &cb
);
1231 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1233 DispAllErrors(henv
, hdbc
);
1234 if (failOnDataTypeUnsupported
)
1238 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_SAG_CLI_CONFORMANCE
, (UCHAR
*) &dbInf
.cliConfLvl
, sizeof(dbInf
.cliConfLvl
), &cb
);
1239 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1241 // Not all drivers support this call - Nick Gorham(unixODBC)
1242 dbInf
.cliConfLvl
= 0;
1243 DispAllErrors(henv
, hdbc
);
1244 if (failOnDataTypeUnsupported
)
1248 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_SQL_CONFORMANCE
, (UCHAR
*) &dbInf
.sqlConfLvl
, sizeof(dbInf
.sqlConfLvl
), &cb
);
1249 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1251 DispAllErrors(henv
, hdbc
);
1252 if (failOnDataTypeUnsupported
)
1256 retcode
= SQLGetInfo(hdbc
, SQL_OUTER_JOINS
, (UCHAR
*) dbInf
.outerJoins
, sizeof(dbInf
.outerJoins
), &cb
);
1257 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1259 DispAllErrors(henv
, hdbc
);
1260 if (failOnDataTypeUnsupported
)
1264 retcode
= SQLGetInfo(hdbc
, SQL_PROCEDURES
, (UCHAR
*) dbInf
.procedureSupport
, sizeof(dbInf
.procedureSupport
), &cb
);
1265 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1267 DispAllErrors(henv
, hdbc
);
1268 if (failOnDataTypeUnsupported
)
1272 retcode
= SQLGetInfo(hdbc
, SQL_ACCESSIBLE_TABLES
, (UCHAR
*) dbInf
.accessibleTables
, sizeof(dbInf
.accessibleTables
), &cb
);
1273 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1275 DispAllErrors(henv
, hdbc
);
1276 if (failOnDataTypeUnsupported
)
1280 retcode
= SQLGetInfo(hdbc
, SQL_CURSOR_COMMIT_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorCommitBehavior
, sizeof(dbInf
.cursorCommitBehavior
), &cb
);
1281 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1283 DispAllErrors(henv
, hdbc
);
1284 if (failOnDataTypeUnsupported
)
1288 retcode
= SQLGetInfo(hdbc
, SQL_CURSOR_ROLLBACK_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorRollbackBehavior
, sizeof(dbInf
.cursorRollbackBehavior
), &cb
);
1289 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1291 DispAllErrors(henv
, hdbc
);
1292 if (failOnDataTypeUnsupported
)
1296 retcode
= SQLGetInfo(hdbc
, SQL_NON_NULLABLE_COLUMNS
, (UCHAR
*) &dbInf
.supportNotNullClause
, sizeof(dbInf
.supportNotNullClause
), &cb
);
1297 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1299 DispAllErrors(henv
, hdbc
);
1300 if (failOnDataTypeUnsupported
)
1304 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_SQL_OPT_IEF
, (UCHAR
*) dbInf
.supportIEF
, sizeof(dbInf
.supportIEF
), &cb
);
1305 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1307 DispAllErrors(henv
, hdbc
);
1308 if (failOnDataTypeUnsupported
)
1312 retcode
= SQLGetInfo(hdbc
, SQL_DEFAULT_TXN_ISOLATION
, (UCHAR
*) &dbInf
.txnIsolation
, sizeof(dbInf
.txnIsolation
), &cb
);
1313 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1315 DispAllErrors(henv
, hdbc
);
1316 if (failOnDataTypeUnsupported
)
1320 retcode
= SQLGetInfo(hdbc
, SQL_TXN_ISOLATION_OPTION
, (UCHAR
*) &dbInf
.txnIsolationOptions
, sizeof(dbInf
.txnIsolationOptions
), &cb
);
1321 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1323 DispAllErrors(henv
, hdbc
);
1324 if (failOnDataTypeUnsupported
)
1328 retcode
= SQLGetInfo(hdbc
, SQL_FETCH_DIRECTION
, (UCHAR
*) &dbInf
.fetchDirections
, sizeof(dbInf
.fetchDirections
), &cb
);
1329 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1331 DispAllErrors(henv
, hdbc
);
1332 if (failOnDataTypeUnsupported
)
1336 retcode
= SQLGetInfo(hdbc
, SQL_LOCK_TYPES
, (UCHAR
*) &dbInf
.lockTypes
, sizeof(dbInf
.lockTypes
), &cb
);
1337 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1339 DispAllErrors(henv
, hdbc
);
1340 if (failOnDataTypeUnsupported
)
1344 retcode
= SQLGetInfo(hdbc
, SQL_POS_OPERATIONS
, (UCHAR
*) &dbInf
.posOperations
, sizeof(dbInf
.posOperations
), &cb
);
1345 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1347 DispAllErrors(henv
, hdbc
);
1348 if (failOnDataTypeUnsupported
)
1352 retcode
= SQLGetInfo(hdbc
, SQL_POSITIONED_STATEMENTS
, (UCHAR
*) &dbInf
.posStmts
, sizeof(dbInf
.posStmts
), &cb
);
1353 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1355 DispAllErrors(henv
, hdbc
);
1356 if (failOnDataTypeUnsupported
)
1360 retcode
= SQLGetInfo(hdbc
, SQL_SCROLL_CONCURRENCY
, (UCHAR
*) &dbInf
.scrollConcurrency
, sizeof(dbInf
.scrollConcurrency
), &cb
);
1361 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1363 DispAllErrors(henv
, hdbc
);
1364 if (failOnDataTypeUnsupported
)
1368 retcode
= SQLGetInfo(hdbc
, SQL_SCROLL_OPTIONS
, (UCHAR
*) &dbInf
.scrollOptions
, sizeof(dbInf
.scrollOptions
), &cb
);
1369 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1371 DispAllErrors(henv
, hdbc
);
1372 if (failOnDataTypeUnsupported
)
1376 retcode
= SQLGetInfo(hdbc
, SQL_STATIC_SENSITIVITY
, (UCHAR
*) &dbInf
.staticSensitivity
, sizeof(dbInf
.staticSensitivity
), &cb
);
1377 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1379 DispAllErrors(henv
, hdbc
);
1380 if (failOnDataTypeUnsupported
)
1384 retcode
= SQLGetInfo(hdbc
, SQL_TXN_CAPABLE
, (UCHAR
*) &dbInf
.txnCapable
, sizeof(dbInf
.txnCapable
), &cb
);
1385 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1387 DispAllErrors(henv
, hdbc
);
1388 if (failOnDataTypeUnsupported
)
1392 retcode
= SQLGetInfo(hdbc
, SQL_LOGIN_TIMEOUT
, (UCHAR
*) &dbInf
.loginTimeout
, sizeof(dbInf
.loginTimeout
), &cb
);
1393 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1395 DispAllErrors(henv
, hdbc
);
1396 if (failOnDataTypeUnsupported
)
1400 #ifdef DBDEBUG_CONSOLE
1401 cout
<< wxT("***** DATA SOURCE INFORMATION *****") << endl
;
1402 cout
<< wxT(wxT("SERVER Name: ") << dbInf
.serverName
<< endl
;
1403 cout
<< wxT("DBMS Name: ") << dbInf
.dbmsName
<< wxT("; DBMS Version: ") << dbInf
.dbmsVer
<< endl
;
1404 cout
<< wxT("ODBC Version: ") << dbInf
.odbcVer
<< wxT("; Driver Version: ") << dbInf
.driverVer
<< endl
;
1406 cout
<< wxT("API Conf. Level: ");
1407 switch(dbInf
.apiConfLvl
)
1409 case SQL_OAC_NONE
: cout
<< wxT("None"); break;
1410 case SQL_OAC_LEVEL1
: cout
<< wxT("Level 1"); break;
1411 case SQL_OAC_LEVEL2
: cout
<< wxT("Level 2"); break;
1415 cout
<< wxT("SAG CLI Conf. Level: ");
1416 switch(dbInf
.cliConfLvl
)
1418 case SQL_OSCC_NOT_COMPLIANT
: cout
<< wxT("Not Compliant"); break;
1419 case SQL_OSCC_COMPLIANT
: cout
<< wxT("Compliant"); break;
1423 cout
<< wxT("SQL Conf. Level: ");
1424 switch(dbInf
.sqlConfLvl
)
1426 case SQL_OSC_MINIMUM
: cout
<< wxT("Minimum Grammar"); break;
1427 case SQL_OSC_CORE
: cout
<< wxT("Core Grammar"); break;
1428 case SQL_OSC_EXTENDED
: cout
<< wxT("Extended Grammar"); break;
1432 cout
<< wxT("Max. Connections: ") << dbInf
.maxConnections
<< endl
;
1433 cout
<< wxT("Outer Joins: ") << dbInf
.outerJoins
<< endl
;
1434 cout
<< wxT("Support for Procedures: ") << dbInf
.procedureSupport
<< endl
;
1435 cout
<< wxT("All tables accessible : ") << dbInf
.accessibleTables
<< endl
;
1436 cout
<< wxT("Cursor COMMIT Behavior: ");
1437 switch(dbInf
.cursorCommitBehavior
)
1439 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1440 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1441 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1445 cout
<< wxT("Cursor ROLLBACK Behavior: ");
1446 switch(dbInf
.cursorRollbackBehavior
)
1448 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1449 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1450 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1454 cout
<< wxT("Support NOT NULL clause: ");
1455 switch(dbInf
.supportNotNullClause
)
1457 case SQL_NNC_NULL
: cout
<< wxT("No"); break;
1458 case SQL_NNC_NON_NULL
: cout
<< wxT("Yes"); break;
1462 cout
<< wxT("Support IEF (Ref. Integrity): ") << dbInf
.supportIEF
<< endl
;
1463 cout
<< wxT("Login Timeout: ") << dbInf
.loginTimeout
<< endl
;
1465 cout
<< endl
<< endl
<< wxT("more ...") << endl
;
1468 cout
<< wxT("Default Transaction Isolation: ";
1469 switch(dbInf
.txnIsolation
)
1471 case SQL_TXN_READ_UNCOMMITTED
: cout
<< wxT("Read Uncommitted"); break;
1472 case SQL_TXN_READ_COMMITTED
: cout
<< wxT("Read Committed"); break;
1473 case SQL_TXN_REPEATABLE_READ
: cout
<< wxT("Repeatable Read"); break;
1474 case SQL_TXN_SERIALIZABLE
: cout
<< wxT("Serializable"); break;
1476 case SQL_TXN_VERSIONING
: cout
<< wxT("Versioning"); break;
1481 cout
<< wxT("Transaction Isolation Options: ");
1482 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_UNCOMMITTED
)
1483 cout
<< wxT("Read Uncommitted, ");
1484 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_COMMITTED
)
1485 cout
<< wxT("Read Committed, ");
1486 if (dbInf
.txnIsolationOptions
& SQL_TXN_REPEATABLE_READ
)
1487 cout
<< wxT("Repeatable Read, ");
1488 if (dbInf
.txnIsolationOptions
& SQL_TXN_SERIALIZABLE
)
1489 cout
<< wxT("Serializable, ");
1491 if (dbInf
.txnIsolationOptions
& SQL_TXN_VERSIONING
)
1492 cout
<< wxT("Versioning");
1496 cout
<< wxT("Fetch Directions Supported:") << endl
<< wxT(" ");
1497 if (dbInf
.fetchDirections
& SQL_FD_FETCH_NEXT
)
1498 cout
<< wxT("Next, ");
1499 if (dbInf
.fetchDirections
& SQL_FD_FETCH_PRIOR
)
1500 cout
<< wxT("Prev, ");
1501 if (dbInf
.fetchDirections
& SQL_FD_FETCH_FIRST
)
1502 cout
<< wxT("First, ");
1503 if (dbInf
.fetchDirections
& SQL_FD_FETCH_LAST
)
1504 cout
<< wxT("Last, ");
1505 if (dbInf
.fetchDirections
& SQL_FD_FETCH_ABSOLUTE
)
1506 cout
<< wxT("Absolute, ");
1507 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RELATIVE
)
1508 cout
<< wxT("Relative, ");
1510 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RESUME
)
1511 cout
<< wxT("Resume, ");
1513 if (dbInf
.fetchDirections
& SQL_FD_FETCH_BOOKMARK
)
1514 cout
<< wxT("Bookmark");
1517 cout
<< wxT("Lock Types Supported (SQLSetPos): ");
1518 if (dbInf
.lockTypes
& SQL_LCK_NO_CHANGE
)
1519 cout
<< wxT("No Change, ");
1520 if (dbInf
.lockTypes
& SQL_LCK_EXCLUSIVE
)
1521 cout
<< wxT("Exclusive, ");
1522 if (dbInf
.lockTypes
& SQL_LCK_UNLOCK
)
1523 cout
<< wxT("UnLock");
1526 cout
<< wxT("Position Operations Supported (SQLSetPos): ");
1527 if (dbInf
.posOperations
& SQL_POS_POSITION
)
1528 cout
<< wxT("Position, ");
1529 if (dbInf
.posOperations
& SQL_POS_REFRESH
)
1530 cout
<< wxT("Refresh, ");
1531 if (dbInf
.posOperations
& SQL_POS_UPDATE
)
1532 cout
<< wxT("Upd, "));
1533 if (dbInf
.posOperations
& SQL_POS_DELETE
)
1534 cout
<< wxT("Del, ");
1535 if (dbInf
.posOperations
& SQL_POS_ADD
)
1539 cout
<< wxT("Positioned Statements Supported: ");
1540 if (dbInf
.posStmts
& SQL_PS_POSITIONED_DELETE
)
1541 cout
<< wxT("Pos delete, ");
1542 if (dbInf
.posStmts
& SQL_PS_POSITIONED_UPDATE
)
1543 cout
<< wxT("Pos update, ");
1544 if (dbInf
.posStmts
& SQL_PS_SELECT_FOR_UPDATE
)
1545 cout
<< wxT("Select for update");
1548 cout
<< wxT("Scroll Concurrency: ");
1549 if (dbInf
.scrollConcurrency
& SQL_SCCO_READ_ONLY
)
1550 cout
<< wxT("Read Only, ");
1551 if (dbInf
.scrollConcurrency
& SQL_SCCO_LOCK
)
1552 cout
<< wxT("Lock, ");
1553 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_ROWVER
)
1554 cout
<< wxT("Opt. Rowver, ");
1555 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_VALUES
)
1556 cout
<< wxT("Opt. Values");
1559 cout
<< wxT("Scroll Options: ");
1560 if (dbInf
.scrollOptions
& SQL_SO_FORWARD_ONLY
)
1561 cout
<< wxT("Fwd Only, ");
1562 if (dbInf
.scrollOptions
& SQL_SO_STATIC
)
1563 cout
<< wxT("Static, ");
1564 if (dbInf
.scrollOptions
& SQL_SO_KEYSET_DRIVEN
)
1565 cout
<< wxT("Keyset Driven, ");
1566 if (dbInf
.scrollOptions
& SQL_SO_DYNAMIC
)
1567 cout
<< wxT("Dynamic, ");
1568 if (dbInf
.scrollOptions
& SQL_SO_MIXED
)
1569 cout
<< wxT("Mixed");
1572 cout
<< wxT("Static Sensitivity: ");
1573 if (dbInf
.staticSensitivity
& SQL_SS_ADDITIONS
)
1574 cout
<< wxT("Additions, ");
1575 if (dbInf
.staticSensitivity
& SQL_SS_DELETIONS
)
1576 cout
<< wxT("Deletions, ");
1577 if (dbInf
.staticSensitivity
& SQL_SS_UPDATES
)
1578 cout
<< wxT("Updates");
1581 cout
<< wxT("Transaction Capable?: ");
1582 switch(dbInf
.txnCapable
)
1584 case SQL_TC_NONE
: cout
<< wxT("No"); break;
1585 case SQL_TC_DML
: cout
<< wxT("DML Only"); break;
1586 case SQL_TC_DDL_COMMIT
: cout
<< wxT("DDL Commit"); break;
1587 case SQL_TC_DDL_IGNORE
: cout
<< wxT("DDL Ignore"); break;
1588 case SQL_TC_ALL
: cout
<< wxT("DDL & DML"); break;
1595 // Completed Successfully
1598 } // wxDb::getDbInfo()
1601 /********** wxDb::getDataTypeInfo() **********/
1602 bool wxDb::getDataTypeInfo(SWORD fSqlType
, wxDbSqlTypeInfo
&structSQLTypeInfo
)
1605 * fSqlType will be something like SQL_VARCHAR. This parameter determines
1606 * the data type inf. is gathered for.
1608 * wxDbSqlTypeInfo is a structure that is filled in with data type information,
1613 // Get information about the data type specified
1614 if (SQLGetTypeInfo(hstmt
, fSqlType
) != SQL_SUCCESS
)
1615 return(DispAllErrors(henv
, hdbc
, hstmt
));
1618 retcode
= SQLFetch(hstmt
);
1619 if (retcode
!= SQL_SUCCESS
)
1621 #ifdef DBDEBUG_CONSOLE
1622 if (retcode
== SQL_NO_DATA_FOUND
)
1623 cout
<< wxT("SQL_NO_DATA_FOUND fetching information about data type.") << endl
;
1625 DispAllErrors(henv
, hdbc
, hstmt
);
1626 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1630 wxChar typeName
[DB_TYPE_NAME_LEN
+1];
1632 // Obtain columns from the record
1633 if (SQLGetData(hstmt
, 1, SQL_C_WXCHAR
, typeName
, sizeof(typeName
), &cbRet
) != SQL_SUCCESS
)
1634 return(DispAllErrors(henv
, hdbc
, hstmt
));
1636 structSQLTypeInfo
.TypeName
= typeName
;
1638 // BJO 20000503: no more needed with new GetColumns...
1641 if (Dbms() == dbmsMY_SQL
)
1643 if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1644 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1645 else if (structSQLTypeInfo
.TypeName
== wxT("middleint unsigned"))
1646 structSQLTypeInfo
.TypeName
= wxT("mediumint unsigned");
1647 else if (structSQLTypeInfo
.TypeName
== wxT("integer"))
1648 structSQLTypeInfo
.TypeName
= wxT("int");
1649 else if (structSQLTypeInfo
.TypeName
== wxT("integer unsigned"))
1650 structSQLTypeInfo
.TypeName
= wxT("int unsigned");
1651 else if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1652 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1653 else if (structSQLTypeInfo
.TypeName
== wxT("varchar"))
1654 structSQLTypeInfo
.TypeName
= wxT("char");
1657 // BJO 20000427 : OpenLink driver
1658 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
1659 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
1661 if (structSQLTypeInfo
.TypeName
== wxT("double precision"))
1662 structSQLTypeInfo
.TypeName
= wxT("real");
1666 if (SQLGetData(hstmt
, 3, SQL_C_LONG
, (UCHAR
*) &structSQLTypeInfo
.Precision
, 0, &cbRet
) != SQL_SUCCESS
)
1667 return(DispAllErrors(henv
, hdbc
, hstmt
));
1668 if (SQLGetData(hstmt
, 8, SQL_C_SHORT
, (UCHAR
*) &structSQLTypeInfo
.CaseSensitive
, 0, &cbRet
) != SQL_SUCCESS
)
1669 return(DispAllErrors(henv
, hdbc
, hstmt
));
1670 // if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
1671 // return(DispAllErrors(henv, hdbc, hstmt));
1673 if (SQLGetData(hstmt
, 15, SQL_C_SHORT
,(UCHAR
*) &structSQLTypeInfo
.MaximumScale
, 0, &cbRet
) != SQL_SUCCESS
)
1674 return(DispAllErrors(henv
, hdbc
, hstmt
));
1676 if (structSQLTypeInfo
.MaximumScale
< 0)
1677 structSQLTypeInfo
.MaximumScale
= 0;
1679 // Close the statement handle which closes open cursors
1680 if (SQLFreeStmt(hstmt
, SQL_CLOSE
) != SQL_SUCCESS
)
1681 return(DispAllErrors(henv
, hdbc
, hstmt
));
1683 // Completed Successfully
1686 } // wxDb::getDataTypeInfo()
1689 /********** wxDb::Close() **********/
1690 void wxDb::Close(void)
1692 // Close the Sql Log file
1699 // Free statement handle
1702 if (SQLFreeStmt(hstmt
, SQL_DROP
) != SQL_SUCCESS
)
1703 DispAllErrors(henv
, hdbc
);
1706 // Disconnect from the datasource
1707 if (SQLDisconnect(hdbc
) != SQL_SUCCESS
)
1708 DispAllErrors(henv
, hdbc
);
1710 // Free the connection to the datasource
1711 if (SQLFreeConnect(hdbc
) != SQL_SUCCESS
)
1712 DispAllErrors(henv
, hdbc
);
1714 // There should be zero Ctable objects still connected to this db object
1715 wxASSERT(nTables
== 0);
1719 wxList::compatibility_iterator pNode
;
1720 pNode
= TablesInUse
.GetFirst();
1724 tiu
= (wxTablesInUse
*)pNode
->GetData();
1725 if (tiu
->pDb
== this)
1727 s
.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu
->tableName
,tiu
->tableID
,tiu
->pDb
);
1728 s2
.Printf(wxT("Orphaned table found using pDb:[%p]"),this);
1729 wxLogDebug(s
.c_str(),s2
.c_str());
1731 pNode
= pNode
->GetNext();
1735 // Copy the error messages to a global variable
1737 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1738 wxStrcpy(DBerrorList
[i
], errorList
[i
]);
1740 dbmsType
= dbmsUNIDENTIFIED
;
1746 /********** wxDb::CommitTrans() **********/
1747 bool wxDb::CommitTrans(void)
1751 // Commit the transaction
1752 if (SQLTransact(henv
, hdbc
, SQL_COMMIT
) != SQL_SUCCESS
)
1753 return(DispAllErrors(henv
, hdbc
));
1756 // Completed successfully
1759 } // wxDb::CommitTrans()
1762 /********** wxDb::RollbackTrans() **********/
1763 bool wxDb::RollbackTrans(void)
1765 // Rollback the transaction
1766 if (SQLTransact(henv
, hdbc
, SQL_ROLLBACK
) != SQL_SUCCESS
)
1767 return(DispAllErrors(henv
, hdbc
));
1769 // Completed successfully
1772 } // wxDb::RollbackTrans()
1775 /********** wxDb::DispAllErrors() **********/
1776 bool wxDb::DispAllErrors(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1778 * This function is called internally whenever an error condition prevents the user's
1779 * request from being executed. This function will query the datasource as to the
1780 * actual error(s) that just occurred on the previous request of the datasource.
1782 * The function will retrieve each error condition from the datasource and
1783 * Printf the codes/text values into a string which it then logs via logError().
1784 * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
1785 * window and program execution will be paused until the user presses a key.
1787 * This function always returns false, so that functions which call this function
1788 * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure
1789 * of the user's request, so that the calling code can then process the error message log.
1792 wxString odbcErrMsg
;
1794 while (SQLError(aHenv
, aHdbc
, aHstmt
, (SQLTCHAR FAR
*) sqlState
, &nativeError
, (SQLTCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1796 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1797 logError(odbcErrMsg
, sqlState
);
1800 #ifdef DBDEBUG_CONSOLE
1801 // When run in console mode, use standard out to display errors.
1802 cout
<< odbcErrMsg
.c_str() << endl
;
1803 cout
<< wxT("Press any key to continue...") << endl
;
1808 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
1813 return false; // This function always returns false.
1815 } // wxDb::DispAllErrors()
1818 /********** wxDb::GetNextError() **********/
1819 bool wxDb::GetNextError(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1821 if (SQLError(aHenv
, aHdbc
, aHstmt
, (SQLTCHAR FAR
*) sqlState
, &nativeError
, (SQLTCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1826 } // wxDb::GetNextError()
1829 /********** wxDb::DispNextError() **********/
1830 void wxDb::DispNextError(void)
1832 wxString odbcErrMsg
;
1834 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1835 logError(odbcErrMsg
, sqlState
);
1840 #ifdef DBDEBUG_CONSOLE
1841 // When run in console mode, use standard out to display errors.
1842 cout
<< odbcErrMsg
.c_str() << endl
;
1843 cout
<< wxT("Press any key to continue...") << endl
;
1848 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE"));
1849 #endif // __WXDEBUG__
1851 } // wxDb::DispNextError()
1854 /********** wxDb::logError() **********/
1855 void wxDb::logError(const wxString
&errMsg
, const wxString
&SQLState
)
1857 wxASSERT(errMsg
.Length());
1859 static int pLast
= -1;
1862 if (++pLast
== DB_MAX_ERROR_HISTORY
)
1865 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
-1; i
++)
1866 wxStrcpy(errorList
[i
], errorList
[i
+1]);
1870 wxStrncpy(errorList
[pLast
], errMsg
, DB_MAX_ERROR_MSG_LEN
);
1871 errorList
[pLast
][DB_MAX_ERROR_MSG_LEN
] = 0;
1873 if (SQLState
.Length())
1874 if ((dbStatus
= TranslateSqlState(SQLState
)) != DB_ERR_FUNCTION_SEQUENCE_ERROR
)
1875 DB_STATUS
= dbStatus
;
1877 // Add the errmsg to the sql log
1878 WriteSqlLog(errMsg
);
1880 } // wxDb::logError()
1883 /**********wxDb::TranslateSqlState() **********/
1884 int wxDb::TranslateSqlState(const wxString
&SQLState
)
1886 if (!wxStrcmp(SQLState
, wxT("01000")))
1887 return(DB_ERR_GENERAL_WARNING
);
1888 if (!wxStrcmp(SQLState
, wxT("01002")))
1889 return(DB_ERR_DISCONNECT_ERROR
);
1890 if (!wxStrcmp(SQLState
, wxT("01004")))
1891 return(DB_ERR_DATA_TRUNCATED
);
1892 if (!wxStrcmp(SQLState
, wxT("01006")))
1893 return(DB_ERR_PRIV_NOT_REVOKED
);
1894 if (!wxStrcmp(SQLState
, wxT("01S00")))
1895 return(DB_ERR_INVALID_CONN_STR_ATTR
);
1896 if (!wxStrcmp(SQLState
, wxT("01S01")))
1897 return(DB_ERR_ERROR_IN_ROW
);
1898 if (!wxStrcmp(SQLState
, wxT("01S02")))
1899 return(DB_ERR_OPTION_VALUE_CHANGED
);
1900 if (!wxStrcmp(SQLState
, wxT("01S03")))
1901 return(DB_ERR_NO_ROWS_UPD_OR_DEL
);
1902 if (!wxStrcmp(SQLState
, wxT("01S04")))
1903 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL
);
1904 if (!wxStrcmp(SQLState
, wxT("07001")))
1905 return(DB_ERR_WRONG_NO_OF_PARAMS
);
1906 if (!wxStrcmp(SQLState
, wxT("07006")))
1907 return(DB_ERR_DATA_TYPE_ATTR_VIOL
);
1908 if (!wxStrcmp(SQLState
, wxT("08001")))
1909 return(DB_ERR_UNABLE_TO_CONNECT
);
1910 if (!wxStrcmp(SQLState
, wxT("08002")))
1911 return(DB_ERR_CONNECTION_IN_USE
);
1912 if (!wxStrcmp(SQLState
, wxT("08003")))
1913 return(DB_ERR_CONNECTION_NOT_OPEN
);
1914 if (!wxStrcmp(SQLState
, wxT("08004")))
1915 return(DB_ERR_REJECTED_CONNECTION
);
1916 if (!wxStrcmp(SQLState
, wxT("08007")))
1917 return(DB_ERR_CONN_FAIL_IN_TRANS
);
1918 if (!wxStrcmp(SQLState
, wxT("08S01")))
1919 return(DB_ERR_COMM_LINK_FAILURE
);
1920 if (!wxStrcmp(SQLState
, wxT("21S01")))
1921 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH
);
1922 if (!wxStrcmp(SQLState
, wxT("21S02")))
1923 return(DB_ERR_DERIVED_TABLE_MISMATCH
);
1924 if (!wxStrcmp(SQLState
, wxT("22001")))
1925 return(DB_ERR_STRING_RIGHT_TRUNC
);
1926 if (!wxStrcmp(SQLState
, wxT("22003")))
1927 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG
);
1928 if (!wxStrcmp(SQLState
, wxT("22005")))
1929 return(DB_ERR_ERROR_IN_ASSIGNMENT
);
1930 if (!wxStrcmp(SQLState
, wxT("22008")))
1931 return(DB_ERR_DATETIME_FLD_OVERFLOW
);
1932 if (!wxStrcmp(SQLState
, wxT("22012")))
1933 return(DB_ERR_DIVIDE_BY_ZERO
);
1934 if (!wxStrcmp(SQLState
, wxT("22026")))
1935 return(DB_ERR_STR_DATA_LENGTH_MISMATCH
);
1936 if (!wxStrcmp(SQLState
, wxT("23000")))
1937 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL
);
1938 if (!wxStrcmp(SQLState
, wxT("24000")))
1939 return(DB_ERR_INVALID_CURSOR_STATE
);
1940 if (!wxStrcmp(SQLState
, wxT("25000")))
1941 return(DB_ERR_INVALID_TRANS_STATE
);
1942 if (!wxStrcmp(SQLState
, wxT("28000")))
1943 return(DB_ERR_INVALID_AUTH_SPEC
);
1944 if (!wxStrcmp(SQLState
, wxT("34000")))
1945 return(DB_ERR_INVALID_CURSOR_NAME
);
1946 if (!wxStrcmp(SQLState
, wxT("37000")))
1947 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL
);
1948 if (!wxStrcmp(SQLState
, wxT("3C000")))
1949 return(DB_ERR_DUPLICATE_CURSOR_NAME
);
1950 if (!wxStrcmp(SQLState
, wxT("40001")))
1951 return(DB_ERR_SERIALIZATION_FAILURE
);
1952 if (!wxStrcmp(SQLState
, wxT("42000")))
1953 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2
);
1954 if (!wxStrcmp(SQLState
, wxT("70100")))
1955 return(DB_ERR_OPERATION_ABORTED
);
1956 if (!wxStrcmp(SQLState
, wxT("IM001")))
1957 return(DB_ERR_UNSUPPORTED_FUNCTION
);
1958 if (!wxStrcmp(SQLState
, wxT("IM002")))
1959 return(DB_ERR_NO_DATA_SOURCE
);
1960 if (!wxStrcmp(SQLState
, wxT("IM003")))
1961 return(DB_ERR_DRIVER_LOAD_ERROR
);
1962 if (!wxStrcmp(SQLState
, wxT("IM004")))
1963 return(DB_ERR_SQLALLOCENV_FAILED
);
1964 if (!wxStrcmp(SQLState
, wxT("IM005")))
1965 return(DB_ERR_SQLALLOCCONNECT_FAILED
);
1966 if (!wxStrcmp(SQLState
, wxT("IM006")))
1967 return(DB_ERR_SQLSETCONNECTOPTION_FAILED
);
1968 if (!wxStrcmp(SQLState
, wxT("IM007")))
1969 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB
);
1970 if (!wxStrcmp(SQLState
, wxT("IM008")))
1971 return(DB_ERR_DIALOG_FAILED
);
1972 if (!wxStrcmp(SQLState
, wxT("IM009")))
1973 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL
);
1974 if (!wxStrcmp(SQLState
, wxT("IM010")))
1975 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG
);
1976 if (!wxStrcmp(SQLState
, wxT("IM011")))
1977 return(DB_ERR_DRIVER_NAME_TOO_LONG
);
1978 if (!wxStrcmp(SQLState
, wxT("IM012")))
1979 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR
);
1980 if (!wxStrcmp(SQLState
, wxT("IM013")))
1981 return(DB_ERR_TRACE_FILE_ERROR
);
1982 if (!wxStrcmp(SQLState
, wxT("S0001")))
1983 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS
);
1984 if (!wxStrcmp(SQLState
, wxT("S0002")))
1985 return(DB_ERR_TABLE_NOT_FOUND
);
1986 if (!wxStrcmp(SQLState
, wxT("S0011")))
1987 return(DB_ERR_INDEX_ALREADY_EXISTS
);
1988 if (!wxStrcmp(SQLState
, wxT("S0012")))
1989 return(DB_ERR_INDEX_NOT_FOUND
);
1990 if (!wxStrcmp(SQLState
, wxT("S0021")))
1991 return(DB_ERR_COLUMN_ALREADY_EXISTS
);
1992 if (!wxStrcmp(SQLState
, wxT("S0022")))
1993 return(DB_ERR_COLUMN_NOT_FOUND
);
1994 if (!wxStrcmp(SQLState
, wxT("S0023")))
1995 return(DB_ERR_NO_DEFAULT_FOR_COLUMN
);
1996 if (!wxStrcmp(SQLState
, wxT("S1000")))
1997 return(DB_ERR_GENERAL_ERROR
);
1998 if (!wxStrcmp(SQLState
, wxT("S1001")))
1999 return(DB_ERR_MEMORY_ALLOCATION_FAILURE
);
2000 if (!wxStrcmp(SQLState
, wxT("S1002")))
2001 return(DB_ERR_INVALID_COLUMN_NUMBER
);
2002 if (!wxStrcmp(SQLState
, wxT("S1003")))
2003 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE
);
2004 if (!wxStrcmp(SQLState
, wxT("S1004")))
2005 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE
);
2006 if (!wxStrcmp(SQLState
, wxT("S1008")))
2007 return(DB_ERR_OPERATION_CANCELLED
);
2008 if (!wxStrcmp(SQLState
, wxT("S1009")))
2009 return(DB_ERR_INVALID_ARGUMENT_VALUE
);
2010 if (!wxStrcmp(SQLState
, wxT("S1010")))
2011 return(DB_ERR_FUNCTION_SEQUENCE_ERROR
);
2012 if (!wxStrcmp(SQLState
, wxT("S1011")))
2013 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME
);
2014 if (!wxStrcmp(SQLState
, wxT("S1012")))
2015 return(DB_ERR_INVALID_TRANS_OPERATION_CODE
);
2016 if (!wxStrcmp(SQLState
, wxT("S1015")))
2017 return(DB_ERR_NO_CURSOR_NAME_AVAIL
);
2018 if (!wxStrcmp(SQLState
, wxT("S1090")))
2019 return(DB_ERR_INVALID_STR_OR_BUF_LEN
);
2020 if (!wxStrcmp(SQLState
, wxT("S1091")))
2021 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE
);
2022 if (!wxStrcmp(SQLState
, wxT("S1092")))
2023 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE
);
2024 if (!wxStrcmp(SQLState
, wxT("S1093")))
2025 return(DB_ERR_INVALID_PARAM_NO
);
2026 if (!wxStrcmp(SQLState
, wxT("S1094")))
2027 return(DB_ERR_INVALID_SCALE_VALUE
);
2028 if (!wxStrcmp(SQLState
, wxT("S1095")))
2029 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE
);
2030 if (!wxStrcmp(SQLState
, wxT("S1096")))
2031 return(DB_ERR_INF_TYPE_OUT_OF_RANGE
);
2032 if (!wxStrcmp(SQLState
, wxT("S1097")))
2033 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE
);
2034 if (!wxStrcmp(SQLState
, wxT("S1098")))
2035 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE
);
2036 if (!wxStrcmp(SQLState
, wxT("S1099")))
2037 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE
);
2038 if (!wxStrcmp(SQLState
, wxT("S1100")))
2039 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE
);
2040 if (!wxStrcmp(SQLState
, wxT("S1101")))
2041 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE
);
2042 if (!wxStrcmp(SQLState
, wxT("S1103")))
2043 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE
);
2044 if (!wxStrcmp(SQLState
, wxT("S1104")))
2045 return(DB_ERR_INVALID_PRECISION_VALUE
);
2046 if (!wxStrcmp(SQLState
, wxT("S1105")))
2047 return(DB_ERR_INVALID_PARAM_TYPE
);
2048 if (!wxStrcmp(SQLState
, wxT("S1106")))
2049 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE
);
2050 if (!wxStrcmp(SQLState
, wxT("S1107")))
2051 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE
);
2052 if (!wxStrcmp(SQLState
, wxT("S1108")))
2053 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE
);
2054 if (!wxStrcmp(SQLState
, wxT("S1109")))
2055 return(DB_ERR_INVALID_CURSOR_POSITION
);
2056 if (!wxStrcmp(SQLState
, wxT("S1110")))
2057 return(DB_ERR_INVALID_DRIVER_COMPLETION
);
2058 if (!wxStrcmp(SQLState
, wxT("S1111")))
2059 return(DB_ERR_INVALID_BOOKMARK_VALUE
);
2060 if (!wxStrcmp(SQLState
, wxT("S1C00")))
2061 return(DB_ERR_DRIVER_NOT_CAPABLE
);
2062 if (!wxStrcmp(SQLState
, wxT("S1T00")))
2063 return(DB_ERR_TIMEOUT_EXPIRED
);
2068 } // wxDb::TranslateSqlState()
2071 /********** wxDb::Grant() **********/
2072 bool wxDb::Grant(int privileges
, const wxString
&tableName
, const wxString
&userList
)
2076 // Build the grant statement
2077 sqlStmt
= wxT("GRANT ");
2078 if (privileges
== DB_GRANT_ALL
)
2079 sqlStmt
+= wxT("ALL");
2083 if (privileges
& DB_GRANT_SELECT
)
2085 sqlStmt
+= wxT("SELECT");
2088 if (privileges
& DB_GRANT_INSERT
)
2091 sqlStmt
+= wxT(", ");
2092 sqlStmt
+= wxT("INSERT");
2094 if (privileges
& DB_GRANT_UPDATE
)
2097 sqlStmt
+= wxT(", ");
2098 sqlStmt
+= wxT("UPDATE");
2100 if (privileges
& DB_GRANT_DELETE
)
2103 sqlStmt
+= wxT(", ");
2104 sqlStmt
+= wxT("DELETE");
2108 sqlStmt
+= wxT(" ON ");
2109 sqlStmt
+= SQLTableName(tableName
);
2110 sqlStmt
+= wxT(" TO ");
2111 sqlStmt
+= userList
;
2113 #ifdef DBDEBUG_CONSOLE
2114 cout
<< endl
<< sqlStmt
.c_str() << endl
;
2117 WriteSqlLog(sqlStmt
);
2119 return(ExecSql(sqlStmt
));
2124 /********** wxDb::CreateView() **********/
2125 bool wxDb::CreateView(const wxString
&viewName
, const wxString
&colList
,
2126 const wxString
&pSqlStmt
, bool attemptDrop
)
2130 // Drop the view first
2131 if (attemptDrop
&& !DropView(viewName
))
2134 // Build the create view statement
2135 sqlStmt
= wxT("CREATE VIEW ");
2136 sqlStmt
+= viewName
;
2138 if (colList
.Length())
2140 sqlStmt
+= wxT(" (");
2142 sqlStmt
+= wxT(")");
2145 sqlStmt
+= wxT(" AS ");
2146 sqlStmt
+= pSqlStmt
;
2148 WriteSqlLog(sqlStmt
);
2150 #ifdef DBDEBUG_CONSOLE
2151 cout
<< sqlStmt
.c_str() << endl
;
2154 return(ExecSql(sqlStmt
));
2156 } // wxDb::CreateView()
2159 /********** wxDb::DropView() **********/
2160 bool wxDb::DropView(const wxString
&viewName
)
2163 * NOTE: This function returns true if the View does not exist, but
2164 * only for identified databases. Code will need to be added
2165 * below for any other databases when those databases are defined
2166 * to handle this situation consistently
2170 sqlStmt
.Printf(wxT("DROP VIEW %s"), viewName
.c_str());
2172 WriteSqlLog(sqlStmt
);
2174 #ifdef DBDEBUG_CONSOLE
2175 cout
<< endl
<< sqlStmt
.c_str() << endl
;
2178 if (SQLExecDirect(hstmt
, (SQLTCHAR FAR
*) sqlStmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
2180 // Check for "Base table not found" error and ignore
2181 GetNextError(henv
, hdbc
, hstmt
);
2182 if (wxStrcmp(sqlState
,wxT("S0002"))) // "Base table not found"
2184 // Check for product specific error codes
2185 if (!((Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(sqlState
,wxT("42000"))))) // 5.x (and lower?)
2188 DispAllErrors(henv
, hdbc
, hstmt
);
2195 // Commit the transaction
2201 } // wxDb::DropView()
2204 /********** wxDb::ExecSql() **********/
2205 bool wxDb::ExecSql(const wxString
&pSqlStmt
)
2209 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2211 retcode
= SQLExecDirect(hstmt
, (SQLTCHAR FAR
*) pSqlStmt
.c_str(), SQL_NTS
);
2212 if (retcode
== SQL_SUCCESS
||
2213 (Dbms() == dbmsDB2
&& (retcode
== SQL_SUCCESS_WITH_INFO
|| retcode
== SQL_NO_DATA_FOUND
)))
2219 DispAllErrors(henv
, hdbc
, hstmt
);
2223 } // wxDb::ExecSql()
2226 /********** wxDb::ExecSql() with column info **********/
2227 bool wxDb::ExecSql(const wxString
&pSqlStmt
, wxDbColInf
** columns
, short& numcols
)
2229 //execute the statement first
2230 if (!ExecSql(pSqlStmt
))
2234 if (SQLNumResultCols(hstmt
, &noCols
) != SQL_SUCCESS
)
2236 DispAllErrors(henv
, hdbc
, hstmt
);
2245 // Get column information
2247 wxChar name
[DB_MAX_COLUMN_NAME_LEN
+1];
2250 wxDbColInf
* pColInf
= new wxDbColInf
[noCols
];
2252 // Fill in column information (name, datatype)
2253 for (colNum
= 0; colNum
< noCols
; colNum
++)
2255 if (SQLColAttributes(hstmt
, (UWORD
)(colNum
+1), SQL_COLUMN_NAME
,
2257 &Sword
, &Sqllen
) != SQL_SUCCESS
)
2259 DispAllErrors(henv
, hdbc
, hstmt
);
2264 wxStrncpy(pColInf
[colNum
].colName
, name
, DB_MAX_COLUMN_NAME_LEN
);
2265 pColInf
[colNum
].colName
[DB_MAX_COLUMN_NAME_LEN
] = 0; // Prevent buffer overrun
2267 if (SQLColAttributes(hstmt
, (UWORD
)(colNum
+1), SQL_COLUMN_TYPE
,
2268 NULL
, 0, &Sword
, &Sqllen
) != SQL_SUCCESS
)
2270 DispAllErrors(henv
, hdbc
, hstmt
);
2278 #if defined(SQL_WCHAR)
2281 #if defined(SQL_WVARCHAR)
2287 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2293 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2300 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2304 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_DATE
;
2307 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_BLOB
;
2312 errMsg
.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sqllen
);
2313 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
2320 } // wxDb::ExecSql()
2322 /********** wxDb::GetNext() **********/
2323 bool wxDb::GetNext(void)
2325 if (SQLFetch(hstmt
) == SQL_SUCCESS
)
2329 DispAllErrors(henv
, hdbc
, hstmt
);
2333 } // wxDb::GetNext()
2336 /********** wxDb::GetData() **********/
2337 bool wxDb::GetData(UWORD colNo
, SWORD cType
, PTR pData
, SDWORD maxLen
, SQLLEN FAR
*cbReturned
)
2340 wxASSERT(cbReturned
);
2342 long bufferSize
= maxLen
;
2344 if (cType
== SQL_C_WXCHAR
)
2345 bufferSize
= maxLen
* sizeof(wxChar
);
2347 if (SQLGetData(hstmt
, colNo
, cType
, pData
, bufferSize
, cbReturned
) == SQL_SUCCESS
)
2351 DispAllErrors(henv
, hdbc
, hstmt
);
2355 } // wxDb::GetData()
2358 /********** wxDb::GetKeyFields() **********/
2359 int wxDb::GetKeyFields(const wxString
&tableName
, wxDbColInf
* colInf
, UWORD noCols
)
2361 wxChar szPkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Primary key table name */
2362 wxChar szFkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Foreign key table name */
2364 wxChar szPkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Primary key column */
2365 wxChar szFkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Foreign key column */
2371 * -----------------------------------------------------------------------
2372 * -- 19991224 : mj10777 : Create ------
2373 * -- : Three things are done and stored here : ------
2374 * -- : 1) which Column(s) is/are Primary Key(s) ------
2375 * -- : 2) which tables use this Key as a Foreign Key ------
2376 * -- : 3) which columns are Foreign Key and the name ------
2377 * -- : of the Table where the Key is the Primary Key -----
2378 * -- : Called from GetColumns(const wxString &tableName, ------
2379 * -- int *numCols,const wxChar *userID ) ------
2380 * -----------------------------------------------------------------------
2383 /*---------------------------------------------------------------------*/
2384 /* Get the names of the columns in the primary key. */
2385 /*---------------------------------------------------------------------*/
2386 retcode
= SQLPrimaryKeys(hstmt
,
2387 NULL
, 0, /* Catalog name */
2388 NULL
, 0, /* Schema name */
2389 (SQLTCHAR FAR
*) tableName
.c_str(), SQL_NTS
); /* Table name */
2391 /*---------------------------------------------------------------------*/
2392 /* Fetch and display the result set. This will be a list of the */
2393 /* columns in the primary key of the tableName table. */
2394 /*---------------------------------------------------------------------*/
2395 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
2397 retcode
= SQLFetch(hstmt
);
2398 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
2400 GetData( 4, SQL_C_WXCHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2401 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
2403 for (i
=0;i
<noCols
;i
++) // Find the Column name
2404 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column
2405 colInf
[i
].PkCol
= iKeySeq
; // Which Primary Key is this (first, second usw.) ?
2408 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
2410 /*---------------------------------------------------------------------*/
2411 /* Get all the foreign keys that refer to tableName primary key. */
2412 /*---------------------------------------------------------------------*/
2413 retcode
= SQLForeignKeys(hstmt
,
2414 NULL
, 0, /* Primary catalog */
2415 NULL
, 0, /* Primary schema */
2416 (SQLTCHAR FAR
*)tableName
.c_str(), SQL_NTS
,/* Primary table */
2417 NULL
, 0, /* Foreign catalog */
2418 NULL
, 0, /* Foreign schema */
2419 NULL
, 0); /* Foreign table */
2421 /*---------------------------------------------------------------------*/
2422 /* Fetch and display the result set. This will be all of the foreign */
2423 /* keys in other tables that refer to the tableName primary key. */
2424 /*---------------------------------------------------------------------*/
2427 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
2429 retcode
= SQLFetch(hstmt
);
2430 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
2432 GetData( 3, SQL_C_WXCHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2433 GetData( 4, SQL_C_WXCHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2434 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
2435 GetData( 7, SQL_C_WXCHAR
, szFkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2436 GetData( 8, SQL_C_WXCHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2437 tempStr
<< _T('[') << szFkTable
<< _T(']'); // [ ] in case there is a blank in the Table name
2441 tempStr
.Trim(); // Get rid of any unneeded blanks
2442 if (!tempStr
.empty())
2444 for (i
=0; i
<noCols
; i
++)
2445 { // Find the Column name
2446 if (!wxStrcmp(colInf
[i
].colName
, szPkCol
)) // We have found the Column, store the Information
2448 wxStrncpy(colInf
[i
].PkTableName
, tempStr
.c_str(), DB_MAX_TABLE_NAME_LEN
); // Name of the Tables where this Primary Key is used as a Foreign Key
2449 colInf
[i
].PkTableName
[DB_MAX_TABLE_NAME_LEN
] = 0; // Prevent buffer overrun
2454 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
2456 /*---------------------------------------------------------------------*/
2457 /* Get all the foreign keys in the tablename table. */
2458 /*---------------------------------------------------------------------*/
2459 retcode
= SQLForeignKeys(hstmt
,
2460 NULL
, 0, /* Primary catalog */
2461 NULL
, 0, /* Primary schema */
2462 NULL
, 0, /* Primary table */
2463 NULL
, 0, /* Foreign catalog */
2464 NULL
, 0, /* Foreign schema */
2465 (SQLTCHAR
*)tableName
.c_str(), SQL_NTS
);/* Foreign table */
2467 /*---------------------------------------------------------------------*/
2468 /* Fetch and display the result set. This will be all of the */
2469 /* primary keys in other tables that are referred to by foreign */
2470 /* keys in the tableName table. */
2471 /*---------------------------------------------------------------------*/
2472 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
2474 retcode
= SQLFetch(hstmt
);
2475 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
2477 GetData( 3, SQL_C_WXCHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2478 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
2479 GetData( 8, SQL_C_WXCHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2481 for (i
=0; i
<noCols
; i
++) // Find the Column name
2483 if (!wxStrcmp(colInf
[i
].colName
,szFkCol
)) // We have found the (Foreign Key) Column
2485 colInf
[i
].FkCol
= iKeySeq
; // Which Foreign Key is this (first, second usw.) ?
2486 wxStrncpy(colInf
[i
].FkTableName
, szFkTable
, DB_MAX_TABLE_NAME_LEN
); // Name of the Table where this Foriegn is the Primary Key
2487 colInf
[i
].FkTableName
[DB_MAX_TABLE_NAME_LEN
] = 0; // Prevent buffer overrun
2492 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
2496 } // wxDb::GetKeyFields()
2500 /********** wxDb::GetColumns() **********/
2501 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2503 * 1) The last array element of the tableName[] argument must be zero (null).
2504 * This is how the end of the array is detected.
2505 * 2) This function returns an array of wxDbColInf structures. If no columns
2506 * were found, or an error occurred, this pointer will be zero (null). THE
2507 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
2508 * IS FINISHED WITH IT. i.e.
2510 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
2513 * // Use the column inf
2515 * // Destroy the memory
2519 * userID is evaluated in the following manner:
2520 * userID == NULL ... UserID is ignored
2521 * userID == "" ... UserID set equal to 'this->uid'
2522 * userID != "" ... UserID set equal to 'userID'
2524 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2525 * by this function. This function should use its own wxDb instance
2526 * to avoid undesired unbinding of columns.
2531 wxDbColInf
*colInf
= 0;
2539 convertUserID(userID
,UserID
);
2541 // Pass 1 - Determine how many columns there are.
2542 // Pass 2 - Allocate the wxDbColInf array and fill in
2543 // the array with the column information.
2545 for (pass
= 1; pass
<= 2; pass
++)
2549 if (noCols
== 0) // Probably a bogus table name(s)
2551 // Allocate n wxDbColInf objects to hold the column information
2552 colInf
= new wxDbColInf
[noCols
+1];
2555 // Mark the end of the array
2556 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2557 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2558 colInf
[noCols
].sqlDataType
= 0;
2560 // Loop through each table name
2562 for (tbl
= 0; tableName
[tbl
]; tbl
++)
2564 TableName
= tableName
[tbl
];
2565 // Oracle and Interbase table names are uppercase only, so force
2566 // the name to uppercase just in case programmer forgot to do this
2567 if ((Dbms() == dbmsORACLE
) ||
2568 (Dbms() == dbmsFIREBIRD
) ||
2569 (Dbms() == dbmsINTERBASE
))
2570 TableName
= TableName
.Upper();
2572 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2574 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2575 // use the call below that leaves out the user name
2576 if (!UserID
.empty() &&
2577 Dbms() != dbmsMY_SQL
&&
2578 Dbms() != dbmsACCESS
&&
2579 Dbms() != dbmsMS_SQL_SERVER
)
2581 retcode
= SQLColumns(hstmt
,
2582 NULL
, 0, // All qualifiers
2583 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2584 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
2585 NULL
, 0); // All columns
2589 retcode
= SQLColumns(hstmt
,
2590 NULL
, 0, // All qualifiers
2592 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
2593 NULL
, 0); // All columns
2595 if (retcode
!= SQL_SUCCESS
)
2596 { // Error occurred, abort
2597 DispAllErrors(henv
, hdbc
, hstmt
);
2600 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2604 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2606 if (pass
== 1) // First pass, just add up the number of columns
2608 else // Pass 2; Fill in the array of structures
2610 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2612 // NOTE: Only the ODBC 1.x fields are retrieved
2613 GetData( 1, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2614 GetData( 2, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2615 GetData( 3, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2616 GetData( 4, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2617 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2618 GetData( 6, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2619 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnLength
, 0, &cb
);
2620 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferSize
, 0, &cb
);
2621 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2622 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2623 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2624 GetData(12, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2626 // Determine the wxDb data type that is used to represent the native data type of this data source
2627 colInf
[colNo
].dbDataType
= 0;
2628 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
2631 // IODBC does not return a correct columnLength, so we set
2632 // columnLength = bufferSize if no column length was returned
2633 // IODBC returns the columnLength in bufferSize. (bug)
2634 if (colInf
[colNo
].columnLength
< 1)
2636 colInf
[colNo
].columnLength
= colInf
[colNo
].bufferSize
;
2639 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2641 else if (!wxStricmp(typeInfInteger
.TypeName
, colInf
[colNo
].typeName
))
2642 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2643 else if (!wxStricmp(typeInfFloat
.TypeName
, colInf
[colNo
].typeName
))
2644 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2645 else if (!wxStricmp(typeInfDate
.TypeName
, colInf
[colNo
].typeName
))
2646 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2647 else if (!wxStricmp(typeInfBlob
.TypeName
, colInf
[colNo
].typeName
))
2648 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_BLOB
;
2653 if (retcode
!= SQL_NO_DATA_FOUND
)
2654 { // Error occurred, abort
2655 DispAllErrors(henv
, hdbc
, hstmt
);
2658 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2664 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2667 } // wxDb::GetColumns()
2670 /********** wxDb::GetColumns() **********/
2672 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, UWORD
*numCols
, const wxChar
*userID
)
2674 // Same as the above GetColumns() function except this one gets columns
2675 // only for a single table, and if 'numCols' is not NULL, the number of
2676 // columns stored in the returned wxDbColInf is set in '*numCols'
2678 // userID is evaluated in the following manner:
2679 // userID == NULL ... UserID is ignored
2680 // userID == "" ... UserID set equal to 'this->uid'
2681 // userID != "" ... UserID set equal to 'userID'
2683 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2684 // by this function. This function should use its own wxDb instance
2685 // to avoid undesired unbinding of columns.
2690 wxDbColInf
*colInf
= 0;
2698 convertUserID(userID
,UserID
);
2700 // Pass 1 - Determine how many columns there are.
2701 // Pass 2 - Allocate the wxDbColInf array and fill in
2702 // the array with the column information.
2704 for (pass
= 1; pass
<= 2; pass
++)
2708 if (noCols
== 0) // Probably a bogus table name(s)
2710 // Allocate n wxDbColInf objects to hold the column information
2711 colInf
= new wxDbColInf
[noCols
+1];
2714 // Mark the end of the array
2715 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2716 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2717 colInf
[noCols
].sqlDataType
= 0;
2720 TableName
= tableName
;
2721 // Oracle and Interbase table names are uppercase only, so force
2722 // the name to uppercase just in case programmer forgot to do this
2723 if ((Dbms() == dbmsORACLE
) ||
2724 (Dbms() == dbmsFIREBIRD
) ||
2725 (Dbms() == dbmsINTERBASE
))
2726 TableName
= TableName
.Upper();
2728 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2730 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2731 // use the call below that leaves out the user name
2732 if (!UserID
.empty() &&
2733 Dbms() != dbmsMY_SQL
&&
2734 Dbms() != dbmsACCESS
&&
2735 Dbms() != dbmsMS_SQL_SERVER
)
2737 retcode
= SQLColumns(hstmt
,
2738 NULL
, 0, // All qualifiers
2739 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2740 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
2741 NULL
, 0); // All columns
2745 retcode
= SQLColumns(hstmt
,
2746 NULL
, 0, // All qualifiers
2748 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
2749 NULL
, 0); // All columns
2751 if (retcode
!= SQL_SUCCESS
)
2752 { // Error occurred, abort
2753 DispAllErrors(henv
, hdbc
, hstmt
);
2756 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2762 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2764 if (pass
== 1) // First pass, just add up the number of columns
2766 else // Pass 2; Fill in the array of structures
2768 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2770 // NOTE: Only the ODBC 1.x fields are retrieved
2771 GetData( 1, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2772 GetData( 2, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2773 GetData( 3, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2774 GetData( 4, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2775 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2776 GetData( 6, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2777 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnLength
, 0, &cb
);
2778 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
2779 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferSize
, 0, &cb
);
2780 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2781 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2782 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2783 GetData(12, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2784 // Start Values for Primary/Foriegn Key (=No)
2785 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2786 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2787 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2788 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
2790 // BJO 20000428 : Virtuoso returns type names with upper cases!
2791 if (Dbms() == dbmsVIRTUOSO
)
2793 wxString s
= colInf
[colNo
].typeName
;
2795 wxStrcmp(colInf
[colNo
].typeName
, s
.c_str());
2798 // Determine the wxDb data type that is used to represent the native data type of this data source
2799 colInf
[colNo
].dbDataType
= 0;
2800 if (!wxStricmp(typeInfVarchar
.TypeName
, colInf
[colNo
].typeName
))
2803 // IODBC does not return a correct columnLength, so we set
2804 // columnLength = bufferSize if no column length was returned
2805 // IODBC returns the columnLength in bufferSize. (bug)
2806 if (colInf
[colNo
].columnLength
< 1)
2808 colInf
[colNo
].columnLength
= colInf
[colNo
].bufferSize
;
2812 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2814 else if (!wxStricmp(typeInfInteger
.TypeName
, colInf
[colNo
].typeName
))
2815 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2816 else if (!wxStricmp(typeInfFloat
.TypeName
, colInf
[colNo
].typeName
))
2817 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2818 else if (!wxStricmp(typeInfDate
.TypeName
, colInf
[colNo
].typeName
))
2819 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2820 else if (!wxStricmp(typeInfBlob
.TypeName
, colInf
[colNo
].typeName
))
2821 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_BLOB
;
2827 if (retcode
!= SQL_NO_DATA_FOUND
)
2828 { // Error occurred, abort
2829 DispAllErrors(henv
, hdbc
, hstmt
);
2832 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2839 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2841 // Store Primary and Foriegn Keys
2842 GetKeyFields(tableName
,colInf
,noCols
);
2848 } // wxDb::GetColumns()
2851 #else // New GetColumns
2856 These are tentative new GetColumns members which should be more database
2857 independent and which always returns the columns in the order they were
2860 - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const
2861 wxChar* userID)) calls the second implementation for each separate table
2862 before merging the results. This makes the code easier to maintain as
2863 only one member (the second) makes the real work
2864 - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const
2865 wxChar *userID) is a little bit improved
2866 - It doesn't anymore rely on the type-name to find out which database-type
2868 - It ends by sorting the columns, so that they are returned in the same
2869 order they were created
2879 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2882 // The last array element of the tableName[] argument must be zero (null).
2883 // This is how the end of the array is detected.
2887 // How many tables ?
2889 for (tbl
= 0 ; tableName
[tbl
]; tbl
++);
2891 // Create a table to maintain the columns for each separate table
2892 _TableColumns
*TableColumns
= new _TableColumns
[tbl
];
2895 for (i
= 0 ; i
< tbl
; i
++)
2898 TableColumns
[i
].colInf
= GetColumns(tableName
[i
], &TableColumns
[i
].noCols
, userID
);
2899 if (TableColumns
[i
].colInf
== NULL
)
2901 noCols
+= TableColumns
[i
].noCols
;
2904 // Now merge all the separate table infos
2905 wxDbColInf
*colInf
= new wxDbColInf
[noCols
+1];
2907 // Mark the end of the array
2908 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2909 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2910 colInf
[noCols
].sqlDataType
= 0;
2915 for (i
= 0 ; i
< tbl
; i
++)
2917 for (j
= 0 ; j
< TableColumns
[i
].noCols
; j
++)
2919 colInf
[offset
++] = TableColumns
[i
].colInf
[j
];
2923 delete [] TableColumns
;
2926 } // wxDb::GetColumns() -- NEW
2929 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, int *numCols
, const wxChar
*userID
)
2931 // Same as the above GetColumns() function except this one gets columns
2932 // only for a single table, and if 'numCols' is not NULL, the number of
2933 // columns stored in the returned wxDbColInf is set in '*numCols'
2935 // userID is evaluated in the following manner:
2936 // userID == NULL ... UserID is ignored
2937 // userID == "" ... UserID set equal to 'this->uid'
2938 // userID != "" ... UserID set equal to 'userID'
2940 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2941 // by this function. This function should use its own wxDb instance
2942 // to avoid undesired unbinding of columns.
2946 wxDbColInf
*colInf
= 0;
2954 convertUserID(userID
,UserID
);
2956 // Pass 1 - Determine how many columns there are.
2957 // Pass 2 - Allocate the wxDbColInf array and fill in
2958 // the array with the column information.
2960 for (pass
= 1; pass
<= 2; pass
++)
2964 if (noCols
== 0) // Probably a bogus table name(s)
2966 // Allocate n wxDbColInf objects to hold the column information
2967 colInf
= new wxDbColInf
[noCols
+1];
2970 // Mark the end of the array
2971 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2972 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2973 colInf
[noCols
].sqlDataType
= 0;
2976 TableName
= tableName
;
2977 // Oracle and Interbase table names are uppercase only, so force
2978 // the name to uppercase just in case programmer forgot to do this
2979 if ((Dbms() == dbmsORACLE
) ||
2980 (Dbms() == dbmsFIREBIRD
) ||
2981 (Dbms() == dbmsINTERBASE
))
2982 TableName
= TableName
.Upper();
2984 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2986 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2987 // use the call below that leaves out the user name
2988 if (!UserID
.empty() &&
2989 Dbms() != dbmsMY_SQL
&&
2990 Dbms() != dbmsACCESS
&&
2991 Dbms() != dbmsMS_SQL_SERVER
)
2993 retcode
= SQLColumns(hstmt
,
2994 NULL
, 0, // All qualifiers
2995 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2996 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2997 NULL
, 0); // All columns
3001 retcode
= SQLColumns(hstmt
,
3002 NULL
, 0, // All qualifiers
3004 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
3005 NULL
, 0); // All columns
3007 if (retcode
!= SQL_SUCCESS
)
3008 { // Error occurred, abort
3009 DispAllErrors(henv
, hdbc
, hstmt
);
3012 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3018 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
3020 if (pass
== 1) // First pass, just add up the number of columns
3022 else // Pass 2; Fill in the array of structures
3024 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
3026 // NOTE: Only the ODBC 1.x fields are retrieved
3027 GetData( 1, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
3028 GetData( 2, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
3029 GetData( 3, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
3030 GetData( 4, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
3031 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
3032 GetData( 6, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
3033 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnLength
, 0, &cb
);
3034 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferSize
, 0, &cb
);
3035 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
3036 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
3037 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
3038 GetData(12, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
3039 // Start Values for Primary/Foriegn Key (=No)
3040 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
3041 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
3042 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
3043 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
3046 // IODBC does not return a correct columnLength, so we set
3047 // columnLength = bufferSize if no column length was returned
3048 // IODBC returns the columnLength in bufferSize. (bug)
3049 if (colInf
[colNo
].columnLength
< 1)
3051 colInf
[colNo
].columnLength
= colInf
[colNo
].bufferSize
;
3055 // Determine the wxDb data type that is used to represent the native data type of this data source
3056 colInf
[colNo
].dbDataType
= 0;
3057 // Get the intern datatype
3058 switch (colInf
[colNo
].sqlDataType
)
3061 #if defined(SQL_WCHAR)
3064 #if defined(SQL_WVARCHAR)
3070 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
3076 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
3083 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
3087 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
3090 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_BLOB
;
3095 errMsg
.Printf(wxT("SQL Data type %d currently not supported by wxWidgets"), colInf
[colNo
].sqlDataType
);
3096 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
3103 if (retcode
!= SQL_NO_DATA_FOUND
)
3104 { // Error occurred, abort
3105 DispAllErrors(henv
, hdbc
, hstmt
);
3108 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3115 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3117 // Store Primary and Foreign Keys
3118 GetKeyFields(tableName
,colInf
,noCols
);
3120 ///////////////////////////////////////////////////////////////////////////
3121 // Now sort the the columns in order to make them appear in the right order
3122 ///////////////////////////////////////////////////////////////////////////
3124 // Build a generic SELECT statement which returns 0 rows
3127 Stmt
.Printf(wxT("select * from \"%s\" where 0=1"), tableName
);
3130 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) Stmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
3132 DispAllErrors(henv
, hdbc
, hstmt
);
3136 // Get the number of result columns
3137 if (SQLNumResultCols (hstmt
, &noCols
) != SQL_SUCCESS
)
3139 DispAllErrors(henv
, hdbc
, hstmt
);
3143 if (noCols
== 0) // Probably a bogus table name
3152 for (colNum
= 0; colNum
< noCols
; colNum
++)
3154 if (SQLColAttributes(hstmt
,colNum
+1, SQL_COLUMN_NAME
,
3156 &Sword
, &Sdword
) != SQL_SUCCESS
)
3158 DispAllErrors(henv
, hdbc
, hstmt
);
3162 wxString Name1
= name
;
3163 Name1
= Name1
.Upper();
3165 // Where is this name in the array ?
3166 for (i
= colNum
; i
< noCols
; i
++)
3168 wxString Name2
= colInf
[i
].colName
;
3169 Name2
= Name2
.Upper();
3172 if (colNum
!= i
) // swap to sort
3174 wxDbColInf tmpColInf
= colInf
[colNum
];
3175 colInf
[colNum
] = colInf
[i
];
3176 colInf
[i
] = tmpColInf
;
3182 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3184 ///////////////////////////////////////////////////////////////////////////
3186 ///////////////////////////////////////////////////////////////////////////
3192 } // wxDb::GetColumns()
3195 #endif // #else OLD_GETCOLUMNS
3198 /********** wxDb::GetColumnCount() **********/
3199 int wxDb::GetColumnCount(const wxString
&tableName
, const wxChar
*userID
)
3201 * Returns a count of how many columns are in a table.
3202 * If an error occurs in computing the number of columns
3203 * this function will return a -1 for the count
3205 * userID is evaluated in the following manner:
3206 * userID == NULL ... UserID is ignored
3207 * userID == "" ... UserID set equal to 'this->uid'
3208 * userID != "" ... UserID set equal to 'userID'
3210 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3211 * by this function. This function should use its own wxDb instance
3212 * to avoid undesired unbinding of columns.
3222 convertUserID(userID
,UserID
);
3224 TableName
= tableName
;
3225 // Oracle and Interbase table names are uppercase only, so force
3226 // the name to uppercase just in case programmer forgot to do this
3227 if ((Dbms() == dbmsORACLE
) ||
3228 (Dbms() == dbmsFIREBIRD
) ||
3229 (Dbms() == dbmsINTERBASE
))
3230 TableName
= TableName
.Upper();
3232 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3234 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
3235 // use the call below that leaves out the user name
3236 if (!UserID
.empty() &&
3237 Dbms() != dbmsMY_SQL
&&
3238 Dbms() != dbmsACCESS
&&
3239 Dbms() != dbmsMS_SQL_SERVER
)
3241 retcode
= SQLColumns(hstmt
,
3242 NULL
, 0, // All qualifiers
3243 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
3244 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
3245 NULL
, 0); // All columns
3249 retcode
= SQLColumns(hstmt
,
3250 NULL
, 0, // All qualifiers
3252 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
3253 NULL
, 0); // All columns
3255 if (retcode
!= SQL_SUCCESS
)
3256 { // Error occurred, abort
3257 DispAllErrors(henv
, hdbc
, hstmt
);
3258 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3262 // Count the columns
3263 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
3266 if (retcode
!= SQL_NO_DATA_FOUND
)
3267 { // Error occurred, abort
3268 DispAllErrors(henv
, hdbc
, hstmt
);
3269 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3273 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3276 } // wxDb::GetColumnCount()
3279 /********** wxDb::GetCatalog() *******/
3280 wxDbInf
*wxDb::GetCatalog(const wxChar
*userID
)
3282 * ---------------------------------------------------------------------
3283 * -- 19991203 : mj10777 : Create ------
3284 * -- : Creates a wxDbInf with Tables / Cols Array ------
3285 * -- : uses SQLTables and fills pTableInf; ------
3286 * -- : pColInf is set to NULL and numCols to 0; ------
3287 * -- : returns pDbInf (wxDbInf) ------
3288 * -- - if unsuccessful (pDbInf == NULL) ------
3289 * -- : pColInf can be filled with GetColumns(..); ------
3290 * -- : numCols can be filled with GetColumnCount(..); ------
3291 * ---------------------------------------------------------------------
3293 * userID is evaluated in the following manner:
3294 * userID == NULL ... UserID is ignored
3295 * userID == "" ... UserID set equal to 'this->uid'
3296 * userID != "" ... UserID set equal to 'userID'
3298 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3299 * by this function. This function should use its own wxDb instance
3300 * to avoid undesired unbinding of columns.
3303 int noTab
= 0; // Counter while filling table entries
3307 wxString tblNameSave
;
3310 convertUserID(userID
,UserID
);
3312 //-------------------------------------------------------------
3313 // Create the Database Array of catalog entries
3315 wxDbInf
*pDbInf
= new wxDbInf
;
3317 //-------------------------------------------------------------
3318 // Table Information
3319 // Pass 1 - Determine how many Tables there are.
3320 // Pass 2 - Create the Table array and fill it
3321 // - Create the Cols array = NULL
3322 //-------------------------------------------------------------
3324 for (pass
= 1; pass
<= 2; pass
++)
3326 SQLFreeStmt(hstmt
, SQL_CLOSE
); // Close if Open
3327 tblNameSave
.Empty();
3329 if (!UserID
.empty() &&
3330 Dbms() != dbmsMY_SQL
&&
3331 Dbms() != dbmsACCESS
&&
3332 Dbms() != dbmsMS_SQL_SERVER
)
3334 retcode
= SQLTables(hstmt
,
3335 NULL
, 0, // All qualifiers
3336 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
3337 NULL
, 0, // All tables
3338 NULL
, 0); // All columns
3342 retcode
= SQLTables(hstmt
,
3343 NULL
, 0, // All qualifiers
3344 NULL
, 0, // User specified
3345 NULL
, 0, // All tables
3346 NULL
, 0); // All columns
3349 if (retcode
!= SQL_SUCCESS
)
3351 DispAllErrors(henv
, hdbc
, hstmt
);
3353 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3357 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
) // Table Information
3359 if (pass
== 1) // First pass, just count the Tables
3361 if (pDbInf
->numTables
== 0)
3363 GetData( 1, SQL_C_WXCHAR
, (UCHAR
*) pDbInf
->catalog
, 128+1, &cb
);
3364 GetData( 2, SQL_C_WXCHAR
, (UCHAR
*) pDbInf
->schema
, 128+1, &cb
);
3366 pDbInf
->numTables
++; // Counter for Tables
3368 if (pass
== 2) // Create and fill the Table entries
3370 if (pDbInf
->pTableInf
== NULL
) // Has the Table Array been created
3371 { // no, then create the Array
3372 pDbInf
->pTableInf
= new wxDbTableInf
[pDbInf
->numTables
];
3374 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
3376 GetData( 3, SQL_C_WXCHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
3377 GetData( 4, SQL_C_WXCHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableType
, 30+1, &cb
);
3378 GetData( 5, SQL_C_WXCHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableRemarks
, 254+1, &cb
);
3384 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3386 // Query how many columns are in each table
3387 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
3389 (pDbInf
->pTableInf
+noTab
)->numCols
= (UWORD
)GetColumnCount((pDbInf
->pTableInf
+noTab
)->tableName
,UserID
);
3394 } // wxDb::GetCatalog()
3397 /********** wxDb::Catalog() **********/
3398 bool wxDb::Catalog(const wxChar
*userID
, const wxString
&fileName
)
3400 * Creates the text file specified in 'filename' which will contain
3401 * a minimal data dictionary of all tables accessible by the user specified
3404 * userID is evaluated in the following manner:
3405 * userID == NULL ... UserID is ignored
3406 * userID == "" ... UserID set equal to 'this->uid'
3407 * userID != "" ... UserID set equal to 'userID'
3409 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3410 * by this function. This function should use its own wxDb instance
3411 * to avoid undesired unbinding of columns.
3414 wxASSERT(fileName
.Length());
3418 wxChar tblName
[DB_MAX_TABLE_NAME_LEN
+1];
3419 wxString tblNameSave
;
3420 wxChar colName
[DB_MAX_COLUMN_NAME_LEN
+1];
3422 wxChar typeName
[30+1];
3423 SDWORD precision
, length
;
3425 FILE *fp
= wxFopen(fileName
.c_str(),wxT("wt"));
3429 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3432 convertUserID(userID
,UserID
);
3434 if (!UserID
.empty() &&
3435 Dbms() != dbmsMY_SQL
&&
3436 Dbms() != dbmsACCESS
&&
3437 Dbms() != dbmsFIREBIRD
&&
3438 Dbms() != dbmsINTERBASE
&&
3439 Dbms() != dbmsMS_SQL_SERVER
)
3441 retcode
= SQLColumns(hstmt
,
3442 NULL
, 0, // All qualifiers
3443 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
3444 NULL
, 0, // All tables
3445 NULL
, 0); // All columns
3449 retcode
= SQLColumns(hstmt
,
3450 NULL
, 0, // All qualifiers
3451 NULL
, 0, // User specified
3452 NULL
, 0, // All tables
3453 NULL
, 0); // All columns
3455 if (retcode
!= SQL_SUCCESS
)
3457 DispAllErrors(henv
, hdbc
, hstmt
);
3463 tblNameSave
.Empty();
3468 retcode
= SQLFetch(hstmt
);
3469 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
3472 GetData(3,SQL_C_WXCHAR
, (UCHAR
*) tblName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
3473 GetData(4,SQL_C_WXCHAR
, (UCHAR
*) colName
, DB_MAX_COLUMN_NAME_LEN
+1,&cb
);
3474 GetData(5,SQL_C_SSHORT
, (UCHAR
*)&sqlDataType
, 0, &cb
);
3475 GetData(6,SQL_C_WXCHAR
, (UCHAR
*) typeName
, sizeof(typeName
), &cb
);
3476 GetData(7,SQL_C_SLONG
, (UCHAR
*)&precision
, 0, &cb
);
3477 GetData(8,SQL_C_SLONG
, (UCHAR
*)&length
, 0, &cb
);
3479 if (wxStrcmp(tblName
, tblNameSave
.c_str()))
3482 wxFputs(wxT("\n"), fp
);
3483 wxFputs(wxT("================================ "), fp
);
3484 wxFputs(wxT("================================ "), fp
);
3485 wxFputs(wxT("===================== "), fp
);
3486 wxFputs(wxT("========= "), fp
);
3487 wxFputs(wxT("=========\n"), fp
);
3488 outStr
.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
3489 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
3490 wxFputs(outStr
.c_str(), fp
);
3491 wxFputs(wxT("================================ "), fp
);
3492 wxFputs(wxT("================================ "), fp
);
3493 wxFputs(wxT("===================== "), fp
);
3494 wxFputs(wxT("========= "), fp
);
3495 wxFputs(wxT("=========\n"), fp
);
3496 tblNameSave
= tblName
;
3499 outStr
.Printf(wxT("%-32s %-32s (%04d)%-15s %9ld %9ld\n"),
3500 tblName
, colName
, sqlDataType
, typeName
, precision
, length
);
3501 if (wxFputs(outStr
.c_str(), fp
) == EOF
)
3503 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3510 if (retcode
!= SQL_NO_DATA_FOUND
)
3511 DispAllErrors(henv
, hdbc
, hstmt
);
3513 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3516 return(retcode
== SQL_NO_DATA_FOUND
);
3518 } // wxDb::Catalog()
3521 bool wxDb::TableExists(const wxString
&tableName
, const wxChar
*userID
, const wxString
&tablePath
)
3523 * Table name can refer to a table, view, alias or synonym. Returns true
3524 * if the object exists in the database. This function does not indicate
3525 * whether or not the user has privleges to query or perform other functions
3528 * userID is evaluated in the following manner:
3529 * userID == NULL ... UserID is ignored
3530 * userID == "" ... UserID set equal to 'this->uid'
3531 * userID != "" ... UserID set equal to 'userID'
3534 wxASSERT(tableName
.Length());
3538 if (Dbms() == dbmsDBASE
)
3541 if (tablePath
.Length())
3542 dbName
.Printf(wxT("%s/%s.dbf"), tablePath
.c_str(), tableName
.c_str());
3544 dbName
.Printf(wxT("%s.dbf"), tableName
.c_str());
3547 exists
= wxFileExists(dbName
);
3552 convertUserID(userID
,UserID
);
3554 TableName
= tableName
;
3555 // Oracle and Interbase table names are uppercase only, so force
3556 // the name to uppercase just in case programmer forgot to do this
3557 if ((Dbms() == dbmsORACLE
) ||
3558 (Dbms() == dbmsFIREBIRD
) ||
3559 (Dbms() == dbmsINTERBASE
))
3560 TableName
= TableName
.Upper();
3562 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3565 // Some databases cannot accept a user name when looking up table names,
3566 // so we use the call below that leaves out the user name
3567 if (!UserID
.empty() &&
3568 Dbms() != dbmsMY_SQL
&&
3569 Dbms() != dbmsACCESS
&&
3570 Dbms() != dbmsMS_SQL_SERVER
&&
3571 Dbms() != dbmsDB2
&&
3572 Dbms() != dbmsFIREBIRD
&&
3573 Dbms() != dbmsINTERBASE
&&
3574 Dbms() != dbmsPERVASIVE_SQL
)
3576 retcode
= SQLTables(hstmt
,
3577 NULL
, 0, // All qualifiers
3578 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // Only tables owned by this user
3579 (SQLTCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3580 NULL
, 0); // All table types
3584 retcode
= SQLTables(hstmt
,
3585 NULL
, 0, // All qualifiers
3586 NULL
, 0, // All owners
3587 (SQLTCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3588 NULL
, 0); // All table types
3590 if (retcode
!= SQL_SUCCESS
)
3591 return(DispAllErrors(henv
, hdbc
, hstmt
));
3593 retcode
= SQLFetch(hstmt
);
3594 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
3596 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3597 return(DispAllErrors(henv
, hdbc
, hstmt
));
3600 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3604 } // wxDb::TableExists()
3607 /********** wxDb::TablePrivileges() **********/
3608 bool wxDb::TablePrivileges(const wxString
&tableName
, const wxString
&priv
, const wxChar
*userID
,
3609 const wxChar
*schema
, const wxString
&WXUNUSED(tablePath
))
3611 wxASSERT(tableName
.Length());
3613 wxDbTablePrivilegeInfo result
;
3617 // We probably need to be able to dynamically set this based on
3618 // the driver type, and state.
3619 wxChar curRole
[]=wxT("public");
3623 wxString UserID
,Schema
;
3624 convertUserID(userID
,UserID
);
3625 convertUserID(schema
,Schema
);
3627 TableName
= tableName
;
3628 // Oracle and Interbase table names are uppercase only, so force
3629 // the name to uppercase just in case programmer forgot to do this
3630 if ((Dbms() == dbmsORACLE
) ||
3631 (Dbms() == dbmsFIREBIRD
) ||
3632 (Dbms() == dbmsINTERBASE
))
3633 TableName
= TableName
.Upper();
3635 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3637 // Some databases cannot accept a user name when looking up table names,
3638 // so we use the call below that leaves out the user name
3639 if (!Schema
.empty() &&
3640 Dbms() != dbmsMY_SQL
&&
3641 Dbms() != dbmsACCESS
&&
3642 Dbms() != dbmsMS_SQL_SERVER
)
3644 retcode
= SQLTablePrivileges(hstmt
,
3646 (SQLTCHAR FAR
*)Schema
.c_str(), SQL_NTS
, // Schema
3647 (SQLTCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3651 retcode
= SQLTablePrivileges(hstmt
,
3654 (SQLTCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3657 #ifdef DBDEBUG_CONSOLE
3658 wxFprintf(stderr
,wxT("SQLTablePrivileges() returned %i \n"),retcode
);
3661 if ((retcode
!= SQL_SUCCESS
) && (retcode
!= SQL_SUCCESS_WITH_INFO
))
3662 return (DispAllErrors(henv
, hdbc
, hstmt
));
3664 bool failed
= false;
3665 retcode
= SQLFetch(hstmt
);
3666 while (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
3668 if (SQLGetData(hstmt
, 1, SQL_C_WXCHAR
, (UCHAR
*) result
.tableQual
, sizeof(result
.tableQual
), &cbRetVal
) != SQL_SUCCESS
)
3671 if (!failed
&& SQLGetData(hstmt
, 2, SQL_C_WXCHAR
, (UCHAR
*) result
.tableOwner
, sizeof(result
.tableOwner
), &cbRetVal
) != SQL_SUCCESS
)
3674 if (!failed
&& SQLGetData(hstmt
, 3, SQL_C_WXCHAR
, (UCHAR
*) result
.tableName
, sizeof(result
.tableName
), &cbRetVal
) != SQL_SUCCESS
)
3677 if (!failed
&& SQLGetData(hstmt
, 4, SQL_C_WXCHAR
, (UCHAR
*) result
.grantor
, sizeof(result
.grantor
), &cbRetVal
) != SQL_SUCCESS
)
3680 if (!failed
&& SQLGetData(hstmt
, 5, SQL_C_WXCHAR
, (UCHAR
*) result
.grantee
, sizeof(result
.grantee
), &cbRetVal
) != SQL_SUCCESS
)
3683 if (!failed
&& SQLGetData(hstmt
, 6, SQL_C_WXCHAR
, (UCHAR
*) result
.privilege
, sizeof(result
.privilege
), &cbRetVal
) != SQL_SUCCESS
)
3686 if (!failed
&& SQLGetData(hstmt
, 7, SQL_C_WXCHAR
, (UCHAR
*) result
.grantable
, sizeof(result
.grantable
), &cbRetVal
) != SQL_SUCCESS
)
3691 return(DispAllErrors(henv
, hdbc
, hstmt
));
3693 #ifdef DBDEBUG_CONSOLE
3694 wxFprintf(stderr
,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
3695 result
.privilege
,result
.tableOwner
,result
.tableName
,
3696 result
.grantor
, result
.grantee
);
3699 if (UserID
.IsSameAs(result
.tableOwner
,false))
3701 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3705 if (UserID
.IsSameAs(result
.grantee
,false) &&
3706 !wxStrcmp(result
.privilege
,priv
))
3708 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3712 if (!wxStrcmp(result
.grantee
,curRole
) &&
3713 !wxStrcmp(result
.privilege
,priv
))
3715 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3719 retcode
= SQLFetch(hstmt
);
3722 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3725 } // wxDb::TablePrivileges
3728 const wxString
wxDb::SQLTableName(const wxChar
*tableName
)
3732 if (Dbms() == dbmsACCESS
)
3733 TableName
= _T("\"");
3734 TableName
+= tableName
;
3735 if (Dbms() == dbmsACCESS
)
3736 TableName
+= _T("\"");
3739 } // wxDb::SQLTableName()
3742 const wxString
wxDb::SQLColumnName(const wxChar
*colName
)
3746 if (Dbms() == dbmsACCESS
)
3749 if (Dbms() == dbmsACCESS
)
3750 ColName
+= _T("\"");
3753 } // wxDb::SQLColumnName()
3756 /********** wxDb::SetSqlLogging() **********/
3757 bool wxDb::SetSqlLogging(wxDbSqlLogState state
, const wxString
&filename
, bool append
)
3759 wxASSERT(state
== sqlLogON
|| state
== sqlLogOFF
);
3760 wxASSERT(state
== sqlLogOFF
|| filename
.Length());
3762 if (state
== sqlLogON
)
3766 fpSqlLog
= wxFopen(filename
.c_str(), (append
? wxT("at") : wxT("wt")));
3767 if (fpSqlLog
== NULL
)
3775 if (fclose(fpSqlLog
))
3781 sqlLogState
= state
;
3784 } // wxDb::SetSqlLogging()
3787 /********** wxDb::WriteSqlLog() **********/
3788 bool wxDb::WriteSqlLog(const wxString
&logMsg
)
3790 wxASSERT(logMsg
.Length());
3792 if (fpSqlLog
== 0 || sqlLogState
== sqlLogOFF
)
3795 if (wxFputs(wxT("\n"), fpSqlLog
) == EOF
)
3797 if (wxFputs(logMsg
, fpSqlLog
) == EOF
)
3799 if (wxFputs(wxT("\n"), fpSqlLog
) == EOF
)
3804 } // wxDb::WriteSqlLog()
3807 /********** wxDb::Dbms() **********/
3808 wxDBMS
wxDb::Dbms(void)
3810 * Be aware that not all database engines use the exact same syntax, and not
3811 * every ODBC compliant database is compliant to the same level of compliancy.
3812 * Some manufacturers support the minimum Level 1 compliancy, and others up
3813 * through Level 3. Others support subsets of features for levels above 1.
3815 * If you find an inconsistency between the wxDb class and a specific database
3816 * engine, and an identifier to this section, and special handle the database in
3817 * the area where behavior is non-conforming with the other databases.
3820 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3821 * ---------------------------------------------------
3824 * - Currently the only database supported by the class to support VIEWS
3827 * - Does not support the SQL_TIMESTAMP structure
3828 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
3829 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
3830 * is true. The user must create ALL indexes from their program.
3831 * - Table names can only be 8 characters long
3832 * - Column names can only be 10 characters long
3835 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3836 * after every table name involved in the query/join if that tables matching record(s)
3838 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
3840 * SYBASE (Enterprise)
3841 * - If a column is part of the Primary Key, the column cannot be NULL
3842 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
3845 * - If a column is part of the Primary Key, the column cannot be NULL
3846 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3847 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3848 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3849 * column definition if it is not defined correctly, but it is experimental
3850 * - Does not support sub-queries in SQL statements
3853 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3854 * - Does not support sub-queries in SQL statements
3857 * - Primary keys must be declared as NOT NULL
3858 * - Table and index names must not be longer than 13 characters in length (technically
3859 * table names can be up to 18 characters, but the primary index is created using the
3860 * base table name plus "_PIDX", so the limit if the table has a primary index is 13.
3865 * - Columns that are part of primary keys must be defined as being NOT NULL
3866 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3867 * column definition if it is not defined correctly, but it is experimental
3870 // Should only need to do this once for each new database connection
3871 // so return the value we already determined it to be to save time
3872 // and lots of string comparisons
3873 if (dbmsType
!= dbmsUNIDENTIFIED
)
3876 #ifdef DBDEBUG_CONSOLE
3877 // When run in console mode, use standard out to display errors.
3878 cout
<< "Database connecting to: " << dbInf
.dbmsName
<< endl
;
3879 #endif // DBDEBUG_CONSOLE
3881 wxLogDebug(wxT("Database connecting to: "));
3882 wxLogDebug(dbInf
.dbmsName
);
3884 wxChar baseName
[25+1];
3885 wxStrncpy(baseName
, dbInf
.dbmsName
, 25);
3888 // RGG 20001025 : add support for Interbase
3889 // GT : Integrated to base classes on 20001121
3890 if (!wxStricmp(dbInf
.dbmsName
,wxT("Interbase")))
3891 return((wxDBMS
)(dbmsType
= dbmsINTERBASE
));
3893 // BJO 20000428 : add support for Virtuoso
3894 if (!wxStricmp(dbInf
.dbmsName
,wxT("OpenLink Virtuoso VDBMS")))
3895 return((wxDBMS
)(dbmsType
= dbmsVIRTUOSO
));
3897 if (!wxStricmp(dbInf
.dbmsName
,wxT("Adaptive Server Anywhere")))
3898 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASA
));
3900 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3901 // connected through an OpenLink driver.
3902 // Is it also returned by Sybase Adapatitve server?
3903 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
3904 if (!wxStricmp(dbInf
.dbmsName
,wxT("SQL Server")))
3906 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
3907 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
3908 return ((wxDBMS
)(dbmsMS_SQL_SERVER
));
3910 return ((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3913 if (!wxStricmp(dbInf
.dbmsName
,wxT("Microsoft SQL Server")))
3914 return((wxDBMS
)(dbmsType
= dbmsMS_SQL_SERVER
));
3917 if (!wxStricmp(baseName
,wxT("PostgreSQL"))) // v6.5.0
3918 return((wxDBMS
)(dbmsType
= dbmsPOSTGRES
));
3921 if (!wxStricmp(baseName
,wxT("Pervasive")))
3922 return((wxDBMS
)(dbmsType
= dbmsPERVASIVE_SQL
));
3925 if (!wxStricmp(baseName
,wxT("Informix")))
3926 return((wxDBMS
)(dbmsType
= dbmsINFORMIX
));
3928 if (!wxStricmp(baseName
,wxT("Firebird")))
3929 return((wxDBMS
)(dbmsType
= dbmsFIREBIRD
));
3932 if (!wxStricmp(baseName
,wxT("Oracle")))
3933 return((wxDBMS
)(dbmsType
= dbmsORACLE
));
3934 if (!wxStricmp(baseName
,wxT("ACCESS")))
3935 return((wxDBMS
)(dbmsType
= dbmsACCESS
));
3936 if (!wxStricmp(baseName
,wxT("Sybase")))
3937 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3940 if (!wxStricmp(baseName
,wxT("DBASE")))
3941 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3942 if (!wxStricmp(baseName
,wxT("xBase")))
3943 return((wxDBMS
)(dbmsType
= dbmsXBASE_SEQUITER
));
3944 if (!wxStricmp(baseName
,wxT("MySQL")))
3945 return((wxDBMS
)(dbmsType
= dbmsMY_SQL
));
3946 if (!wxStricmp(baseName
,wxT("MaxDB")))
3947 return((wxDBMS
)(dbmsType
= dbmsMAXDB
));
3950 if (!wxStricmp(baseName
,wxT("DB2")))
3951 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3953 return((wxDBMS
)(dbmsType
= dbmsUNIDENTIFIED
));
3958 bool wxDb::ModifyColumn(const wxString
&tableName
, const wxString
&columnName
,
3959 int dataType
, ULONG columnLength
,
3960 const wxString
&optionalParam
)
3962 wxASSERT(tableName
.Length());
3963 wxASSERT(columnName
.Length());
3964 wxASSERT((dataType
== DB_DATA_TYPE_VARCHAR
&& columnLength
> 0) ||
3965 dataType
!= DB_DATA_TYPE_VARCHAR
);
3967 // Must specify a columnLength if modifying a VARCHAR type column
3968 if (dataType
== DB_DATA_TYPE_VARCHAR
&& !columnLength
)
3971 wxString dataTypeName
;
3973 wxString alterSlashModify
;
3977 case DB_DATA_TYPE_VARCHAR
:
3978 dataTypeName
= typeInfVarchar
.TypeName
;
3980 case DB_DATA_TYPE_INTEGER
:
3981 dataTypeName
= typeInfInteger
.TypeName
;
3983 case DB_DATA_TYPE_FLOAT
:
3984 dataTypeName
= typeInfFloat
.TypeName
;
3986 case DB_DATA_TYPE_DATE
:
3987 dataTypeName
= typeInfDate
.TypeName
;
3989 case DB_DATA_TYPE_BLOB
:
3990 dataTypeName
= typeInfBlob
.TypeName
;
3996 // Set the modify or alter syntax depending on the type of database connected to
4000 alterSlashModify
= _T("MODIFY");
4002 case dbmsMS_SQL_SERVER
:
4003 alterSlashModify
= _T("ALTER COLUMN");
4005 case dbmsUNIDENTIFIED
:
4007 case dbmsSYBASE_ASA
:
4008 case dbmsSYBASE_ASE
:
4013 case dbmsXBASE_SEQUITER
:
4015 alterSlashModify
= _T("MODIFY");
4019 // create the SQL statement
4020 if ( Dbms() == dbmsMY_SQL
)
4022 sqlStmt
.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName
.c_str(), alterSlashModify
.c_str(),
4023 columnName
.c_str(), dataTypeName
.c_str());
4027 sqlStmt
.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName
.c_str(), alterSlashModify
.c_str(),
4028 columnName
.c_str(), dataTypeName
.c_str());
4031 // For varchars only, append the size of the column
4032 if (dataType
== DB_DATA_TYPE_VARCHAR
&&
4033 (Dbms() != dbmsMY_SQL
|| dataTypeName
!= _T("text")))
4036 s
.Printf(wxT("(%lu)"), columnLength
);
4040 // for passing things like "NOT NULL"
4041 if (optionalParam
.Length())
4043 sqlStmt
+= wxT(" ");
4044 sqlStmt
+= optionalParam
;
4047 return ExecSql(sqlStmt
);
4049 } // wxDb::ModifyColumn()
4052 /********** wxDbGetConnection() **********/
4053 wxDb WXDLLIMPEXP_ODBC
*wxDbGetConnection(wxDbConnectInf
*pDbConfig
, bool FwdOnlyCursors
)
4057 // Used to keep a pointer to a DB connection that matches the requested
4058 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
4059 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
4060 // rather than having to re-query the datasource to get all the values
4061 // using the wxDb::Open(Dsn,Uid,AuthStr) function
4062 wxDb
*matchingDbConnection
= NULL
;
4064 // Scan the linked list searching for an available database connection
4065 // that's already been opened but is currently not in use.
4066 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
4068 // The database connection must be for the same datasource
4069 // name and must currently not be in use.
4071 (pList
->PtrDb
->FwdOnlyCursors() == FwdOnlyCursors
))
4073 if (pDbConfig
->UseConnectionStr())
4075 if (pList
->PtrDb
->OpenedWithConnectionString() &&
4076 (!wxStrcmp(pDbConfig
->GetConnectionStr(), pList
->ConnectionStr
)))
4078 // Found a free connection
4079 pList
->Free
= false;
4080 return(pList
->PtrDb
);
4085 if (!pList
->PtrDb
->OpenedWithConnectionString() &&
4086 (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
)))
4088 // Found a free connection
4089 pList
->Free
= false;
4090 return(pList
->PtrDb
);
4095 if (pDbConfig
->UseConnectionStr())
4097 if (!wxStrcmp(pDbConfig
->GetConnectionStr(), pList
->ConnectionStr
))
4098 matchingDbConnection
= pList
->PtrDb
;
4102 if (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
) &&
4103 !wxStrcmp(pDbConfig
->GetUserID(), pList
->Uid
) &&
4104 !wxStrcmp(pDbConfig
->GetPassword(), pList
->AuthStr
))
4105 matchingDbConnection
= pList
->PtrDb
;
4109 // No available connections. A new connection must be made and
4110 // appended to the end of the linked list.
4113 // Find the end of the list
4114 for (pList
= PtrBegDbList
; pList
->PtrNext
; pList
= pList
->PtrNext
);
4115 // Append a new list item
4116 pList
->PtrNext
= new wxDbList
;
4117 pList
->PtrNext
->PtrPrev
= pList
;
4118 pList
= pList
->PtrNext
;
4122 // Create the first node on the list
4123 pList
= PtrBegDbList
= new wxDbList
;
4127 // Initialize new node in the linked list
4129 pList
->Free
= false;
4130 pList
->Dsn
= pDbConfig
->GetDsn();
4131 pList
->Uid
= pDbConfig
->GetUserID();
4132 pList
->AuthStr
= pDbConfig
->GetPassword();
4133 pList
->ConnectionStr
= pDbConfig
->GetConnectionStr();
4135 pList
->PtrDb
= new wxDb(pDbConfig
->GetHenv(), FwdOnlyCursors
);
4139 if (!matchingDbConnection
)
4141 if (pDbConfig
->UseConnectionStr())
4143 opened
= pList
->PtrDb
->Open(pDbConfig
->GetConnectionStr());
4147 opened
= pList
->PtrDb
->Open(pDbConfig
->GetDsn(), pDbConfig
->GetUserID(), pDbConfig
->GetPassword());
4151 opened
= pList
->PtrDb
->Open(matchingDbConnection
);
4153 // Connect to the datasource
4156 pList
->PtrDb
->setCached(true); // Prevent a user from deleting a cached connection
4157 pList
->PtrDb
->SetSqlLogging(SQLLOGstate
, SQLLOGfn
, true);
4158 return(pList
->PtrDb
);
4160 else // Unable to connect, destroy list item
4163 pList
->PtrPrev
->PtrNext
= 0;
4165 PtrBegDbList
= 0; // Empty list again
4167 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
4168 pList
->PtrDb
->Close(); // Close the wxDb object
4169 delete pList
->PtrDb
; // Deletes the wxDb object
4170 delete pList
; // Deletes the linked list object
4174 } // wxDbGetConnection()
4177 /********** wxDbFreeConnection() **********/
4178 bool WXDLLIMPEXP_ODBC
wxDbFreeConnection(wxDb
*pDb
)
4182 // Scan the linked list searching for the database connection
4183 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
4185 if (pList
->PtrDb
== pDb
) // Found it, now free it!!!
4186 return (pList
->Free
= true);
4189 // Never found the database object, return failure
4192 } // wxDbFreeConnection()
4195 /********** wxDbCloseConnections() **********/
4196 void WXDLLIMPEXP_ODBC
wxDbCloseConnections(void)
4198 wxDbList
*pList
, *pNext
;
4200 // Traverse the linked list closing database connections and freeing memory as I go.
4201 for (pList
= PtrBegDbList
; pList
; pList
= pNext
)
4203 pNext
= pList
->PtrNext
; // Save the pointer to next
4204 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
4205 pList
->PtrDb
->Close(); // Close the wxDb object
4206 pList
->PtrDb
->setCached(false); // Allows deletion of the wxDb instance
4207 delete pList
->PtrDb
; // Deletes the wxDb object
4208 delete pList
; // Deletes the linked list object
4211 // Mark the list as empty
4214 } // wxDbCloseConnections()
4217 /********** wxDbConnectionsInUse() **********/
4218 int WXDLLIMPEXP_ODBC
wxDbConnectionsInUse(void)
4223 // Scan the linked list counting db connections that are currently in use
4224 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
4226 if (pList
->Free
== false)
4232 } // wxDbConnectionsInUse()
4236 /********** wxDbLogExtendedErrorMsg() **********/
4237 // DEBUG ONLY function
4238 const wxChar WXDLLIMPEXP_ODBC
*wxDbLogExtendedErrorMsg(const wxChar
*userText
,
4240 const wxChar
*ErrFile
,
4243 static wxString msg
;
4248 if (ErrFile
|| ErrLine
)
4250 msg
+= wxT("File: ");
4252 msg
+= wxT(" Line: ");
4253 tStr
.Printf(wxT("%d"),ErrLine
);
4254 msg
+= tStr
.c_str();
4258 msg
.Append (wxT("\nODBC errors:\n"));
4261 // Display errors for this connection
4263 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
4265 if (pDb
->errorList
[i
])
4267 msg
.Append(pDb
->errorList
[i
]);
4268 if (wxStrcmp(pDb
->errorList
[i
], wxEmptyString
) != 0)
4269 msg
.Append(wxT("\n"));
4270 // Clear the errmsg buffer so the next error will not
4271 // end up showing the previous error that have occurred
4272 wxStrcpy(pDb
->errorList
[i
], wxEmptyString
);
4277 wxLogDebug(msg
.c_str());
4280 } // wxDbLogExtendedErrorMsg()
4283 /********** wxDbSqlLog() **********/
4284 bool wxDbSqlLog(wxDbSqlLogState state
, const wxChar
*filename
)
4286 bool append
= false;
4289 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
4291 if (!pList
->PtrDb
->SetSqlLogging(state
,filename
,append
))
4296 SQLLOGstate
= state
;
4297 SQLLOGfn
= filename
;
4305 /********** wxDbCreateDataSource() **********/
4306 int wxDbCreateDataSource(const wxString
&driverName
, const wxString
&dsn
, const wxString
&description
,
4307 bool sysDSN
, const wxString
&defDir
, wxWindow
*parent
)
4309 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
4310 * Very rudimentary creation of an ODBC data source.
4312 * ODBC driver must be ODBC 3.0 compliant to use this function
4317 //!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
4323 dsnLocation
= ODBC_ADD_SYS_DSN
;
4325 dsnLocation
= ODBC_ADD_DSN
;
4327 // NOTE: The decimal 2 is an invalid character in all keyword pairs
4328 // so that is why I used it, as wxString does not deal well with
4329 // embedded nulls in strings
4330 setupStr
.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn
,2,description
,2,defDir
,2);
4332 // Replace the separator from above with the '\0' separator needed
4333 // by the SQLConfigDataSource() function
4337 k
= setupStr
.Find((wxChar
)2,true);
4338 if (k
!= wxNOT_FOUND
)
4339 setupStr
[(UINT
)k
] = wxT('\0');
4341 while (k
!= wxNOT_FOUND
);
4343 result
= SQLConfigDataSource((HWND
)parent
->GetHWND(), dsnLocation
,
4344 driverName
, setupStr
.c_str());
4346 if ((result
!= SQL_SUCCESS
) && (result
!= SQL_SUCCESS_WITH_INFO
))
4348 // check for errors caused by ConfigDSN based functions
4351 wxChar errMsg
[SQL_MAX_MESSAGE_LENGTH
];
4352 errMsg
[0] = wxT('\0');
4354 // This function is only supported in ODBC drivers v3.0 compliant and above
4355 SQLInstallerError(1,&retcode
,errMsg
,SQL_MAX_MESSAGE_LENGTH
-1,&cb
);
4358 #ifdef DBDEBUG_CONSOLE
4359 // When run in console mode, use standard out to display errors.
4360 cout
<< errMsg
<< endl
;
4361 cout
<< wxT("Press any key to continue...") << endl
;
4363 #endif // DBDEBUG_CONSOLE
4366 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
4367 #endif // __WXDEBUG__
4373 // Using iODBC/unixODBC or some other compiler which does not support the APIs
4374 // necessary to use this function, so this function is not supported
4376 wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
4379 #endif // __VISUALC__
4383 } // wxDbCreateDataSource()
4387 /********** wxDbGetDataSource() **********/
4388 bool wxDbGetDataSource(HENV henv
, wxChar
*Dsn
, SWORD DsnMaxLength
, wxChar
*DsDesc
,
4389 SWORD DsDescMaxLength
, UWORD direction
)
4391 * Dsn and DsDesc will contain the data source name and data source
4392 * description upon return
4396 SWORD lengthDsn
= (SWORD
)(DsnMaxLength
*sizeof(wxChar
));
4397 SWORD lengthDsDesc
= (SWORD
)(DsDescMaxLength
*sizeof(wxChar
));
4399 if (SQLDataSources(henv
, direction
, (SQLTCHAR FAR
*) Dsn
, lengthDsn
, &cb1
,
4400 (SQLTCHAR FAR
*) DsDesc
, lengthDsDesc
, &cb2
) == SQL_SUCCESS
)
4405 } // wxDbGetDataSource()
4408 // Change this to 0 to remove use of all deprecated functions
4409 #if wxODBC_BACKWARD_COMPATABILITY
4410 /********************************************************************
4411 ********************************************************************
4413 * The following functions are all DEPRECATED and are included for
4414 * backward compatibility reasons only
4416 ********************************************************************
4417 ********************************************************************/
4418 bool SqlLog(sqlLog state
, const wxChar
*filename
)
4420 return wxDbSqlLog((enum wxDbSqlLogState
)state
, filename
);
4422 /***** DEPRECATED: use wxGetDataSource() *****/
4423 bool GetDataSource(HENV henv
, char *Dsn
, SWORD DsnMax
, char *DsDesc
, SWORD DsDescMax
,
4426 return wxDbGetDataSource(henv
, Dsn
, DsnMax
, DsDesc
, DsDescMax
, direction
);
4428 /***** DEPRECATED: use wxDbGetConnection() *****/
4429 wxDb WXDLLIMPEXP_ODBC
*GetDbConnection(DbStuff
*pDbStuff
, bool FwdOnlyCursors
)
4431 return wxDbGetConnection((wxDbConnectInf
*)pDbStuff
, FwdOnlyCursors
);
4433 /***** DEPRECATED: use wxDbFreeConnection() *****/
4434 bool WXDLLIMPEXP_ODBC
FreeDbConnection(wxDb
*pDb
)
4436 return wxDbFreeConnection(pDb
);
4438 /***** DEPRECATED: use wxDbCloseConnections() *****/
4439 void WXDLLIMPEXP_ODBC
CloseDbConnections(void)
4441 wxDbCloseConnections();
4443 /***** DEPRECATED: use wxDbConnectionsInUse() *****/
4444 int WXDLLIMPEXP_ODBC
NumberDbConnectionsInUse(void)
4446 return wxDbConnectionsInUse();