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