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 ///////////////////////////////////////////////////////////////////////////////
28 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
29 #pragma implementation "db.h"
32 #include "wx/wxprec.h"
38 #ifdef DBDEBUG_CONSOLE
39 #include "wx/ioswrap.h"
43 #include "wx/string.h"
44 #include "wx/object.h"
49 #include "wx/filefn.h"
50 #include "wx/wxchar.h"
62 // DLL options compatibility check:
64 WX_CHECK_BUILD_OPTIONS("wxODBC")
66 WXDLLIMPEXP_DATA_ODBC(wxDbList
*) PtrBegDbList
= 0;
68 wxChar
const *SQL_LOG_FILENAME
= wxT("sqllog.txt");
69 wxChar
const *SQL_CATALOG_FILENAME
= wxT("catalog.txt");
72 extern wxList TablesInUse
;
75 // SQL Log defaults to be used by GetDbConnection
76 wxDbSqlLogState SQLLOGstate
= sqlLogOFF
;
78 static wxString SQLLOGfn
= SQL_LOG_FILENAME
;
80 // The wxDb::errorList is copied to this variable when the wxDb object
81 // is closed. This way, the error list is still available after the
82 // database object is closed. This is necessary if the database
83 // connection fails so the calling application can show the operator
84 // why the connection failed. Note: as each wxDb object is closed, it
85 // will overwrite the errors of the previously destroyed wxDb object in
86 // this variable. NOTE: This occurs during a CLOSE, not a FREEing of the
88 wxChar DBerrorList
[DB_MAX_ERROR_HISTORY
][DB_MAX_ERROR_MSG_LEN
];
91 // This type defines the return row-struct form
92 // SQLTablePrivileges, and is used by wxDB::TablePrivileges.
95 wxChar tableQual
[128+1];
96 wxChar tableOwner
[128+1];
97 wxChar tableName
[128+1];
98 wxChar grantor
[128+1];
99 wxChar grantee
[128+1];
100 wxChar privilege
[128+1];
101 wxChar grantable
[3+1];
102 } wxDbTablePrivilegeInfo
;
105 /********** wxDbConnectInf Constructor - form 1 **********/
106 wxDbConnectInf::wxDbConnectInf()
109 freeHenvOnDestroy
= false;
115 /********** wxDbConnectInf Constructor - form 2 **********/
116 wxDbConnectInf::wxDbConnectInf(HENV henv
, const wxString
&dsn
, const wxString
&userID
,
117 const wxString
&password
, const wxString
&defaultDir
,
118 const wxString
&fileType
, const wxString
&description
)
121 freeHenvOnDestroy
= false;
132 SetPassword(password
);
133 SetDescription(description
);
134 SetFileType(fileType
);
135 SetDefaultDir(defaultDir
);
136 } // wxDbConnectInf Constructor
139 wxDbConnectInf::~wxDbConnectInf()
141 if (freeHenvOnDestroy
)
145 } // wxDbConnectInf Destructor
149 /********** wxDbConnectInf::Initialize() **********/
150 bool wxDbConnectInf::Initialize()
152 freeHenvOnDestroy
= false;
154 if (freeHenvOnDestroy
&& Henv
)
161 ConnectionStr
[0] = 0;
166 useConnectionStr
= false;
169 } // wxDbConnectInf::Initialize()
172 /********** wxDbConnectInf::AllocHenv() **********/
173 bool wxDbConnectInf::AllocHenv()
175 // This is here to help trap if you are getting a new henv
176 // without releasing an existing henv
179 // Initialize the ODBC Environment for Database Operations
180 if (SQLAllocEnv(&Henv
) != SQL_SUCCESS
)
182 wxLogDebug(wxT("A problem occured while trying to get a connection to the data source"));
186 freeHenvOnDestroy
= true;
189 } // wxDbConnectInf::AllocHenv()
192 void wxDbConnectInf::FreeHenv()
200 freeHenvOnDestroy
= false;
202 } // wxDbConnectInf::FreeHenv()
205 void wxDbConnectInf::SetDsn(const wxString
&dsn
)
207 wxASSERT(dsn
.Length() < sizeof(Dsn
));
210 } // wxDbConnectInf::SetDsn()
213 void wxDbConnectInf::SetUserID(const wxString
&uid
)
215 wxASSERT(uid
.Length() < sizeof(Uid
));
217 } // wxDbConnectInf::SetUserID()
220 void wxDbConnectInf::SetPassword(const wxString
&password
)
222 wxASSERT(password
.Length() < sizeof(AuthStr
));
224 wxStrcpy(AuthStr
, password
);
225 } // wxDbConnectInf::SetPassword()
227 void wxDbConnectInf::SetConnectionStr(const wxString
&connectStr
)
229 wxASSERT(connectStr
.Length() < sizeof(ConnectionStr
));
231 useConnectionStr
= wxStrlen(connectStr
) > 0;
233 wxStrcpy(ConnectionStr
, connectStr
);
234 } // wxDbConnectInf::SetConnectionStr()
237 /********** wxDbColFor Constructor **********/
238 wxDbColFor::wxDbColFor()
241 } // wxDbColFor::wxDbColFor()
244 /********** wxDbColFor::Initialize() **********/
245 void wxDbColFor::Initialize()
255 i_Nation
= 0; // 0=EU, 1=UK, 2=International, 3=US
258 Format(1,DB_DATA_TYPE_VARCHAR
,0,0,0); // the Function that does the work
259 } // wxDbColFor::Initialize()
262 /********** wxDbColFor::Format() **********/
263 int wxDbColFor::Format(int Nation
, int dbDataType
, SWORD sqlDataType
,
264 short columnLength
, short decimalDigits
)
266 // ----------------------------------------------------------------------------------------
267 // -- 19991224 : mj10777 : Create
268 // There is still a lot of work to do here, but it is a start
269 // It handles all the basic data-types that I have run into up to now
270 // The main work will have be with Dates and float Formatting
271 // (US 1,000.00 ; EU 1.000,00)
272 // There are wxWindow plans for locale support and the new wxDateTime. If
273 // they define some constants (wxEUROPEAN) that can be gloably used,
274 // they should be used here.
275 // ----------------------------------------------------------------------------------------
276 // There should also be a function to scan in a string to fill the variable
277 // ----------------------------------------------------------------------------------------
279 i_Nation
= Nation
; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
280 i_dbDataType
= dbDataType
;
281 i_sqlDataType
= sqlDataType
;
282 s_Field
.Printf(wxT("%s%d"),s_Amount
[1].c_str(),i_Amount
[1]); // OK for VARCHAR, INTEGER and FLOAT
284 if (i_dbDataType
== 0) // Filter unsupported dbDataTypes
286 if ((i_sqlDataType
== SQL_VARCHAR
) || (i_sqlDataType
== SQL_LONGVARCHAR
))
287 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
288 if ((i_sqlDataType
== SQL_C_DATE
) || (i_sqlDataType
== SQL_C_TIMESTAMP
))
289 i_dbDataType
= DB_DATA_TYPE_DATE
;
290 if (i_sqlDataType
== SQL_C_BIT
)
291 i_dbDataType
= DB_DATA_TYPE_INTEGER
;
292 if (i_sqlDataType
== SQL_NUMERIC
)
293 i_dbDataType
= DB_DATA_TYPE_VARCHAR
;
294 if (i_sqlDataType
== SQL_REAL
)
295 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
296 if (i_sqlDataType
== SQL_C_BINARY
)
297 i_dbDataType
= DB_DATA_TYPE_BLOB
;
300 if ((i_dbDataType
== DB_DATA_TYPE_INTEGER
) && (i_sqlDataType
== SQL_C_DOUBLE
))
302 i_dbDataType
= DB_DATA_TYPE_FLOAT
;
305 switch(i_dbDataType
) // TBD: Still a lot of proper formatting to do
307 case DB_DATA_TYPE_VARCHAR
:
310 case DB_DATA_TYPE_INTEGER
:
313 case DB_DATA_TYPE_FLOAT
:
314 if (decimalDigits
== 0)
317 tempStr
.Printf(wxT("%s%d.%d"), tempStr
.c_str(),columnLength
, decimalDigits
);
318 s_Field
.Printf(wxT("%sf"), tempStr
.c_str());
320 case DB_DATA_TYPE_DATE
:
321 if (i_Nation
== 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
323 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
325 if (i_Nation
== 1) // European DD.MM.YYYY HH:MM:SS.SSS
327 s_Field
= wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d");
329 if (i_Nation
== 2) // UK DD/MM/YYYY HH:MM:SS.SSS
331 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
333 if (i_Nation
== 3) // International YYYY-MM-DD HH:MM:SS.SSS
335 s_Field
= wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d");
337 if (i_Nation
== 4) // US MM/DD/YYYY HH:MM:SS.SSS
339 s_Field
= wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d");
342 case DB_DATA_TYPE_BLOB
:
343 s_Field
.Printf(wxT("Unable to format(%d)-SQL(%d)"), dbDataType
,sqlDataType
); //
346 s_Field
.Printf(wxT("Unknown Format(%d)-SQL(%d)"), dbDataType
,sqlDataType
); //
350 } // wxDbColFor::Format()
353 /********** wxDbColInf Constructor **********/
354 wxDbColInf::wxDbColInf()
357 } // wxDbColInf::wxDbColInf()
360 /********** wxDbColInf Destructor ********/
361 wxDbColInf::~wxDbColInf()
366 } // wxDbColInf::~wxDbColInf()
369 bool wxDbColInf::Initialize()
391 } // wxDbColInf::Initialize()
394 /********** wxDbTableInf Constructor ********/
395 wxDbTableInf::wxDbTableInf()
398 } // wxDbTableInf::wxDbTableInf()
401 /********** wxDbTableInf Constructor ********/
402 wxDbTableInf::~wxDbTableInf()
407 } // wxDbTableInf::~wxDbTableInf()
410 bool wxDbTableInf::Initialize()
419 } // wxDbTableInf::Initialize()
422 /********** wxDbInf Constructor *************/
426 } // wxDbInf::wxDbInf()
429 /********** wxDbInf Destructor *************/
435 } // wxDbInf::~wxDbInf()
438 /********** wxDbInf::Initialize() *************/
439 bool wxDbInf::Initialize()
447 } // wxDbInf::Initialize()
450 /********** wxDb Constructor **********/
451 wxDb::wxDb(const HENV
&aHenv
, bool FwdOnlyCursors
)
453 // Copy the HENV into the db class
455 fwdOnlyCursors
= FwdOnlyCursors
;
461 /********** wxDb Destructor **********/
464 wxASSERT_MSG(!IsCached(),wxT("Cached connections must not be manually deleted, use\nwxDbFreeConnection() or wxDbCloseConnections()."));
474 /********** PRIVATE! wxDb::initialize PRIVATE! **********/
475 /********** wxDb::initialize() **********/
476 void wxDb::initialize()
478 * Private member function that sets all wxDb member variables to
479 * known values at creation of the wxDb
484 fpSqlLog
= 0; // Sql Log file pointer
485 sqlLogState
= sqlLogOFF
; // By default, logging is turned off
487 dbmsType
= dbmsUNIDENTIFIED
;
489 wxStrcpy(sqlState
,wxEmptyString
);
490 wxStrcpy(errorMsg
,wxEmptyString
);
491 nativeError
= cbErrorMsg
= 0;
492 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
493 wxStrcpy(errorList
[i
], wxEmptyString
);
495 // Init typeInf structures
496 typeInfVarchar
.TypeName
.Empty();
497 typeInfVarchar
.FsqlType
= 0;
498 typeInfVarchar
.Precision
= 0;
499 typeInfVarchar
.CaseSensitive
= 0;
500 typeInfVarchar
.MaximumScale
= 0;
502 typeInfInteger
.TypeName
.Empty();
503 typeInfInteger
.FsqlType
= 0;
504 typeInfInteger
.Precision
= 0;
505 typeInfInteger
.CaseSensitive
= 0;
506 typeInfInteger
.MaximumScale
= 0;
508 typeInfFloat
.TypeName
.Empty();
509 typeInfFloat
.FsqlType
= 0;
510 typeInfFloat
.Precision
= 0;
511 typeInfFloat
.CaseSensitive
= 0;
512 typeInfFloat
.MaximumScale
= 0;
514 typeInfDate
.TypeName
.Empty();
515 typeInfDate
.FsqlType
= 0;
516 typeInfDate
.Precision
= 0;
517 typeInfDate
.CaseSensitive
= 0;
518 typeInfDate
.MaximumScale
= 0;
520 typeInfBlob
.TypeName
.Empty();
521 typeInfBlob
.FsqlType
= 0;
522 typeInfBlob
.Precision
= 0;
523 typeInfBlob
.CaseSensitive
= 0;
524 typeInfBlob
.MaximumScale
= 0;
526 // Error reporting is turned OFF by default
529 // Allocate a data source connection handle
530 if (SQLAllocConnect(henv
, &hdbc
) != SQL_SUCCESS
)
533 // Initialize the db status flag
536 // Mark database as not open as of yet
539 dbOpenedWithConnectionString
= false;
540 } // wxDb::initialize()
543 /********** PRIVATE! wxDb::convertUserID PRIVATE! **********/
545 // NOTE: Return value from this function MUST be copied
546 // immediately, as the value is not good after
547 // this function has left scope.
549 const wxChar
*wxDb::convertUserID(const wxChar
*userID
, wxString
&UserID
)
553 if (!wxStrlen(userID
))
561 // dBase does not use user names, and some drivers fail if you try to pass one
562 if ( Dbms() == dbmsDBASE
563 || Dbms() == dbmsXBASE_SEQUITER
)
566 // Oracle user names may only be in uppercase, so force
567 // the name to uppercase
568 if (Dbms() == dbmsORACLE
)
569 UserID
= UserID
.Upper();
571 return UserID
.c_str();
572 } // wxDb::convertUserID()
575 bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported
)
579 // These are the possible SQL types we check for use against the datasource we are connected
580 // to for the purpose of determining which data type to use for the basic character strings
583 // NOTE: The first type in this enumeration that is determined to be supported by the
584 // datasource/driver is the one that will be used.
585 SWORD PossibleSqlCharTypes
[] = {
586 #if wxUSE_UNICODE && defined(SQL_WVARCHAR)
590 #if wxUSE_UNICODE && defined(SQL_WVARCHAR)
596 // These are the possible SQL types we check for use against the datasource we are connected
597 // to for the purpose of determining which data type to use for the basic non-floating point
600 // NOTE: The first type in this enumeration that is determined to be supported by the
601 // datasource/driver is the one that will be used.
602 SWORD PossibleSqlIntegerTypes
[] = {
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 floating point number
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 PossibleSqlFloatTypes
[] = {
620 // These are the possible SQL types we check for use agains the datasource we are connected
621 // to for the purpose of determining which data type to use for the date/time column types
623 // NOTE: The first type in this enumeration that is determined to be supported by the
624 // datasource/driver is the one that will be used.
625 SWORD PossibleSqlDateTypes
[] = {
633 // These are the possible SQL types we check for use agains the datasource we are connected
634 // to for the purpose of determining which data type to use for the BLOB column types.
636 // NOTE: The first type in this enumeration that is determined to be supported by the
637 // datasource/driver is the one that will be used.
638 SWORD PossibleSqlBlobTypes
[] = {
644 // Query the data source regarding data type information
647 // The way it was determined which SQL data types to use was by calling SQLGetInfo
648 // for all of the possible SQL data types to see which ones were supported. If
649 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
650 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
651 // types I've selected below will not always be what we want. These are just
652 // what happened to work against an Oracle 7/Intersolv combination. The following is
653 // a complete list of the results I got back against the Oracle 7 database:
655 // SQL_BIGINT SQL_NO_DATA_FOUND
656 // SQL_BINARY SQL_NO_DATA_FOUND
657 // SQL_BIT SQL_NO_DATA_FOUND
658 // SQL_CHAR type name = 'CHAR', Precision = 255
659 // SQL_DATE SQL_NO_DATA_FOUND
660 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
661 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
662 // SQL_FLOAT SQL_NO_DATA_FOUND
663 // SQL_INTEGER SQL_NO_DATA_FOUND
664 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
665 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
666 // SQL_NUMERIC SQL_NO_DATA_FOUND
667 // SQL_REAL SQL_NO_DATA_FOUND
668 // SQL_SMALLINT SQL_NO_DATA_FOUND
669 // SQL_TIME SQL_NO_DATA_FOUND
670 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
671 // SQL_VARBINARY type name = 'RAW', Precision = 255
672 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
673 // =====================================================================
674 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
676 // SQL_VARCHAR type name = 'TEXT', Precision = 255
677 // SQL_TIMESTAMP type name = 'DATETIME'
678 // SQL_DECIMAL SQL_NO_DATA_FOUND
679 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
680 // SQL_FLOAT SQL_NO_DATA_FOUND
681 // SQL_REAL type name = 'SINGLE', Precision = 7
682 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
683 // SQL_INTEGER type name = 'LONG', Precision = 10
685 // Query the data source for info about itself
686 if (!getDbInfo(failOnDataTypeUnsupported
))
689 // --------------- Varchar - (Variable length character string) ---------------
690 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlCharTypes
) &&
691 !getDataTypeInfo(PossibleSqlCharTypes
[iIndex
], typeInfVarchar
); ++iIndex
)
694 if (iIndex
< WXSIZEOF(PossibleSqlCharTypes
))
695 typeInfVarchar
.FsqlType
= PossibleSqlCharTypes
[iIndex
];
696 else if (failOnDataTypeUnsupported
)
699 // --------------- Float ---------------
700 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlFloatTypes
) &&
701 !getDataTypeInfo(PossibleSqlFloatTypes
[iIndex
], typeInfFloat
); ++iIndex
)
704 if (iIndex
< WXSIZEOF(PossibleSqlFloatTypes
))
705 typeInfFloat
.FsqlType
= PossibleSqlFloatTypes
[iIndex
];
706 else if (failOnDataTypeUnsupported
)
709 // --------------- Integer -------------
710 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlIntegerTypes
) &&
711 !getDataTypeInfo(PossibleSqlIntegerTypes
[iIndex
], typeInfInteger
); ++iIndex
)
714 if (iIndex
< WXSIZEOF(PossibleSqlIntegerTypes
))
715 typeInfInteger
.FsqlType
= PossibleSqlIntegerTypes
[iIndex
];
716 else if (failOnDataTypeUnsupported
)
718 // If no non-floating point data types are supported, we'll
719 // use the type assigned for floats to store integers as well
720 if (!getDataTypeInfo(typeInfFloat
.FsqlType
, typeInfInteger
))
722 if (failOnDataTypeUnsupported
)
726 typeInfInteger
.FsqlType
= typeInfFloat
.FsqlType
;
729 // --------------- Date/Time ---------------
730 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlDateTypes
) &&
731 !getDataTypeInfo(PossibleSqlDateTypes
[iIndex
], typeInfDate
); ++iIndex
)
734 if (iIndex
< WXSIZEOF(PossibleSqlDateTypes
))
735 typeInfDate
.FsqlType
= PossibleSqlDateTypes
[iIndex
];
736 else if (failOnDataTypeUnsupported
)
739 // --------------- BLOB ---------------
740 for (iIndex
= 0; iIndex
< WXSIZEOF(PossibleSqlBlobTypes
) &&
741 !getDataTypeInfo(PossibleSqlBlobTypes
[iIndex
], typeInfBlob
); ++iIndex
)
744 if (iIndex
< WXSIZEOF(PossibleSqlBlobTypes
))
745 typeInfBlob
.FsqlType
= PossibleSqlBlobTypes
[iIndex
];
746 else if (failOnDataTypeUnsupported
)
750 } // wxDb::determineDataTypes
753 bool wxDb::open(bool failOnDataTypeUnsupported
)
756 If using Intersolv branded ODBC drivers, this is the place where you would substitute
757 your branded driver license information
759 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
760 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
763 // Mark database as open
766 // Allocate a statement handle for the database connection
767 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
768 return(DispAllErrors(henv
, hdbc
));
770 // Set Connection Options
771 if (!setConnectionOptions())
774 if (!determineDataTypes(failOnDataTypeUnsupported
))
777 #ifdef DBDEBUG_CONSOLE
778 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
779 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
780 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
781 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
782 cout
<< wxT("BLOB DATA TYPE: ") << typeInfBlob
.TypeName
<< endl
;
786 // Completed Successfully
790 bool wxDb::Open(const wxString
& inConnectStr
, bool failOnDataTypeUnsupported
)
792 wxASSERT(inConnectStr
.Length());
799 if (!FwdOnlyCursors())
801 // Specify that the ODBC cursor library be used, if needed. This must be
802 // specified before the connection is made.
803 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
805 #ifdef DBDEBUG_CONSOLE
806 if (retcode
== SQL_SUCCESS
)
807 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
809 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
811 wxUnusedVar(retcode
);
815 // Connect to the data source
816 SQLTCHAR outConnectBuffer
[SQL_MAX_CONNECTSTR_LEN
+1]; // MS recommends at least 1k buffer
817 short outConnectBufferLen
;
819 inConnectionStr
= inConnectStr
;
821 retcode
= SQLDriverConnect(hdbc
, NULL
, (SQLTCHAR FAR
*)inConnectionStr
.c_str(),
822 (SWORD
)inConnectionStr
.Length(), (SQLTCHAR FAR
*)outConnectBuffer
,
823 sizeof(outConnectBuffer
), &outConnectBufferLen
, SQL_DRIVER_COMPLETE
);
825 if ((retcode
!= SQL_SUCCESS
) &&
826 (retcode
!= SQL_SUCCESS_WITH_INFO
))
827 return(DispAllErrors(henv
, hdbc
));
829 outConnectBuffer
[outConnectBufferLen
] = 0;
830 outConnectionStr
= outConnectBuffer
;
831 dbOpenedWithConnectionString
= true;
833 return open(failOnDataTypeUnsupported
);
836 /********** wxDb::Open() **********/
837 bool wxDb::Open(const wxString
&Dsn
, const wxString
&Uid
, const wxString
&AuthStr
, bool failOnDataTypeUnsupported
)
839 wxASSERT(Dsn
.Length());
844 inConnectionStr
= wxT("");
845 outConnectionStr
= wxT("");
849 if (!FwdOnlyCursors())
851 // Specify that the ODBC cursor library be used, if needed. This must be
852 // specified before the connection is made.
853 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
855 #ifdef DBDEBUG_CONSOLE
856 if (retcode
== SQL_SUCCESS
)
857 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
859 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
861 wxUnusedVar( retcode
);
865 // Connect to the data source
866 retcode
= SQLConnect(hdbc
, (SQLTCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
867 (SQLTCHAR FAR
*) uid
.c_str(), SQL_NTS
,
868 (SQLTCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
870 if ((retcode
!= SQL_SUCCESS
) &&
871 (retcode
!= SQL_SUCCESS_WITH_INFO
))
872 return(DispAllErrors(henv
, hdbc
));
874 return open(failOnDataTypeUnsupported
);
879 bool wxDb::Open(wxDbConnectInf
*dbConnectInf
, bool failOnDataTypeUnsupported
)
881 wxASSERT(dbConnectInf
);
883 // Use the connection string if one is present
884 if (dbConnectInf
->UseConnectionStr())
885 return Open(GetConnectionInStr(), failOnDataTypeUnsupported
);
887 return Open(dbConnectInf
->GetDsn(), dbConnectInf
->GetUserID(),
888 dbConnectInf
->GetPassword(), failOnDataTypeUnsupported
);
892 bool wxDb::Open(wxDb
*copyDb
)
894 dsn
= copyDb
->GetDatasourceName();
895 uid
= copyDb
->GetUsername();
896 authStr
= copyDb
->GetPassword();
897 inConnectionStr
= copyDb
->GetConnectionInStr();
898 outConnectionStr
= copyDb
->GetConnectionOutStr();
902 if (!FwdOnlyCursors())
904 // Specify that the ODBC cursor library be used, if needed. This must be
905 // specified before the connection is made.
906 retcode
= SQLSetConnectOption(hdbc
, SQL_ODBC_CURSORS
, SQL_CUR_USE_IF_NEEDED
);
908 #ifdef DBDEBUG_CONSOLE
909 if (retcode
== SQL_SUCCESS
)
910 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl
;
912 cout
<< wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl
;
914 wxUnusedVar( retcode
);
918 if (copyDb
->OpenedWithConnectionString())
920 // Connect to the data source
921 SQLTCHAR outConnectBuffer
[SQL_MAX_CONNECTSTR_LEN
+1];
922 short outConnectBufferLen
;
924 inConnectionStr
= copyDb
->GetConnectionInStr();
926 retcode
= SQLDriverConnect(hdbc
, NULL
, (SQLTCHAR FAR
*)inConnectionStr
.c_str(),
927 (SWORD
)inConnectionStr
.Length(), (SQLTCHAR FAR
*)outConnectBuffer
,
928 sizeof(outConnectBuffer
), &outConnectBufferLen
, SQL_DRIVER_COMPLETE
);
930 if ((retcode
!= SQL_SUCCESS
) &&
931 (retcode
!= SQL_SUCCESS_WITH_INFO
))
932 return(DispAllErrors(henv
, hdbc
));
934 outConnectBuffer
[outConnectBufferLen
] = 0;
935 outConnectionStr
= outConnectBuffer
;
936 dbOpenedWithConnectionString
= true;
940 // Connect to the data source
941 retcode
= SQLConnect(hdbc
, (SQLTCHAR FAR
*) dsn
.c_str(), SQL_NTS
,
942 (SQLTCHAR FAR
*) uid
.c_str(), SQL_NTS
,
943 (SQLTCHAR FAR
*) authStr
.c_str(), SQL_NTS
);
946 if ((retcode
!= SQL_SUCCESS
) &&
947 (retcode
!= SQL_SUCCESS_WITH_INFO
))
948 return(DispAllErrors(henv
, hdbc
));
951 If using Intersolv branded ODBC drivers, this is the place where you would substitute
952 your branded driver license information
954 SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString);
955 SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString);
958 // Mark database as open
961 // Allocate a statement handle for the database connection
962 if (SQLAllocStmt(hdbc
, &hstmt
) != SQL_SUCCESS
)
963 return(DispAllErrors(henv
, hdbc
));
965 // Set Connection Options
966 if (!setConnectionOptions())
969 // Instead of Querying the data source for info about itself, it can just be copied
970 // from the wxDb instance that was passed in (copyDb).
971 wxStrcpy(dbInf
.serverName
,copyDb
->dbInf
.serverName
);
972 wxStrcpy(dbInf
.databaseName
,copyDb
->dbInf
.databaseName
);
973 wxStrcpy(dbInf
.dbmsName
,copyDb
->dbInf
.dbmsName
);
974 wxStrcpy(dbInf
.dbmsVer
,copyDb
->dbInf
.dbmsVer
);
975 dbInf
.maxConnections
= copyDb
->dbInf
.maxConnections
;
976 dbInf
.maxStmts
= copyDb
->dbInf
.maxStmts
;
977 wxStrcpy(dbInf
.driverName
,copyDb
->dbInf
.driverName
);
978 wxStrcpy(dbInf
.odbcVer
,copyDb
->dbInf
.odbcVer
);
979 wxStrcpy(dbInf
.drvMgrOdbcVer
,copyDb
->dbInf
.drvMgrOdbcVer
);
980 wxStrcpy(dbInf
.driverVer
,copyDb
->dbInf
.driverVer
);
981 dbInf
.apiConfLvl
= copyDb
->dbInf
.apiConfLvl
;
982 dbInf
.cliConfLvl
= copyDb
->dbInf
.cliConfLvl
;
983 dbInf
.sqlConfLvl
= copyDb
->dbInf
.sqlConfLvl
;
984 wxStrcpy(dbInf
.outerJoins
,copyDb
->dbInf
.outerJoins
);
985 wxStrcpy(dbInf
.procedureSupport
,copyDb
->dbInf
.procedureSupport
);
986 wxStrcpy(dbInf
.accessibleTables
,copyDb
->dbInf
.accessibleTables
);
987 dbInf
.cursorCommitBehavior
= copyDb
->dbInf
.cursorCommitBehavior
;
988 dbInf
.cursorRollbackBehavior
= copyDb
->dbInf
.cursorRollbackBehavior
;
989 dbInf
.supportNotNullClause
= copyDb
->dbInf
.supportNotNullClause
;
990 wxStrcpy(dbInf
.supportIEF
,copyDb
->dbInf
.supportIEF
);
991 dbInf
.txnIsolation
= copyDb
->dbInf
.txnIsolation
;
992 dbInf
.txnIsolationOptions
= copyDb
->dbInf
.txnIsolationOptions
;
993 dbInf
.fetchDirections
= copyDb
->dbInf
.fetchDirections
;
994 dbInf
.lockTypes
= copyDb
->dbInf
.lockTypes
;
995 dbInf
.posOperations
= copyDb
->dbInf
.posOperations
;
996 dbInf
.posStmts
= copyDb
->dbInf
.posStmts
;
997 dbInf
.scrollConcurrency
= copyDb
->dbInf
.scrollConcurrency
;
998 dbInf
.scrollOptions
= copyDb
->dbInf
.scrollOptions
;
999 dbInf
.staticSensitivity
= copyDb
->dbInf
.staticSensitivity
;
1000 dbInf
.txnCapable
= copyDb
->dbInf
.txnCapable
;
1001 dbInf
.loginTimeout
= copyDb
->dbInf
.loginTimeout
;
1003 // VARCHAR = Variable length character string
1004 typeInfVarchar
.FsqlType
= copyDb
->typeInfVarchar
.FsqlType
;
1005 typeInfVarchar
.TypeName
= copyDb
->typeInfVarchar
.TypeName
;
1006 typeInfVarchar
.Precision
= copyDb
->typeInfVarchar
.Precision
;
1007 typeInfVarchar
.CaseSensitive
= copyDb
->typeInfVarchar
.CaseSensitive
;
1008 typeInfVarchar
.MaximumScale
= copyDb
->typeInfVarchar
.MaximumScale
;
1011 typeInfFloat
.FsqlType
= copyDb
->typeInfFloat
.FsqlType
;
1012 typeInfFloat
.TypeName
= copyDb
->typeInfFloat
.TypeName
;
1013 typeInfFloat
.Precision
= copyDb
->typeInfFloat
.Precision
;
1014 typeInfFloat
.CaseSensitive
= copyDb
->typeInfFloat
.CaseSensitive
;
1015 typeInfFloat
.MaximumScale
= copyDb
->typeInfFloat
.MaximumScale
;
1018 typeInfInteger
.FsqlType
= copyDb
->typeInfInteger
.FsqlType
;
1019 typeInfInteger
.TypeName
= copyDb
->typeInfInteger
.TypeName
;
1020 typeInfInteger
.Precision
= copyDb
->typeInfInteger
.Precision
;
1021 typeInfInteger
.CaseSensitive
= copyDb
->typeInfInteger
.CaseSensitive
;
1022 typeInfInteger
.MaximumScale
= copyDb
->typeInfInteger
.MaximumScale
;
1025 typeInfDate
.FsqlType
= copyDb
->typeInfDate
.FsqlType
;
1026 typeInfDate
.TypeName
= copyDb
->typeInfDate
.TypeName
;
1027 typeInfDate
.Precision
= copyDb
->typeInfDate
.Precision
;
1028 typeInfDate
.CaseSensitive
= copyDb
->typeInfDate
.CaseSensitive
;
1029 typeInfDate
.MaximumScale
= copyDb
->typeInfDate
.MaximumScale
;
1032 typeInfBlob
.FsqlType
= copyDb
->typeInfBlob
.FsqlType
;
1033 typeInfBlob
.TypeName
= copyDb
->typeInfBlob
.TypeName
;
1034 typeInfBlob
.Precision
= copyDb
->typeInfBlob
.Precision
;
1035 typeInfBlob
.CaseSensitive
= copyDb
->typeInfBlob
.CaseSensitive
;
1036 typeInfBlob
.MaximumScale
= copyDb
->typeInfBlob
.MaximumScale
;
1038 #ifdef DBDEBUG_CONSOLE
1039 cout
<< wxT("VARCHAR DATA TYPE: ") << typeInfVarchar
.TypeName
<< endl
;
1040 cout
<< wxT("INTEGER DATA TYPE: ") << typeInfInteger
.TypeName
<< endl
;
1041 cout
<< wxT("FLOAT DATA TYPE: ") << typeInfFloat
.TypeName
<< endl
;
1042 cout
<< wxT("DATE DATA TYPE: ") << typeInfDate
.TypeName
<< endl
;
1043 cout
<< wxT("BLOB DATA TYPE: ") << typeInfBlob
.TypeName
<< endl
;
1047 // Completed Successfully
1052 /********** wxDb::setConnectionOptions() **********/
1053 bool wxDb::setConnectionOptions(void)
1055 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
1060 // I need to get the DBMS name here, because some of the connection options
1061 // are database specific and need to call the Dbms() function.
1064 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, sizeof(dbInf
.dbmsName
), &cb
);
1065 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1066 return(DispAllErrors(henv
, hdbc
));
1068 /* retcode = */ SQLSetConnectOption(hdbc
, SQL_AUTOCOMMIT
, SQL_AUTOCOMMIT_OFF
);
1069 /* retcode = */ SQLSetConnectOption(hdbc
, SQL_OPT_TRACE
, SQL_OPT_TRACE_OFF
);
1070 // SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads
1072 // By default, MS Sql Server closes cursors on commit and rollback. The following
1073 // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors
1074 // after a transaction. This is a driver specific option and is not part of the
1075 // ODBC standard. Note: this behavior is specific to the ODBC interface to SQL Server.
1076 // The database settings don't have any effect one way or the other.
1077 if (Dbms() == dbmsMS_SQL_SERVER
)
1079 const long SQL_PRESERVE_CURSORS
= 1204L;
1080 const long SQL_PC_ON
= 1L;
1081 /* retcode = */ SQLSetConnectOption(hdbc
, SQL_PRESERVE_CURSORS
, SQL_PC_ON
);
1084 // Display the connection options to verify them
1085 #ifdef DBDEBUG_CONSOLE
1087 cout
<< wxT("****** CONNECTION OPTIONS ******") << endl
;
1089 retcode
= SQLGetConnectOption(hdbc
, SQL_AUTOCOMMIT
, &l
);
1090 if (retcode
!= SQL_SUCCESS
)
1091 return(DispAllErrors(henv
, hdbc
));
1092 cout
<< wxT("AUTOCOMMIT: ") << (l
== SQL_AUTOCOMMIT_OFF
? "OFF" : "ON") << endl
;
1094 retcode
= SQLGetConnectOption(hdbc
, SQL_ODBC_CURSORS
, &l
);
1095 if (retcode
!= SQL_SUCCESS
)
1096 return(DispAllErrors(henv
, hdbc
));
1097 cout
<< wxT("ODBC CURSORS: ");
1100 case(SQL_CUR_USE_IF_NEEDED
):
1101 cout
<< wxT("SQL_CUR_USE_IF_NEEDED");
1103 case(SQL_CUR_USE_ODBC
):
1104 cout
<< wxT("SQL_CUR_USE_ODBC");
1106 case(SQL_CUR_USE_DRIVER
):
1107 cout
<< wxT("SQL_CUR_USE_DRIVER");
1112 retcode
= SQLGetConnectOption(hdbc
, SQL_OPT_TRACE
, &l
)
1113 if (retcode
!= SQL_SUCCESS
)
1114 return(DispAllErrors(henv
, hdbc
));
1115 cout
<< wxT("TRACING: ") << (l
== SQL_OPT_TRACE_OFF
? wxT("OFF") : wxT("ON")) << endl
;
1120 // Completed Successfully
1123 } // wxDb::setConnectionOptions()
1126 /********** wxDb::getDbInfo() **********/
1127 bool wxDb::getDbInfo(bool failOnDataTypeUnsupported
)
1132 retcode
= SQLGetInfo(hdbc
, SQL_SERVER_NAME
, (UCHAR
*) dbInf
.serverName
, sizeof(dbInf
.serverName
), &cb
);
1133 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1135 DispAllErrors(henv
, hdbc
);
1136 if (failOnDataTypeUnsupported
)
1140 retcode
= SQLGetInfo(hdbc
, SQL_DATABASE_NAME
, (UCHAR
*) dbInf
.databaseName
, sizeof(dbInf
.databaseName
), &cb
);
1141 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1143 DispAllErrors(henv
, hdbc
);
1144 if (failOnDataTypeUnsupported
)
1148 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_NAME
, (UCHAR
*) dbInf
.dbmsName
, sizeof(dbInf
.dbmsName
), &cb
);
1149 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1151 DispAllErrors(henv
, hdbc
);
1152 if (failOnDataTypeUnsupported
)
1157 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
1158 // causing database connectivity to fail in some cases.
1159 retcode
= SQLGetInfo(hdbc
, SQL_DBMS_VER
, (UCHAR
*) dbInf
.dbmsVer
, sizeof(dbInf
.dbmsVer
), &cb
);
1160 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1162 DispAllErrors(henv
, hdbc
);
1163 if (failOnDataTypeUnsupported
)
1167 retcode
= SQLGetInfo(hdbc
, SQL_ACTIVE_CONNECTIONS
, (UCHAR
*) &dbInf
.maxConnections
, sizeof(dbInf
.maxConnections
), &cb
);
1168 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1170 DispAllErrors(henv
, hdbc
);
1171 if (failOnDataTypeUnsupported
)
1175 retcode
= SQLGetInfo(hdbc
, SQL_ACTIVE_STATEMENTS
, (UCHAR
*) &dbInf
.maxStmts
, sizeof(dbInf
.maxStmts
), &cb
);
1176 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1178 DispAllErrors(henv
, hdbc
);
1179 if (failOnDataTypeUnsupported
)
1183 retcode
= SQLGetInfo(hdbc
, SQL_DRIVER_NAME
, (UCHAR
*) dbInf
.driverName
, sizeof(dbInf
.driverName
), &cb
);
1184 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1186 DispAllErrors(henv
, hdbc
);
1187 if (failOnDataTypeUnsupported
)
1191 retcode
= SQLGetInfo(hdbc
, SQL_DRIVER_ODBC_VER
, (UCHAR
*) dbInf
.odbcVer
, sizeof(dbInf
.odbcVer
), &cb
);
1192 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1194 DispAllErrors(henv
, hdbc
);
1195 if (failOnDataTypeUnsupported
)
1199 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_VER
, (UCHAR
*) dbInf
.drvMgrOdbcVer
, sizeof(dbInf
.drvMgrOdbcVer
), &cb
);
1200 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1202 DispAllErrors(henv
, hdbc
);
1203 if (failOnDataTypeUnsupported
)
1207 retcode
= SQLGetInfo(hdbc
, SQL_DRIVER_VER
, (UCHAR
*) dbInf
.driverVer
, sizeof(dbInf
.driverVer
), &cb
);
1208 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1210 DispAllErrors(henv
, hdbc
);
1211 if (failOnDataTypeUnsupported
)
1215 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_API_CONFORMANCE
, (UCHAR
*) &dbInf
.apiConfLvl
, sizeof(dbInf
.apiConfLvl
), &cb
);
1216 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1218 DispAllErrors(henv
, hdbc
);
1219 if (failOnDataTypeUnsupported
)
1223 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_SAG_CLI_CONFORMANCE
, (UCHAR
*) &dbInf
.cliConfLvl
, sizeof(dbInf
.cliConfLvl
), &cb
);
1224 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1226 // Not all drivers support this call - Nick Gorham(unixODBC)
1227 dbInf
.cliConfLvl
= 0;
1228 DispAllErrors(henv
, hdbc
);
1229 if (failOnDataTypeUnsupported
)
1233 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_SQL_CONFORMANCE
, (UCHAR
*) &dbInf
.sqlConfLvl
, sizeof(dbInf
.sqlConfLvl
), &cb
);
1234 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1236 DispAllErrors(henv
, hdbc
);
1237 if (failOnDataTypeUnsupported
)
1241 retcode
= SQLGetInfo(hdbc
, SQL_OUTER_JOINS
, (UCHAR
*) dbInf
.outerJoins
, sizeof(dbInf
.outerJoins
), &cb
);
1242 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1244 DispAllErrors(henv
, hdbc
);
1245 if (failOnDataTypeUnsupported
)
1249 retcode
= SQLGetInfo(hdbc
, SQL_PROCEDURES
, (UCHAR
*) dbInf
.procedureSupport
, sizeof(dbInf
.procedureSupport
), &cb
);
1250 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1252 DispAllErrors(henv
, hdbc
);
1253 if (failOnDataTypeUnsupported
)
1257 retcode
= SQLGetInfo(hdbc
, SQL_ACCESSIBLE_TABLES
, (UCHAR
*) dbInf
.accessibleTables
, sizeof(dbInf
.accessibleTables
), &cb
);
1258 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1260 DispAllErrors(henv
, hdbc
);
1261 if (failOnDataTypeUnsupported
)
1265 retcode
= SQLGetInfo(hdbc
, SQL_CURSOR_COMMIT_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorCommitBehavior
, sizeof(dbInf
.cursorCommitBehavior
), &cb
);
1266 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1268 DispAllErrors(henv
, hdbc
);
1269 if (failOnDataTypeUnsupported
)
1273 retcode
= SQLGetInfo(hdbc
, SQL_CURSOR_ROLLBACK_BEHAVIOR
, (UCHAR
*) &dbInf
.cursorRollbackBehavior
, sizeof(dbInf
.cursorRollbackBehavior
), &cb
);
1274 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1276 DispAllErrors(henv
, hdbc
);
1277 if (failOnDataTypeUnsupported
)
1281 retcode
= SQLGetInfo(hdbc
, SQL_NON_NULLABLE_COLUMNS
, (UCHAR
*) &dbInf
.supportNotNullClause
, sizeof(dbInf
.supportNotNullClause
), &cb
);
1282 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1284 DispAllErrors(henv
, hdbc
);
1285 if (failOnDataTypeUnsupported
)
1289 retcode
= SQLGetInfo(hdbc
, SQL_ODBC_SQL_OPT_IEF
, (UCHAR
*) dbInf
.supportIEF
, sizeof(dbInf
.supportIEF
), &cb
);
1290 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1292 DispAllErrors(henv
, hdbc
);
1293 if (failOnDataTypeUnsupported
)
1297 retcode
= SQLGetInfo(hdbc
, SQL_DEFAULT_TXN_ISOLATION
, (UCHAR
*) &dbInf
.txnIsolation
, sizeof(dbInf
.txnIsolation
), &cb
);
1298 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1300 DispAllErrors(henv
, hdbc
);
1301 if (failOnDataTypeUnsupported
)
1305 retcode
= SQLGetInfo(hdbc
, SQL_TXN_ISOLATION_OPTION
, (UCHAR
*) &dbInf
.txnIsolationOptions
, sizeof(dbInf
.txnIsolationOptions
), &cb
);
1306 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1308 DispAllErrors(henv
, hdbc
);
1309 if (failOnDataTypeUnsupported
)
1313 retcode
= SQLGetInfo(hdbc
, SQL_FETCH_DIRECTION
, (UCHAR
*) &dbInf
.fetchDirections
, sizeof(dbInf
.fetchDirections
), &cb
);
1314 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1316 DispAllErrors(henv
, hdbc
);
1317 if (failOnDataTypeUnsupported
)
1321 retcode
= SQLGetInfo(hdbc
, SQL_LOCK_TYPES
, (UCHAR
*) &dbInf
.lockTypes
, sizeof(dbInf
.lockTypes
), &cb
);
1322 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1324 DispAllErrors(henv
, hdbc
);
1325 if (failOnDataTypeUnsupported
)
1329 retcode
= SQLGetInfo(hdbc
, SQL_POS_OPERATIONS
, (UCHAR
*) &dbInf
.posOperations
, sizeof(dbInf
.posOperations
), &cb
);
1330 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1332 DispAllErrors(henv
, hdbc
);
1333 if (failOnDataTypeUnsupported
)
1337 retcode
= SQLGetInfo(hdbc
, SQL_POSITIONED_STATEMENTS
, (UCHAR
*) &dbInf
.posStmts
, sizeof(dbInf
.posStmts
), &cb
);
1338 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1340 DispAllErrors(henv
, hdbc
);
1341 if (failOnDataTypeUnsupported
)
1345 retcode
= SQLGetInfo(hdbc
, SQL_SCROLL_CONCURRENCY
, (UCHAR
*) &dbInf
.scrollConcurrency
, sizeof(dbInf
.scrollConcurrency
), &cb
);
1346 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1348 DispAllErrors(henv
, hdbc
);
1349 if (failOnDataTypeUnsupported
)
1353 retcode
= SQLGetInfo(hdbc
, SQL_SCROLL_OPTIONS
, (UCHAR
*) &dbInf
.scrollOptions
, sizeof(dbInf
.scrollOptions
), &cb
);
1354 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1356 DispAllErrors(henv
, hdbc
);
1357 if (failOnDataTypeUnsupported
)
1361 retcode
= SQLGetInfo(hdbc
, SQL_STATIC_SENSITIVITY
, (UCHAR
*) &dbInf
.staticSensitivity
, sizeof(dbInf
.staticSensitivity
), &cb
);
1362 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1364 DispAllErrors(henv
, hdbc
);
1365 if (failOnDataTypeUnsupported
)
1369 retcode
= SQLGetInfo(hdbc
, SQL_TXN_CAPABLE
, (UCHAR
*) &dbInf
.txnCapable
, sizeof(dbInf
.txnCapable
), &cb
);
1370 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1372 DispAllErrors(henv
, hdbc
);
1373 if (failOnDataTypeUnsupported
)
1377 retcode
= SQLGetInfo(hdbc
, SQL_LOGIN_TIMEOUT
, (UCHAR
*) &dbInf
.loginTimeout
, sizeof(dbInf
.loginTimeout
), &cb
);
1378 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
1380 DispAllErrors(henv
, hdbc
);
1381 if (failOnDataTypeUnsupported
)
1385 #ifdef DBDEBUG_CONSOLE
1386 cout
<< wxT("***** DATA SOURCE INFORMATION *****") << endl
;
1387 cout
<< wxT(wxT("SERVER Name: ") << dbInf
.serverName
<< endl
;
1388 cout
<< wxT("DBMS Name: ") << dbInf
.dbmsName
<< wxT("; DBMS Version: ") << dbInf
.dbmsVer
<< endl
;
1389 cout
<< wxT("ODBC Version: ") << dbInf
.odbcVer
<< wxT("; Driver Version: ") << dbInf
.driverVer
<< endl
;
1391 cout
<< wxT("API Conf. Level: ");
1392 switch(dbInf
.apiConfLvl
)
1394 case SQL_OAC_NONE
: cout
<< wxT("None"); break;
1395 case SQL_OAC_LEVEL1
: cout
<< wxT("Level 1"); break;
1396 case SQL_OAC_LEVEL2
: cout
<< wxT("Level 2"); break;
1400 cout
<< wxT("SAG CLI Conf. Level: ");
1401 switch(dbInf
.cliConfLvl
)
1403 case SQL_OSCC_NOT_COMPLIANT
: cout
<< wxT("Not Compliant"); break;
1404 case SQL_OSCC_COMPLIANT
: cout
<< wxT("Compliant"); break;
1408 cout
<< wxT("SQL Conf. Level: ");
1409 switch(dbInf
.sqlConfLvl
)
1411 case SQL_OSC_MINIMUM
: cout
<< wxT("Minimum Grammar"); break;
1412 case SQL_OSC_CORE
: cout
<< wxT("Core Grammar"); break;
1413 case SQL_OSC_EXTENDED
: cout
<< wxT("Extended Grammar"); break;
1417 cout
<< wxT("Max. Connections: ") << dbInf
.maxConnections
<< endl
;
1418 cout
<< wxT("Outer Joins: ") << dbInf
.outerJoins
<< endl
;
1419 cout
<< wxT("Support for Procedures: ") << dbInf
.procedureSupport
<< endl
;
1420 cout
<< wxT("All tables accessible : ") << dbInf
.accessibleTables
<< endl
;
1421 cout
<< wxT("Cursor COMMIT Behavior: ");
1422 switch(dbInf
.cursorCommitBehavior
)
1424 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1425 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1426 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1430 cout
<< wxT("Cursor ROLLBACK Behavior: ");
1431 switch(dbInf
.cursorRollbackBehavior
)
1433 case SQL_CB_DELETE
: cout
<< wxT("Delete cursors"); break;
1434 case SQL_CB_CLOSE
: cout
<< wxT("Close cursors"); break;
1435 case SQL_CB_PRESERVE
: cout
<< wxT("Preserve cursors"); break;
1439 cout
<< wxT("Support NOT NULL clause: ");
1440 switch(dbInf
.supportNotNullClause
)
1442 case SQL_NNC_NULL
: cout
<< wxT("No"); break;
1443 case SQL_NNC_NON_NULL
: cout
<< wxT("Yes"); break;
1447 cout
<< wxT("Support IEF (Ref. Integrity): ") << dbInf
.supportIEF
<< endl
;
1448 cout
<< wxT("Login Timeout: ") << dbInf
.loginTimeout
<< endl
;
1450 cout
<< endl
<< endl
<< wxT("more ...") << endl
;
1453 cout
<< wxT("Default Transaction Isolation: ";
1454 switch(dbInf
.txnIsolation
)
1456 case SQL_TXN_READ_UNCOMMITTED
: cout
<< wxT("Read Uncommitted"); break;
1457 case SQL_TXN_READ_COMMITTED
: cout
<< wxT("Read Committed"); break;
1458 case SQL_TXN_REPEATABLE_READ
: cout
<< wxT("Repeatable Read"); break;
1459 case SQL_TXN_SERIALIZABLE
: cout
<< wxT("Serializable"); break;
1461 case SQL_TXN_VERSIONING
: cout
<< wxT("Versioning"); break;
1466 cout
<< wxT("Transaction Isolation Options: ");
1467 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_UNCOMMITTED
)
1468 cout
<< wxT("Read Uncommitted, ");
1469 if (dbInf
.txnIsolationOptions
& SQL_TXN_READ_COMMITTED
)
1470 cout
<< wxT("Read Committed, ");
1471 if (dbInf
.txnIsolationOptions
& SQL_TXN_REPEATABLE_READ
)
1472 cout
<< wxT("Repeatable Read, ");
1473 if (dbInf
.txnIsolationOptions
& SQL_TXN_SERIALIZABLE
)
1474 cout
<< wxT("Serializable, ");
1476 if (dbInf
.txnIsolationOptions
& SQL_TXN_VERSIONING
)
1477 cout
<< wxT("Versioning");
1481 cout
<< wxT("Fetch Directions Supported:") << endl
<< wxT(" ");
1482 if (dbInf
.fetchDirections
& SQL_FD_FETCH_NEXT
)
1483 cout
<< wxT("Next, ");
1484 if (dbInf
.fetchDirections
& SQL_FD_FETCH_PRIOR
)
1485 cout
<< wxT("Prev, ");
1486 if (dbInf
.fetchDirections
& SQL_FD_FETCH_FIRST
)
1487 cout
<< wxT("First, ");
1488 if (dbInf
.fetchDirections
& SQL_FD_FETCH_LAST
)
1489 cout
<< wxT("Last, ");
1490 if (dbInf
.fetchDirections
& SQL_FD_FETCH_ABSOLUTE
)
1491 cout
<< wxT("Absolute, ");
1492 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RELATIVE
)
1493 cout
<< wxT("Relative, ");
1495 if (dbInf
.fetchDirections
& SQL_FD_FETCH_RESUME
)
1496 cout
<< wxT("Resume, ");
1498 if (dbInf
.fetchDirections
& SQL_FD_FETCH_BOOKMARK
)
1499 cout
<< wxT("Bookmark");
1502 cout
<< wxT("Lock Types Supported (SQLSetPos): ");
1503 if (dbInf
.lockTypes
& SQL_LCK_NO_CHANGE
)
1504 cout
<< wxT("No Change, ");
1505 if (dbInf
.lockTypes
& SQL_LCK_EXCLUSIVE
)
1506 cout
<< wxT("Exclusive, ");
1507 if (dbInf
.lockTypes
& SQL_LCK_UNLOCK
)
1508 cout
<< wxT("UnLock");
1511 cout
<< wxT("Position Operations Supported (SQLSetPos): ");
1512 if (dbInf
.posOperations
& SQL_POS_POSITION
)
1513 cout
<< wxT("Position, ");
1514 if (dbInf
.posOperations
& SQL_POS_REFRESH
)
1515 cout
<< wxT("Refresh, ");
1516 if (dbInf
.posOperations
& SQL_POS_UPDATE
)
1517 cout
<< wxT("Upd, "));
1518 if (dbInf
.posOperations
& SQL_POS_DELETE
)
1519 cout
<< wxT("Del, ");
1520 if (dbInf
.posOperations
& SQL_POS_ADD
)
1524 cout
<< wxT("Positioned Statements Supported: ");
1525 if (dbInf
.posStmts
& SQL_PS_POSITIONED_DELETE
)
1526 cout
<< wxT("Pos delete, ");
1527 if (dbInf
.posStmts
& SQL_PS_POSITIONED_UPDATE
)
1528 cout
<< wxT("Pos update, ");
1529 if (dbInf
.posStmts
& SQL_PS_SELECT_FOR_UPDATE
)
1530 cout
<< wxT("Select for update");
1533 cout
<< wxT("Scroll Concurrency: ");
1534 if (dbInf
.scrollConcurrency
& SQL_SCCO_READ_ONLY
)
1535 cout
<< wxT("Read Only, ");
1536 if (dbInf
.scrollConcurrency
& SQL_SCCO_LOCK
)
1537 cout
<< wxT("Lock, ");
1538 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_ROWVER
)
1539 cout
<< wxT("Opt. Rowver, ");
1540 if (dbInf
.scrollConcurrency
& SQL_SCCO_OPT_VALUES
)
1541 cout
<< wxT("Opt. Values");
1544 cout
<< wxT("Scroll Options: ");
1545 if (dbInf
.scrollOptions
& SQL_SO_FORWARD_ONLY
)
1546 cout
<< wxT("Fwd Only, ");
1547 if (dbInf
.scrollOptions
& SQL_SO_STATIC
)
1548 cout
<< wxT("Static, ");
1549 if (dbInf
.scrollOptions
& SQL_SO_KEYSET_DRIVEN
)
1550 cout
<< wxT("Keyset Driven, ");
1551 if (dbInf
.scrollOptions
& SQL_SO_DYNAMIC
)
1552 cout
<< wxT("Dynamic, ");
1553 if (dbInf
.scrollOptions
& SQL_SO_MIXED
)
1554 cout
<< wxT("Mixed");
1557 cout
<< wxT("Static Sensitivity: ");
1558 if (dbInf
.staticSensitivity
& SQL_SS_ADDITIONS
)
1559 cout
<< wxT("Additions, ");
1560 if (dbInf
.staticSensitivity
& SQL_SS_DELETIONS
)
1561 cout
<< wxT("Deletions, ");
1562 if (dbInf
.staticSensitivity
& SQL_SS_UPDATES
)
1563 cout
<< wxT("Updates");
1566 cout
<< wxT("Transaction Capable?: ");
1567 switch(dbInf
.txnCapable
)
1569 case SQL_TC_NONE
: cout
<< wxT("No"); break;
1570 case SQL_TC_DML
: cout
<< wxT("DML Only"); break;
1571 case SQL_TC_DDL_COMMIT
: cout
<< wxT("DDL Commit"); break;
1572 case SQL_TC_DDL_IGNORE
: cout
<< wxT("DDL Ignore"); break;
1573 case SQL_TC_ALL
: cout
<< wxT("DDL & DML"); break;
1580 // Completed Successfully
1583 } // wxDb::getDbInfo()
1586 /********** wxDb::getDataTypeInfo() **********/
1587 bool wxDb::getDataTypeInfo(SWORD fSqlType
, wxDbSqlTypeInfo
&structSQLTypeInfo
)
1590 * fSqlType will be something like SQL_VARCHAR. This parameter determines
1591 * the data type inf. is gathered for.
1593 * wxDbSqlTypeInfo is a structure that is filled in with data type information,
1598 // Get information about the data type specified
1599 if (SQLGetTypeInfo(hstmt
, fSqlType
) != SQL_SUCCESS
)
1600 return(DispAllErrors(henv
, hdbc
, hstmt
));
1603 retcode
= SQLFetch(hstmt
);
1604 if (retcode
!= SQL_SUCCESS
)
1606 #ifdef DBDEBUG_CONSOLE
1607 if (retcode
== SQL_NO_DATA_FOUND
)
1608 cout
<< wxT("SQL_NO_DATA_FOUND fetching information about data type.") << endl
;
1610 DispAllErrors(henv
, hdbc
, hstmt
);
1611 SQLFreeStmt(hstmt
, SQL_CLOSE
);
1615 wxChar typeName
[DB_TYPE_NAME_LEN
+1];
1617 // Obtain columns from the record
1618 if (SQLGetData(hstmt
, 1, SQL_C_WXCHAR
, typeName
, sizeof(typeName
), &cbRet
) != SQL_SUCCESS
)
1619 return(DispAllErrors(henv
, hdbc
, hstmt
));
1621 structSQLTypeInfo
.TypeName
= typeName
;
1623 // BJO 20000503: no more needed with new GetColumns...
1626 if (Dbms() == dbmsMY_SQL
)
1628 if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1629 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1630 else if (structSQLTypeInfo
.TypeName
== wxT("middleint unsigned"))
1631 structSQLTypeInfo
.TypeName
= wxT("mediumint unsigned");
1632 else if (structSQLTypeInfo
.TypeName
== wxT("integer"))
1633 structSQLTypeInfo
.TypeName
= wxT("int");
1634 else if (structSQLTypeInfo
.TypeName
== wxT("integer unsigned"))
1635 structSQLTypeInfo
.TypeName
= wxT("int unsigned");
1636 else if (structSQLTypeInfo
.TypeName
== wxT("middleint"))
1637 structSQLTypeInfo
.TypeName
= wxT("mediumint");
1638 else if (structSQLTypeInfo
.TypeName
== wxT("varchar"))
1639 structSQLTypeInfo
.TypeName
= wxT("char");
1642 // BJO 20000427 : OpenLink driver
1643 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
1644 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
1646 if (structSQLTypeInfo
.TypeName
== wxT("double precision"))
1647 structSQLTypeInfo
.TypeName
= wxT("real");
1651 if (SQLGetData(hstmt
, 3, SQL_C_LONG
, (UCHAR
*) &structSQLTypeInfo
.Precision
, 0, &cbRet
) != SQL_SUCCESS
)
1652 return(DispAllErrors(henv
, hdbc
, hstmt
));
1653 if (SQLGetData(hstmt
, 8, SQL_C_SHORT
, (UCHAR
*) &structSQLTypeInfo
.CaseSensitive
, 0, &cbRet
) != SQL_SUCCESS
)
1654 return(DispAllErrors(henv
, hdbc
, hstmt
));
1655 // if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
1656 // return(DispAllErrors(henv, hdbc, hstmt));
1658 if (SQLGetData(hstmt
, 15, SQL_C_SHORT
,(UCHAR
*) &structSQLTypeInfo
.MaximumScale
, 0, &cbRet
) != SQL_SUCCESS
)
1659 return(DispAllErrors(henv
, hdbc
, hstmt
));
1661 if (structSQLTypeInfo
.MaximumScale
< 0)
1662 structSQLTypeInfo
.MaximumScale
= 0;
1664 // Close the statement handle which closes open cursors
1665 if (SQLFreeStmt(hstmt
, SQL_CLOSE
) != SQL_SUCCESS
)
1666 return(DispAllErrors(henv
, hdbc
, hstmt
));
1668 // Completed Successfully
1671 } // wxDb::getDataTypeInfo()
1674 /********** wxDb::Close() **********/
1675 void wxDb::Close(void)
1677 // Close the Sql Log file
1684 // Free statement handle
1687 if (SQLFreeStmt(hstmt
, SQL_DROP
) != SQL_SUCCESS
)
1688 DispAllErrors(henv
, hdbc
);
1691 // Disconnect from the datasource
1692 if (SQLDisconnect(hdbc
) != SQL_SUCCESS
)
1693 DispAllErrors(henv
, hdbc
);
1695 // Free the connection to the datasource
1696 if (SQLFreeConnect(hdbc
) != SQL_SUCCESS
)
1697 DispAllErrors(henv
, hdbc
);
1699 // There should be zero Ctable objects still connected to this db object
1700 wxASSERT(nTables
== 0);
1704 wxList::compatibility_iterator pNode
;
1705 pNode
= TablesInUse
.GetFirst();
1709 tiu
= (wxTablesInUse
*)pNode
->GetData();
1710 if (tiu
->pDb
== this)
1712 s
.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu
->tableName
,tiu
->tableID
,tiu
->pDb
);
1713 s2
.Printf(wxT("Orphaned table found using pDb:[%p]"),this);
1714 wxLogDebug(s
.c_str(),s2
.c_str());
1716 pNode
= pNode
->GetNext();
1720 // Copy the error messages to a global variable
1722 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1723 wxStrcpy(DBerrorList
[i
], errorList
[i
]);
1725 dbmsType
= dbmsUNIDENTIFIED
;
1731 /********** wxDb::CommitTrans() **********/
1732 bool wxDb::CommitTrans(void)
1736 // Commit the transaction
1737 if (SQLTransact(henv
, hdbc
, SQL_COMMIT
) != SQL_SUCCESS
)
1738 return(DispAllErrors(henv
, hdbc
));
1741 // Completed successfully
1744 } // wxDb::CommitTrans()
1747 /********** wxDb::RollbackTrans() **********/
1748 bool wxDb::RollbackTrans(void)
1750 // Rollback the transaction
1751 if (SQLTransact(henv
, hdbc
, SQL_ROLLBACK
) != SQL_SUCCESS
)
1752 return(DispAllErrors(henv
, hdbc
));
1754 // Completed successfully
1757 } // wxDb::RollbackTrans()
1760 /********** wxDb::DispAllErrors() **********/
1761 bool wxDb::DispAllErrors(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1763 * This function is called internally whenever an error condition prevents the user's
1764 * request from being executed. This function will query the datasource as to the
1765 * actual error(s) that just occured on the previous request of the datasource.
1767 * The function will retrieve each error condition from the datasource and
1768 * Printf the codes/text values into a string which it then logs via logError().
1769 * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
1770 * window and program execution will be paused until the user presses a key.
1772 * This function always returns a false, so that functions which call this function
1773 * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure
1774 * of the users request, so that the calling code can then process the error msg log
1777 wxString odbcErrMsg
;
1780 while (SQLError(aHenv
, aHdbc
, aHstmt
, (SQLTCHAR FAR
*) sqlState
, (SQLINTEGER
*) &nativeError
, (SQLTCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1782 while (SQLError(aHenv
, aHdbc
, aHstmt
, (SQLTCHAR FAR
*) sqlState
, (long*) &nativeError
, (SQLTCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1785 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1786 logError(odbcErrMsg
, sqlState
);
1789 #ifdef DBDEBUG_CONSOLE
1790 // When run in console mode, use standard out to display errors.
1791 cout
<< odbcErrMsg
.c_str() << endl
;
1792 cout
<< wxT("Press any key to continue...") << endl
;
1797 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
1802 return false; // This function always returns false.
1804 } // wxDb::DispAllErrors()
1807 /********** wxDb::GetNextError() **********/
1808 bool wxDb::GetNextError(HENV aHenv
, HDBC aHdbc
, HSTMT aHstmt
)
1811 if (SQLError(aHenv
, aHdbc
, aHstmt
, (SQLTCHAR FAR
*) sqlState
, (SQLINTEGER
*) &nativeError
, (SQLTCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1813 if (SQLError(aHenv
, aHdbc
, aHstmt
, (SQLTCHAR FAR
*) sqlState
, (long*) &nativeError
, (SQLTCHAR FAR
*) errorMsg
, SQL_MAX_MESSAGE_LENGTH
- 1, &cbErrorMsg
) == SQL_SUCCESS
)
1819 } // wxDb::GetNextError()
1822 /********** wxDb::DispNextError() **********/
1823 void wxDb::DispNextError(void)
1825 wxString odbcErrMsg
;
1827 odbcErrMsg
.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState
, nativeError
, errorMsg
);
1828 logError(odbcErrMsg
, sqlState
);
1833 #ifdef DBDEBUG_CONSOLE
1834 // When run in console mode, use standard out to display errors.
1835 cout
<< odbcErrMsg
.c_str() << endl
;
1836 cout
<< wxT("Press any key to continue...") << endl
;
1841 wxLogDebug(odbcErrMsg
,wxT("ODBC DEBUG MESSAGE"));
1842 #endif // __WXDEBUG__
1844 } // wxDb::DispNextError()
1847 /********** wxDb::logError() **********/
1848 void wxDb::logError(const wxString
&errMsg
, const wxString
&SQLState
)
1850 wxASSERT(errMsg
.Length());
1852 static int pLast
= -1;
1855 if (++pLast
== DB_MAX_ERROR_HISTORY
)
1858 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
1859 wxStrcpy(errorList
[i
], errorList
[i
+1]);
1863 wxStrcpy(errorList
[pLast
], errMsg
);
1865 if (SQLState
.Length())
1866 if ((dbStatus
= TranslateSqlState(SQLState
)) != DB_ERR_FUNCTION_SEQUENCE_ERROR
)
1867 DB_STATUS
= dbStatus
;
1869 // Add the errmsg to the sql log
1870 WriteSqlLog(errMsg
);
1872 } // wxDb::logError()
1875 /**********wxDb::TranslateSqlState() **********/
1876 int wxDb::TranslateSqlState(const wxString
&SQLState
)
1878 if (!wxStrcmp(SQLState
, wxT("01000")))
1879 return(DB_ERR_GENERAL_WARNING
);
1880 if (!wxStrcmp(SQLState
, wxT("01002")))
1881 return(DB_ERR_DISCONNECT_ERROR
);
1882 if (!wxStrcmp(SQLState
, wxT("01004")))
1883 return(DB_ERR_DATA_TRUNCATED
);
1884 if (!wxStrcmp(SQLState
, wxT("01006")))
1885 return(DB_ERR_PRIV_NOT_REVOKED
);
1886 if (!wxStrcmp(SQLState
, wxT("01S00")))
1887 return(DB_ERR_INVALID_CONN_STR_ATTR
);
1888 if (!wxStrcmp(SQLState
, wxT("01S01")))
1889 return(DB_ERR_ERROR_IN_ROW
);
1890 if (!wxStrcmp(SQLState
, wxT("01S02")))
1891 return(DB_ERR_OPTION_VALUE_CHANGED
);
1892 if (!wxStrcmp(SQLState
, wxT("01S03")))
1893 return(DB_ERR_NO_ROWS_UPD_OR_DEL
);
1894 if (!wxStrcmp(SQLState
, wxT("01S04")))
1895 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL
);
1896 if (!wxStrcmp(SQLState
, wxT("07001")))
1897 return(DB_ERR_WRONG_NO_OF_PARAMS
);
1898 if (!wxStrcmp(SQLState
, wxT("07006")))
1899 return(DB_ERR_DATA_TYPE_ATTR_VIOL
);
1900 if (!wxStrcmp(SQLState
, wxT("08001")))
1901 return(DB_ERR_UNABLE_TO_CONNECT
);
1902 if (!wxStrcmp(SQLState
, wxT("08002")))
1903 return(DB_ERR_CONNECTION_IN_USE
);
1904 if (!wxStrcmp(SQLState
, wxT("08003")))
1905 return(DB_ERR_CONNECTION_NOT_OPEN
);
1906 if (!wxStrcmp(SQLState
, wxT("08004")))
1907 return(DB_ERR_REJECTED_CONNECTION
);
1908 if (!wxStrcmp(SQLState
, wxT("08007")))
1909 return(DB_ERR_CONN_FAIL_IN_TRANS
);
1910 if (!wxStrcmp(SQLState
, wxT("08S01")))
1911 return(DB_ERR_COMM_LINK_FAILURE
);
1912 if (!wxStrcmp(SQLState
, wxT("21S01")))
1913 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH
);
1914 if (!wxStrcmp(SQLState
, wxT("21S02")))
1915 return(DB_ERR_DERIVED_TABLE_MISMATCH
);
1916 if (!wxStrcmp(SQLState
, wxT("22001")))
1917 return(DB_ERR_STRING_RIGHT_TRUNC
);
1918 if (!wxStrcmp(SQLState
, wxT("22003")))
1919 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG
);
1920 if (!wxStrcmp(SQLState
, wxT("22005")))
1921 return(DB_ERR_ERROR_IN_ASSIGNMENT
);
1922 if (!wxStrcmp(SQLState
, wxT("22008")))
1923 return(DB_ERR_DATETIME_FLD_OVERFLOW
);
1924 if (!wxStrcmp(SQLState
, wxT("22012")))
1925 return(DB_ERR_DIVIDE_BY_ZERO
);
1926 if (!wxStrcmp(SQLState
, wxT("22026")))
1927 return(DB_ERR_STR_DATA_LENGTH_MISMATCH
);
1928 if (!wxStrcmp(SQLState
, wxT("23000")))
1929 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL
);
1930 if (!wxStrcmp(SQLState
, wxT("24000")))
1931 return(DB_ERR_INVALID_CURSOR_STATE
);
1932 if (!wxStrcmp(SQLState
, wxT("25000")))
1933 return(DB_ERR_INVALID_TRANS_STATE
);
1934 if (!wxStrcmp(SQLState
, wxT("28000")))
1935 return(DB_ERR_INVALID_AUTH_SPEC
);
1936 if (!wxStrcmp(SQLState
, wxT("34000")))
1937 return(DB_ERR_INVALID_CURSOR_NAME
);
1938 if (!wxStrcmp(SQLState
, wxT("37000")))
1939 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL
);
1940 if (!wxStrcmp(SQLState
, wxT("3C000")))
1941 return(DB_ERR_DUPLICATE_CURSOR_NAME
);
1942 if (!wxStrcmp(SQLState
, wxT("40001")))
1943 return(DB_ERR_SERIALIZATION_FAILURE
);
1944 if (!wxStrcmp(SQLState
, wxT("42000")))
1945 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2
);
1946 if (!wxStrcmp(SQLState
, wxT("70100")))
1947 return(DB_ERR_OPERATION_ABORTED
);
1948 if (!wxStrcmp(SQLState
, wxT("IM001")))
1949 return(DB_ERR_UNSUPPORTED_FUNCTION
);
1950 if (!wxStrcmp(SQLState
, wxT("IM002")))
1951 return(DB_ERR_NO_DATA_SOURCE
);
1952 if (!wxStrcmp(SQLState
, wxT("IM003")))
1953 return(DB_ERR_DRIVER_LOAD_ERROR
);
1954 if (!wxStrcmp(SQLState
, wxT("IM004")))
1955 return(DB_ERR_SQLALLOCENV_FAILED
);
1956 if (!wxStrcmp(SQLState
, wxT("IM005")))
1957 return(DB_ERR_SQLALLOCCONNECT_FAILED
);
1958 if (!wxStrcmp(SQLState
, wxT("IM006")))
1959 return(DB_ERR_SQLSETCONNECTOPTION_FAILED
);
1960 if (!wxStrcmp(SQLState
, wxT("IM007")))
1961 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB
);
1962 if (!wxStrcmp(SQLState
, wxT("IM008")))
1963 return(DB_ERR_DIALOG_FAILED
);
1964 if (!wxStrcmp(SQLState
, wxT("IM009")))
1965 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL
);
1966 if (!wxStrcmp(SQLState
, wxT("IM010")))
1967 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG
);
1968 if (!wxStrcmp(SQLState
, wxT("IM011")))
1969 return(DB_ERR_DRIVER_NAME_TOO_LONG
);
1970 if (!wxStrcmp(SQLState
, wxT("IM012")))
1971 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR
);
1972 if (!wxStrcmp(SQLState
, wxT("IM013")))
1973 return(DB_ERR_TRACE_FILE_ERROR
);
1974 if (!wxStrcmp(SQLState
, wxT("S0001")))
1975 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS
);
1976 if (!wxStrcmp(SQLState
, wxT("S0002")))
1977 return(DB_ERR_TABLE_NOT_FOUND
);
1978 if (!wxStrcmp(SQLState
, wxT("S0011")))
1979 return(DB_ERR_INDEX_ALREADY_EXISTS
);
1980 if (!wxStrcmp(SQLState
, wxT("S0012")))
1981 return(DB_ERR_INDEX_NOT_FOUND
);
1982 if (!wxStrcmp(SQLState
, wxT("S0021")))
1983 return(DB_ERR_COLUMN_ALREADY_EXISTS
);
1984 if (!wxStrcmp(SQLState
, wxT("S0022")))
1985 return(DB_ERR_COLUMN_NOT_FOUND
);
1986 if (!wxStrcmp(SQLState
, wxT("S0023")))
1987 return(DB_ERR_NO_DEFAULT_FOR_COLUMN
);
1988 if (!wxStrcmp(SQLState
, wxT("S1000")))
1989 return(DB_ERR_GENERAL_ERROR
);
1990 if (!wxStrcmp(SQLState
, wxT("S1001")))
1991 return(DB_ERR_MEMORY_ALLOCATION_FAILURE
);
1992 if (!wxStrcmp(SQLState
, wxT("S1002")))
1993 return(DB_ERR_INVALID_COLUMN_NUMBER
);
1994 if (!wxStrcmp(SQLState
, wxT("S1003")))
1995 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE
);
1996 if (!wxStrcmp(SQLState
, wxT("S1004")))
1997 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE
);
1998 if (!wxStrcmp(SQLState
, wxT("S1008")))
1999 return(DB_ERR_OPERATION_CANCELLED
);
2000 if (!wxStrcmp(SQLState
, wxT("S1009")))
2001 return(DB_ERR_INVALID_ARGUMENT_VALUE
);
2002 if (!wxStrcmp(SQLState
, wxT("S1010")))
2003 return(DB_ERR_FUNCTION_SEQUENCE_ERROR
);
2004 if (!wxStrcmp(SQLState
, wxT("S1011")))
2005 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME
);
2006 if (!wxStrcmp(SQLState
, wxT("S1012")))
2007 return(DB_ERR_INVALID_TRANS_OPERATION_CODE
);
2008 if (!wxStrcmp(SQLState
, wxT("S1015")))
2009 return(DB_ERR_NO_CURSOR_NAME_AVAIL
);
2010 if (!wxStrcmp(SQLState
, wxT("S1090")))
2011 return(DB_ERR_INVALID_STR_OR_BUF_LEN
);
2012 if (!wxStrcmp(SQLState
, wxT("S1091")))
2013 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE
);
2014 if (!wxStrcmp(SQLState
, wxT("S1092")))
2015 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE
);
2016 if (!wxStrcmp(SQLState
, wxT("S1093")))
2017 return(DB_ERR_INVALID_PARAM_NO
);
2018 if (!wxStrcmp(SQLState
, wxT("S1094")))
2019 return(DB_ERR_INVALID_SCALE_VALUE
);
2020 if (!wxStrcmp(SQLState
, wxT("S1095")))
2021 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE
);
2022 if (!wxStrcmp(SQLState
, wxT("S1096")))
2023 return(DB_ERR_INF_TYPE_OUT_OF_RANGE
);
2024 if (!wxStrcmp(SQLState
, wxT("S1097")))
2025 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE
);
2026 if (!wxStrcmp(SQLState
, wxT("S1098")))
2027 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE
);
2028 if (!wxStrcmp(SQLState
, wxT("S1099")))
2029 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE
);
2030 if (!wxStrcmp(SQLState
, wxT("S1100")))
2031 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE
);
2032 if (!wxStrcmp(SQLState
, wxT("S1101")))
2033 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE
);
2034 if (!wxStrcmp(SQLState
, wxT("S1103")))
2035 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE
);
2036 if (!wxStrcmp(SQLState
, wxT("S1104")))
2037 return(DB_ERR_INVALID_PRECISION_VALUE
);
2038 if (!wxStrcmp(SQLState
, wxT("S1105")))
2039 return(DB_ERR_INVALID_PARAM_TYPE
);
2040 if (!wxStrcmp(SQLState
, wxT("S1106")))
2041 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE
);
2042 if (!wxStrcmp(SQLState
, wxT("S1107")))
2043 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE
);
2044 if (!wxStrcmp(SQLState
, wxT("S1108")))
2045 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE
);
2046 if (!wxStrcmp(SQLState
, wxT("S1109")))
2047 return(DB_ERR_INVALID_CURSOR_POSITION
);
2048 if (!wxStrcmp(SQLState
, wxT("S1110")))
2049 return(DB_ERR_INVALID_DRIVER_COMPLETION
);
2050 if (!wxStrcmp(SQLState
, wxT("S1111")))
2051 return(DB_ERR_INVALID_BOOKMARK_VALUE
);
2052 if (!wxStrcmp(SQLState
, wxT("S1C00")))
2053 return(DB_ERR_DRIVER_NOT_CAPABLE
);
2054 if (!wxStrcmp(SQLState
, wxT("S1T00")))
2055 return(DB_ERR_TIMEOUT_EXPIRED
);
2060 } // wxDb::TranslateSqlState()
2063 /********** wxDb::Grant() **********/
2064 bool wxDb::Grant(int privileges
, const wxString
&tableName
, const wxString
&userList
)
2068 // Build the grant statement
2069 sqlStmt
= wxT("GRANT ");
2070 if (privileges
== DB_GRANT_ALL
)
2071 sqlStmt
+= wxT("ALL");
2075 if (privileges
& DB_GRANT_SELECT
)
2077 sqlStmt
+= wxT("SELECT");
2080 if (privileges
& DB_GRANT_INSERT
)
2083 sqlStmt
+= wxT(", ");
2084 sqlStmt
+= wxT("INSERT");
2086 if (privileges
& DB_GRANT_UPDATE
)
2089 sqlStmt
+= wxT(", ");
2090 sqlStmt
+= wxT("UPDATE");
2092 if (privileges
& DB_GRANT_DELETE
)
2095 sqlStmt
+= wxT(", ");
2096 sqlStmt
+= wxT("DELETE");
2100 sqlStmt
+= wxT(" ON ");
2101 sqlStmt
+= SQLTableName(tableName
);
2102 sqlStmt
+= wxT(" TO ");
2103 sqlStmt
+= userList
;
2105 #ifdef DBDEBUG_CONSOLE
2106 cout
<< endl
<< sqlStmt
.c_str() << endl
;
2109 WriteSqlLog(sqlStmt
);
2111 return(ExecSql(sqlStmt
));
2116 /********** wxDb::CreateView() **********/
2117 bool wxDb::CreateView(const wxString
&viewName
, const wxString
&colList
,
2118 const wxString
&pSqlStmt
, bool attemptDrop
)
2122 // Drop the view first
2123 if (attemptDrop
&& !DropView(viewName
))
2126 // Build the create view statement
2127 sqlStmt
= wxT("CREATE VIEW ");
2128 sqlStmt
+= viewName
;
2130 if (colList
.Length())
2132 sqlStmt
+= wxT(" (");
2134 sqlStmt
+= wxT(")");
2137 sqlStmt
+= wxT(" AS ");
2138 sqlStmt
+= pSqlStmt
;
2140 WriteSqlLog(sqlStmt
);
2142 #ifdef DBDEBUG_CONSOLE
2143 cout
<< sqlStmt
.c_str() << endl
;
2146 return(ExecSql(sqlStmt
));
2148 } // wxDb::CreateView()
2151 /********** wxDb::DropView() **********/
2152 bool wxDb::DropView(const wxString
&viewName
)
2155 * NOTE: This function returns true if the View does not exist, but
2156 * only for identified databases. Code will need to be added
2157 * below for any other databases when those databases are defined
2158 * to handle this situation consistently
2162 sqlStmt
.Printf(wxT("DROP VIEW %s"), viewName
.c_str());
2164 WriteSqlLog(sqlStmt
);
2166 #ifdef DBDEBUG_CONSOLE
2167 cout
<< endl
<< sqlStmt
.c_str() << endl
;
2170 if (SQLExecDirect(hstmt
, (SQLTCHAR FAR
*) sqlStmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
2172 // Check for "Base table not found" error and ignore
2173 GetNextError(henv
, hdbc
, hstmt
);
2174 if (wxStrcmp(sqlState
,wxT("S0002"))) // "Base table not found"
2176 // Check for product specific error codes
2177 if (!((Dbms() == dbmsSYBASE_ASA
&& !wxStrcmp(sqlState
,wxT("42000"))))) // 5.x (and lower?)
2180 DispAllErrors(henv
, hdbc
, hstmt
);
2187 // Commit the transaction
2193 } // wxDb::DropView()
2196 /********** wxDb::ExecSql() **********/
2197 bool wxDb::ExecSql(const wxString
&pSqlStmt
)
2201 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2203 retcode
= SQLExecDirect(hstmt
, (SQLTCHAR FAR
*) pSqlStmt
.c_str(), SQL_NTS
);
2204 if (retcode
== SQL_SUCCESS
||
2205 (Dbms() == dbmsDB2
&& (retcode
== SQL_SUCCESS_WITH_INFO
|| retcode
== SQL_NO_DATA_FOUND
)))
2211 DispAllErrors(henv
, hdbc
, hstmt
);
2215 } // wxDb::ExecSql()
2218 /********** wxDb::ExecSql() with column info **********/
2219 bool wxDb::ExecSql(const wxString
&pSqlStmt
, wxDbColInf
** columns
, short& numcols
)
2221 //execute the statement first
2222 if (!ExecSql(pSqlStmt
))
2226 if (SQLNumResultCols(hstmt
, &noCols
) != SQL_SUCCESS
)
2228 DispAllErrors(henv
, hdbc
, hstmt
);
2237 // Get column information
2239 wxChar name
[DB_MAX_COLUMN_NAME_LEN
+1];
2242 wxDbColInf
* pColInf
= new wxDbColInf
[noCols
];
2244 //fill in column information (name, datatype)
2245 for (colNum
= 0; colNum
< noCols
; colNum
++)
2247 if (SQLColAttributes(hstmt
, (UWORD
)(colNum
+1), SQL_COLUMN_NAME
,
2249 &Sword
, &Sdword
) != SQL_SUCCESS
)
2251 DispAllErrors(henv
, hdbc
, hstmt
);
2256 wxStrncpy(pColInf
[colNum
].colName
, name
, DB_MAX_COLUMN_NAME_LEN
);
2258 if (SQLColAttributes(hstmt
, (UWORD
)(colNum
+1), SQL_COLUMN_TYPE
,
2259 NULL
, 0, &Sword
, &Sdword
) != SQL_SUCCESS
)
2261 DispAllErrors(henv
, hdbc
, hstmt
);
2270 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2276 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2283 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2287 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_DATE
;
2290 pColInf
[colNum
].dbDataType
= DB_DATA_TYPE_BLOB
;
2295 errMsg
.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sdword
);
2296 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
2303 } // wxDb::ExecSql()
2305 /********** wxDb::GetNext() **********/
2306 bool wxDb::GetNext(void)
2308 if (SQLFetch(hstmt
) == SQL_SUCCESS
)
2312 DispAllErrors(henv
, hdbc
, hstmt
);
2316 } // wxDb::GetNext()
2319 /********** wxDb::GetData() **********/
2320 bool wxDb::GetData(UWORD colNo
, SWORD cType
, PTR pData
, SDWORD maxLen
, SDWORD FAR
*cbReturned
)
2323 wxASSERT(cbReturned
);
2325 long bufferSize
= maxLen
;
2327 if (cType
== SQL_C_WXCHAR
)
2328 bufferSize
= maxLen
* sizeof(wxChar
);
2330 if (SQLGetData(hstmt
, colNo
, cType
, pData
, bufferSize
, cbReturned
) == SQL_SUCCESS
)
2334 DispAllErrors(henv
, hdbc
, hstmt
);
2338 } // wxDb::GetData()
2341 /********** wxDb::GetKeyFields() **********/
2342 int wxDb::GetKeyFields(const wxString
&tableName
, wxDbColInf
* colInf
, UWORD noCols
)
2344 wxChar szPkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Primary key table name */
2345 wxChar szFkTable
[DB_MAX_TABLE_NAME_LEN
+1]; /* Foreign key table name */
2347 wxChar szPkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Primary key column */
2348 wxChar szFkCol
[DB_MAX_COLUMN_NAME_LEN
+1]; /* Foreign key column */
2354 * -----------------------------------------------------------------------
2355 * -- 19991224 : mj10777 : Create ------
2356 * -- : Three things are done and stored here : ------
2357 * -- : 1) which Column(s) is/are Primary Key(s) ------
2358 * -- : 2) which tables use this Key as a Foreign Key ------
2359 * -- : 3) which columns are Foreign Key and the name ------
2360 * -- : of the Table where the Key is the Primary Key -----
2361 * -- : Called from GetColumns(const wxString &tableName, ------
2362 * -- int *numCols,const wxChar *userID ) ------
2363 * -----------------------------------------------------------------------
2366 /*---------------------------------------------------------------------*/
2367 /* Get the names of the columns in the primary key. */
2368 /*---------------------------------------------------------------------*/
2369 retcode
= SQLPrimaryKeys(hstmt
,
2370 NULL
, 0, /* Catalog name */
2371 NULL
, 0, /* Schema name */
2372 (SQLTCHAR FAR
*) tableName
.c_str(), SQL_NTS
); /* Table name */
2374 /*---------------------------------------------------------------------*/
2375 /* Fetch and display the result set. This will be a list of the */
2376 /* columns in the primary key of the tableName table. */
2377 /*---------------------------------------------------------------------*/
2378 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
2380 retcode
= SQLFetch(hstmt
);
2381 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
2383 GetData( 4, SQL_C_WXCHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2384 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
2386 for (i
=0;i
<noCols
;i
++) // Find the Column name
2387 if (!wxStrcmp(colInf
[i
].colName
,szPkCol
)) // We have found the Column
2388 colInf
[i
].PkCol
= iKeySeq
; // Which Primary Key is this (first, second usw.) ?
2391 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
2393 /*---------------------------------------------------------------------*/
2394 /* Get all the foreign keys that refer to tableName primary key. */
2395 /*---------------------------------------------------------------------*/
2396 retcode
= SQLForeignKeys(hstmt
,
2397 NULL
, 0, /* Primary catalog */
2398 NULL
, 0, /* Primary schema */
2399 (SQLTCHAR FAR
*)tableName
.c_str(), SQL_NTS
,/* Primary table */
2400 NULL
, 0, /* Foreign catalog */
2401 NULL
, 0, /* Foreign schema */
2402 NULL
, 0); /* Foreign table */
2404 /*---------------------------------------------------------------------*/
2405 /* Fetch and display the result set. This will be all of the foreign */
2406 /* keys in other tables that refer to the tableName primary key. */
2407 /*---------------------------------------------------------------------*/
2410 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
2412 retcode
= SQLFetch(hstmt
);
2413 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
2415 GetData( 3, SQL_C_WXCHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2416 GetData( 4, SQL_C_WXCHAR
, szPkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2417 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
2418 GetData( 7, SQL_C_WXCHAR
, szFkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2419 GetData( 8, SQL_C_WXCHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2420 tempStr
.Printf(wxT("%s[%s] "),tempStr
.c_str(),szFkTable
); // [ ] in case there is a blank in the Table name
2424 tempStr
.Trim(); // Get rid of any unneeded blanks
2425 if (!tempStr
.empty())
2427 for (i
=0; i
<noCols
; i
++)
2428 { // Find the Column name
2429 if (!wxStrcmp(colInf
[i
].colName
, szPkCol
)) // We have found the Column, store the Information
2430 wxStrcpy(colInf
[i
].PkTableName
, tempStr
.c_str()); // Name of the Tables where this Primary Key is used as a Foreign Key
2434 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
2436 /*---------------------------------------------------------------------*/
2437 /* Get all the foreign keys in the tablename table. */
2438 /*---------------------------------------------------------------------*/
2439 retcode
= SQLForeignKeys(hstmt
,
2440 NULL
, 0, /* Primary catalog */
2441 NULL
, 0, /* Primary schema */
2442 NULL
, 0, /* Primary table */
2443 NULL
, 0, /* Foreign catalog */
2444 NULL
, 0, /* Foreign schema */
2445 (SQLTCHAR
*)tableName
.c_str(), SQL_NTS
);/* Foreign table */
2447 /*---------------------------------------------------------------------*/
2448 /* Fetch and display the result set. This will be all of the */
2449 /* primary keys in other tables that are referred to by foreign */
2450 /* keys in the tableName table. */
2451 /*---------------------------------------------------------------------*/
2452 while ((retcode
== SQL_SUCCESS
) || (retcode
== SQL_SUCCESS_WITH_INFO
))
2454 retcode
= SQLFetch(hstmt
);
2455 if (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
2457 GetData( 3, SQL_C_WXCHAR
, szPkTable
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2458 GetData( 5, SQL_C_SSHORT
, &iKeySeq
, 0, &cb
);
2459 GetData( 8, SQL_C_WXCHAR
, szFkCol
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2461 for (i
=0; i
<noCols
; i
++) // Find the Column name
2463 if (!wxStrcmp(colInf
[i
].colName
,szFkCol
)) // We have found the (Foreign Key) Column
2465 colInf
[i
].FkCol
= iKeySeq
; // Which Foreign Key is this (first, second usw.) ?
2466 wxStrcpy(colInf
[i
].FkTableName
,szPkTable
); // Name of the Table where this Foriegn is the Primary Key
2471 SQLFreeStmt(hstmt
, SQL_CLOSE
); /* Close the cursor (the hstmt is still allocated). */
2475 } // wxDb::GetKeyFields()
2479 /********** wxDb::GetColumns() **********/
2480 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2482 * 1) The last array element of the tableName[] argument must be zero (null).
2483 * This is how the end of the array is detected.
2484 * 2) This function returns an array of wxDbColInf structures. If no columns
2485 * were found, or an error occured, this pointer will be zero (null). THE
2486 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
2487 * IS FINISHED WITH IT. i.e.
2489 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
2492 * // Use the column inf
2494 * // Destroy the memory
2498 * userID is evaluated in the following manner:
2499 * userID == NULL ... UserID is ignored
2500 * userID == "" ... UserID set equal to 'this->uid'
2501 * userID != "" ... UserID set equal to 'userID'
2503 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2504 * by this function. This function should use its own wxDb instance
2505 * to avoid undesired unbinding of columns.
2510 wxDbColInf
*colInf
= 0;
2518 convertUserID(userID
,UserID
);
2520 // Pass 1 - Determine how many columns there are.
2521 // Pass 2 - Allocate the wxDbColInf array and fill in
2522 // the array with the column information.
2524 for (pass
= 1; pass
<= 2; pass
++)
2528 if (noCols
== 0) // Probably a bogus table name(s)
2530 // Allocate n wxDbColInf objects to hold the column information
2531 colInf
= new wxDbColInf
[noCols
+1];
2534 // Mark the end of the array
2535 wxStrcpy(colInf
[noCols
].tableName
,wxEmptyString
);
2536 wxStrcpy(colInf
[noCols
].colName
,wxEmptyString
);
2537 colInf
[noCols
].sqlDataType
= 0;
2539 // Loop through each table name
2541 for (tbl
= 0; tableName
[tbl
]; tbl
++)
2543 TableName
= tableName
[tbl
];
2544 // Oracle and Interbase table names are uppercase only, so force
2545 // the name to uppercase just in case programmer forgot to do this
2546 if ((Dbms() == dbmsORACLE
) ||
2547 (Dbms() == dbmsFIREBIRD
) ||
2548 (Dbms() == dbmsINTERBASE
))
2549 TableName
= TableName
.Upper();
2551 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2553 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2554 // use the call below that leaves out the user name
2555 if (!UserID
.empty() &&
2556 Dbms() != dbmsMY_SQL
&&
2557 Dbms() != dbmsACCESS
&&
2558 Dbms() != dbmsMS_SQL_SERVER
)
2560 retcode
= SQLColumns(hstmt
,
2561 NULL
, 0, // All qualifiers
2562 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2563 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
2564 NULL
, 0); // All columns
2568 retcode
= SQLColumns(hstmt
,
2569 NULL
, 0, // All qualifiers
2571 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
2572 NULL
, 0); // All columns
2574 if (retcode
!= SQL_SUCCESS
)
2575 { // Error occured, abort
2576 DispAllErrors(henv
, hdbc
, hstmt
);
2579 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2583 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2585 if (pass
== 1) // First pass, just add up the number of columns
2587 else // Pass 2; Fill in the array of structures
2589 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2591 // NOTE: Only the ODBC 1.x fields are retrieved
2592 GetData( 1, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2593 GetData( 2, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2594 GetData( 3, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2595 GetData( 4, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2596 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2597 GetData( 6, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2598 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnLength
, 0, &cb
);
2599 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferSize
, 0, &cb
);
2600 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2601 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2602 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2603 GetData(12, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2605 // Determine the wxDb data type that is used to represent the native data type of this data source
2606 colInf
[colNo
].dbDataType
= 0;
2607 if (!wxStricmp(typeInfVarchar
.TypeName
,colInf
[colNo
].typeName
))
2610 // IODBC does not return a correct columnLength, so we set
2611 // columnLength = bufferSize if no column length was returned
2612 // IODBC returns the columnLength in bufferSize. (bug)
2613 if (colInf
[colNo
].columnLength
< 1)
2615 colInf
[colNo
].columnLength
= colInf
[colNo
].bufferSize
;
2618 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2620 else if (!wxStricmp(typeInfInteger
.TypeName
, colInf
[colNo
].typeName
))
2621 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2622 else if (!wxStricmp(typeInfFloat
.TypeName
, colInf
[colNo
].typeName
))
2623 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2624 else if (!wxStricmp(typeInfDate
.TypeName
, colInf
[colNo
].typeName
))
2625 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2626 else if (!wxStricmp(typeInfBlob
.TypeName
, colInf
[colNo
].typeName
))
2627 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_BLOB
;
2632 if (retcode
!= SQL_NO_DATA_FOUND
)
2633 { // Error occured, abort
2634 DispAllErrors(henv
, hdbc
, hstmt
);
2637 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2643 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2646 } // wxDb::GetColumns()
2649 /********** wxDb::GetColumns() **********/
2651 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, UWORD
*numCols
, const wxChar
*userID
)
2653 // Same as the above GetColumns() function except this one gets columns
2654 // only for a single table, and if 'numCols' is not NULL, the number of
2655 // columns stored in the returned wxDbColInf is set in '*numCols'
2657 // userID is evaluated in the following manner:
2658 // userID == NULL ... UserID is ignored
2659 // userID == "" ... UserID set equal to 'this->uid'
2660 // userID != "" ... UserID set equal to 'userID'
2662 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2663 // by this function. This function should use its own wxDb instance
2664 // to avoid undesired unbinding of columns.
2669 wxDbColInf
*colInf
= 0;
2677 convertUserID(userID
,UserID
);
2679 // Pass 1 - Determine how many columns there are.
2680 // Pass 2 - Allocate the wxDbColInf array and fill in
2681 // the array with the column information.
2683 for (pass
= 1; pass
<= 2; pass
++)
2687 if (noCols
== 0) // Probably a bogus table name(s)
2689 // Allocate n wxDbColInf objects to hold the column information
2690 colInf
= new wxDbColInf
[noCols
+1];
2693 // Mark the end of the array
2694 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2695 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2696 colInf
[noCols
].sqlDataType
= 0;
2699 TableName
= tableName
;
2700 // Oracle and Interbase table names are uppercase only, so force
2701 // the name to uppercase just in case programmer forgot to do this
2702 if ((Dbms() == dbmsORACLE
) ||
2703 (Dbms() == dbmsFIREBIRD
) ||
2704 (Dbms() == dbmsINTERBASE
))
2705 TableName
= TableName
.Upper();
2707 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2709 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2710 // use the call below that leaves out the user name
2711 if (!UserID
.empty() &&
2712 Dbms() != dbmsMY_SQL
&&
2713 Dbms() != dbmsACCESS
&&
2714 Dbms() != dbmsMS_SQL_SERVER
)
2716 retcode
= SQLColumns(hstmt
,
2717 NULL
, 0, // All qualifiers
2718 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2719 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
2720 NULL
, 0); // All columns
2724 retcode
= SQLColumns(hstmt
,
2725 NULL
, 0, // All qualifiers
2727 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
2728 NULL
, 0); // All columns
2730 if (retcode
!= SQL_SUCCESS
)
2731 { // Error occured, abort
2732 DispAllErrors(henv
, hdbc
, hstmt
);
2735 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2741 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2743 if (pass
== 1) // First pass, just add up the number of columns
2745 else // Pass 2; Fill in the array of structures
2747 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
2749 // NOTE: Only the ODBC 1.x fields are retrieved
2750 GetData( 1, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
2751 GetData( 2, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
2752 GetData( 3, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
2753 GetData( 4, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
2754 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
2755 GetData( 6, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
2756 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnLength
, 0, &cb
);
2757 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
2758 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferSize
, 0, &cb
);
2759 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
2760 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
2761 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
2762 GetData(12, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
2763 // Start Values for Primary/Foriegn Key (=No)
2764 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2765 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2766 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2767 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
2769 // BJO 20000428 : Virtuoso returns type names with upper cases!
2770 if (Dbms() == dbmsVIRTUOSO
)
2772 wxString s
= colInf
[colNo
].typeName
;
2774 wxStrcmp(colInf
[colNo
].typeName
, s
.c_str());
2777 // Determine the wxDb data type that is used to represent the native data type of this data source
2778 colInf
[colNo
].dbDataType
= 0;
2779 if (!wxStricmp(typeInfVarchar
.TypeName
, colInf
[colNo
].typeName
))
2782 // IODBC does not return a correct columnLength, so we set
2783 // columnLength = bufferSize if no column length was returned
2784 // IODBC returns the columnLength in bufferSize. (bug)
2785 if (colInf
[colNo
].columnLength
< 1)
2787 colInf
[colNo
].columnLength
= colInf
[colNo
].bufferSize
;
2791 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
2793 else if (!wxStricmp(typeInfInteger
.TypeName
, colInf
[colNo
].typeName
))
2794 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
2795 else if (!wxStricmp(typeInfFloat
.TypeName
, colInf
[colNo
].typeName
))
2796 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
2797 else if (!wxStricmp(typeInfDate
.TypeName
, colInf
[colNo
].typeName
))
2798 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
2799 else if (!wxStricmp(typeInfBlob
.TypeName
, colInf
[colNo
].typeName
))
2800 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_BLOB
;
2806 if (retcode
!= SQL_NO_DATA_FOUND
)
2807 { // Error occured, abort
2808 DispAllErrors(henv
, hdbc
, hstmt
);
2811 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2818 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2820 // Store Primary and Foriegn Keys
2821 GetKeyFields(tableName
,colInf
,noCols
);
2827 } // wxDb::GetColumns()
2830 #else // New GetColumns
2835 These are tentative new GetColumns members which should be more database
2836 independant and which always returns the columns in the order they were
2839 - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const
2840 wxChar* userID)) calls the second implementation for each separate table
2841 before merging the results. This makes the code easier to maintain as
2842 only one member (the second) makes the real work
2843 - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const
2844 wxChar *userID) is a little bit improved
2845 - It doesn't anymore rely on the type-name to find out which database-type
2847 - It ends by sorting the columns, so that they are returned in the same
2848 order they were created
2858 wxDbColInf
*wxDb::GetColumns(wxChar
*tableName
[], const wxChar
*userID
)
2861 // The last array element of the tableName[] argument must be zero (null).
2862 // This is how the end of the array is detected.
2866 // How many tables ?
2868 for (tbl
= 0 ; tableName
[tbl
]; tbl
++);
2870 // Create a table to maintain the columns for each separate table
2871 _TableColumns
*TableColumns
= new _TableColumns
[tbl
];
2874 for (i
= 0 ; i
< tbl
; i
++)
2877 TableColumns
[i
].colInf
= GetColumns(tableName
[i
], &TableColumns
[i
].noCols
, userID
);
2878 if (TableColumns
[i
].colInf
== NULL
)
2880 noCols
+= TableColumns
[i
].noCols
;
2883 // Now merge all the separate table infos
2884 wxDbColInf
*colInf
= new wxDbColInf
[noCols
+1];
2886 // Mark the end of the array
2887 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2888 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2889 colInf
[noCols
].sqlDataType
= 0;
2894 for (i
= 0 ; i
< tbl
; i
++)
2896 for (j
= 0 ; j
< TableColumns
[i
].noCols
; j
++)
2898 colInf
[offset
++] = TableColumns
[i
].colInf
[j
];
2902 delete [] TableColumns
;
2905 } // wxDb::GetColumns() -- NEW
2908 wxDbColInf
*wxDb::GetColumns(const wxString
&tableName
, int *numCols
, const wxChar
*userID
)
2910 // Same as the above GetColumns() function except this one gets columns
2911 // only for a single table, and if 'numCols' is not NULL, the number of
2912 // columns stored in the returned wxDbColInf is set in '*numCols'
2914 // userID is evaluated in the following manner:
2915 // userID == NULL ... UserID is ignored
2916 // userID == "" ... UserID set equal to 'this->uid'
2917 // userID != "" ... UserID set equal to 'userID'
2919 // NOTE: ALL column bindings associated with this wxDb instance are unbound
2920 // by this function. This function should use its own wxDb instance
2921 // to avoid undesired unbinding of columns.
2925 wxDbColInf
*colInf
= 0;
2933 convertUserID(userID
,UserID
);
2935 // Pass 1 - Determine how many columns there are.
2936 // Pass 2 - Allocate the wxDbColInf array and fill in
2937 // the array with the column information.
2939 for (pass
= 1; pass
<= 2; pass
++)
2943 if (noCols
== 0) // Probably a bogus table name(s)
2945 // Allocate n wxDbColInf objects to hold the column information
2946 colInf
= new wxDbColInf
[noCols
+1];
2949 // Mark the end of the array
2950 wxStrcpy(colInf
[noCols
].tableName
, wxEmptyString
);
2951 wxStrcpy(colInf
[noCols
].colName
, wxEmptyString
);
2952 colInf
[noCols
].sqlDataType
= 0;
2955 TableName
= tableName
;
2956 // Oracle and Interbase table names are uppercase only, so force
2957 // the name to uppercase just in case programmer forgot to do this
2958 if ((Dbms() == dbmsORACLE
) ||
2959 (Dbms() == dbmsFIREBIRD
) ||
2960 (Dbms() == dbmsINTERBASE
))
2961 TableName
= TableName
.Upper();
2963 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2965 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
2966 // use the call below that leaves out the user name
2967 if (!UserID
.empty() &&
2968 Dbms() != dbmsMY_SQL
&&
2969 Dbms() != dbmsACCESS
&&
2970 Dbms() != dbmsMS_SQL_SERVER
)
2972 retcode
= SQLColumns(hstmt
,
2973 NULL
, 0, // All qualifiers
2974 (UCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
2975 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2976 NULL
, 0); // All columns
2980 retcode
= SQLColumns(hstmt
,
2981 NULL
, 0, // All qualifiers
2983 (UCHAR
*) TableName
.c_str(), SQL_NTS
,
2984 NULL
, 0); // All columns
2986 if (retcode
!= SQL_SUCCESS
)
2987 { // Error occured, abort
2988 DispAllErrors(henv
, hdbc
, hstmt
);
2991 SQLFreeStmt(hstmt
, SQL_CLOSE
);
2997 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
2999 if (pass
== 1) // First pass, just add up the number of columns
3001 else // Pass 2; Fill in the array of structures
3003 if (colNo
< noCols
) // Some extra error checking to prevent memory overwrites
3005 // NOTE: Only the ODBC 1.x fields are retrieved
3006 GetData( 1, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].catalog
, 128+1, &cb
);
3007 GetData( 2, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].schema
, 128+1, &cb
);
3008 GetData( 3, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
3009 GetData( 4, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].colName
, DB_MAX_COLUMN_NAME_LEN
+1, &cb
);
3010 GetData( 5, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].sqlDataType
, 0, &cb
);
3011 GetData( 6, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].typeName
, 128+1, &cb
);
3012 GetData( 7, SQL_C_SLONG
, (UCHAR
*) &colInf
[colNo
].columnLength
, 0, &cb
);
3013 GetData( 8, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].bufferSize
, 0, &cb
);
3014 GetData( 9, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].decimalDigits
,0, &cb
);
3015 GetData(10, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].numPrecRadix
, 0, &cb
);
3016 GetData(11, SQL_C_SSHORT
, (UCHAR
*) &colInf
[colNo
].nullable
, 0, &cb
);
3017 GetData(12, SQL_C_WXCHAR
, (UCHAR
*) colInf
[colNo
].remarks
, 254+1, &cb
);
3018 // Start Values for Primary/Foriegn Key (=No)
3019 colInf
[colNo
].PkCol
= 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
3020 colInf
[colNo
].PkTableName
[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
3021 colInf
[colNo
].FkCol
= 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
3022 colInf
[colNo
].FkTableName
[0] = 0; // Foreign key table name
3025 // IODBC does not return a correct columnLength, so we set
3026 // columnLength = bufferSize if no column length was returned
3027 // IODBC returns the columnLength in bufferSize. (bug)
3028 if (colInf
[colNo
].columnLength
< 1)
3030 colInf
[colNo
].columnLength
= colInf
[colNo
].bufferSize
;
3034 // Determine the wxDb data type that is used to represent the native data type of this data source
3035 colInf
[colNo
].dbDataType
= 0;
3036 // Get the intern datatype
3037 switch (colInf
[colNo
].sqlDataType
)
3041 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_VARCHAR
;
3047 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_INTEGER
;
3054 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_FLOAT
;
3058 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_DATE
;
3061 colInf
[colNo
].dbDataType
= DB_DATA_TYPE_BLOB
;
3066 errMsg
.Printf(wxT("SQL Data type %d currently not supported by wxWidgets"), colInf
[colNo
].sqlDataType
);
3067 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
3074 if (retcode
!= SQL_NO_DATA_FOUND
)
3075 { // Error occured, abort
3076 DispAllErrors(henv
, hdbc
, hstmt
);
3079 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3086 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3088 // Store Primary and Foreign Keys
3089 GetKeyFields(tableName
,colInf
,noCols
);
3091 ///////////////////////////////////////////////////////////////////////////
3092 // Now sort the the columns in order to make them appear in the right order
3093 ///////////////////////////////////////////////////////////////////////////
3095 // Build a generic SELECT statement which returns 0 rows
3098 Stmt
.Printf(wxT("select * from \"%s\" where 0=1"), tableName
);
3101 if (SQLExecDirect(hstmt
, (UCHAR FAR
*) Stmt
.c_str(), SQL_NTS
) != SQL_SUCCESS
)
3103 DispAllErrors(henv
, hdbc
, hstmt
);
3107 // Get the number of result columns
3108 if (SQLNumResultCols (hstmt
, &noCols
) != SQL_SUCCESS
)
3110 DispAllErrors(henv
, hdbc
, hstmt
);
3114 if (noCols
== 0) // Probably a bogus table name
3123 for (colNum
= 0; colNum
< noCols
; colNum
++)
3125 if (SQLColAttributes(hstmt
,colNum
+1, SQL_COLUMN_NAME
,
3127 &Sword
, &Sdword
) != SQL_SUCCESS
)
3129 DispAllErrors(henv
, hdbc
, hstmt
);
3133 wxString Name1
= name
;
3134 Name1
= Name1
.Upper();
3136 // Where is this name in the array ?
3137 for (i
= colNum
; i
< noCols
; i
++)
3139 wxString Name2
= colInf
[i
].colName
;
3140 Name2
= Name2
.Upper();
3143 if (colNum
!= i
) // swap to sort
3145 wxDbColInf tmpColInf
= colInf
[colNum
];
3146 colInf
[colNum
] = colInf
[i
];
3147 colInf
[i
] = tmpColInf
;
3153 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3155 ///////////////////////////////////////////////////////////////////////////
3157 ///////////////////////////////////////////////////////////////////////////
3163 } // wxDb::GetColumns()
3166 #endif // #else OLD_GETCOLUMNS
3169 /********** wxDb::GetColumnCount() **********/
3170 int wxDb::GetColumnCount(const wxString
&tableName
, const wxChar
*userID
)
3172 * Returns a count of how many columns are in a table.
3173 * If an error occurs in computing the number of columns
3174 * this function will return a -1 for the count
3176 * userID is evaluated in the following manner:
3177 * userID == NULL ... UserID is ignored
3178 * userID == "" ... UserID set equal to 'this->uid'
3179 * userID != "" ... UserID set equal to 'userID'
3181 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3182 * by this function. This function should use its own wxDb instance
3183 * to avoid undesired unbinding of columns.
3193 convertUserID(userID
,UserID
);
3195 TableName
= tableName
;
3196 // Oracle and Interbase table names are uppercase only, so force
3197 // the name to uppercase just in case programmer forgot to do this
3198 if ((Dbms() == dbmsORACLE
) ||
3199 (Dbms() == dbmsFIREBIRD
) ||
3200 (Dbms() == dbmsINTERBASE
))
3201 TableName
= TableName
.Upper();
3203 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3205 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
3206 // use the call below that leaves out the user name
3207 if (!UserID
.empty() &&
3208 Dbms() != dbmsMY_SQL
&&
3209 Dbms() != dbmsACCESS
&&
3210 Dbms() != dbmsMS_SQL_SERVER
)
3212 retcode
= SQLColumns(hstmt
,
3213 NULL
, 0, // All qualifiers
3214 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // Owner
3215 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
3216 NULL
, 0); // All columns
3220 retcode
= SQLColumns(hstmt
,
3221 NULL
, 0, // All qualifiers
3223 (SQLTCHAR
*) TableName
.c_str(), SQL_NTS
,
3224 NULL
, 0); // All columns
3226 if (retcode
!= SQL_SUCCESS
)
3227 { // Error occured, abort
3228 DispAllErrors(henv
, hdbc
, hstmt
);
3229 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3233 // Count the columns
3234 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
)
3237 if (retcode
!= SQL_NO_DATA_FOUND
)
3238 { // Error occured, abort
3239 DispAllErrors(henv
, hdbc
, hstmt
);
3240 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3244 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3247 } // wxDb::GetColumnCount()
3250 /********** wxDb::GetCatalog() *******/
3251 wxDbInf
*wxDb::GetCatalog(const wxChar
*userID
)
3253 * ---------------------------------------------------------------------
3254 * -- 19991203 : mj10777 : Create ------
3255 * -- : Creates a wxDbInf with Tables / Cols Array ------
3256 * -- : uses SQLTables and fills pTableInf; ------
3257 * -- : pColInf is set to NULL and numCols to 0; ------
3258 * -- : returns pDbInf (wxDbInf) ------
3259 * -- - if unsuccesfull (pDbInf == NULL) ------
3260 * -- : pColInf can be filled with GetColumns(..); ------
3261 * -- : numCols can be filled with GetColumnCount(..); ------
3262 * ---------------------------------------------------------------------
3264 * userID is evaluated in the following manner:
3265 * userID == NULL ... UserID is ignored
3266 * userID == "" ... UserID set equal to 'this->uid'
3267 * userID != "" ... UserID set equal to 'userID'
3269 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3270 * by this function. This function should use its own wxDb instance
3271 * to avoid undesired unbinding of columns.
3274 int noTab
= 0; // Counter while filling table entries
3278 wxString tblNameSave
;
3281 convertUserID(userID
,UserID
);
3283 //-------------------------------------------------------------
3284 // Create the Database Array of catalog entries
3286 wxDbInf
*pDbInf
= new wxDbInf
;
3288 //-------------------------------------------------------------
3289 // Table Information
3290 // Pass 1 - Determine how many Tables there are.
3291 // Pass 2 - Create the Table array and fill it
3292 // - Create the Cols array = NULL
3293 //-------------------------------------------------------------
3295 for (pass
= 1; pass
<= 2; pass
++)
3297 SQLFreeStmt(hstmt
, SQL_CLOSE
); // Close if Open
3298 tblNameSave
.Empty();
3300 if (!UserID
.empty() &&
3301 Dbms() != dbmsMY_SQL
&&
3302 Dbms() != dbmsACCESS
&&
3303 Dbms() != dbmsMS_SQL_SERVER
)
3305 retcode
= SQLTables(hstmt
,
3306 NULL
, 0, // All qualifiers
3307 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
3308 NULL
, 0, // All tables
3309 NULL
, 0); // All columns
3313 retcode
= SQLTables(hstmt
,
3314 NULL
, 0, // All qualifiers
3315 NULL
, 0, // User specified
3316 NULL
, 0, // All tables
3317 NULL
, 0); // All columns
3320 if (retcode
!= SQL_SUCCESS
)
3322 DispAllErrors(henv
, hdbc
, hstmt
);
3324 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3328 while ((retcode
= SQLFetch(hstmt
)) == SQL_SUCCESS
) // Table Information
3330 if (pass
== 1) // First pass, just count the Tables
3332 if (pDbInf
->numTables
== 0)
3334 GetData( 1, SQL_C_WXCHAR
, (UCHAR
*) pDbInf
->catalog
, 128+1, &cb
);
3335 GetData( 2, SQL_C_WXCHAR
, (UCHAR
*) pDbInf
->schema
, 128+1, &cb
);
3337 pDbInf
->numTables
++; // Counter for Tables
3339 if (pass
== 2) // Create and fill the Table entries
3341 if (pDbInf
->pTableInf
== NULL
) // Has the Table Array been created
3342 { // no, then create the Array
3343 pDbInf
->pTableInf
= new wxDbTableInf
[pDbInf
->numTables
];
3345 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
3347 GetData( 3, SQL_C_WXCHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
3348 GetData( 4, SQL_C_WXCHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableType
, 30+1, &cb
);
3349 GetData( 5, SQL_C_WXCHAR
, (UCHAR
*) (pDbInf
->pTableInf
+noTab
)->tableRemarks
, 254+1, &cb
);
3355 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3357 // Query how many columns are in each table
3358 for (noTab
=0;noTab
<pDbInf
->numTables
;noTab
++)
3360 (pDbInf
->pTableInf
+noTab
)->numCols
= (UWORD
)GetColumnCount((pDbInf
->pTableInf
+noTab
)->tableName
,UserID
);
3365 } // wxDb::GetCatalog()
3368 /********** wxDb::Catalog() **********/
3369 bool wxDb::Catalog(const wxChar
*userID
, const wxString
&fileName
)
3371 * Creates the text file specified in 'filename' which will contain
3372 * a minimal data dictionary of all tables accessible by the user specified
3375 * userID is evaluated in the following manner:
3376 * userID == NULL ... UserID is ignored
3377 * userID == "" ... UserID set equal to 'this->uid'
3378 * userID != "" ... UserID set equal to 'userID'
3380 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3381 * by this function. This function should use its own wxDb instance
3382 * to avoid undesired unbinding of columns.
3385 wxASSERT(fileName
.Length());
3389 wxChar tblName
[DB_MAX_TABLE_NAME_LEN
+1];
3390 wxString tblNameSave
;
3391 wxChar colName
[DB_MAX_COLUMN_NAME_LEN
+1];
3393 wxChar typeName
[30+1];
3394 SDWORD precision
, length
;
3396 FILE *fp
= wxFopen(fileName
.fn_str(),wxT("wt"));
3400 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3403 convertUserID(userID
,UserID
);
3405 if (!UserID
.empty() &&
3406 Dbms() != dbmsMY_SQL
&&
3407 Dbms() != dbmsACCESS
&&
3408 Dbms() != dbmsFIREBIRD
&&
3409 Dbms() != dbmsINTERBASE
&&
3410 Dbms() != dbmsMS_SQL_SERVER
)
3412 retcode
= SQLColumns(hstmt
,
3413 NULL
, 0, // All qualifiers
3414 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // User specified
3415 NULL
, 0, // All tables
3416 NULL
, 0); // All columns
3420 retcode
= SQLColumns(hstmt
,
3421 NULL
, 0, // All qualifiers
3422 NULL
, 0, // User specified
3423 NULL
, 0, // All tables
3424 NULL
, 0); // All columns
3426 if (retcode
!= SQL_SUCCESS
)
3428 DispAllErrors(henv
, hdbc
, hstmt
);
3434 tblNameSave
.Empty();
3439 retcode
= SQLFetch(hstmt
);
3440 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
3443 GetData(3,SQL_C_WXCHAR
, (UCHAR
*) tblName
, DB_MAX_TABLE_NAME_LEN
+1, &cb
);
3444 GetData(4,SQL_C_WXCHAR
, (UCHAR
*) colName
, DB_MAX_COLUMN_NAME_LEN
+1,&cb
);
3445 GetData(5,SQL_C_SSHORT
, (UCHAR
*)&sqlDataType
, 0, &cb
);
3446 GetData(6,SQL_C_WXCHAR
, (UCHAR
*) typeName
, sizeof(typeName
), &cb
);
3447 GetData(7,SQL_C_SLONG
, (UCHAR
*)&precision
, 0, &cb
);
3448 GetData(8,SQL_C_SLONG
, (UCHAR
*)&length
, 0, &cb
);
3450 if (wxStrcmp(tblName
, tblNameSave
.c_str()))
3453 wxFputs(wxT("\n"), fp
);
3454 wxFputs(wxT("================================ "), fp
);
3455 wxFputs(wxT("================================ "), fp
);
3456 wxFputs(wxT("===================== "), fp
);
3457 wxFputs(wxT("========= "), fp
);
3458 wxFputs(wxT("=========\n"), fp
);
3459 outStr
.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
3460 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
3461 wxFputs(outStr
.c_str(), fp
);
3462 wxFputs(wxT("================================ "), fp
);
3463 wxFputs(wxT("================================ "), fp
);
3464 wxFputs(wxT("===================== "), fp
);
3465 wxFputs(wxT("========= "), fp
);
3466 wxFputs(wxT("=========\n"), fp
);
3467 tblNameSave
= tblName
;
3470 outStr
.Printf(wxT("%-32s %-32s (%04d)%-15s %9ld %9ld\n"),
3471 tblName
, colName
, sqlDataType
, typeName
, precision
, length
);
3472 if (wxFputs(outStr
.c_str(), fp
) == EOF
)
3474 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3481 if (retcode
!= SQL_NO_DATA_FOUND
)
3482 DispAllErrors(henv
, hdbc
, hstmt
);
3484 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3487 return(retcode
== SQL_NO_DATA_FOUND
);
3489 } // wxDb::Catalog()
3492 bool wxDb::TableExists(const wxString
&tableName
, const wxChar
*userID
, const wxString
&tablePath
)
3494 * Table name can refer to a table, view, alias or synonym. Returns true
3495 * if the object exists in the database. This function does not indicate
3496 * whether or not the user has privleges to query or perform other functions
3499 * userID is evaluated in the following manner:
3500 * userID == NULL ... UserID is ignored
3501 * userID == "" ... UserID set equal to 'this->uid'
3502 * userID != "" ... UserID set equal to 'userID'
3505 wxASSERT(tableName
.Length());
3509 if (Dbms() == dbmsDBASE
)
3512 if (tablePath
.Length())
3513 dbName
.Printf(wxT("%s/%s.dbf"), tablePath
.c_str(), tableName
.c_str());
3515 dbName
.Printf(wxT("%s.dbf"), tableName
.c_str());
3518 exists
= wxFileExists(dbName
);
3523 convertUserID(userID
,UserID
);
3525 TableName
= tableName
;
3526 // Oracle and Interbase table names are uppercase only, so force
3527 // the name to uppercase just in case programmer forgot to do this
3528 if ((Dbms() == dbmsORACLE
) ||
3529 (Dbms() == dbmsFIREBIRD
) ||
3530 (Dbms() == dbmsINTERBASE
))
3531 TableName
= TableName
.Upper();
3533 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3536 // Some databases cannot accept a user name when looking up table names,
3537 // so we use the call below that leaves out the user name
3538 if (!UserID
.empty() &&
3539 Dbms() != dbmsMY_SQL
&&
3540 Dbms() != dbmsACCESS
&&
3541 Dbms() != dbmsMS_SQL_SERVER
&&
3542 Dbms() != dbmsDB2
&&
3543 Dbms() != dbmsFIREBIRD
&&
3544 Dbms() != dbmsINTERBASE
&&
3545 Dbms() != dbmsPERVASIVE_SQL
)
3547 retcode
= SQLTables(hstmt
,
3548 NULL
, 0, // All qualifiers
3549 (SQLTCHAR
*) UserID
.c_str(), SQL_NTS
, // Only tables owned by this user
3550 (SQLTCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3551 NULL
, 0); // All table types
3555 retcode
= SQLTables(hstmt
,
3556 NULL
, 0, // All qualifiers
3557 NULL
, 0, // All owners
3558 (SQLTCHAR FAR
*)TableName
.c_str(), SQL_NTS
,
3559 NULL
, 0); // All table types
3561 if (retcode
!= SQL_SUCCESS
)
3562 return(DispAllErrors(henv
, hdbc
, hstmt
));
3564 retcode
= SQLFetch(hstmt
);
3565 if (retcode
!= SQL_SUCCESS
&& retcode
!= SQL_SUCCESS_WITH_INFO
)
3567 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3568 return(DispAllErrors(henv
, hdbc
, hstmt
));
3571 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3575 } // wxDb::TableExists()
3578 /********** wxDb::TablePrivileges() **********/
3579 bool wxDb::TablePrivileges(const wxString
&tableName
, const wxString
&priv
, const wxChar
*userID
,
3580 const wxChar
*schema
, const wxString
&WXUNUSED(tablePath
))
3582 wxASSERT(tableName
.Length());
3584 wxDbTablePrivilegeInfo result
;
3588 // We probably need to be able to dynamically set this based on
3589 // the driver type, and state.
3590 wxChar curRole
[]=wxT("public");
3594 wxString UserID
,Schema
;
3595 convertUserID(userID
,UserID
);
3596 convertUserID(schema
,Schema
);
3598 TableName
= tableName
;
3599 // Oracle and Interbase table names are uppercase only, so force
3600 // the name to uppercase just in case programmer forgot to do this
3601 if ((Dbms() == dbmsORACLE
) ||
3602 (Dbms() == dbmsFIREBIRD
) ||
3603 (Dbms() == dbmsINTERBASE
))
3604 TableName
= TableName
.Upper();
3606 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3608 // Some databases cannot accept a user name when looking up table names,
3609 // so we use the call below that leaves out the user name
3610 if (!Schema
.empty() &&
3611 Dbms() != dbmsMY_SQL
&&
3612 Dbms() != dbmsACCESS
&&
3613 Dbms() != dbmsMS_SQL_SERVER
)
3615 retcode
= SQLTablePrivileges(hstmt
,
3617 (SQLTCHAR FAR
*)Schema
.c_str(), SQL_NTS
, // Schema
3618 (SQLTCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3622 retcode
= SQLTablePrivileges(hstmt
,
3625 (SQLTCHAR FAR
*)TableName
.c_str(), SQL_NTS
);
3628 #ifdef DBDEBUG_CONSOLE
3629 wxFprintf(stderr
,wxT("SQLTablePrivileges() returned %i \n"),retcode
);
3632 if ((retcode
!= SQL_SUCCESS
) && (retcode
!= SQL_SUCCESS_WITH_INFO
))
3633 return (DispAllErrors(henv
, hdbc
, hstmt
));
3635 bool failed
= false;
3636 retcode
= SQLFetch(hstmt
);
3637 while (retcode
== SQL_SUCCESS
|| retcode
== SQL_SUCCESS_WITH_INFO
)
3639 if (SQLGetData(hstmt
, 1, SQL_C_WXCHAR
, (UCHAR
*) result
.tableQual
, sizeof(result
.tableQual
), &cbRetVal
) != SQL_SUCCESS
)
3642 if (!failed
&& SQLGetData(hstmt
, 2, SQL_C_WXCHAR
, (UCHAR
*) result
.tableOwner
, sizeof(result
.tableOwner
), &cbRetVal
) != SQL_SUCCESS
)
3645 if (!failed
&& SQLGetData(hstmt
, 3, SQL_C_WXCHAR
, (UCHAR
*) result
.tableName
, sizeof(result
.tableName
), &cbRetVal
) != SQL_SUCCESS
)
3648 if (!failed
&& SQLGetData(hstmt
, 4, SQL_C_WXCHAR
, (UCHAR
*) result
.grantor
, sizeof(result
.grantor
), &cbRetVal
) != SQL_SUCCESS
)
3651 if (!failed
&& SQLGetData(hstmt
, 5, SQL_C_WXCHAR
, (UCHAR
*) result
.grantee
, sizeof(result
.grantee
), &cbRetVal
) != SQL_SUCCESS
)
3654 if (!failed
&& SQLGetData(hstmt
, 6, SQL_C_WXCHAR
, (UCHAR
*) result
.privilege
, sizeof(result
.privilege
), &cbRetVal
) != SQL_SUCCESS
)
3657 if (!failed
&& SQLGetData(hstmt
, 7, SQL_C_WXCHAR
, (UCHAR
*) result
.grantable
, sizeof(result
.grantable
), &cbRetVal
) != SQL_SUCCESS
)
3662 return(DispAllErrors(henv
, hdbc
, hstmt
));
3664 #ifdef DBDEBUG_CONSOLE
3665 wxFprintf(stderr
,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
3666 result
.privilege
,result
.tableOwner
,result
.tableName
,
3667 result
.grantor
, result
.grantee
);
3670 if (UserID
.IsSameAs(result
.tableOwner
,false))
3672 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3676 if (UserID
.IsSameAs(result
.grantee
,false) &&
3677 !wxStrcmp(result
.privilege
,priv
))
3679 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3683 if (!wxStrcmp(result
.grantee
,curRole
) &&
3684 !wxStrcmp(result
.privilege
,priv
))
3686 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3690 retcode
= SQLFetch(hstmt
);
3693 SQLFreeStmt(hstmt
, SQL_CLOSE
);
3696 } // wxDb::TablePrivileges
3699 const wxString
wxDb::SQLTableName(const wxChar
*tableName
)
3703 if (Dbms() == dbmsACCESS
)
3704 TableName
= _T("\"");
3705 TableName
+= tableName
;
3706 if (Dbms() == dbmsACCESS
)
3707 TableName
+= _T("\"");
3710 } // wxDb::SQLTableName()
3713 const wxString
wxDb::SQLColumnName(const wxChar
*colName
)
3717 if (Dbms() == dbmsACCESS
)
3720 if (Dbms() == dbmsACCESS
)
3721 ColName
+= _T("\"");
3724 } // wxDb::SQLColumnName()
3727 /********** wxDb::SetSqlLogging() **********/
3728 bool wxDb::SetSqlLogging(wxDbSqlLogState state
, const wxString
&filename
, bool append
)
3730 wxASSERT(state
== sqlLogON
|| state
== sqlLogOFF
);
3731 wxASSERT(state
== sqlLogOFF
|| filename
.Length());
3733 if (state
== sqlLogON
)
3737 fpSqlLog
= wxFopen(filename
.fn_str(), (append
? wxT("at") : wxT("wt")));
3738 if (fpSqlLog
== NULL
)
3746 if (fclose(fpSqlLog
))
3752 sqlLogState
= state
;
3755 } // wxDb::SetSqlLogging()
3758 /********** wxDb::WriteSqlLog() **********/
3759 bool wxDb::WriteSqlLog(const wxString
&logMsg
)
3761 wxASSERT(logMsg
.Length());
3763 if (fpSqlLog
== 0 || sqlLogState
== sqlLogOFF
)
3766 if (wxFputs(wxT("\n"), fpSqlLog
) == EOF
)
3768 if (wxFputs(logMsg
, fpSqlLog
) == EOF
)
3770 if (wxFputs(wxT("\n"), fpSqlLog
) == EOF
)
3775 } // wxDb::WriteSqlLog()
3778 /********** wxDb::Dbms() **********/
3779 wxDBMS
wxDb::Dbms(void)
3781 * Be aware that not all database engines use the exact same syntax, and not
3782 * every ODBC compliant database is compliant to the same level of compliancy.
3783 * Some manufacturers support the minimum Level 1 compliancy, and others up
3784 * through Level 3. Others support subsets of features for levels above 1.
3786 * If you find an inconsistency between the wxDb class and a specific database
3787 * engine, and an identifier to this section, and special handle the database in
3788 * the area where behavior is non-conforming with the other databases.
3791 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3792 * ---------------------------------------------------
3795 * - Currently the only database supported by the class to support VIEWS
3798 * - Does not support the SQL_TIMESTAMP structure
3799 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
3800 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
3801 * is true. The user must create ALL indexes from their program.
3802 * - Table names can only be 8 characters long
3803 * - Column names can only be 10 characters long
3806 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3807 * after every table name involved in the query/join if that tables matching record(s)
3809 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
3811 * SYBASE (Enterprise)
3812 * - If a column is part of the Primary Key, the column cannot be NULL
3813 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
3816 * - If a column is part of the Primary Key, the column cannot be NULL
3817 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3818 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3819 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3820 * column definition if it is not defined correctly, but it is experimental
3821 * - Does not support sub-queries in SQL statements
3824 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3825 * - Does not support sub-queries in SQL statements
3828 * - Primary keys must be declared as NOT NULL
3829 * - Table and index names must not be longer than 13 characters in length (technically
3830 * table names can be up to 18 characters, but the primary index is created using the
3831 * base table name plus "_PIDX", so the limit if the table has a primary index is 13.
3836 * - Columns that are part of primary keys must be defined as being NOT NULL
3837 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3838 * column definition if it is not defined correctly, but it is experimental
3841 // Should only need to do this once for each new database connection
3842 // so return the value we already determined it to be to save time
3843 // and lots of string comparisons
3844 if (dbmsType
!= dbmsUNIDENTIFIED
)
3847 #ifdef DBDEBUG_CONSOLE
3848 // When run in console mode, use standard out to display errors.
3849 cout
<< "Database connecting to: " << dbInf
.dbmsName
<< endl
;
3850 #endif // DBDEBUG_CONSOLE
3852 wxLogDebug(wxT("Database connecting to: "));
3853 wxLogDebug(dbInf
.dbmsName
);
3855 wxChar baseName
[25+1];
3856 wxStrncpy(baseName
, dbInf
.dbmsName
, 25);
3859 // RGG 20001025 : add support for Interbase
3860 // GT : Integrated to base classes on 20001121
3861 if (!wxStricmp(dbInf
.dbmsName
,wxT("Interbase")))
3862 return((wxDBMS
)(dbmsType
= dbmsINTERBASE
));
3864 // BJO 20000428 : add support for Virtuoso
3865 if (!wxStricmp(dbInf
.dbmsName
,wxT("OpenLink Virtuoso VDBMS")))
3866 return((wxDBMS
)(dbmsType
= dbmsVIRTUOSO
));
3868 if (!wxStricmp(dbInf
.dbmsName
,wxT("Adaptive Server Anywhere")))
3869 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASA
));
3871 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3872 // connected through an OpenLink driver.
3873 // Is it also returned by Sybase Adapatitve server?
3874 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
3875 if (!wxStricmp(dbInf
.dbmsName
,wxT("SQL Server")))
3877 if (!wxStrncmp(dbInf
.driverName
, wxT("oplodbc"), 7) ||
3878 !wxStrncmp(dbInf
.driverName
, wxT("OLOD"), 4))
3879 return ((wxDBMS
)(dbmsMS_SQL_SERVER
));
3881 return ((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3884 if (!wxStricmp(dbInf
.dbmsName
,wxT("Microsoft SQL Server")))
3885 return((wxDBMS
)(dbmsType
= dbmsMS_SQL_SERVER
));
3888 if (!wxStricmp(baseName
,wxT("PostgreSQL"))) // v6.5.0
3889 return((wxDBMS
)(dbmsType
= dbmsPOSTGRES
));
3892 if (!wxStricmp(baseName
,wxT("Pervasive")))
3893 return((wxDBMS
)(dbmsType
= dbmsPERVASIVE_SQL
));
3896 if (!wxStricmp(baseName
,wxT("Informix")))
3897 return((wxDBMS
)(dbmsType
= dbmsINFORMIX
));
3899 if (!wxStricmp(baseName
,wxT("Firebird")))
3900 return((wxDBMS
)(dbmsType
= dbmsFIREBIRD
));
3903 if (!wxStricmp(baseName
,wxT("Oracle")))
3904 return((wxDBMS
)(dbmsType
= dbmsORACLE
));
3905 if (!wxStricmp(baseName
,wxT("ACCESS")))
3906 return((wxDBMS
)(dbmsType
= dbmsACCESS
));
3907 if (!wxStricmp(baseName
,wxT("Sybase")))
3908 return((wxDBMS
)(dbmsType
= dbmsSYBASE_ASE
));
3911 if (!wxStricmp(baseName
,wxT("DBASE")))
3912 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3913 if (!wxStricmp(baseName
,wxT("xBase")))
3914 return((wxDBMS
)(dbmsType
= dbmsXBASE_SEQUITER
));
3915 if (!wxStricmp(baseName
,wxT("MySQL")))
3916 return((wxDBMS
)(dbmsType
= dbmsMY_SQL
));
3919 if (!wxStricmp(baseName
,wxT("DB2")))
3920 return((wxDBMS
)(dbmsType
= dbmsDBASE
));
3922 return((wxDBMS
)(dbmsType
= dbmsUNIDENTIFIED
));
3927 bool wxDb::ModifyColumn(const wxString
&tableName
, const wxString
&columnName
,
3928 int dataType
, ULONG columnLength
,
3929 const wxString
&optionalParam
)
3931 wxASSERT(tableName
.Length());
3932 wxASSERT(columnName
.Length());
3933 wxASSERT((dataType
== DB_DATA_TYPE_VARCHAR
&& columnLength
> 0) ||
3934 dataType
!= DB_DATA_TYPE_VARCHAR
);
3936 // Must specify a columnLength if modifying a VARCHAR type column
3937 if (dataType
== DB_DATA_TYPE_VARCHAR
&& !columnLength
)
3940 wxString dataTypeName
;
3942 wxString alterSlashModify
;
3946 case DB_DATA_TYPE_VARCHAR
:
3947 dataTypeName
= typeInfVarchar
.TypeName
;
3949 case DB_DATA_TYPE_INTEGER
:
3950 dataTypeName
= typeInfInteger
.TypeName
;
3952 case DB_DATA_TYPE_FLOAT
:
3953 dataTypeName
= typeInfFloat
.TypeName
;
3955 case DB_DATA_TYPE_DATE
:
3956 dataTypeName
= typeInfDate
.TypeName
;
3958 case DB_DATA_TYPE_BLOB
:
3959 dataTypeName
= typeInfBlob
.TypeName
;
3965 // Set the modify or alter syntax depending on the type of database connected to
3969 alterSlashModify
= _T("MODIFY");
3971 case dbmsMS_SQL_SERVER
:
3972 alterSlashModify
= _T("ALTER COLUMN");
3974 case dbmsUNIDENTIFIED
:
3976 case dbmsSYBASE_ASA
:
3977 case dbmsSYBASE_ASE
:
3982 case dbmsXBASE_SEQUITER
:
3984 alterSlashModify
= _T("MODIFY");
3988 // create the SQL statement
3989 if ( Dbms() == dbmsMY_SQL
)
3991 sqlStmt
.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName
.c_str(), alterSlashModify
.c_str(),
3992 columnName
.c_str(), dataTypeName
.c_str());
3996 sqlStmt
.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName
.c_str(), alterSlashModify
.c_str(),
3997 columnName
.c_str(), dataTypeName
.c_str());
4000 // For varchars only, append the size of the column
4001 if (dataType
== DB_DATA_TYPE_VARCHAR
&&
4002 (Dbms() != dbmsMY_SQL
|| dataTypeName
!= _T("text")))
4005 s
.Printf(wxT("(%lu)"), columnLength
);
4009 // for passing things like "NOT NULL"
4010 if (optionalParam
.Length())
4012 sqlStmt
+= wxT(" ");
4013 sqlStmt
+= optionalParam
;
4016 return ExecSql(sqlStmt
);
4018 } // wxDb::ModifyColumn()
4021 /********** wxDbGetConnection() **********/
4022 wxDb WXDLLIMPEXP_ODBC
*wxDbGetConnection(wxDbConnectInf
*pDbConfig
, bool FwdOnlyCursors
)
4026 // Used to keep a pointer to a DB connection that matches the requested
4027 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
4028 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
4029 // rather than having to re-query the datasource to get all the values
4030 // using the wxDb::Open(Dsn,Uid,AuthStr) function
4031 wxDb
*matchingDbConnection
= NULL
;
4033 // Scan the linked list searching for an available database connection
4034 // that's already been opened but is currently not in use.
4035 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
4037 // The database connection must be for the same datasource
4038 // name and must currently not be in use.
4040 (pList
->PtrDb
->FwdOnlyCursors() == FwdOnlyCursors
))
4042 if (pDbConfig
->UseConnectionStr())
4044 if (pList
->PtrDb
->OpenedWithConnectionString() &&
4045 (!wxStrcmp(pDbConfig
->GetConnectionStr(), pList
->ConnectionStr
)))
4047 // Found a free connection
4048 pList
->Free
= false;
4049 return(pList
->PtrDb
);
4054 if (!pList
->PtrDb
->OpenedWithConnectionString() &&
4055 (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
)))
4057 // Found a free connection
4058 pList
->Free
= false;
4059 return(pList
->PtrDb
);
4064 if (pDbConfig
->UseConnectionStr())
4066 if (!wxStrcmp(pDbConfig
->GetConnectionStr(), pList
->ConnectionStr
))
4067 matchingDbConnection
= pList
->PtrDb
;
4071 if (!wxStrcmp(pDbConfig
->GetDsn(), pList
->Dsn
) &&
4072 !wxStrcmp(pDbConfig
->GetUserID(), pList
->Uid
) &&
4073 !wxStrcmp(pDbConfig
->GetPassword(), pList
->AuthStr
))
4074 matchingDbConnection
= pList
->PtrDb
;
4078 // No available connections. A new connection must be made and
4079 // appended to the end of the linked list.
4082 // Find the end of the list
4083 for (pList
= PtrBegDbList
; pList
->PtrNext
; pList
= pList
->PtrNext
);
4084 // Append a new list item
4085 pList
->PtrNext
= new wxDbList
;
4086 pList
->PtrNext
->PtrPrev
= pList
;
4087 pList
= pList
->PtrNext
;
4091 // Create the first node on the list
4092 pList
= PtrBegDbList
= new wxDbList
;
4096 // Initialize new node in the linked list
4098 pList
->Free
= false;
4099 pList
->Dsn
= pDbConfig
->GetDsn();
4100 pList
->Uid
= pDbConfig
->GetUserID();
4101 pList
->AuthStr
= pDbConfig
->GetPassword();
4102 pList
->ConnectionStr
= pDbConfig
->GetConnectionStr();
4104 pList
->PtrDb
= new wxDb(pDbConfig
->GetHenv(), FwdOnlyCursors
);
4108 if (!matchingDbConnection
)
4110 if (pDbConfig
->UseConnectionStr())
4112 opened
= pList
->PtrDb
->Open(pDbConfig
->GetConnectionStr());
4116 opened
= pList
->PtrDb
->Open(pDbConfig
->GetDsn(), pDbConfig
->GetUserID(), pDbConfig
->GetPassword());
4120 opened
= pList
->PtrDb
->Open(matchingDbConnection
);
4122 // Connect to the datasource
4125 pList
->PtrDb
->setCached(true); // Prevent a user from deleting a cached connection
4126 pList
->PtrDb
->SetSqlLogging(SQLLOGstate
, SQLLOGfn
, true);
4127 return(pList
->PtrDb
);
4129 else // Unable to connect, destroy list item
4132 pList
->PtrPrev
->PtrNext
= 0;
4134 PtrBegDbList
= 0; // Empty list again
4136 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
4137 pList
->PtrDb
->Close(); // Close the wxDb object
4138 delete pList
->PtrDb
; // Deletes the wxDb object
4139 delete pList
; // Deletes the linked list object
4143 } // wxDbGetConnection()
4146 /********** wxDbFreeConnection() **********/
4147 bool WXDLLIMPEXP_ODBC
wxDbFreeConnection(wxDb
*pDb
)
4151 // Scan the linked list searching for the database connection
4152 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
4154 if (pList
->PtrDb
== pDb
) // Found it, now free it!!!
4155 return (pList
->Free
= true);
4158 // Never found the database object, return failure
4161 } // wxDbFreeConnection()
4164 /********** wxDbCloseConnections() **********/
4165 void WXDLLIMPEXP_ODBC
wxDbCloseConnections(void)
4167 wxDbList
*pList
, *pNext
;
4169 // Traverse the linked list closing database connections and freeing memory as I go.
4170 for (pList
= PtrBegDbList
; pList
; pList
= pNext
)
4172 pNext
= pList
->PtrNext
; // Save the pointer to next
4173 pList
->PtrDb
->CommitTrans(); // Commit any open transactions on wxDb object
4174 pList
->PtrDb
->Close(); // Close the wxDb object
4175 pList
->PtrDb
->setCached(false); // Allows deletion of the wxDb instance
4176 delete pList
->PtrDb
; // Deletes the wxDb object
4177 delete pList
; // Deletes the linked list object
4180 // Mark the list as empty
4183 } // wxDbCloseConnections()
4186 /********** wxDbConnectionsInUse() **********/
4187 int WXDLLIMPEXP_ODBC
wxDbConnectionsInUse(void)
4192 // Scan the linked list counting db connections that are currently in use
4193 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
4195 if (pList
->Free
== false)
4201 } // wxDbConnectionsInUse()
4205 /********** wxDbLogExtendedErrorMsg() **********/
4206 // DEBUG ONLY function
4207 const wxChar WXDLLIMPEXP_ODBC
*wxDbLogExtendedErrorMsg(const wxChar
*userText
,
4209 const wxChar
*ErrFile
,
4212 static wxString msg
;
4217 if (ErrFile
|| ErrLine
)
4219 msg
+= wxT("File: ");
4221 msg
+= wxT(" Line: ");
4222 tStr
.Printf(wxT("%d"),ErrLine
);
4223 msg
+= tStr
.c_str();
4227 msg
.Append (wxT("\nODBC errors:\n"));
4230 // Display errors for this connection
4232 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
4234 if (pDb
->errorList
[i
])
4236 msg
.Append(pDb
->errorList
[i
]);
4237 if (wxStrcmp(pDb
->errorList
[i
],wxT("")) != 0)
4238 msg
.Append(wxT("\n"));
4239 // Clear the errmsg buffer so the next error will not
4240 // end up showing the previous error that have occurred
4241 wxStrcpy(pDb
->errorList
[i
],wxT(""));
4246 wxLogDebug(msg
.c_str());
4249 } // wxDbLogExtendedErrorMsg()
4252 /********** wxDbSqlLog() **********/
4253 bool wxDbSqlLog(wxDbSqlLogState state
, const wxChar
*filename
)
4255 bool append
= false;
4258 for (pList
= PtrBegDbList
; pList
; pList
= pList
->PtrNext
)
4260 if (!pList
->PtrDb
->SetSqlLogging(state
,filename
,append
))
4265 SQLLOGstate
= state
;
4266 SQLLOGfn
= filename
;
4274 /********** wxDbCreateDataSource() **********/
4275 int wxDbCreateDataSource(const wxString
&driverName
, const wxString
&dsn
, const wxString
&description
,
4276 bool sysDSN
, const wxString
&defDir
, wxWindow
*parent
)
4278 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
4279 * Very rudimentary creation of an ODBC data source.
4281 * ODBC driver must be ODBC 3.0 compliant to use this function
4286 //!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
4292 dsnLocation
= ODBC_ADD_SYS_DSN
;
4294 dsnLocation
= ODBC_ADD_DSN
;
4296 // NOTE: The decimal 2 is an invalid character in all keyword pairs
4297 // so that is why I used it, as wxString does not deal well with
4298 // embedded nulls in strings
4299 setupStr
.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn
,2,description
,2,defDir
,2);
4301 // Replace the separator from above with the '\0' seperator needed
4302 // by the SQLConfigDataSource() function
4306 k
= setupStr
.Find((wxChar
)2,true);
4307 if (k
!= wxNOT_FOUND
)
4308 setupStr
[(UINT
)k
] = wxT('\0');
4310 while (k
!= wxNOT_FOUND
);
4312 result
= SQLConfigDataSource((HWND
)parent
->GetHWND(), dsnLocation
,
4313 driverName
, setupStr
.c_str());
4315 if ((result
!= SQL_SUCCESS
) && (result
!= SQL_SUCCESS_WITH_INFO
))
4317 // check for errors caused by ConfigDSN based functions
4320 wxChar errMsg
[SQL_MAX_MESSAGE_LENGTH
];
4321 errMsg
[0] = wxT('\0');
4323 // This function is only supported in ODBC drivers v3.0 compliant and above
4324 SQLInstallerError(1,&retcode
,errMsg
,SQL_MAX_MESSAGE_LENGTH
-1,&cb
);
4327 #ifdef DBDEBUG_CONSOLE
4328 // When run in console mode, use standard out to display errors.
4329 cout
<< errMsg
<< endl
;
4330 cout
<< wxT("Press any key to continue...") << endl
;
4332 #endif // DBDEBUG_CONSOLE
4335 wxLogDebug(errMsg
,wxT("ODBC DEBUG MESSAGE"));
4336 #endif // __WXDEBUG__
4342 // Using iODBC/unixODBC or some other compiler which does not support the APIs
4343 // necessary to use this function, so this function is not supported
4345 wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
4348 #endif // __VISUALC__
4352 } // wxDbCreateDataSource()
4356 /********** wxDbGetDataSource() **********/
4357 bool wxDbGetDataSource(HENV henv
, wxChar
*Dsn
, SWORD DsnMaxLength
, wxChar
*DsDesc
,
4358 SWORD DsDescMaxLength
, UWORD direction
)
4360 * Dsn and DsDesc will contain the data source name and data source
4361 * description upon return
4365 SWORD lengthDsn
= (SWORD
)(DsnMaxLength
*sizeof(wxChar
));
4366 SWORD lengthDsDesc
= (SWORD
)(DsDescMaxLength
*sizeof(wxChar
));
4368 if (SQLDataSources(henv
, direction
, (SQLTCHAR FAR
*) Dsn
, lengthDsn
, &cb1
,
4369 (SQLTCHAR FAR
*) DsDesc
, lengthDsDesc
, &cb2
) == SQL_SUCCESS
)
4374 } // wxDbGetDataSource()
4377 // Change this to 0 to remove use of all deprecated functions
4378 #if wxODBC_BACKWARD_COMPATABILITY
4379 /********************************************************************
4380 ********************************************************************
4382 * The following functions are all DEPRECATED and are included for
4383 * backward compatability reasons only
4385 ********************************************************************
4386 ********************************************************************/
4387 bool SqlLog(sqlLog state
, const wxChar
*filename
)
4389 return wxDbSqlLog((enum wxDbSqlLogState
)state
, filename
);
4391 /***** DEPRECATED: use wxGetDataSource() *****/
4392 bool GetDataSource(HENV henv
, char *Dsn
, SWORD DsnMax
, char *DsDesc
, SWORD DsDescMax
,
4395 return wxDbGetDataSource(henv
, Dsn
, DsnMax
, DsDesc
, DsDescMax
, direction
);
4397 /***** DEPRECATED: use wxDbGetConnection() *****/
4398 wxDb WXDLLIMPEXP_ODBC
*GetDbConnection(DbStuff
*pDbStuff
, bool FwdOnlyCursors
)
4400 return wxDbGetConnection((wxDbConnectInf
*)pDbStuff
, FwdOnlyCursors
);
4402 /***** DEPRECATED: use wxDbFreeConnection() *****/
4403 bool WXDLLIMPEXP_ODBC
FreeDbConnection(wxDb
*pDb
)
4405 return wxDbFreeConnection(pDb
);
4407 /***** DEPRECATED: use wxDbCloseConnections() *****/
4408 void WXDLLIMPEXP_ODBC
CloseDbConnections(void)
4410 wxDbCloseConnections();
4412 /***** DEPRECATED: use wxDbConnectionsInUse() *****/
4413 int WXDLLIMPEXP_ODBC
NumberDbConnectionsInUse(void)
4415 return wxDbConnectionsInUse();