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