]> git.saurik.com Git - wxWidgets.git/blame - src/common/db.cpp
Applied some of the SGI fixes. Don't know about the
[wxWidgets.git] / src / common / db.cpp
CommitLineData
108106cf
JS
1///////////////////////////////////////////////////////////////////////////////
2// Name: db.cpp
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.
6// Author: Doug Card
67e9aaa3 7// Modified by: George Tasker
a2115c88
GT
8// Mods: Dec, 1998:
9// -Added support for SQL statement logging and database cataloging
10// Mods: April, 1999
11// -Added QUERY_ONLY mode support to reduce default number of cursors
12// -Added additional SQL logging code
13// -Added DEBUG-ONLY tracking of wxTable objects to detect orphaned DB connections
14// -Set ODBC option to only read committed writes to the DB so all
15// databases operate the same in that respect
108106cf
JS
16// Created: 9.96
17// RCS-ID: $Id$
18// Copyright: (c) 1996 Remstar International, Inc.
19// Licence: wxWindows licence, plus:
a2115c88 20// Notice: This class library and its intellectual design are free of charge for use,
108106cf
JS
21// modification, enhancement, debugging under the following conditions:
22// 1) These classes may only be used as part of the implementation of a
23// wxWindows-based application
24// 2) All enhancements and bug fixes are to be submitted back to the wxWindows
25// user groups free of all charges for use with the wxWindows library.
26// 3) These classes may not be distributed as part of any other class library,
27// DLL, text (written or electronic), other than a complete distribution of
28// the wxWindows GUI development toolkit.
29///////////////////////////////////////////////////////////////////////////////
30
31/*
32// SYNOPSIS START
33// SYNOPSIS STOP
34*/
35
01dba85a
JS
36#include "wx/wxprec.h"
37
a2115c88
GT
38// Use this line for wxWindows v1.x
39//#include "wx_ver.h"
40// Use this line for wxWindows v2.x
41#include "wx/version.h"
a2115c88
GT
42
43#if wxMAJOR_VERSION == 2
44 #ifdef __GNUG__
45 #pragma implementation "db.h"
46 #endif
47#endif
48
1fc5dd6f 49#ifdef DBDEBUG_CONSOLE
108106cf
JS
50 #include <iostream.h>
51#endif
108106cf
JS
52
53#ifdef __BORLANDC__
a2115c88 54 #pragma hdrstop
108106cf
JS
55#endif //__BORLANDC__
56
a2115c88 57#if wxMAJOR_VERSION == 2
9199e66f
RR
58 #ifndef WX_PRECOMP
59 #include "wx/string.h"
60 #include "wx/object.h"
61 #include "wx/list.h"
62 #include "wx/utils.h"
63 #include "wx/msgdlg.h"
64 #endif
3351164d 65 #include "wx/filefn.h"
aa33452c 66 #include "wx/wxchar.h"
a2115c88
GT
67#endif
68
69#if wxMAJOR_VERSION == 1
70# if defined(wx_msw) || defined(wx_x)
71# ifdef WX_PRECOMP
72# include "wx_prec.h"
73# else
74# include "wx.h"
75# endif
76# endif
77# define wxUSE_ODBC 1
78#endif
108106cf 79
47d67540 80#if wxUSE_ODBC
108106cf 81
108106cf
JS
82#include <stdio.h>
83#include <string.h>
84#include <assert.h>
7e616b10
RR
85#include <stdlib.h>
86#include <ctype.h>
67e9aaa3 87
a2115c88
GT
88#if wxMAJOR_VERSION == 1
89 #include "db.h"
90#elif wxMAJOR_VERSION == 2
91 #include "wx/db.h"
92#endif
108106cf 93
a497618a 94DbList WXDLLEXPORT *PtrBegDbList = 0;
108106cf 95
e041ce57 96#ifdef __WXDEBUG__
a2115c88
GT
97 extern wxList TablesInUse;
98#endif
99
100// SQL Log defaults to be used by GetDbConnection
101enum sqlLog SQLLOGstate = sqlLogOFF;
102
103char SQLLOGfn[DB_PATH_MAX+1] = "sqllog.txt";
104
105// The wxDB::errorList is copied to this variable when the wxDB object
106// is closed. This way, the error list is still available after the
107// database object is closed. This is necessary if the database
108// connection fails so the calling application can show the operator
109// why the connection failed. Note: as each wxDB object is closed, it
110// will overwrite the errors of the previously destroyed wxDB object in
111// this variable.
112char DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN];
113
67e9aaa3
GT
114
115/********** wxColFor Constructor **********/
116wxColFor::wxColFor()
117{
118 i_Nation = 0; // 0=EU, 1=UK, 2=International, 3=US
119 s_Field = "";
120 for (int i=0;i<7;i++)
121 {
122 s_Format[i] = "";
123 s_Menge[i] = "";
124 i_Menge[i] = 0;
125 }
126 Format(1,DB_DATA_TYPE_VARCHAR,0,0,0); // the Function that does the work
127} // wxColFor::wxColFor()
128
129
130wxColFor::~wxColFor()
131{
132} // wxColFor::~wxColFor()
133
134
135int wxColFor::Format(int Nation,int dbDataType,SWORD sqlDataType,short columnSize,short decimalDigits)
136{
137 // ----------------------------------------------------------------------------------------
138 // -- 19991224 : mj10777@gmx.net : Create
139 // There is still a lot of work to do here, but it is a start
140 // It handles all the basic data-types that I have run into up to now
141 // The main work will have be with Dates and float Formatting (US 1,000.00 ; EU 1.000,00)
142 // There are wxWindow plans for locale support and the new wxDateTime.
143 // - if they define some constants (wxEUROPEAN) that can be gloably used,
144 // they should be used here.
145 // ----------------------------------------------------------------------------------------
146 // There should also be a Function to scan in a string to fill the variable
147 // ----------------------------------------------------------------------------------------
148 wxString Temp0;
149 i_Nation = Nation; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
150 i_dbDataType = dbDataType;
151 i_sqlDataType = sqlDataType;
152 s_Field.Printf("%s%d",s_Menge[1].c_str(),i_Menge[1]); // OK for VARCHAR, INTEGER and FLOAT
153 if (i_dbDataType == 0) // Filter unsupported dbDataTypes
154 {
155 if ((i_sqlDataType == SQL_VARCHAR) || (i_sqlDataType == SQL_LONGVARCHAR))
156 i_dbDataType = DB_DATA_TYPE_VARCHAR;
157 if (i_sqlDataType == SQL_C_DATE)
158 i_dbDataType = DB_DATA_TYPE_DATE;
159 if (i_sqlDataType == SQL_C_BIT)
160 i_dbDataType = DB_DATA_TYPE_INTEGER;
161 if (i_sqlDataType == SQL_NUMERIC)
162 i_dbDataType = DB_DATA_TYPE_VARCHAR;
163 if (i_sqlDataType == SQL_REAL)
164 i_dbDataType = DB_DATA_TYPE_FLOAT;
165 }
166 if ((i_dbDataType == DB_DATA_TYPE_INTEGER) && (i_sqlDataType == SQL_C_DOUBLE))
167 { // DBASE Numeric
168 i_dbDataType = DB_DATA_TYPE_FLOAT;
169 }
170 switch(i_dbDataType) // -A-> Still a lot of proper formatting to do
171 {
172 case DB_DATA_TYPE_VARCHAR:
173 s_Field = "%s"; //
174 break;
175 case DB_DATA_TYPE_INTEGER:
176 s_Field = "%d"; //
177 break;
178 case DB_DATA_TYPE_FLOAT:
179 if (decimalDigits == 0)
180 decimalDigits = 2;
181 Temp0 = "%";
182 Temp0.Printf("%s%d.%d",Temp0.c_str(),columnSize,decimalDigits);
183 s_Field.Printf("%sf",Temp0.c_str()); //
184 break;
185 case DB_DATA_TYPE_DATE:
186 if (i_Nation == 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
187 {
188 s_Field = "%04d-%02d-%02d %02d:%02d:%02d.%03d";
189 }
190 if (i_Nation == 1) // European DD.MM.YYYY HH:MM:SS.SSS
191 {
192 s_Field = "%02d.%02d.%04d %02d:%02d:%02d.%03d";
193 }
194 if (i_Nation == 2) // UK DD/MM/YYYY HH:MM:SS.SSS
195 {
196 s_Field = "%02d/%02d/%04d %02d:%02d:%02d.%03d";
197 }
198 if (i_Nation == 3) // International YYYY-MM-DD HH:MM:SS.SSS
199 {
200 s_Field = "%04d-%02d-%02d %02d:%02d:%02d.%03d";
201 }
202 if (i_Nation == 4) // US MM/DD/YYYY HH:MM:SS.SSS
203 {
204 s_Field = "%02d/%02d/%04d %02d:%02d:%02d.%03d";
205 }
206 break;
207 default:
208 s_Field.Printf("-E-> unknown Format(%d)-sql(%d)",dbDataType,sqlDataType); //
209 break;
210 };
211 return TRUE;
212} // wxColFor::Format()
213
214
108106cf 215/********** wxDB Constructor **********/
a3439c7d 216wxDB::wxDB(HENV &aHenv, bool FwdOnlyCursors)
108106cf
JS
217{
218 int i;
1fc5dd6f
JS
219
220 fpSqlLog = 0; // Sql Log file pointer
221 sqlLogState = sqlLogOFF; // By default, logging is turned off
a2115c88 222 nTables = 0;
108106cf 223
e8af3814
GT
224 wxStrcpy(sqlState,"");
225 wxStrcpy(errorMsg,"");
108106cf
JS
226 nativeError = cbErrorMsg = 0;
227 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
e8af3814 228 wxStrcpy(errorList[i], "");
108106cf
JS
229
230 // Init typeInf structures
e8af3814 231 wxStrcpy(typeInfVarchar.TypeName,"");
108106cf
JS
232 typeInfVarchar.FsqlType = 0;
233 typeInfVarchar.Precision = 0;
234 typeInfVarchar.CaseSensitive = 0;
235 typeInfVarchar.MaximumScale = 0;
236
e8af3814 237 wxStrcpy(typeInfInteger.TypeName,"");
108106cf
JS
238 typeInfInteger.FsqlType = 0;
239 typeInfInteger.Precision = 0;
240 typeInfInteger.CaseSensitive = 0;
241 typeInfInteger.MaximumScale = 0;
242
e8af3814 243 wxStrcpy(typeInfFloat.TypeName,"");
108106cf
JS
244 typeInfFloat.FsqlType = 0;
245 typeInfFloat.Precision = 0;
246 typeInfFloat.CaseSensitive = 0;
247 typeInfFloat.MaximumScale = 0;
248
e8af3814 249 wxStrcpy(typeInfDate.TypeName,"");
108106cf
JS
250 typeInfDate.FsqlType = 0;
251 typeInfDate.Precision = 0;
252 typeInfDate.CaseSensitive = 0;
253 typeInfDate.MaximumScale = 0;
254
255 // Error reporting is turned OFF by default
256 silent = TRUE;
257
258 // Copy the HENV into the db class
259 henv = aHenv;
a3439c7d 260 fwdOnlyCursors = FwdOnlyCursors;
108106cf
JS
261
262 // Allocate a data source connection handle
263 if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS)
264 DispAllErrors(henv);
265
266 // Initialize the db status flag
267 DB_STATUS = 0;
268
269 // Mark database as not open as of yet
270 dbIsOpen = FALSE;
271
272} // wxDB::wxDB()
273
67e9aaa3 274
108106cf
JS
275/********** wxDB::Open() **********/
276bool wxDB::Open(char *Dsn, char *Uid, char *AuthStr)
277{
e8af3814 278 assert(Dsn && wxStrlen(Dsn));
108106cf
JS
279 dsn = Dsn;
280 uid = Uid;
281 authStr = AuthStr;
282
108106cf
JS
283 RETCODE retcode;
284
a3439c7d
GT
285 if (!FwdOnlyCursors())
286 {
287 // Specify that the ODBC cursor library be used, if needed. This must be
288 // specified before the connection is made.
289 retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED);
108106cf 290
6919c53f 291#ifdef DBDEBUG_CONSOLE
108106cf
JS
292 if (retcode == SQL_SUCCESS)
293 cout << "SQLSetConnectOption(CURSOR_LIB) successful" << endl;
294 else
295 cout << "SQLSetConnectOption(CURSOR_LIB) failed" << endl;
6919c53f 296#endif
a3439c7d 297 }
108106cf
JS
298
299 // Connect to the data source
67e9aaa3
GT
300 retcode = SQLConnect(hdbc, (UCHAR FAR *) Dsn, SQL_NTS,
301 (UCHAR FAR *) Uid, SQL_NTS,
302 (UCHAR FAR *) AuthStr,SQL_NTS);
a2115c88
GT
303 if (retcode == SQL_SUCCESS_WITH_INFO)
304 DispAllErrors(henv, hdbc);
305 else if (retcode != SQL_SUCCESS)
108106cf
JS
306 return(DispAllErrors(henv, hdbc));
307
a2115c88
GT
308/*
309 If using Intersolv branded ODBC drivers, this is the place where you would substitute
310 your branded driver license information
311
312 SQLSetConnectOption(hdbc, 1041, (UDWORD) "");
313 SQLSetConnectOption(hdbc, 1042, (UDWORD) "");
314*/
67e9aaa3 315
108106cf
JS
316 // Mark database as open
317 dbIsOpen = TRUE;
318
319 // Allocate a statement handle for the database connection
320 if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
321 return(DispAllErrors(henv, hdbc));
322
323 // Set Connection Options
324 if (! setConnectionOptions())
325 return(FALSE);
326
327 // Query the data source for inf. about itself
328 if (! getDbInfo())
329 return(FALSE);
330
331 // Query the data source regarding data type information
332
333 //
334 // The way I determined which SQL data types to use was by calling SQLGetInfo
335 // for all of the possible SQL data types to see which ones were supported. If
336 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
337 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
338 // types I've selected below will not alway's be what we want. These are just
339 // what happened to work against an Oracle 7/Intersolv combination. The following is
340 // a complete list of the results I got back against the Oracle 7 database:
341 //
342 // SQL_BIGINT SQL_NO_DATA_FOUND
343 // SQL_BINARY SQL_NO_DATA_FOUND
344 // SQL_BIT SQL_NO_DATA_FOUND
345 // SQL_CHAR type name = 'CHAR', Precision = 255
346 // SQL_DATE SQL_NO_DATA_FOUND
347 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
348 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
349 // SQL_FLOAT SQL_NO_DATA_FOUND
350 // SQL_INTEGER SQL_NO_DATA_FOUND
351 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
67e9aaa3 352 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
108106cf
JS
353 // SQL_NUMERIC SQL_NO_DATA_FOUND
354 // SQL_REAL SQL_NO_DATA_FOUND
67e9aaa3 355 // SQL_SMALLINT SQL_NO_DATA_FOUND
108106cf
JS
356 // SQL_TIME SQL_NO_DATA_FOUND
357 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
358 // SQL_VARBINARY type name = 'RAW', Precision = 255
359 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
360 // =====================================================================
361 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
362 //
a2115c88 363 // SQL_VARCHAR type name = 'TEXT', Precision = 255
108106cf
JS
364 // SQL_TIMESTAMP type name = 'DATETIME'
365 // SQL_DECIMAL SQL_NO_DATA_FOUND
366 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
367 // SQL_FLOAT SQL_NO_DATA_FOUND
368 // SQL_REAL type name = 'SINGLE', Precision = 7
369 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
370 // SQL_INTEGER type name = 'LONG', Precision = 10
371
372 // VARCHAR = Variable length character string
373 if (! getDataTypeInfo(SQL_VARCHAR, typeInfVarchar))
374 if (! getDataTypeInfo(SQL_CHAR, typeInfVarchar))
375 return(FALSE);
376 else
377 typeInfVarchar.FsqlType = SQL_CHAR;
378 else
379 typeInfVarchar.FsqlType = SQL_VARCHAR;
380
381 // Float
382 if (! getDataTypeInfo(SQL_DOUBLE, typeInfFloat))
383 if (! getDataTypeInfo(SQL_REAL, typeInfFloat))
384 if (! getDataTypeInfo(SQL_FLOAT, typeInfFloat))
385 if (! getDataTypeInfo(SQL_DECIMAL, typeInfFloat))
386 if (! getDataTypeInfo(SQL_NUMERIC, typeInfFloat))
387 return(FALSE);
388 else
389 typeInfFloat.FsqlType = SQL_NUMERIC;
390 else
391 typeInfFloat.FsqlType = SQL_DECIMAL;
392 else
393 typeInfFloat.FsqlType = SQL_FLOAT;
394 else
395 typeInfFloat.FsqlType = SQL_REAL;
396 else
397 typeInfFloat.FsqlType = SQL_DOUBLE;
398
399 // Integer
400 if (! getDataTypeInfo(SQL_INTEGER, typeInfInteger))
401 // If SQL_INTEGER is not supported, use the floating point
402 // data type to store integers as well as floats
403 if (! getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger))
404 return(FALSE);
405 else
406 typeInfInteger.FsqlType = typeInfFloat.FsqlType;
407 else
408 typeInfInteger.FsqlType = SQL_INTEGER;
409
410 // Date/Time
a2115c88
GT
411 if (Dbms() != dbmsDBASE)
412 {
413 if (! getDataTypeInfo(SQL_TIMESTAMP, typeInfDate))
414 return(FALSE);
415 else
416 typeInfDate.FsqlType = SQL_TIMESTAMP;
417 }
108106cf 418 else
a2115c88
GT
419 {
420 if (! getDataTypeInfo(SQL_DATE, typeInfDate))
421 return(FALSE);
422 else
423 typeInfDate.FsqlType = SQL_DATE;
424 }
108106cf 425
1fc5dd6f 426#ifdef DBDEBUG_CONSOLE
108106cf
JS
427 cout << "VARCHAR DATA TYPE: " << typeInfVarchar.TypeName << endl;
428 cout << "INTEGER DATA TYPE: " << typeInfInteger.TypeName << endl;
429 cout << "FLOAT DATA TYPE: " << typeInfFloat.TypeName << endl;
430 cout << "DATE DATA TYPE: " << typeInfDate.TypeName << endl;
431 cout << endl;
432#endif
433
434 // Completed Successfully
435 return(TRUE);
436
437} // wxDB::Open()
438
108106cf
JS
439
440/********** wxDB::setConnectionOptions() **********/
441bool wxDB::setConnectionOptions(void)
67e9aaa3
GT
442/*
443 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
444 */
108106cf
JS
445{
446 SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
447 SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF);
448
449 // Display the connection options to verify them
1fc5dd6f 450#ifdef DBDEBUG_CONSOLE
108106cf
JS
451 long l;
452 cout << ">>>>> CONNECTION OPTIONS <<<<<<" << endl;
453
454 if (SQLGetConnectOption(hdbc, SQL_AUTOCOMMIT, &l) != SQL_SUCCESS)
455 return(DispAllErrors(henv, hdbc));
456 cout << "AUTOCOMMIT: " << (l == SQL_AUTOCOMMIT_OFF ? "OFF" : "ON") << endl;
457
458 if (SQLGetConnectOption(hdbc, SQL_ODBC_CURSORS, &l) != SQL_SUCCESS)
459 return(DispAllErrors(henv, hdbc));
460 cout << "ODBC CURSORS: ";
461 switch(l)
462 {
463 case(SQL_CUR_USE_IF_NEEDED):
464 cout << "SQL_CUR_USE_IF_NEEDED";
465 break;
466 case(SQL_CUR_USE_ODBC):
467 cout << "SQL_CUR_USE_ODBC";
468 break;
469 case(SQL_CUR_USE_DRIVER):
470 cout << "SQL_CUR_USE_DRIVER";
471 break;
472 }
473 cout << endl;
474
475 if (SQLGetConnectOption(hdbc, SQL_OPT_TRACE, &l) != SQL_SUCCESS)
476 return(DispAllErrors(henv, hdbc));
477 cout << "TRACING: " << (l == SQL_OPT_TRACE_OFF ? "OFF" : "ON") << endl;
478
479 cout << endl;
480#endif
481
482 // Completed Successfully
483 return(TRUE);
484
485} // wxDB::setConnectionOptions()
486
67e9aaa3 487
108106cf
JS
488/********** wxDB::getDbInfo() **********/
489bool wxDB::getDbInfo(void)
490{
491 SWORD cb;
a2115c88 492 RETCODE retcode;
108106cf 493
a2115c88 494 if (SQLGetInfo(hdbc, SQL_SERVER_NAME, (UCHAR*) dbInf.serverName, 80, &cb) != SQL_SUCCESS)
108106cf
JS
495 return(DispAllErrors(henv, hdbc));
496
7e616b10 497 if (SQLGetInfo(hdbc, SQL_DATABASE_NAME, (UCHAR*) dbInf.databaseName, 128, &cb) != SQL_SUCCESS)
108106cf
JS
498 return(DispAllErrors(henv, hdbc));
499
7e616b10 500 if (SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, 40, &cb) != SQL_SUCCESS)
108106cf
JS
501 return(DispAllErrors(henv, hdbc));
502
a2115c88
GT
503 // 16-Mar-1999
504 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
505 // causing database connectivity to fail in some cases.
506 retcode = SQLGetInfo(hdbc, SQL_DBMS_VER, (UCHAR*) dbInf.dbmsVer, 64, &cb);
507 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
108106cf
JS
508 return(DispAllErrors(henv, hdbc));
509
7e616b10 510 if (SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, (UCHAR*) &dbInf.maxConnections, sizeof(dbInf.maxConnections), &cb) != SQL_SUCCESS)
108106cf
JS
511 return(DispAllErrors(henv, hdbc));
512
7e616b10 513 if (SQLGetInfo(hdbc, SQL_ACTIVE_STATEMENTS, (UCHAR*) &dbInf.maxStmts, sizeof(dbInf.maxStmts), &cb) != SQL_SUCCESS)
108106cf
JS
514 return(DispAllErrors(henv, hdbc));
515
7e616b10 516 if (SQLGetInfo(hdbc, SQL_DRIVER_NAME, (UCHAR*) dbInf.driverName, 40, &cb) != SQL_SUCCESS)
108106cf
JS
517 return(DispAllErrors(henv, hdbc));
518
1acd7ba6 519 if (SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, (UCHAR*) dbInf.odbcVer, 60, &cb) == SQL_ERROR)
108106cf
JS
520 return(DispAllErrors(henv, hdbc));
521
a2115c88
GT
522 retcode = SQLGetInfo(hdbc, SQL_ODBC_VER, (UCHAR*) dbInf.drvMgrOdbcVer, 60, &cb);
523 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
108106cf
JS
524 return(DispAllErrors(henv, hdbc));
525
1acd7ba6 526 if (SQLGetInfo(hdbc, SQL_DRIVER_VER, (UCHAR*) dbInf.driverVer, 60, &cb) == SQL_ERROR)
108106cf
JS
527 return(DispAllErrors(henv, hdbc));
528
7e616b10 529 if (SQLGetInfo(hdbc, SQL_ODBC_API_CONFORMANCE, (UCHAR*) &dbInf.apiConfLvl, sizeof(dbInf.apiConfLvl), &cb) != SQL_SUCCESS)
108106cf
JS
530 return(DispAllErrors(henv, hdbc));
531
7e616b10 532 if (SQLGetInfo(hdbc, SQL_ODBC_SAG_CLI_CONFORMANCE, (UCHAR*) &dbInf.cliConfLvl, sizeof(dbInf.cliConfLvl), &cb) != SQL_SUCCESS)
108106cf
JS
533 return(DispAllErrors(henv, hdbc));
534
7e616b10 535 if (SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, (UCHAR*) &dbInf.sqlConfLvl, sizeof(dbInf.sqlConfLvl), &cb) != SQL_SUCCESS)
108106cf
JS
536 return(DispAllErrors(henv, hdbc));
537
7e616b10 538 if (SQLGetInfo(hdbc, SQL_OUTER_JOINS, (UCHAR*) dbInf.outerJoins, 2, &cb) != SQL_SUCCESS)
108106cf
JS
539 return(DispAllErrors(henv, hdbc));
540
7e616b10 541 if (SQLGetInfo(hdbc, SQL_PROCEDURES, (UCHAR*) dbInf.procedureSupport, 2, &cb) != SQL_SUCCESS)
108106cf
JS
542 return(DispAllErrors(henv, hdbc));
543
7e616b10 544 if (SQLGetInfo(hdbc, SQL_CURSOR_COMMIT_BEHAVIOR, (UCHAR*) &dbInf.cursorCommitBehavior, sizeof(dbInf.cursorCommitBehavior), &cb) != SQL_SUCCESS)
108106cf
JS
545 return(DispAllErrors(henv, hdbc));
546
7e616b10 547 if (SQLGetInfo(hdbc, SQL_CURSOR_ROLLBACK_BEHAVIOR, (UCHAR*) &dbInf.cursorRollbackBehavior, sizeof(dbInf.cursorRollbackBehavior), &cb) != SQL_SUCCESS)
108106cf
JS
548 return(DispAllErrors(henv, hdbc));
549
7e616b10 550 if (SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, (UCHAR*) &dbInf.supportNotNullClause, sizeof(dbInf.supportNotNullClause), &cb) != SQL_SUCCESS)
108106cf
JS
551 return(DispAllErrors(henv, hdbc));
552
7e616b10 553 if (SQLGetInfo(hdbc, SQL_ODBC_SQL_OPT_IEF, (UCHAR*) dbInf.supportIEF, 2, &cb) != SQL_SUCCESS)
108106cf
JS
554 return(DispAllErrors(henv, hdbc));
555
7e616b10 556 if (SQLGetInfo(hdbc, SQL_DEFAULT_TXN_ISOLATION, (UCHAR*) &dbInf.txnIsolation, sizeof(dbInf.txnIsolation), &cb) != SQL_SUCCESS)
108106cf
JS
557 return(DispAllErrors(henv, hdbc));
558
7e616b10 559 if (SQLGetInfo(hdbc, SQL_TXN_ISOLATION_OPTION, (UCHAR*) &dbInf.txnIsolationOptions, sizeof(dbInf.txnIsolationOptions), &cb) != SQL_SUCCESS)
108106cf
JS
560 return(DispAllErrors(henv, hdbc));
561
7e616b10 562 if (SQLGetInfo(hdbc, SQL_FETCH_DIRECTION, (UCHAR*) &dbInf.fetchDirections, sizeof(dbInf.fetchDirections), &cb) != SQL_SUCCESS)
108106cf
JS
563 return(DispAllErrors(henv, hdbc));
564
7e616b10 565 if (SQLGetInfo(hdbc, SQL_LOCK_TYPES, (UCHAR*) &dbInf.lockTypes, sizeof(dbInf.lockTypes), &cb) != SQL_SUCCESS)
108106cf
JS
566 return(DispAllErrors(henv, hdbc));
567
7e616b10 568 if (SQLGetInfo(hdbc, SQL_POS_OPERATIONS, (UCHAR*) &dbInf.posOperations, sizeof(dbInf.posOperations), &cb) != SQL_SUCCESS)
108106cf
JS
569 return(DispAllErrors(henv, hdbc));
570
7e616b10 571 if (SQLGetInfo(hdbc, SQL_POSITIONED_STATEMENTS, (UCHAR*) &dbInf.posStmts, sizeof(dbInf.posStmts), &cb) != SQL_SUCCESS)
108106cf
JS
572 return(DispAllErrors(henv, hdbc));
573
7e616b10 574 if (SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, (UCHAR*) &dbInf.scrollConcurrency, sizeof(dbInf.scrollConcurrency), &cb) != SQL_SUCCESS)
108106cf
JS
575 return(DispAllErrors(henv, hdbc));
576
7e616b10 577 if (SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, (UCHAR*) &dbInf.scrollOptions, sizeof(dbInf.scrollOptions), &cb) != SQL_SUCCESS)
108106cf
JS
578 return(DispAllErrors(henv, hdbc));
579
7e616b10 580 if (SQLGetInfo(hdbc, SQL_STATIC_SENSITIVITY, (UCHAR*) &dbInf.staticSensitivity, sizeof(dbInf.staticSensitivity), &cb) != SQL_SUCCESS)
108106cf
JS
581 return(DispAllErrors(henv, hdbc));
582
7e616b10 583 if (SQLGetInfo(hdbc, SQL_TXN_CAPABLE, (UCHAR*) &dbInf.txnCapable, sizeof(dbInf.txnCapable), &cb) != SQL_SUCCESS)
108106cf
JS
584 return(DispAllErrors(henv, hdbc));
585
7e616b10 586 if (SQLGetInfo(hdbc, SQL_LOGIN_TIMEOUT, (UCHAR*) &dbInf.loginTimeout, sizeof(dbInf.loginTimeout), &cb) != SQL_SUCCESS)
108106cf
JS
587 return(DispAllErrors(henv, hdbc));
588
1fc5dd6f 589#ifdef DBDEBUG_CONSOLE
108106cf
JS
590 cout << ">>>>> DATA SOURCE INFORMATION <<<<<" << endl;
591 cout << "SERVER Name: " << dbInf.serverName << endl;
592 cout << "DBMS Name: " << dbInf.dbmsName << "; DBMS Version: " << dbInf.dbmsVer << endl;
593 cout << "ODBC Version: " << dbInf.odbcVer << "; Driver Version: " << dbInf.driverVer << endl;
594
595 cout << "API Conf. Level: ";
596 switch(dbInf.apiConfLvl)
597 {
598 case SQL_OAC_NONE: cout << "None"; break;
599 case SQL_OAC_LEVEL1: cout << "Level 1"; break;
600 case SQL_OAC_LEVEL2: cout << "Level 2"; break;
601 }
602 cout << endl;
603
604 cout << "SAG CLI Conf. Level: ";
605 switch(dbInf.cliConfLvl)
606 {
607 case SQL_OSCC_NOT_COMPLIANT: cout << "Not Compliant"; break;
608 case SQL_OSCC_COMPLIANT: cout << "Compliant"; break;
609 }
610 cout << endl;
611
612 cout << "SQL Conf. Level: ";
613 switch(dbInf.sqlConfLvl)
614 {
615 case SQL_OSC_MINIMUM: cout << "Minimum Grammer"; break;
616 case SQL_OSC_CORE: cout << "Core Grammer"; break;
617 case SQL_OSC_EXTENDED: cout << "Extended Grammer"; break;
618 }
619 cout << endl;
620
621 cout << "Max. Connections: " << dbInf.maxConnections << endl;
622 cout << "Outer Joins: " << dbInf.outerJoins << endl;
623 cout << "Support for Procedures: " << dbInf.procedureSupport << endl;
624
625 cout << "Cursor COMMIT Behavior: ";
626 switch(dbInf.cursorCommitBehavior)
627 {
628 case SQL_CB_DELETE: cout << "Delete cursors"; break;
629 case SQL_CB_CLOSE: cout << "Close cursors"; break;
630 case SQL_CB_PRESERVE: cout << "Preserve cursors"; break;
631 }
632 cout << endl;
633
634 cout << "Cursor ROLLBACK Behavior: ";
635 switch(dbInf.cursorRollbackBehavior)
636 {
637 case SQL_CB_DELETE: cout << "Delete cursors"; break;
638 case SQL_CB_CLOSE: cout << "Close cursors"; break;
639 case SQL_CB_PRESERVE: cout << "Preserve cursors"; break;
640 }
641 cout << endl;
642
643 cout << "Support NOT NULL clause: ";
644 switch(dbInf.supportNotNullClause)
645 {
646 case SQL_NNC_NULL: cout << "No"; break;
647 case SQL_NNC_NON_NULL: cout << "Yes"; break;
648 }
649 cout << endl;
650
651 cout << "Support IEF (Ref. Integrity): " << dbInf.supportIEF << endl;
652 cout << "Login Timeout: " << dbInf.loginTimeout << endl;
653
654 cout << endl << endl << "more ..." << endl;
655 getchar();
656
657 cout << "Default Transaction Isolation: ";
658 switch(dbInf.txnIsolation)
659 {
660 case SQL_TXN_READ_UNCOMMITTED: cout << "Read Uncommitted"; break;
661 case SQL_TXN_READ_COMMITTED: cout << "Read Committed"; break;
662 case SQL_TXN_REPEATABLE_READ: cout << "Repeatable Read"; break;
663 case SQL_TXN_SERIALIZABLE: cout << "Serializable"; break;
664#ifdef ODBC_V20
665 case SQL_TXN_VERSIONING: cout << "Versioning"; break;
666#endif
667 }
668 cout << endl;
669
670 cout << "Transaction Isolation Options: ";
671 if (dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED)
672 cout << "Read Uncommitted, ";
673 if (dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED)
674 cout << "Read Committed, ";
675 if (dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ)
676 cout << "Repeatable Read, ";
677 if (dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE)
678 cout << "Serializable, ";
679#ifdef ODBC_V20
680 if (dbInf.txnIsolationOptions & SQL_TXN_VERSIONING)
681 cout << "Versioning";
682#endif
683 cout << endl;
684
685 cout << "Fetch Directions Supported:" << endl << " ";
686 if (dbInf.fetchDirections & SQL_FD_FETCH_NEXT)
687 cout << "Next, ";
688 if (dbInf.fetchDirections & SQL_FD_FETCH_PRIOR)
689 cout << "Prev, ";
690 if (dbInf.fetchDirections & SQL_FD_FETCH_FIRST)
691 cout << "First, ";
692 if (dbInf.fetchDirections & SQL_FD_FETCH_LAST)
693 cout << "Last, ";
694 if (dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE)
695 cout << "Absolute, ";
696 if (dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE)
697 cout << "Relative, ";
698#ifdef ODBC_V20
699 if (dbInf.fetchDirections & SQL_FD_FETCH_RESUME)
700 cout << "Resume, ";
701#endif
702 if (dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK)
703 cout << "Bookmark";
704 cout << endl;
705
706 cout << "Lock Types Supported (SQLSetPos): ";
707 if (dbInf.lockTypes & SQL_LCK_NO_CHANGE)
708 cout << "No Change, ";
709 if (dbInf.lockTypes & SQL_LCK_EXCLUSIVE)
710 cout << "Exclusive, ";
711 if (dbInf.lockTypes & SQL_LCK_UNLOCK)
712 cout << "UnLock";
713 cout << endl;
714
715 cout << "Position Operations Supported (SQLSetPos): ";
716 if (dbInf.posOperations & SQL_POS_POSITION)
717 cout << "Position, ";
718 if (dbInf.posOperations & SQL_POS_REFRESH)
719 cout << "Refresh, ";
720 if (dbInf.posOperations & SQL_POS_UPDATE)
721 cout << "Upd, ";
722 if (dbInf.posOperations & SQL_POS_DELETE)
723 cout << "Del, ";
724 if (dbInf.posOperations & SQL_POS_ADD)
725 cout << "Add";
726 cout << endl;
727
728 cout << "Positioned Statements Supported: ";
729 if (dbInf.posStmts & SQL_PS_POSITIONED_DELETE)
730 cout << "Pos delete, ";
731 if (dbInf.posStmts & SQL_PS_POSITIONED_UPDATE)
732 cout << "Pos update, ";
733 if (dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)
734 cout << "Select for update";
735 cout << endl;
736
737 cout << "Scroll Concurrency: ";
738 if (dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY)
739 cout << "Read Only, ";
740 if (dbInf.scrollConcurrency & SQL_SCCO_LOCK)
741 cout << "Lock, ";
742 if (dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER)
743 cout << "Opt. Rowver, ";
744 if (dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES)
745 cout << "Opt. Values";
746 cout << endl;
747
748 cout << "Scroll Options: ";
749 if (dbInf.scrollOptions & SQL_SO_FORWARD_ONLY)
750 cout << "Fwd Only, ";
751 if (dbInf.scrollOptions & SQL_SO_STATIC)
752 cout << "Static, ";
753 if (dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN)
754 cout << "Keyset Driven, ";
755 if (dbInf.scrollOptions & SQL_SO_DYNAMIC)
756 cout << "Dynamic, ";
757 if (dbInf.scrollOptions & SQL_SO_MIXED)
758 cout << "Mixed";
759 cout << endl;
760
761 cout << "Static Sensitivity: ";
762 if (dbInf.staticSensitivity & SQL_SS_ADDITIONS)
763 cout << "Additions, ";
764 if (dbInf.staticSensitivity & SQL_SS_DELETIONS)
765 cout << "Deletions, ";
766 if (dbInf.staticSensitivity & SQL_SS_UPDATES)
767 cout << "Updates";
768 cout << endl;
769
770 cout << "Transaction Capable?: ";
771 switch(dbInf.txnCapable)
772 {
773 case SQL_TC_NONE: cout << "No"; break;
774 case SQL_TC_DML: cout << "DML Only"; break;
775 case SQL_TC_DDL_COMMIT: cout << "DDL Commit"; break;
776 case SQL_TC_DDL_IGNORE: cout << "DDL Ignore"; break;
777 case SQL_TC_ALL: cout << "DDL & DML"; break;
778 }
779 cout << endl;
780
781 cout << endl;
108106cf
JS
782#endif
783
784 // Completed Successfully
785 return(TRUE);
786
787} // wxDB::getDbInfo()
788
67e9aaa3 789
108106cf
JS
790/********** wxDB::getDataTypeInfo() **********/
791bool wxDB::getDataTypeInfo(SWORD fSqlType, SqlTypeInfo &structSQLTypeInfo)
792{
67e9aaa3
GT
793/*
794 * fSqlType will be something like SQL_VARCHAR. This parameter determines
795 * the data type inf. is gathered for.
796 *
797 * SqlTypeInfo is a structure that is filled in with data type information,
798 */
108106cf
JS
799 RETCODE retcode;
800 SDWORD cbRet;
801
802 // Get information about the data type specified
803 if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS)
804 return(DispAllErrors(henv, hdbc, hstmt));
805 // Fetch the record
806 if ((retcode = SQLFetch(hstmt)) != SQL_SUCCESS)
807 {
1fc5dd6f 808#ifdef DBDEBUG_CONSOLE
108106cf
JS
809 if (retcode == SQL_NO_DATA_FOUND)
810 cout << "SQL_NO_DATA_FOUND fetching inf. about data type." << endl;
811#endif
812 DispAllErrors(henv, hdbc, hstmt);
813 SQLFreeStmt(hstmt, SQL_CLOSE);
814 return(FALSE);
815 }
816 // Obtain columns from the record
7e616b10 817 if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) structSQLTypeInfo.TypeName, DB_TYPE_NAME_LEN, &cbRet) != SQL_SUCCESS)
108106cf 818 return(DispAllErrors(henv, hdbc, hstmt));
67e9aaa3
GT
819
820 // BJO 991209
821 if (Dbms() == dbmsMY_SQL)
822 {
823 if (!strcmp(structSQLTypeInfo.TypeName, "middleint")) strcpy(structSQLTypeInfo.TypeName, "mediumint");
824 if (!strcmp(structSQLTypeInfo.TypeName, "middleint unsigned")) strcpy(structSQLTypeInfo.TypeName, "mediumint unsigned");
825 if (!strcmp(structSQLTypeInfo.TypeName, "integer")) strcpy(structSQLTypeInfo.TypeName, "int");
826 if (!strcmp(structSQLTypeInfo.TypeName, "integer unsigned")) strcpy(structSQLTypeInfo.TypeName, "int unsigned");
827 if (!strcmp(structSQLTypeInfo.TypeName, "middleint")) strcpy(structSQLTypeInfo.TypeName, "mediumint");
828 if (!strcmp(structSQLTypeInfo.TypeName, "varchar")) strcpy(structSQLTypeInfo.TypeName, "char");
829 }
830
7e616b10 831 if (SQLGetData(hstmt, 3, SQL_C_LONG, (UCHAR*) &structSQLTypeInfo.Precision, 0, &cbRet) != SQL_SUCCESS)
108106cf 832 return(DispAllErrors(henv, hdbc, hstmt));
7e616b10 833 if (SQLGetData(hstmt, 8, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.CaseSensitive, 0, &cbRet) != SQL_SUCCESS)
108106cf 834 return(DispAllErrors(henv, hdbc, hstmt));
7e616b10 835// if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
108106cf 836// return(DispAllErrors(henv, hdbc, hstmt));
a2115c88 837
a2115c88 838 if (SQLGetData(hstmt, 15, SQL_C_SHORT,(UCHAR*) &structSQLTypeInfo.MaximumScale, 0, &cbRet) != SQL_SUCCESS)
108106cf
JS
839 return(DispAllErrors(henv, hdbc, hstmt));
840
841 if (structSQLTypeInfo.MaximumScale < 0)
842 structSQLTypeInfo.MaximumScale = 0;
843
844 // Close the statement handle which closes open cursors
845 if (SQLFreeStmt(hstmt, SQL_CLOSE) != SQL_SUCCESS)
846 return(DispAllErrors(henv, hdbc, hstmt));
847
848 // Completed Successfully
849 return(TRUE);
850
851} // wxDB::getDataTypeInfo()
852
67e9aaa3 853
108106cf
JS
854/********** wxDB::Close() **********/
855void wxDB::Close(void)
856{
1fc5dd6f
JS
857 // Close the Sql Log file
858 if (fpSqlLog)
859 {
860 fclose(fpSqlLog);
a2115c88 861 fpSqlLog = 0;
1fc5dd6f
JS
862 }
863
108106cf
JS
864 // Free statement handle
865 if (dbIsOpen)
866 {
867 if (SQLFreeStmt(hstmt, SQL_DROP) != SQL_SUCCESS)
868 DispAllErrors(henv, hdbc);
869 }
870
871 // Disconnect from the datasource
872 if (SQLDisconnect(hdbc) != SQL_SUCCESS)
873 DispAllErrors(henv, hdbc);
874
875 // Free the connection to the datasource
876 if (SQLFreeConnect(hdbc) != SQL_SUCCESS)
877 DispAllErrors(henv, hdbc);
878
a2115c88
GT
879 // There should be zero Ctable objects still connected to this db object
880 assert(nTables == 0);
881
e041ce57 882#ifdef __WXDEBUG__
a2115c88
GT
883 CstructTablesInUse *tiu;
884 wxNode *pNode;
885 pNode = TablesInUse.First();
886 char s[80];
887 char s2[80];
888 while (pNode)
889 {
890 tiu = (CstructTablesInUse *)pNode->Data();
891 if (tiu->pDb == this)
892 {
12234741
VZ
893 sprintf(s, "(%-20s) tableID:[%6lu] pDb:[%p]", tiu->tableName,tiu->tableID,tiu->pDb);
894 sprintf(s2,"Orphaned found using pDb:[%p]",this);
a2115c88
GT
895 wxMessageBox (s,s2);
896 }
897 pNode = pNode->Next();
898 }
899#endif
900
901 // Copy the error messages to a global variable
9c40a88d
GT
902 int i;
903 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
e8af3814 904 wxStrcpy(DBerrorList[i],errorList[i]);
a2115c88 905
108106cf
JS
906} // wxDB::Close()
907
67e9aaa3 908
108106cf
JS
909/********** wxDB::CommitTrans() **********/
910bool wxDB::CommitTrans(void)
911{
a2115c88
GT
912 if (this)
913 {
914 // Commit the transaction
915 if (SQLTransact(henv, hdbc, SQL_COMMIT) != SQL_SUCCESS)
916 return(DispAllErrors(henv, hdbc));
917 }
108106cf
JS
918
919 // Completed successfully
920 return(TRUE);
921
922} // wxDB::CommitTrans()
923
67e9aaa3 924
108106cf
JS
925/********** wxDB::RollbackTrans() **********/
926bool wxDB::RollbackTrans(void)
927{
928 // Rollback the transaction
929 if (SQLTransact(henv, hdbc, SQL_ROLLBACK) != SQL_SUCCESS)
930 return(DispAllErrors(henv, hdbc));
931
932 // Completed successfully
933 return(TRUE);
934
935} // wxDB::RollbackTrans()
936
67e9aaa3 937
108106cf
JS
938/********** wxDB::DispAllErrors() **********/
939bool wxDB::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
940{
941 char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
942
943 while (SQLError(aHenv, aHdbc, aHstmt, (UCHAR FAR *) sqlState, &nativeError, (UCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
944 {
945 sprintf(odbcErrMsg, "SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState, nativeError, errorMsg);
946 logError(odbcErrMsg, sqlState);
947 if (!silent)
948 {
1fc5dd6f 949#ifdef DBDEBUG_CONSOLE
108106cf
JS
950 // When run in console mode, use standard out to display errors.
951 cout << odbcErrMsg << endl;
952 cout << "Press any key to continue..." << endl;
953 getchar();
954#endif
955 }
a2115c88
GT
956
957#ifdef __WXDEBUG__
958 wxMessageBox(odbcErrMsg);
959#endif
108106cf
JS
960 }
961
a2115c88 962 return(FALSE); // This function always returns false.
108106cf
JS
963
964} // wxDB::DispAllErrors()
965
67e9aaa3 966
108106cf
JS
967/********** wxDB::GetNextError() **********/
968bool wxDB::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
969{
970 if (SQLError(aHenv, aHdbc, aHstmt, (UCHAR FAR *) sqlState, &nativeError, (UCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
971 return(TRUE);
972 else
973 return(FALSE);
974
975} // wxDB::GetNextError()
976
67e9aaa3 977
108106cf
JS
978/********** wxDB::DispNextError() **********/
979void wxDB::DispNextError(void)
980{
981 char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
982
983 sprintf(odbcErrMsg, "SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState, nativeError, errorMsg);
984 logError(odbcErrMsg, sqlState);
985
986 if (silent)
987 return;
988
1fc5dd6f 989#ifdef DBDEBUG_CONSOLE
108106cf
JS
990 // When run in console mode, use standard out to display errors.
991 cout << odbcErrMsg << endl;
992 cout << "Press any key to continue..." << endl;
993 getchar();
994#endif
995
996} // wxDB::DispNextError()
997
67e9aaa3 998
108106cf 999/********** wxDB::logError() **********/
6919c53f 1000void wxDB::logError(const char *errMsg, const char *SQLState)
108106cf 1001{
e8af3814 1002 assert(errMsg && wxStrlen(errMsg));
108106cf
JS
1003
1004 static int pLast = -1;
1005 int dbStatus;
1006
1007 if (++pLast == DB_MAX_ERROR_HISTORY)
1008 {
a2115c88
GT
1009 int i;
1010 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
e8af3814 1011 wxStrcpy(errorList[i], errorList[i+1]);
108106cf
JS
1012 pLast--;
1013 }
1014
e8af3814 1015 wxStrcpy(errorList[pLast], errMsg);
108106cf 1016
e8af3814 1017 if (SQLState && wxStrlen(SQLState))
108106cf
JS
1018 if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
1019 DB_STATUS = dbStatus;
1020
a2115c88
GT
1021 // Add the errmsg to the sql log
1022 WriteSqlLog(errMsg);
1023
108106cf
JS
1024} // wxDB::logError()
1025
67e9aaa3 1026
108106cf 1027/**********wxDB::TranslateSqlState() **********/
6919c53f 1028int wxDB::TranslateSqlState(const char *SQLState)
108106cf 1029{
9199e66f 1030 if (!wxStrcmp(SQLState, "01000"))
108106cf 1031 return(DB_ERR_GENERAL_WARNING);
9199e66f 1032 if (!wxStrcmp(SQLState, "01002"))
108106cf 1033 return(DB_ERR_DISCONNECT_ERROR);
9199e66f 1034 if (!wxStrcmp(SQLState, "01004"))
108106cf 1035 return(DB_ERR_DATA_TRUNCATED);
9199e66f 1036 if (!wxStrcmp(SQLState, "01006"))
108106cf 1037 return(DB_ERR_PRIV_NOT_REVOKED);
9199e66f 1038 if (!wxStrcmp(SQLState, "01S00"))
108106cf 1039 return(DB_ERR_INVALID_CONN_STR_ATTR);
9199e66f 1040 if (!wxStrcmp(SQLState, "01S01"))
108106cf 1041 return(DB_ERR_ERROR_IN_ROW);
9199e66f 1042 if (!wxStrcmp(SQLState, "01S02"))
108106cf 1043 return(DB_ERR_OPTION_VALUE_CHANGED);
9199e66f 1044 if (!wxStrcmp(SQLState, "01S03"))
108106cf 1045 return(DB_ERR_NO_ROWS_UPD_OR_DEL);
9199e66f 1046 if (!wxStrcmp(SQLState, "01S04"))
108106cf 1047 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL);
9199e66f 1048 if (!wxStrcmp(SQLState, "07001"))
108106cf 1049 return(DB_ERR_WRONG_NO_OF_PARAMS);
9199e66f 1050 if (!wxStrcmp(SQLState, "07006"))
108106cf 1051 return(DB_ERR_DATA_TYPE_ATTR_VIOL);
9199e66f 1052 if (!wxStrcmp(SQLState, "08001"))
108106cf 1053 return(DB_ERR_UNABLE_TO_CONNECT);
9199e66f 1054 if (!wxStrcmp(SQLState, "08002"))
108106cf 1055 return(DB_ERR_CONNECTION_IN_USE);
9199e66f 1056 if (!wxStrcmp(SQLState, "08003"))
108106cf 1057 return(DB_ERR_CONNECTION_NOT_OPEN);
9199e66f 1058 if (!wxStrcmp(SQLState, "08004"))
108106cf 1059 return(DB_ERR_REJECTED_CONNECTION);
9199e66f 1060 if (!wxStrcmp(SQLState, "08007"))
108106cf 1061 return(DB_ERR_CONN_FAIL_IN_TRANS);
9199e66f 1062 if (!wxStrcmp(SQLState, "08S01"))
108106cf 1063 return(DB_ERR_COMM_LINK_FAILURE);
9199e66f 1064 if (!wxStrcmp(SQLState, "21S01"))
108106cf 1065 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH);
9199e66f 1066 if (!wxStrcmp(SQLState, "21S02"))
108106cf 1067 return(DB_ERR_DERIVED_TABLE_MISMATCH);
9199e66f 1068 if (!wxStrcmp(SQLState, "22001"))
108106cf 1069 return(DB_ERR_STRING_RIGHT_TRUNC);
9199e66f 1070 if (!wxStrcmp(SQLState, "22003"))
108106cf 1071 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG);
9199e66f 1072 if (!wxStrcmp(SQLState, "22005"))
108106cf 1073 return(DB_ERR_ERROR_IN_ASSIGNMENT);
9199e66f 1074 if (!wxStrcmp(SQLState, "22008"))
108106cf 1075 return(DB_ERR_DATETIME_FLD_OVERFLOW);
9199e66f 1076 if (!wxStrcmp(SQLState, "22012"))
108106cf 1077 return(DB_ERR_DIVIDE_BY_ZERO);
9199e66f 1078 if (!wxStrcmp(SQLState, "22026"))
108106cf 1079 return(DB_ERR_STR_DATA_LENGTH_MISMATCH);
9199e66f 1080 if (!wxStrcmp(SQLState, "23000"))
108106cf 1081 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL);
9199e66f 1082 if (!wxStrcmp(SQLState, "24000"))
108106cf 1083 return(DB_ERR_INVALID_CURSOR_STATE);
9199e66f 1084 if (!wxStrcmp(SQLState, "25000"))
108106cf 1085 return(DB_ERR_INVALID_TRANS_STATE);
9199e66f 1086 if (!wxStrcmp(SQLState, "28000"))
108106cf 1087 return(DB_ERR_INVALID_AUTH_SPEC);
9199e66f 1088 if (!wxStrcmp(SQLState, "34000"))
108106cf 1089 return(DB_ERR_INVALID_CURSOR_NAME);
9199e66f 1090 if (!wxStrcmp(SQLState, "37000"))
108106cf 1091 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL);
9199e66f 1092 if (!wxStrcmp(SQLState, "3C000"))
108106cf 1093 return(DB_ERR_DUPLICATE_CURSOR_NAME);
9199e66f 1094 if (!wxStrcmp(SQLState, "40001"))
108106cf 1095 return(DB_ERR_SERIALIZATION_FAILURE);
9199e66f 1096 if (!wxStrcmp(SQLState, "42000"))
108106cf 1097 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2);
9199e66f 1098 if (!wxStrcmp(SQLState, "70100"))
108106cf 1099 return(DB_ERR_OPERATION_ABORTED);
9199e66f 1100 if (!wxStrcmp(SQLState, "IM001"))
108106cf 1101 return(DB_ERR_UNSUPPORTED_FUNCTION);
9199e66f 1102 if (!wxStrcmp(SQLState, "IM002"))
108106cf 1103 return(DB_ERR_NO_DATA_SOURCE);
9199e66f 1104 if (!wxStrcmp(SQLState, "IM003"))
108106cf 1105 return(DB_ERR_DRIVER_LOAD_ERROR);
9199e66f 1106 if (!wxStrcmp(SQLState, "IM004"))
108106cf 1107 return(DB_ERR_SQLALLOCENV_FAILED);
9199e66f 1108 if (!wxStrcmp(SQLState, "IM005"))
108106cf 1109 return(DB_ERR_SQLALLOCCONNECT_FAILED);
9199e66f 1110 if (!wxStrcmp(SQLState, "IM006"))
108106cf 1111 return(DB_ERR_SQLSETCONNECTOPTION_FAILED);
9199e66f 1112 if (!wxStrcmp(SQLState, "IM007"))
108106cf 1113 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB);
9199e66f 1114 if (!wxStrcmp(SQLState, "IM008"))
108106cf 1115 return(DB_ERR_DIALOG_FAILED);
9199e66f 1116 if (!wxStrcmp(SQLState, "IM009"))
108106cf 1117 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL);
9199e66f 1118 if (!wxStrcmp(SQLState, "IM010"))
108106cf 1119 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG);
9199e66f 1120 if (!wxStrcmp(SQLState, "IM011"))
108106cf 1121 return(DB_ERR_DRIVER_NAME_TOO_LONG);
9199e66f 1122 if (!wxStrcmp(SQLState, "IM012"))
108106cf 1123 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR);
9199e66f 1124 if (!wxStrcmp(SQLState, "IM013"))
108106cf 1125 return(DB_ERR_TRACE_FILE_ERROR);
9199e66f 1126 if (!wxStrcmp(SQLState, "S0001"))
108106cf 1127 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS);
9199e66f 1128 if (!wxStrcmp(SQLState, "S0002"))
108106cf 1129 return(DB_ERR_TABLE_NOT_FOUND);
9199e66f 1130 if (!wxStrcmp(SQLState, "S0011"))
108106cf 1131 return(DB_ERR_INDEX_ALREADY_EXISTS);
9199e66f 1132 if (!wxStrcmp(SQLState, "S0012"))
108106cf 1133 return(DB_ERR_INDEX_NOT_FOUND);
9199e66f 1134 if (!wxStrcmp(SQLState, "S0021"))
108106cf 1135 return(DB_ERR_COLUMN_ALREADY_EXISTS);
9199e66f 1136 if (!wxStrcmp(SQLState, "S0022"))
108106cf 1137 return(DB_ERR_COLUMN_NOT_FOUND);
9199e66f 1138 if (!wxStrcmp(SQLState, "S0023"))
108106cf 1139 return(DB_ERR_NO_DEFAULT_FOR_COLUMN);
9199e66f 1140 if (!wxStrcmp(SQLState, "S1000"))
108106cf 1141 return(DB_ERR_GENERAL_ERROR);
9199e66f 1142 if (!wxStrcmp(SQLState, "S1001"))
108106cf 1143 return(DB_ERR_MEMORY_ALLOCATION_FAILURE);
9199e66f 1144 if (!wxStrcmp(SQLState, "S1002"))
108106cf 1145 return(DB_ERR_INVALID_COLUMN_NUMBER);
9199e66f 1146 if (!wxStrcmp(SQLState, "S1003"))
108106cf 1147 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE);
9199e66f 1148 if (!wxStrcmp(SQLState, "S1004"))
108106cf 1149 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE);
9199e66f 1150 if (!wxStrcmp(SQLState, "S1008"))
108106cf 1151 return(DB_ERR_OPERATION_CANCELLED);
9199e66f 1152 if (!wxStrcmp(SQLState, "S1009"))
108106cf 1153 return(DB_ERR_INVALID_ARGUMENT_VALUE);
9199e66f 1154 if (!wxStrcmp(SQLState, "S1010"))
108106cf 1155 return(DB_ERR_FUNCTION_SEQUENCE_ERROR);
9199e66f 1156 if (!wxStrcmp(SQLState, "S1011"))
108106cf 1157 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME);
9199e66f 1158 if (!wxStrcmp(SQLState, "S1012"))
108106cf 1159 return(DB_ERR_INVALID_TRANS_OPERATION_CODE);
9199e66f 1160 if (!wxStrcmp(SQLState, "S1015"))
108106cf 1161 return(DB_ERR_NO_CURSOR_NAME_AVAIL);
9199e66f 1162 if (!wxStrcmp(SQLState, "S1090"))
108106cf 1163 return(DB_ERR_INVALID_STR_OR_BUF_LEN);
9199e66f 1164 if (!wxStrcmp(SQLState, "S1091"))
108106cf 1165 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE);
9199e66f 1166 if (!wxStrcmp(SQLState, "S1092"))
108106cf 1167 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE);
9199e66f 1168 if (!wxStrcmp(SQLState, "S1093"))
108106cf 1169 return(DB_ERR_INVALID_PARAM_NO);
9199e66f 1170 if (!wxStrcmp(SQLState, "S1094"))
108106cf 1171 return(DB_ERR_INVALID_SCALE_VALUE);
9199e66f 1172 if (!wxStrcmp(SQLState, "S1095"))
108106cf 1173 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE);
9199e66f 1174 if (!wxStrcmp(SQLState, "S1096"))
108106cf 1175 return(DB_ERR_INF_TYPE_OUT_OF_RANGE);
9199e66f 1176 if (!wxStrcmp(SQLState, "S1097"))
108106cf 1177 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE);
9199e66f 1178 if (!wxStrcmp(SQLState, "S1098"))
108106cf 1179 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE);
9199e66f 1180 if (!wxStrcmp(SQLState, "S1099"))
108106cf 1181 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE);
9199e66f 1182 if (!wxStrcmp(SQLState, "S1100"))
108106cf 1183 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE);
9199e66f 1184 if (!wxStrcmp(SQLState, "S1101"))
108106cf 1185 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE);
9199e66f 1186 if (!wxStrcmp(SQLState, "S1103"))
108106cf 1187 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE);
9199e66f 1188 if (!wxStrcmp(SQLState, "S1104"))
108106cf 1189 return(DB_ERR_INVALID_PRECISION_VALUE);
9199e66f 1190 if (!wxStrcmp(SQLState, "S1105"))
108106cf 1191 return(DB_ERR_INVALID_PARAM_TYPE);
9199e66f 1192 if (!wxStrcmp(SQLState, "S1106"))
108106cf 1193 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE);
9199e66f 1194 if (!wxStrcmp(SQLState, "S1107"))
108106cf 1195 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE);
9199e66f 1196 if (!wxStrcmp(SQLState, "S1108"))
108106cf 1197 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE);
9199e66f 1198 if (!wxStrcmp(SQLState, "S1109"))
108106cf 1199 return(DB_ERR_INVALID_CURSOR_POSITION);
9199e66f 1200 if (!wxStrcmp(SQLState, "S1110"))
108106cf 1201 return(DB_ERR_INVALID_DRIVER_COMPLETION);
9199e66f 1202 if (!wxStrcmp(SQLState, "S1111"))
108106cf 1203 return(DB_ERR_INVALID_BOOKMARK_VALUE);
9199e66f 1204 if (!wxStrcmp(SQLState, "S1C00"))
108106cf 1205 return(DB_ERR_DRIVER_NOT_CAPABLE);
9199e66f 1206 if (!wxStrcmp(SQLState, "S1T00"))
108106cf
JS
1207 return(DB_ERR_TIMEOUT_EXPIRED);
1208
1209 // No match
1210 return(0);
1211
1212} // wxDB::TranslateSqlState()
67e9aaa3 1213
108106cf
JS
1214
1215/********** wxDB::Grant() **********/
6919c53f 1216bool wxDB::Grant(int privileges, const char *tableName, const char *userList)
108106cf
JS
1217{
1218 char sqlStmt[DB_MAX_STATEMENT_LEN];
1219
1220 // Build the grant statement
e8af3814 1221 wxStrcpy(sqlStmt, "GRANT ");
108106cf 1222 if (privileges == DB_GRANT_ALL)
e8af3814 1223 wxStrcat(sqlStmt, "ALL");
108106cf
JS
1224 else
1225 {
1226 int c = 0;
1227 if (privileges & DB_GRANT_SELECT)
1228 {
e8af3814 1229 wxStrcat(sqlStmt, "SELECT");
108106cf
JS
1230 c++;
1231 }
1232 if (privileges & DB_GRANT_INSERT)
1233 {
1234 if (c++)
e8af3814
GT
1235 wxStrcat(sqlStmt, ", ");
1236 wxStrcat(sqlStmt, "INSERT");
108106cf
JS
1237 }
1238 if (privileges & DB_GRANT_UPDATE)
1239 {
1240 if (c++)
e8af3814
GT
1241 wxStrcat(sqlStmt, ", ");
1242 wxStrcat(sqlStmt, "UPDATE");
108106cf
JS
1243 }
1244 if (privileges & DB_GRANT_DELETE)
1245 {
1246 if (c++)
e8af3814
GT
1247 wxStrcat(sqlStmt, ", ");
1248 wxStrcat(sqlStmt, "DELETE");
108106cf
JS
1249 }
1250 }
1251
e8af3814
GT
1252 wxStrcat(sqlStmt, " ON ");
1253 wxStrcat(sqlStmt, tableName);
1254 wxStrcat(sqlStmt, " TO ");
1255 wxStrcat(sqlStmt, userList);
108106cf 1256
1fc5dd6f 1257#ifdef DBDEBUG_CONSOLE
108106cf
JS
1258 cout << endl << sqlStmt << endl;
1259#endif
1260
1fc5dd6f
JS
1261 WriteSqlLog(sqlStmt);
1262
108106cf
JS
1263 return(ExecSql(sqlStmt));
1264
1265} // wxDB::Grant()
1266
67e9aaa3 1267
108106cf 1268/********** wxDB::CreateView() **********/
6919c53f 1269bool wxDB::CreateView(const char *viewName, const char *colList, const char *pSqlStmt, bool attemptDrop)
108106cf
JS
1270{
1271 char sqlStmt[DB_MAX_STATEMENT_LEN];
1272
1273 // Drop the view first
a2115c88
GT
1274 if (attemptDrop && !DropView(viewName))
1275 return FALSE;
108106cf
JS
1276
1277 // Build the create view statement
e8af3814
GT
1278 wxStrcpy(sqlStmt, "CREATE VIEW ");
1279 wxStrcat(sqlStmt, viewName);
108106cf 1280
e8af3814 1281 if (wxStrlen(colList))
108106cf 1282 {
e8af3814
GT
1283 wxStrcat(sqlStmt, " (");
1284 wxStrcat(sqlStmt, colList);
1285 wxStrcat(sqlStmt, ")");
108106cf
JS
1286 }
1287
e8af3814
GT
1288 wxStrcat(sqlStmt, " AS ");
1289 wxStrcat(sqlStmt, pSqlStmt);
108106cf 1290
1fc5dd6f
JS
1291 WriteSqlLog(sqlStmt);
1292
1293#ifdef DBDEBUG_CONSOLE
108106cf
JS
1294 cout << sqlStmt << endl;
1295#endif
1296
1297 return(ExecSql(sqlStmt));
1298
1299} // wxDB::CreateView()
1300
67e9aaa3 1301
a2115c88 1302/********** wxDB::DropView() **********/
6919c53f 1303bool wxDB::DropView(const char *viewName)
a2115c88 1304{
67e9aaa3
GT
1305/*
1306 * NOTE: This function returns TRUE if the View does not exist, but
1307 * only for identified databases. Code will need to be added
1308 * below for any other databases when those databases are defined
1309 * to handle this situation consistently
1310 */
a2115c88
GT
1311 char sqlStmt[DB_MAX_STATEMENT_LEN];
1312
1313 sprintf(sqlStmt, "DROP VIEW %s", viewName);
1314
1315 WriteSqlLog(sqlStmt);
1316
1317#ifdef DBDEBUG_CONSOLE
1318 cout << endl << sqlStmt << endl;
1319#endif
1320
1321 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS)
1322 {
1323 // Check for "Base table not found" error and ignore
1324 GetNextError(henv, hdbc, hstmt);
9199e66f 1325 if (wxStrcmp(sqlState,"S0002")) // "Base table not found"
a2115c88
GT
1326 {
1327 // Check for product specific error codes
9199e66f 1328 if (!((Dbms() == dbmsSYBASE_ASA && !wxStrcmp(sqlState,"42000")))) // 5.x (and lower?)
a2115c88
GT
1329 {
1330 DispNextError();
1331 DispAllErrors(henv, hdbc, hstmt);
1332 RollbackTrans();
1333 return(FALSE);
1334 }
1335 }
1336 }
1337
1338 // Commit the transaction
1339 if (! CommitTrans())
1340 return(FALSE);
1341
1342 return TRUE;
1343
1344} // wxDB::DropView()
1345
1346
108106cf 1347/********** wxDB::ExecSql() **********/
6919c53f 1348bool wxDB::ExecSql(const char *pSqlStmt)
108106cf 1349{
a2115c88 1350 SQLFreeStmt(hstmt, SQL_CLOSE);
108106cf
JS
1351 if (SQLExecDirect(hstmt, (UCHAR FAR *) pSqlStmt, SQL_NTS) == SQL_SUCCESS)
1352 return(TRUE);
1353 else
1354 {
1355 DispAllErrors(henv, hdbc, hstmt);
1356 return(FALSE);
1357 }
1358
1359} // wxDB::ExecSql()
1360
67e9aaa3 1361
a2115c88
GT
1362/********** wxDB::GetNext() **********/
1363bool wxDB::GetNext(void)
1364{
1365 if (SQLFetch(hstmt) == SQL_SUCCESS)
1366 return(TRUE);
1367 else
1368 {
1369 DispAllErrors(henv, hdbc, hstmt);
1370 return(FALSE);
1371 }
1372
1373} // wxDB::GetNext()
1374
67e9aaa3 1375
a2115c88
GT
1376/********** wxDB::GetData() **********/
1377bool wxDB::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FAR *cbReturned)
1378{
1379 assert(pData);
1380 assert(cbReturned);
1381
1382 if (SQLGetData(hstmt, colNo, cType, pData, maxLen, cbReturned) == SQL_SUCCESS)
1383 return(TRUE);
1384 else
1385 {
1386 DispAllErrors(henv, hdbc, hstmt);
1387 return(FALSE);
1388 }
1389
1390} // wxDB::GetData()
1391
67e9aaa3
GT
1392
1393/********** wxDB::GetKeyFields() **********/
1394int wxDB::GetKeyFields(char *tableName, wxColInf* colInf,int noCols)
1395{
1396 char szPkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Primary key table name */
1397 char szFkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Foreign key table name */
1398 short iKeySeq;
1399// SQLSMALLINT iKeySeq;
1400 char szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */
1401 char szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */
1402 SQLRETURN retcode;
1403 SDWORD cb;
1404 int i;
1405 wxString Temp0;
1406 /*
1407 * ---------------------------------------------------------------------
1408 * -- 19991224 : mj10777@gmx.net : Create ------
1409 * -- : Three things are done and stored here : ------
1410 * -- : 1) which Column(s) is/are Primary Key(s) ------
1411 * -- : 2) which tables use this Key as a Foreign Key ------
1412 * -- : 3) which columns are Foreign Key and the name ------
1413 * -- : of the Table where the Key is the Primary Key -----
1414 * -- : Called from GetColumns(char *tableName, ------
1415 * -- int *numCols,const char *userID ) ------
1416 * ---------------------------------------------------------------------
1417 */
1418
1419 /*---------------------------------------------------------------------*/
1420 /* Get the names of the columns in the primary key. */
1421 /*---------------------------------------------------------------------*/
1422 retcode = SQLPrimaryKeys(hstmt,
1423 NULL, 0, /* Catalog name */
1424 NULL, 0, /* Schema name */
1425 (UCHAR *) tableName, SQL_NTS); /* Table name */
1426
1427 /*---------------------------------------------------------------------*/
1428 /* Fetch and display the result set. This will be a list of the */
1429 /* columns in the primary key of the tableName table. */
1430 /*---------------------------------------------------------------------*/
1431 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1432 {
1433 retcode = SQLFetch(hstmt);
1434 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1435 {
1436 GetData( 4, SQL_C_CHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1437 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
1438 //-------
1439 for (i=0;i<noCols;i++) // Find the Column name
1440 if (!wxStrcmp(colInf[i].colName,szPkCol)) // We have found the Column
1441 colInf[i].PkCol = iKeySeq; // Which Primary Key is this (first, second usw.) ?
1442 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1443 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1444 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
1445
1446 /*---------------------------------------------------------------------*/
1447 /* Get all the foreign keys that refer to tableName primary key. */
1448 /*---------------------------------------------------------------------*/
1449 retcode = SQLForeignKeys(hstmt,
1450 NULL, 0, /* Primary catalog */
1451 NULL, 0, /* Primary schema */
1452 (UCHAR *)tableName, SQL_NTS, /* Primary table */
1453 NULL, 0, /* Foreign catalog */
1454 NULL, 0, /* Foreign schema */
1455 NULL, 0); /* Foreign table */
1456
1457 /*---------------------------------------------------------------------*/
1458 /* Fetch and display the result set. This will be all of the foreign */
1459 /* keys in other tables that refer to the tableName primary key. */
1460 /*---------------------------------------------------------------------*/
1461 Temp0.Empty();
1462 szPkCol[0] = 0;
1463 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1464 {
1465 retcode = SQLFetch(hstmt);
1466 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1467 {
1468 GetData( 3, SQL_C_CHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
1469 GetData( 4, SQL_C_CHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1470 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
1471 GetData( 7, SQL_C_CHAR, szFkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
1472 GetData( 8, SQL_C_CHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1473 Temp0.Printf("%s[%s] ",Temp0.c_str(),szFkTable); // [ ] in case there is a blank in the Table name
1474 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1475 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1476 Temp0.Trim(); // Get rid of any unneeded blanks
1477 if (Temp0 != "")
1478 {
1479 for (i=0;i<noCols;i++) // Find the Column name
1480 if (!wxStrcmp(colInf[i].colName,szPkCol)) // We have found the Column, store the Information
1481 strcpy(colInf[i].PkTableName,Temp0); // Name of the Tables where this Primary Key is used as a Foreign Key
1482 } // if (Temp0 != "")
1483 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
1484
1485 /*---------------------------------------------------------------------*/
1486 /* Get all the foreign keys in the tablename table. */
1487 /*---------------------------------------------------------------------*/
1488 retcode = SQLForeignKeys(hstmt,
1489 NULL, 0, /* Primary catalog */
1490 NULL, 0, /* Primary schema */
1491 NULL, 0, /* Primary table */
1492 NULL, 0, /* Foreign catalog */
1493 NULL, 0, /* Foreign schema */
1494 (UCHAR *)tableName, SQL_NTS); /* Foreign table */
1495
1496 /*---------------------------------------------------------------------*/
1497 /* Fetch and display the result set. This will be all of the */
1498 /* primary keys in other tables that are referred to by foreign */
1499 /* keys in the tableName table. */
1500 /*---------------------------------------------------------------------*/
1501 i = 0;
1502 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1503 {
1504 retcode = SQLFetch(hstmt);
1505 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1506 {
1507 GetData( 3, SQL_C_CHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
1508 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
1509 GetData( 8, SQL_C_CHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1510 //-------
1511 for (i=0;i<noCols;i++) // Find the Column name
1512 {
1513 if (!wxStrcmp(colInf[i].colName,szFkCol)) // We have found the (Foreign Key) Column
1514 {
1515 colInf[i].FkCol = iKeySeq; // Which Foreign Key is this (first, second usw.) ?
1516 strcpy(colInf[i].FkTableName,szPkTable); // Name of the Table where this Foriegn is the Primary Key
1517 } // if (!wxStrcmp(colInf[i].colName,szFkCol))
1518 } // for (i=0;i<noCols;i++)
1519 } // if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1520 } // while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1521 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
1522
1523 /*---------------------------------------------------------------------*/
1524 return TRUE;
1525} // wxDB::GetKeyFields()
1526
1527
108106cf 1528/********** wxDB::GetColumns() **********/
67e9aaa3 1529wxColInf *wxDB::GetColumns(char *tableName[], const char *userID)
108106cf
JS
1530/*
1531 * 1) The last array element of the tableName[] argument must be zero (null).
1532 * This is how the end of the array is detected.
67e9aaa3 1533 * 2) This function returns an array of wxColInf structures. If no columns
108106cf
JS
1534 * were found, or an error occured, this pointer will be zero (null). THE
1535 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
1536 * IS FINISHED WITH IT. i.e.
1537 *
67e9aaa3 1538 * wxColInf *colInf = pDb->GetColumns(tableList, userID);
108106cf
JS
1539 * if (colInf)
1540 * {
1541 * // Use the column inf
1542 * .......
1543 * // Destroy the memory
1544 * delete [] colInf;
1545 * }
67e9aaa3
GT
1546 *
1547 * userID is evaluated in the following manner:
1548 * userID == NULL ... UserID is ignored
1549 * userID == "" ... UserID set equal to 'this->uid'
1550 * userID != "" ... UserID set equal to 'userID'
1551 *
1552 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1553 * by this function. This function should use its own wxDB instance
1554 * to avoid undesired unbinding of columns.
108106cf 1555 */
108106cf 1556{
67e9aaa3
GT
1557 int noCols = 0;
1558 int colNo = 0;
1559 wxColInf *colInf = 0;
6919c53f
GT
1560
1561 RETCODE retcode;
1562 SDWORD cb;
6919c53f
GT
1563
1564 wxString UserID;
1565 wxString TableName;
a2115c88 1566
67e9aaa3
GT
1567 if (userID)
1568 {
1569 if (!wxStrlen(userID))
1570 UserID = uid;
1571 else
1572 UserID = userID;
1573 }
6919c53f 1574 else
67e9aaa3 1575 UserID = "";
a2115c88
GT
1576
1577 // dBase does not use user names, and some drivers fail if you try to pass one
1578 if (Dbms() == dbmsDBASE)
6919c53f 1579 UserID = "";
a2115c88
GT
1580
1581 // Oracle user names may only be in uppercase, so force
1582 // the name to uppercase
1583 if (Dbms() == dbmsORACLE)
6919c53f 1584 UserID = UserID.Upper();
108106cf
JS
1585
1586 // Pass 1 - Determine how many columns there are.
67e9aaa3 1587 // Pass 2 - Allocate the wxColInf array and fill in
108106cf 1588 // the array with the column information.
a2115c88
GT
1589 int pass;
1590 for (pass = 1; pass <= 2; pass++)
108106cf
JS
1591 {
1592 if (pass == 2)
1593 {
1594 if (noCols == 0) // Probably a bogus table name(s)
1595 break;
67e9aaa3
GT
1596 // Allocate n wxColInf objects to hold the column information
1597 colInf = new wxColInf[noCols+1];
108106cf
JS
1598 if (!colInf)
1599 break;
1600 // Mark the end of the array
e8af3814
GT
1601 wxStrcpy(colInf[noCols].tableName, "");
1602 wxStrcpy(colInf[noCols].colName, "");
108106cf
JS
1603 colInf[noCols].sqlDataType = 0;
1604 }
1605 // Loop through each table name
a2115c88
GT
1606 int tbl;
1607 for (tbl = 0; tableName[tbl]; tbl++)
108106cf 1608 {
6919c53f 1609 TableName = tableName[tbl];
a2115c88
GT
1610 // Oracle table names are uppercase only, so force
1611 // the name to uppercase just in case programmer forgot to do this
1612 if (Dbms() == dbmsORACLE)
6919c53f 1613 TableName = TableName.Upper();
a2115c88 1614
108106cf 1615 SQLFreeStmt(hstmt, SQL_CLOSE);
a2115c88
GT
1616
1617 // MySQL and Access cannot accept a user name when looking up column names, so we
1618 // use the call below that leaves out the user name
6919c53f 1619 if (wxStrcmp(UserID.GetData(),"") &&
a2115c88
GT
1620 Dbms() != dbmsMY_SQL &&
1621 Dbms() != dbmsACCESS)
1622 {
1623 retcode = SQLColumns(hstmt,
1624 NULL, 0, // All qualifiers
6919c53f
GT
1625 (UCHAR *) UserID.GetData(), SQL_NTS, // Owner
1626 (UCHAR *) TableName.GetData(), SQL_NTS,
a2115c88
GT
1627 NULL, 0); // All columns
1628 }
1629 else
1630 {
1631 retcode = SQLColumns(hstmt,
1632 NULL, 0, // All qualifiers
1633 NULL, 0, // Owner
6919c53f 1634 (UCHAR *) TableName.GetData(), SQL_NTS,
a2115c88
GT
1635 NULL, 0); // All columns
1636 }
108106cf
JS
1637 if (retcode != SQL_SUCCESS)
1638 { // Error occured, abort
1639 DispAllErrors(henv, hdbc, hstmt);
1640 if (colInf)
1641 delete [] colInf;
a2115c88 1642 SQLFreeStmt(hstmt, SQL_CLOSE);
108106cf
JS
1643 return(0);
1644 }
67e9aaa3 1645
108106cf
JS
1646 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
1647 {
1648 if (pass == 1) // First pass, just add up the number of columns
1649 noCols++;
1650 else // Pass 2; Fill in the array of structures
1651 {
1652 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
1653 {
67e9aaa3
GT
1654 // NOTE: Only the ODBC 1.x fields are retrieved
1655 GetData( 1, SQL_C_CHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
1656 GetData( 2, SQL_C_CHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
1657 GetData( 3, SQL_C_CHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
1658 GetData( 4, SQL_C_CHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1659 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
1660 GetData( 6, SQL_C_CHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
1661 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnSize, 0, &cb);
1662 GetData( 8, SQL_C_SLONG, (UCHAR*) &colInf[colNo].bufferLength, 0, &cb);
1663 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
1664 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
1665 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
1666 GetData(12, SQL_C_CHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
1667
1668 // Determine the wxDB data type that is used to represent the native data type of this data source
1669 colInf[colNo].dbDataType = 0;
1670 if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
1671 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
1672 else if (!wxStricmp(typeInfInteger.TypeName,colInf[colNo].typeName))
1673 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
1674 else if (!wxStricmp(typeInfFloat.TypeName,colInf[colNo].typeName))
1675 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
1676 else if (!wxStricmp(typeInfDate.TypeName,colInf[colNo].typeName))
1677 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
1678
108106cf
JS
1679 colNo++;
1680 }
1681 }
1682 }
1683 if (retcode != SQL_NO_DATA_FOUND)
1684 { // Error occured, abort
1685 DispAllErrors(henv, hdbc, hstmt);
1686 if (colInf)
1687 delete [] colInf;
a2115c88 1688 SQLFreeStmt(hstmt, SQL_CLOSE);
108106cf
JS
1689 return(0);
1690 }
1691 }
1692 }
1693
1694 SQLFreeStmt(hstmt, SQL_CLOSE);
1695 return colInf;
1696
1697} // wxDB::GetColumns()
1698
1699
67e9aaa3
GT
1700/********** wxDB::GetColumns() **********/
1701wxColInf *wxDB::GetColumns(char *tableName, int *numCols, const char *userID)
1702/*
1703 * Same as the above GetColumns() function except this one gets columns
1704 * only for a single table, and if 'numCols' is not NULL, the number of
1705 * columns stored in the returned wxColInf is set in '*numCols'
1706 *
1707 * userID is evaluated in the following manner:
1708 * userID == NULL ... UserID is ignored
1709 * userID == "" ... UserID set equal to 'this->uid'
1710 * userID != "" ... UserID set equal to 'userID'
1711 *
1712 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1713 * by this function. This function should use its own wxDB instance
1714 * to avoid undesired unbinding of columns.
1715 */
1716{
1717 int noCols = 0;
1718 int colNo = 0;
1719 wxColInf *colInf = 0;
1720
1721 RETCODE retcode;
1722 SDWORD cb;
1723
1724 wxString UserID;
1725 wxString TableName;
1726
1727 if (userID)
1728 {
1729 if (!wxStrlen(userID))
1730 UserID = uid;
1731 else
1732 UserID = userID;
1733 }
1734 else
1735 UserID = "";
1736
1737 // dBase does not use user names, and some drivers fail if you try to pass one
1738 if (Dbms() == dbmsDBASE)
1739 UserID = "";
1740
1741 // Oracle user names may only be in uppercase, so force
1742 // the name to uppercase
1743 if (Dbms() == dbmsORACLE)
1744 UserID = UserID.Upper();
1745
1746 // Pass 1 - Determine how many columns there are.
1747 // Pass 2 - Allocate the wxColInf array and fill in
1748 // the array with the column information.
1749 int pass;
1750 for (pass = 1; pass <= 2; pass++)
1751 {
1752 if (pass == 2)
1753 {
1754 if (noCols == 0) // Probably a bogus table name(s)
1755 break;
1756 // Allocate n wxColInf objects to hold the column information
1757 colInf = new wxColInf[noCols+1];
1758 if (!colInf)
1759 break;
1760 // Mark the end of the array
1761 wxStrcpy(colInf[noCols].tableName, "");
1762 wxStrcpy(colInf[noCols].colName, "");
1763 colInf[noCols].sqlDataType = 0;
1764 }
1765
1766 TableName = tableName;
1767 // Oracle table names are uppercase only, so force
1768 // the name to uppercase just in case programmer forgot to do this
1769 if (Dbms() == dbmsORACLE)
1770 TableName = TableName.Upper();
1771
1772 SQLFreeStmt(hstmt, SQL_CLOSE);
1773
1774 // MySQL and Access cannot accept a user name when looking up column names, so we
1775 // use the call below that leaves out the user name
1776 if (wxStrcmp(UserID.GetData(),"") &&
1777 Dbms() != dbmsMY_SQL &&
1778 Dbms() != dbmsACCESS)
1779 {
1780 retcode = SQLColumns(hstmt,
1781 NULL, 0, // All qualifiers
1782 (UCHAR *) UserID.GetData(), SQL_NTS, // Owner
1783 (UCHAR *) TableName.GetData(), SQL_NTS,
1784 NULL, 0); // All columns
1785 }
1786 else
1787 {
1788 retcode = SQLColumns(hstmt,
1789 NULL, 0, // All qualifiers
1790 NULL, 0, // Owner
1791 (UCHAR *) TableName.GetData(), SQL_NTS,
1792 NULL, 0); // All columns
1793 }
1794 if (retcode != SQL_SUCCESS)
1795 { // Error occured, abort
1796 DispAllErrors(henv, hdbc, hstmt);
1797 if (colInf)
1798 delete [] colInf;
1799 SQLFreeStmt(hstmt, SQL_CLOSE);
1800 if (numCols)
1801 *numCols = 0;
1802 return(0);
1803 }
1804
1805 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
1806 {
1807 if (pass == 1) // First pass, just add up the number of columns
1808 noCols++;
1809 else // Pass 2; Fill in the array of structures
1810 {
1811 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
1812 {
1813 // NOTE: Only the ODBC 1.x fields are retrieved
1814 GetData( 1, SQL_C_CHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
1815 GetData( 2, SQL_C_CHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
1816 GetData( 3, SQL_C_CHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
1817 GetData( 4, SQL_C_CHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1818 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
1819 GetData( 6, SQL_C_CHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
1820 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnSize, 0, &cb);
1821 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
1822 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferLength, 0, &cb);
1823 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
1824 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
1825 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
1826 GetData(12, SQL_C_CHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
1827 // Start Values for Primary/Foriegn Key (=No)
1828 colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
1829 colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
1830 colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
1831 colInf[colNo].FkTableName[0] = 0; // Foreign key table name
1832
1833 // Determine the wxDB data type that is used to represent the native data type of this data source
1834 colInf[colNo].dbDataType = 0;
1835 if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
1836 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
1837 else if (!wxStricmp(typeInfInteger.TypeName,colInf[colNo].typeName))
1838 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
1839 else if (!wxStricmp(typeInfFloat.TypeName,colInf[colNo].typeName))
1840 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
1841 else if (!wxStricmp(typeInfDate.TypeName,colInf[colNo].typeName))
1842 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
1843
1844 colNo++;
1845 }
1846 }
1847 }
1848 if (retcode != SQL_NO_DATA_FOUND)
1849 { // Error occured, abort
1850 DispAllErrors(henv, hdbc, hstmt);
1851 if (colInf)
1852 delete [] colInf;
1853 SQLFreeStmt(hstmt, SQL_CLOSE);
1854 if (numCols)
1855 *numCols = 0;
1856 return(0);
1857 }
1858 }
1859
1860 SQLFreeStmt(hstmt, SQL_CLOSE);
1861
1862 // Store Primary and Foriegn Keys
1863 GetKeyFields(tableName,colInf,noCols);
1864
1865 if (numCols)
1866 *numCols = noCols;
1867 return colInf;
1868
1869} // wxDB::GetColumns()
1870
1871
1872/********** wxDB::GetColumnCount() **********/
1873int wxDB::GetColumnCount(char *tableName, const char *userID)
1874/*
1875 * Returns a count of how many columns are in a table.
1876 * If an error occurs in computing the number of columns
1877 * this function will return a -1 for the count
1878 *
1879 * userID is evaluated in the following manner:
1880 * userID == NULL ... UserID is ignored
1881 * userID == "" ... UserID set equal to 'this->uid'
1882 * userID != "" ... UserID set equal to 'userID'
1883 *
1884 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1885 * by this function. This function should use its own wxDB instance
1886 * to avoid undesired unbinding of columns.
1887 */
1888{
1889 int noCols = 0;
1890
1891 RETCODE retcode;
1892
1893 wxString UserID;
1894 wxString TableName;
1895
1896 if (userID)
1897 {
1898 if (!wxStrlen(userID))
1899 UserID = uid;
1900 else
1901 UserID = userID;
1902 }
1903 else
1904 UserID = "";
1905
1906 // dBase does not use user names, and some drivers fail if you try to pass one
1907 if (Dbms() == dbmsDBASE)
1908 UserID = "";
1909
1910 // Oracle user names may only be in uppercase, so force
1911 // the name to uppercase
1912 if (Dbms() == dbmsORACLE)
1913 UserID = UserID.Upper();
1914
1915 {
1916 // Loop through each table name
1917 {
1918 TableName = tableName;
1919 // Oracle table names are uppercase only, so force
1920 // the name to uppercase just in case programmer forgot to do this
1921 if (Dbms() == dbmsORACLE)
1922 TableName = TableName.Upper();
1923
1924 SQLFreeStmt(hstmt, SQL_CLOSE);
1925
1926 // MySQL and Access cannot accept a user name when looking up column names, so we
1927 // use the call below that leaves out the user name
1928 if (wxStrcmp(UserID.GetData(),"") &&
1929 Dbms() != dbmsMY_SQL &&
1930 Dbms() != dbmsACCESS)
1931 {
1932 retcode = SQLColumns(hstmt,
1933 NULL, 0, // All qualifiers
1934 (UCHAR *) UserID.GetData(), SQL_NTS, // Owner
1935 (UCHAR *) TableName.GetData(), SQL_NTS,
1936 NULL, 0); // All columns
1937 }
1938 else
1939 {
1940 retcode = SQLColumns(hstmt,
1941 NULL, 0, // All qualifiers
1942 NULL, 0, // Owner
1943 (UCHAR *) TableName.GetData(), SQL_NTS,
1944 NULL, 0); // All columns
1945 }
1946 if (retcode != SQL_SUCCESS)
1947 { // Error occured, abort
1948 DispAllErrors(henv, hdbc, hstmt);
1949 SQLFreeStmt(hstmt, SQL_CLOSE);
1950 return(-1);
1951 }
1952
1953 // Count the columns
1954 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
1955 noCols++;
1956
1957 if (retcode != SQL_NO_DATA_FOUND)
1958 { // Error occured, abort
1959 DispAllErrors(henv, hdbc, hstmt);
1960 SQLFreeStmt(hstmt, SQL_CLOSE);
1961 return(-1);
1962 }
1963 }
1964 }
1965
1966 SQLFreeStmt(hstmt, SQL_CLOSE);
1967 return noCols;
1968
1969} // wxDB::GetColumnCount()
1970
1971
1972/********** wxDB::GetCatalog() *******/
1973wxDbInf *wxDB::GetCatalog(char *userID)
1974/*
1975 * ---------------------------------------------------------------------
1976 * -- 19991203 : mj10777@gmx.net : Create ------
1977 * -- : Creates a wxDbInf with Tables / Cols Array ------
1978 * -- : uses SQLTables and fills pTableInf; ------
1979 * -- : pColInf is set to NULL and numCols to 0; ------
1980 * -- : returns pDbInf (wxDbInf) ------
1981 * -- - if unsuccesfull (pDbInf == NULL) ------
1982 * -- : pColInf can be filled with GetColumns(..); ------
1983 * -- : numCols can be filled with GetColumnCount(..); ------
1984 * ---------------------------------------------------------------------
1985 *
1986 * userID is evaluated in the following manner:
1987 * userID == NULL ... UserID is ignored
1988 * userID == "" ... UserID set equal to 'this->uid'
1989 * userID != "" ... UserID set equal to 'userID'
1990 *
1991 * NOTE: ALL column bindings associated with this wxDB instance are unbound
1992 * by this function. This function should use its own wxDB instance
1993 * to avoid undesired unbinding of columns.
1994 */
1995{
1996 wxDbInf *pDbInf = NULL; // Array of catalog entries
1997 int noTab = 0; // Counter while filling table entries
67e9aaa3
GT
1998 int pass;
1999 RETCODE retcode;
2000 SDWORD cb;
2001 char tblNameSave[DB_MAX_TABLE_NAME_LEN+1];
2002
2003 wxString UserID;
2004
2005 if (userID)
2006 {
2007 if (!wxStrlen(userID))
2008 UserID = uid;
2009 else
2010 UserID = userID;
2011 }
2012 else
2013 UserID = "";
2014
2015 // dBase does not use user names, and some drivers fail if you try to pass one
2016 if (Dbms() == dbmsDBASE)
2017 UserID = "";
2018
2019 // Oracle user names may only be in uppercase, so force
2020 // the name to uppercase
2021 if (Dbms() == dbmsORACLE)
2022 UserID = UserID.Upper();
2023
2024 //-------------------------------------------------------------
2025 pDbInf = new wxDbInf; // Create the Database Arrray
2026 pDbInf->catalog[0] = 0;
2027 pDbInf->schema[0] = 0;
2028 pDbInf->numTables = 0; // Counter for Tables
2029 pDbInf->pTableInf = NULL; // Array of Tables
2030 //-------------------------------------------------------------
2031 // Table Information
2032 // Pass 1 - Determine how many Tables there are.
2033 // Pass 2 - Create the Table array and fill it
2034 // - Create the Cols array = NULL
2035 //-------------------------------------------------------------
2036 for (pass = 1; pass <= 2; pass++)
2037 {
2038 SQLFreeStmt(hstmt, SQL_CLOSE); // Close if Open
2039 strcpy(tblNameSave,"");
2040
2041 if (wxStrcmp(UserID.GetData(),"") &&
2042 Dbms() != dbmsMY_SQL &&
2043 Dbms() != dbmsACCESS)
2044 {
2045 retcode = SQLTables(hstmt,
2046 NULL, 0, // All qualifiers
2047 (UCHAR *) UserID.GetData(), SQL_NTS, // User specified
2048 NULL, 0, // All tables
2049 NULL, 0); // All columns
2050 }
2051 else
2052 {
2053 retcode = SQLTables(hstmt,
2054 NULL, 0, // All qualifiers
2055 NULL, 0, // User specified
2056 NULL, 0, // All tables
2057 NULL, 0); // All columns
2058 }
2059 if (retcode != SQL_SUCCESS)
2060 {
2061 DispAllErrors(henv, hdbc, hstmt);
2062 pDbInf = NULL;
2063 SQLFreeStmt(hstmt, SQL_CLOSE);
2064 return pDbInf;
2065 }
2066
2067 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) // Table Information
2068 {
2069 if (pass == 1) // First pass, just count the Tables
2070 {
2071 if (pDbInf->numTables == 0)
2072 {
2073 GetData( 1, SQL_C_CHAR, (UCHAR*) pDbInf->catalog, 128+1, &cb);
2074 GetData( 2, SQL_C_CHAR, (UCHAR*) pDbInf->schema, 128+1, &cb);
2075 }
2076 pDbInf->numTables++; // Counter for Tables
2077 } // if (pass == 1)
2078 if (pass == 2) // Create and fill the Table entries
2079 {
2080 if (pDbInf->pTableInf == NULL) // Has the Table Array been created
2081 { // no, then create the Array
2082 pDbInf->pTableInf = new wxTableInf[pDbInf->numTables];
2083 for (noTab=0;noTab<pDbInf->numTables;noTab++)
2084 {
2085 (pDbInf->pTableInf+noTab)->tableName[0] = 0;
2086 (pDbInf->pTableInf+noTab)->tableType[0] = 0;
2087 (pDbInf->pTableInf+noTab)->tableRemarks[0] = 0;
2088 (pDbInf->pTableInf+noTab)->numCols = 0;
2089 (pDbInf->pTableInf+noTab)->pColInf = NULL;
2090 }
2091 noTab = 0;
2092 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
2093 GetData( 3, SQL_C_CHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2094 GetData( 4, SQL_C_CHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableType, 30+1, &cb);
2095 GetData( 5, SQL_C_CHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableRemarks, 254+1, &cb);
2096 noTab++;
2097 } // if (pass == 2) We now know the amount of Tables
2098 } // while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2099 } // for (pass = 1; pass <= 2; pass++)
2100 SQLFreeStmt(hstmt, SQL_CLOSE);
2101
2102 // Query how many columns are in each table
2103 for (noTab=0;noTab<pDbInf->numTables;noTab++)
2104 {
2105 (pDbInf->pTableInf+noTab)->numCols = GetColumnCount((pDbInf->pTableInf+noTab)->tableName,UserID);
2106 }
2107 return pDbInf;
2108} // wxDB::GetCatalog()
2109
2110
1fc5dd6f 2111/********** wxDB::Catalog() **********/
6919c53f 2112bool wxDB::Catalog(const char *userID, const char *fileName)
67e9aaa3
GT
2113/*
2114 * Creates the text file specified in 'filename' which will contain
2115 * a minimal data dictionary of all tables accessible by the user specified
2116 * in 'userID'
2117 *
2118 * userID is evaluated in the following manner:
2119 * userID == NULL ... UserID is ignored
2120 * userID == "" ... UserID set equal to 'this->uid'
2121 * userID != "" ... UserID set equal to 'userID'
2122 *
2123 * NOTE: ALL column bindings associated with this wxDB instance are unbound
2124 * by this function. This function should use its own wxDB instance
2125 * to avoid undesired unbinding of columns.
2126 */
1fc5dd6f 2127{
e8af3814 2128 assert(fileName && wxStrlen(fileName));
1fc5dd6f
JS
2129
2130 RETCODE retcode;
2131 SDWORD cb;
2132 char tblName[DB_MAX_TABLE_NAME_LEN+1];
2133 char tblNameSave[DB_MAX_TABLE_NAME_LEN+1];
2134 char colName[DB_MAX_COLUMN_NAME_LEN+1];
2135 SWORD sqlDataType;
a2115c88 2136 char typeName[30+1];
1fc5dd6f
JS
2137 SWORD precision, length;
2138
6919c53f
GT
2139 wxString UserID;
2140
1fc5dd6f
JS
2141 FILE *fp = fopen(fileName,"wt");
2142 if (fp == NULL)
2143 return(FALSE);
2144
2145 SQLFreeStmt(hstmt, SQL_CLOSE);
2146
67e9aaa3
GT
2147 if (userID)
2148 {
2149 if (!wxStrlen(userID))
2150 UserID = uid;
2151 else
2152 UserID = userID;
2153 }
6919c53f 2154 else
67e9aaa3
GT
2155 UserID = "";
2156
2157 // dBase does not use user names, and some drivers fail if you try to pass one
2158 if (Dbms() == dbmsDBASE)
2159 UserID = "";
a2115c88 2160
a2115c88
GT
2161 // Oracle user names may only be in uppercase, so force
2162 // the name to uppercase
2163 if (Dbms() == dbmsORACLE)
6919c53f 2164 UserID = UserID.Upper();
a2115c88 2165
67e9aaa3
GT
2166 if (wxStrcmp(UserID.GetData(),"") &&
2167 Dbms() != dbmsMY_SQL &&
2168 Dbms() != dbmsACCESS)
a2115c88
GT
2169 {
2170 retcode = SQLColumns(hstmt,
2171 NULL, 0, // All qualifiers
6919c53f 2172 (UCHAR *) UserID.GetData(), SQL_NTS, // User specified
a2115c88
GT
2173 NULL, 0, // All tables
2174 NULL, 0); // All columns
2175 }
2176 else
2177 {
2178 retcode = SQLColumns(hstmt,
2179 NULL, 0, // All qualifiers
2180 NULL, 0, // User specified
2181 NULL, 0, // All tables
2182 NULL, 0); // All columns
2183 }
1fc5dd6f
JS
2184 if (retcode != SQL_SUCCESS)
2185 {
2186 DispAllErrors(henv, hdbc, hstmt);
2187 fclose(fp);
2188 return(FALSE);
2189 }
2190
67e9aaa3 2191 wxString outStr;
e8af3814 2192 wxStrcpy(tblNameSave,"");
1fc5dd6f
JS
2193 int cnt = 0;
2194
2195 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2196 {
9199e66f 2197 if (wxStrcmp(tblName,tblNameSave))
1fc5dd6f
JS
2198 {
2199 if (cnt)
2200 fputs("\n", fp);
2201 fputs("================================ ", fp);
2202 fputs("================================ ", fp);
2203 fputs("===================== ", fp);
2204 fputs("========= ", fp);
2205 fputs("=========\n", fp);
67e9aaa3 2206 outStr.sprintf("%-32s %-32s %-21s %9s %9s\n",
1fc5dd6f 2207 "TABLE NAME", "COLUMN NAME", "DATA TYPE", "PRECISION", "LENGTH");
67e9aaa3 2208 fputs(outStr.GetData(), fp);
1fc5dd6f
JS
2209 fputs("================================ ", fp);
2210 fputs("================================ ", fp);
2211 fputs("===================== ", fp);
2212 fputs("========= ", fp);
2213 fputs("=========\n", fp);
e8af3814 2214 wxStrcpy(tblNameSave,tblName);
1fc5dd6f 2215 }
67e9aaa3
GT
2216
2217 GetData(3,SQL_C_CHAR, (UCHAR *)tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2218 GetData(4,SQL_C_CHAR, (UCHAR *)colName, DB_MAX_COLUMN_NAME_LEN+1,&cb);
2219 GetData(5,SQL_C_SSHORT,(UCHAR *)&sqlDataType,0, &cb);
2220 GetData(6,SQL_C_CHAR, (UCHAR *)typeName, sizeof(typeName), &cb);
2221 GetData(7,SQL_C_SSHORT,(UCHAR *)&precision, 0, &cb);
2222 GetData(8,SQL_C_SSHORT,(UCHAR *)&length, 0, &cb);
2223
2224 outStr.sprintf("%-32s %-32s (%04d)%-15s %9d %9d\n",
1fc5dd6f 2225 tblName, colName, sqlDataType, typeName, precision, length);
67e9aaa3 2226 if (fputs(outStr.GetData(), fp) == EOF)
1fc5dd6f 2227 {
a2115c88 2228 SQLFreeStmt(hstmt, SQL_CLOSE);
1fc5dd6f
JS
2229 fclose(fp);
2230 return(FALSE);
2231 }
2232 cnt++;
2233 }
2234
2235 if (retcode != SQL_NO_DATA_FOUND)
1fc5dd6f 2236 DispAllErrors(henv, hdbc, hstmt);
1fc5dd6f
JS
2237
2238 SQLFreeStmt(hstmt, SQL_CLOSE);
a2115c88 2239
1fc5dd6f 2240 fclose(fp);
a2115c88 2241 return(retcode == SQL_NO_DATA_FOUND);
1fc5dd6f
JS
2242
2243} // wxDB::Catalog()
2244
2245
6919c53f 2246bool wxDB::TableExists(const char *tableName, const char *userID, const char *tablePath)
67e9aaa3
GT
2247/*
2248 * Table name can refer to a table, view, alias or synonym. Returns true
2249 * if the object exists in the database. This function does not indicate
2250 * whether or not the user has privleges to query or perform other functions
2251 * on the table.
2252 *
2253 * userID is evaluated in the following manner:
2254 * userID == NULL ... UserID is ignored
2255 * userID == "" ... UserID set equal to 'this->uid'
2256 * userID != "" ... UserID set equal to 'userID'
2257 */
108106cf 2258{
6919c53f
GT
2259 wxString UserID;
2260 wxString TableName;
2261
e8af3814 2262 assert(tableName && wxStrlen(tableName));
108106cf 2263
a2115c88
GT
2264 if (Dbms() == dbmsDBASE)
2265 {
2266 wxString dbName;
e8af3814 2267 if (tablePath && wxStrlen(tablePath))
a2115c88
GT
2268 dbName.sprintf("%s/%s.dbf",tablePath,tableName);
2269 else
2270 dbName.sprintf("%s.dbf",tableName);
6919c53f
GT
2271
2272 bool exists;
2273 exists = wxFileExists(dbName.GetData());
2274 return exists;
a2115c88
GT
2275 }
2276
67e9aaa3
GT
2277 if (userID)
2278 {
2279 if (!wxStrlen(userID))
2280 UserID = uid;
2281 else
2282 UserID = userID;
2283 }
6919c53f 2284 else
67e9aaa3 2285 UserID = "";
a2115c88 2286
a2115c88
GT
2287 // Oracle user names may only be in uppercase, so force
2288 // the name to uppercase
2289 if (Dbms() == dbmsORACLE)
6919c53f 2290 UserID = UserID.Upper();
a2115c88 2291
6919c53f 2292 TableName = tableName;
a2115c88
GT
2293 // Oracle table names are uppercase only, so force
2294 // the name to uppercase just in case programmer forgot to do this
2295 if (Dbms() == dbmsORACLE)
6919c53f 2296 TableName = TableName.Upper();
a2115c88 2297
108106cf 2298 SQLFreeStmt(hstmt, SQL_CLOSE);
a2115c88
GT
2299 RETCODE retcode;
2300
2301 // MySQL and Access cannot accept a user name when looking up table names, so we
2302 // use the call below that leaves out the user name
6919c53f 2303 if (wxStrcmp(UserID,"") &&
a2115c88
GT
2304 Dbms() != dbmsMY_SQL &&
2305 Dbms() != dbmsACCESS)
2306 {
2307 retcode = SQLTables(hstmt,
6919c53f
GT
2308 NULL, 0, // All qualifiers
2309 (UCHAR *) UserID.GetData(), SQL_NTS, // All owners
2310 (UCHAR FAR *)TableName.GetData(), SQL_NTS,
2311 NULL, 0); // All table types
a2115c88
GT
2312 }
2313 else
2314 {
2315 retcode = SQLTables(hstmt,
6919c53f
GT
2316 NULL, 0, // All qualifiers
2317 NULL, 0, // All owners
2318 (UCHAR FAR *)TableName.GetData(), SQL_NTS,
2319 NULL, 0); // All table types
a2115c88 2320 }
108106cf
JS
2321 if (retcode != SQL_SUCCESS)
2322 return(DispAllErrors(henv, hdbc, hstmt));
2323
a2115c88
GT
2324 retcode = SQLFetch(hstmt);
2325 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
108106cf
JS
2326 {
2327 SQLFreeStmt(hstmt, SQL_CLOSE);
2328 return(DispAllErrors(henv, hdbc, hstmt));
2329 }
2330
2331 SQLFreeStmt(hstmt, SQL_CLOSE);
2332 return(TRUE);
2333
2334} // wxDB::TableExists()
2335
2336
1fc5dd6f 2337/********** wxDB::SqlLog() **********/
6919c53f 2338bool wxDB::SqlLog(enum sqlLog state, const char *filename, bool append)
1fc5dd6f
JS
2339{
2340 assert(state == sqlLogON || state == sqlLogOFF);
2341 assert(state == sqlLogOFF || filename);
2342
2343 if (state == sqlLogON)
2344 {
2345 if (fpSqlLog == 0)
2346 {
2347 fpSqlLog = fopen(filename, (append ? "at" : "wt"));
2348 if (fpSqlLog == NULL)
2349 return(FALSE);
2350 }
2351 }
2352 else // sqlLogOFF
2353 {
2354 if (fpSqlLog)
2355 {
2356 if (fclose(fpSqlLog))
2357 return(FALSE);
2358 fpSqlLog = 0;
2359 }
2360 }
2361
2362 sqlLogState = state;
2363 return(TRUE);
2364
2365} // wxDB::SqlLog()
2366
2367
2368/********** wxDB::WriteSqlLog() **********/
6919c53f 2369bool wxDB::WriteSqlLog(const char *logMsg)
1fc5dd6f
JS
2370{
2371 assert(logMsg);
2372
2373 if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
2374 return(FALSE);
2375
2376 if (fputs("\n", fpSqlLog) == EOF) return(FALSE);
2377 if (fputs(logMsg, fpSqlLog) == EOF) return(FALSE);
2378 if (fputs("\n", fpSqlLog) == EOF) return(FALSE);
2379
2380 return(TRUE);
2381
2382} // wxDB::WriteSqlLog()
2383
2384
a2115c88 2385/********** wxDB::Dbms() **********/
67e9aaa3 2386DBMS wxDB::Dbms(void)
a2115c88
GT
2387/*
2388 * Be aware that not all database engines use the exact same syntax, and not
2389 * every ODBC compliant database is compliant to the same level of compliancy.
2390 * Some manufacturers support the minimum Level 1 compliancy, and others up
2391 * through Level 3. Others support subsets of features for levels above 1.
2392 *
2393 * If you find an inconsistency between the wxDB class and a specific database
2394 * engine, and an identifier to this section, and special handle the database in
2395 * the area where behavior is non-conforming with the other databases.
2396 *
2397 *
2398 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
2399 * ---------------------------------------------------
2400 *
2401 * ORACLE
2402 * - Currently the only database supported by the class to support VIEWS
2403 *
2404 * DBASE
2405 * - Does not support the SQL_TIMESTAMP structure
2406 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
2407 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
2408 * is TRUE. The user must create ALL indexes from their program.
2409 * - Table names can only be 8 characters long
2410 * - Column names can only be 10 characters long
2411 *
2412 * SYBASE (all)
2413 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
2414 * after every table name involved in the query/join if that tables matching record(s)
2415 * are to be locked
2416 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
2417 *
2418 * SYBASE (Enterprise)
2419 * - If a column is part of the Primary Key, the column cannot be NULL
2420 *
2421 * MY_SQL
2422 * - If a column is part of the Primary Key, the column cannot be NULL
2423 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
2424 *
2425 * POSTGRES
2426 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
2427 *
2428 *
2429 */
a2115c88 2430{
a3439c7d 2431 wxChar baseName[25+1];
aa33452c 2432
a3439c7d 2433 wxStrncpy(baseName,dbInf.dbmsName,25);
9199e66f 2434 if (!wxStricmp(dbInf.dbmsName,"Adaptive Server Anywhere"))
a2115c88 2435 return(dbmsSYBASE_ASA);
a3439c7d 2436 if (!wxStricmp(dbInf.dbmsName,"SQL Server")) // Sybase Adaptive Server
a2115c88 2437 return(dbmsSYBASE_ASE);
9199e66f 2438 if (!wxStricmp(dbInf.dbmsName,"Microsoft SQL Server"))
a2115c88 2439 return(dbmsMS_SQL_SERVER);
9199e66f 2440 if (!wxStricmp(dbInf.dbmsName,"MySQL"))
a2115c88 2441 return(dbmsMY_SQL);
9199e66f 2442 if (!wxStricmp(dbInf.dbmsName,"PostgreSQL")) // v6.5.0
a2115c88 2443 return(dbmsPOSTGRES);
a3439c7d
GT
2444
2445 baseName[8] = 0;
2446 if (!wxStricmp(baseName,"Informix"))
2447 return(dbmsINFORMIX);
2448
2449 baseName[6] = 0;
2450 if (!wxStricmp(baseName,"Oracle"))
2451 return(dbmsORACLE);
9199e66f 2452 if (!wxStricmp(dbInf.dbmsName,"ACCESS"))
a2115c88 2453 return(dbmsACCESS);
a3439c7d
GT
2454 if (!wxStricmp(dbInf.dbmsName,"MySQL"))
2455 return(dbmsMY_SQL);
2456
aa33452c 2457 baseName[5] = 0;
aa33452c 2458 if (!wxStricmp(baseName,"DBASE"))
a2115c88 2459 return(dbmsDBASE);
e8af3814 2460
a2115c88 2461 return(dbmsUNIDENTIFIED);
a2115c88
GT
2462} // wxDB::Dbms()
2463
2464
108106cf 2465/********** GetDbConnection() **********/
a3439c7d 2466wxDB WXDLLEXPORT *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors)
108106cf
JS
2467{
2468 DbList *pList;
2469
2470 // Scan the linked list searching for an available database connection
2471 // that's already been opened but is currently not in use.
2472 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
2473 {
2474 // The database connection must be for the same datasource
2475 // name and must currently not be in use.
9199e66f 2476 if (pList->Free && (! wxStrcmp(pDbStuff->Dsn, pList->Dsn))) // Found a free connection
108106cf
JS
2477 {
2478 pList->Free = FALSE;
2479 return(pList->PtrDb);
2480 }
2481 }
2482
2483 // No available connections. A new connection must be made and
2484 // appended to the end of the linked list.
2485 if (PtrBegDbList)
2486 {
2487 // Find the end of the list
2488 for (pList = PtrBegDbList; pList->PtrNext; pList = pList->PtrNext);
2489 // Append a new list item
2490 pList->PtrNext = new DbList;
2491 pList->PtrNext->PtrPrev = pList;
2492 pList = pList->PtrNext;
2493 }
2494 else // Empty list
2495 {
2496 // Create the first node on the list
2497 pList = PtrBegDbList = new DbList;
2498 pList->PtrPrev = 0;
2499 }
2500
2501 // Initialize new node in the linked list
2502 pList->PtrNext = 0;
2503 pList->Free = FALSE;
e8af3814 2504 wxStrcpy(pList->Dsn, pDbStuff->Dsn);
a3439c7d 2505 pList->PtrDb = new wxDB(pDbStuff->Henv,FwdOnlyCursors);
108106cf
JS
2506
2507 // Connect to the datasource
2508 if (pList->PtrDb->Open(pDbStuff->Dsn, pDbStuff->Uid, pDbStuff->AuthStr))
a2115c88
GT
2509 {
2510 pList->PtrDb->SqlLog(SQLLOGstate,SQLLOGfn,TRUE);
108106cf 2511 return(pList->PtrDb);
a2115c88 2512 }
108106cf
JS
2513 else // Unable to connect, destroy list item
2514 {
2515 if (pList->PtrPrev)
2516 pList->PtrPrev->PtrNext = 0;
2517 else
2518 PtrBegDbList = 0; // Empty list again
2519 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDB object
2520 pList->PtrDb->Close(); // Close the wxDB object
2521 delete pList->PtrDb; // Deletes the wxDB object
2522 delete pList; // Deletes the linked list object
2523 return(0);
2524 }
2525
2526} // GetDbConnection()
2527
67e9aaa3 2528
108106cf 2529/********** FreeDbConnection() **********/
a1218415 2530bool WXDLLEXPORT FreeDbConnection(wxDB *pDb)
108106cf
JS
2531{
2532 DbList *pList;
2533
2534 // Scan the linked list searching for the database connection
2535 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
2536 {
2537 if (pList->PtrDb == pDb) // Found it!!!
2538 return(pList->Free = TRUE);
2539 }
2540
2541 // Never found the database object, return failure
2542 return(FALSE);
2543
2544} // FreeDbConnection()
2545
67e9aaa3 2546
108106cf 2547/********** CloseDbConnections() **********/
a1218415 2548void WXDLLEXPORT CloseDbConnections(void)
108106cf
JS
2549{
2550 DbList *pList, *pNext;
2551
2552 // Traverse the linked list closing database connections and freeing memory as I go.
2553 for (pList = PtrBegDbList; pList; pList = pNext)
2554 {
2555 pNext = pList->PtrNext; // Save the pointer to next
2556 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDB object
2557 pList->PtrDb->Close(); // Close the wxDB object
2558 delete pList->PtrDb; // Deletes the wxDB object
2559 delete pList; // Deletes the linked list object
2560 }
2561
2562 // Mark the list as empty
2563 PtrBegDbList = 0;
2564
2565} // CloseDbConnections()
2566
67e9aaa3 2567
108106cf 2568/********** NumberDbConnectionsInUse() **********/
a1218415 2569int WXDLLEXPORT NumberDbConnectionsInUse(void)
108106cf
JS
2570{
2571 DbList *pList;
2572 int cnt = 0;
2573
2574 // Scan the linked list counting db connections that are currently in use
2575 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
2576 {
2577 if (pList->Free == FALSE)
2578 cnt++;
2579 }
2580
2581 return(cnt);
2582
2583} // NumberDbConnectionsInUse()
2584
67e9aaa3 2585
a2115c88
GT
2586/********** SqlLog() **********/
2587bool SqlLog(enum sqlLog state, char *filename)
2588{
2589 bool append = FALSE;
2590 DbList *pList;
2591
2592 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
2593 {
2594 if (!pList->PtrDb->SqlLog(state,filename,append))
2595 return(FALSE);
2596 append = TRUE;
2597 }
2598
2599 SQLLOGstate = state;
e8af3814 2600 wxStrcpy(SQLLOGfn,filename);
a2115c88
GT
2601
2602 return(TRUE);
2603
2604} // SqlLog()
2605
67e9aaa3 2606
108106cf 2607/********** GetDataSource() **********/
67e9aaa3 2608bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
108106cf 2609 UWORD direction)
67e9aaa3
GT
2610/*
2611 * Dsn and DsDesc will contain the data source name and data source
2612 * description upon return
2613 */
108106cf
JS
2614{
2615 SWORD cb;
2616
2617 if (SQLDataSources(henv, direction, (UCHAR FAR *) Dsn, DsnMax, &cb,
2618 (UCHAR FAR *) DsDesc, DsDescMax, &cb) == SQL_SUCCESS)
67e9aaa3
GT
2619 {
2620 DsDesc[cb+1] = 0; // Set the terminating character for the string
108106cf 2621 return(TRUE);
67e9aaa3 2622 }
108106cf
JS
2623 else
2624 return(FALSE);
2625
2626} // GetDataSource()
2627
2628#endif
1fc5dd6f
JS
2629 // wxUSE_ODBC
2630