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