]> git.saurik.com Git - wxWidgets.git/blame - src/common/db.cpp
fixed Set(wxPercentOf) (bug #12227)
[wxWidgets.git] / src / common / db.cpp
CommitLineData
108106cf
JS
1///////////////////////////////////////////////////////////////////////////////
2// Name: db.cpp
f6bcfd97
BP
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
108106cf
JS
5// source such as opening and closing the data source.
6// Author: Doug Card
67e9aaa3 7// Modified by: George Tasker
3ca6a5f0 8// Bart Jourquin
0cd121f9 9// Mark Johnson, wxWindows@mj10777.de
23f681ec 10// Mods: Dec, 1998:
a2115c88
GT
11// -Added support for SQL statement logging and database cataloging
12// Mods: April, 1999
1e92909e
GT
13// -Added QUERY_ONLY mode support to reduce default number of cursors
14// -Added additional SQL logging code
a2115c88 15// -Added DEBUG-ONLY tracking of wxTable objects to detect orphaned DB connections
1e92909e 16// -Set ODBC option to only read committed writes to the DB so all
a2115c88 17// databases operate the same in that respect
108106cf
JS
18// Created: 9.96
19// RCS-ID: $Id$
20// Copyright: (c) 1996 Remstar International, Inc.
21// Licence: wxWindows licence, plus:
1e92909e 22// Notice: This class library and its intellectual design are free of charge for use,
108106cf
JS
23// modification, enhancement, debugging under the following conditions:
24// 1) These classes may only be used as part of the implementation of a
25// wxWindows-based application
26// 2) All enhancements and bug fixes are to be submitted back to the wxWindows
27// user groups free of all charges for use with the wxWindows library.
28// 3) These classes may not be distributed as part of any other class library,
29// DLL, text (written or electronic), other than a complete distribution of
30// the wxWindows GUI development toolkit.
31///////////////////////////////////////////////////////////////////////////////
32
33/*
34// SYNOPSIS START
35// SYNOPSIS STOP
36*/
37
01dba85a
JS
38#include "wx/wxprec.h"
39
f6bcfd97 40
a2115c88
GT
41// Use this line for wxWindows v1.x
42//#include "wx_ver.h"
43// Use this line for wxWindows v2.x
44#include "wx/version.h"
a2115c88
GT
45
46#if wxMAJOR_VERSION == 2
1e92909e 47 #ifdef __GNUG__
3ca6a5f0 48 #pragma implementation "db.h"
1e92909e 49 #endif
a2115c88
GT
50#endif
51
1fc5dd6f 52#ifdef DBDEBUG_CONSOLE
52a17fe5 53 #include "wx/ioswrap.h"
108106cf 54#endif
108106cf
JS
55
56#ifdef __BORLANDC__
1e92909e 57 #pragma hdrstop
108106cf
JS
58#endif //__BORLANDC__
59
a2115c88 60#if wxMAJOR_VERSION == 2
1e92909e
GT
61 #ifndef WX_PRECOMP
62 #include "wx/string.h"
63 #include "wx/object.h"
64 #include "wx/list.h"
65 #include "wx/utils.h"
66 #include "wx/msgdlg.h"
0efe4a98 67 #include "wx/log.h"
1e92909e
GT
68 #endif
69 #include "wx/filefn.h"
70 #include "wx/wxchar.h"
a2115c88
GT
71#endif
72
f6bcfd97 73
a2115c88 74#if wxMAJOR_VERSION == 1
1e92909e
GT
75# if defined(wx_msw) || defined(wx_x)
76# ifdef WX_PRECOMP
77# include "wx_prec.h"
78# else
79# include "wx.h"
80# endif
81# endif
82# define wxUSE_ODBC 1
a2115c88 83#endif
108106cf 84
47d67540 85#if wxUSE_ODBC
108106cf 86
108106cf
JS
87#include <stdio.h>
88#include <string.h>
89#include <assert.h>
7e616b10
RR
90#include <stdlib.h>
91#include <ctype.h>
67e9aaa3 92
a2115c88 93#if wxMAJOR_VERSION == 1
1e92909e 94 #include "db.h"
a2115c88 95#elif wxMAJOR_VERSION == 2
1e92909e 96 #include "wx/db.h"
a2115c88 97#endif
108106cf 98
d50af714 99WXDLLEXPORT_DATA(wxDbList*) PtrBegDbList = 0;
108106cf 100
f6bcfd97 101
9453a61b
BJ
102char const *SQL_LOG_FILENAME = "sqllog.txt";
103char const *SQL_CATALOG_FILENAME = "catalog.txt";
104
e041ce57 105#ifdef __WXDEBUG__
1e92909e 106 extern wxList TablesInUse;
a2115c88
GT
107#endif
108
109// SQL Log defaults to be used by GetDbConnection
f6bcfd97 110wxDbSqlLogState SQLLOGstate = sqlLogOFF;
a2115c88 111
f6bcfd97 112//char SQLLOGfn[wxDB_PATH_MAX+1] = SQL_LOG_FILENAME;
3ca6a5f0
BP
113//wxChar *SQLLOGfn = (wxChar*) SQL_LOG_FILENAME;
114static wxString SQLLOGfn = SQL_LOG_FILENAME;
a2115c88 115
f6bcfd97 116// The wxDb::errorList is copied to this variable when the wxDb object
a2115c88 117// is closed. This way, the error list is still available after the
9453a61b 118// database object is closed. This is necessary if the database
a2115c88 119// connection fails so the calling application can show the operator
f6bcfd97
BP
120// why the connection failed. Note: as each wxDb object is closed, it
121// will overwrite the errors of the previously destroyed wxDb object in
3ca6a5f0
BP
122// this variable. NOTE: This occurs during a CLOSE, not a FREEing of the
123// connection
a2115c88
GT
124char DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN];
125
3ca6a5f0
BP
126// This type defines the return row-struct form
127// SQLTablePrivileges, and is used by wxDB::TablePrivileges.
128typedef struct
129{
a8aa2258
GT
130 wxChar tableQual[128+1];
131 wxChar tableOwner[128+1];
132 wxChar tableName[128+1];
133 wxChar grantor[128+1];
134 wxChar grantee[128+1];
135 wxChar privilege[128+1];
136 wxChar grantable[3+1];
3ca6a5f0 137} wxDbTablePrivilegeInfo;
3ca6a5f0 138
67e9aaa3 139
f6bcfd97
BP
140/********** wxDbColFor Constructor **********/
141wxDbColFor::wxDbColFor()
67e9aaa3 142{
3ca6a5f0 143 s_Field = "";
1e92909e
GT
144 int i;
145 for (i=0;i<7;i++)
67e9aaa3
GT
146 {
147 s_Format[i] = "";
3ca6a5f0
BP
148 s_Amount[i] = "";
149 i_Amount[i] = 0;
67e9aaa3 150 }
3ca6a5f0
BP
151 i_Nation = 0; // 0=EU, 1=UK, 2=International, 3=US
152 i_dbDataType = 0;
153 i_sqlDataType = 0;
154 Format(1,DB_DATA_TYPE_VARCHAR,0,0,0); // the Function that does the work
f6bcfd97 155} // wxDbColFor::wxDbColFor()
67e9aaa3
GT
156
157
f6bcfd97 158wxDbColFor::~wxDbColFor()
67e9aaa3 159{
f6bcfd97 160} // wxDbColFor::~wxDbColFor()
67e9aaa3
GT
161
162
3ca6a5f0
BP
163/********** wxDbColInf Con / Destructor **********/
164wxDbColInf::wxDbColInf()
165{
166 catalog[0] = 0;
167 schema[0] = 0;
168 tableName[0] = 0;
169 colName[0] = 0;
170 sqlDataType = 0;
171 typeName[0] = 0;
172 columnSize = 0;
173 bufferLength = 0;
174 decimalDigits = 0;
175 numPrecRadix = 0;
176 nullable = 0;
177 remarks[0] = 0;
178 dbDataType = 0;
179 PkCol = 0;
180 PkTableName[0] = 0;
181 FkCol = 0;
182 FkTableName[0] = 0;
183 pColFor = NULL;
184} // wxDbColInf::wxDbColFor()
185
186
187wxDbColInf::~wxDbColInf()
188{
189 if (pColFor)
190 delete pColFor;
191 pColFor = NULL;
192} // wxDbColInf::~wxDbColInf()
193
194
195/********** wxDbTableInf Constructor ********/
196wxDbTableInf::wxDbTableInf()
197{
198 tableName[0] = 0;
199 tableType[0] = 0;
200 tableRemarks[0] = 0;
201 numCols = 0;
202 pColInf = NULL;
203} // wxDbTableInf::wxDbTableFor()
204
205
206/********** wxDbTableInf Constructor ********/
207wxDbTableInf::~wxDbTableInf()
208{
209 if (pColInf)
210 delete [] pColInf;
211 pColInf = NULL;
212} // wxDbTableInf::~wxDbTableInf()
213
214
215/********** wxDbInf Constructor *************/
216wxDbInf::wxDbInf()
217{
218 catalog[0] = 0;
219 schema[0] = 0;
220 numTables = 0;
221 pTableInf = NULL;
222} // wxDbInf::wxDbFor()
223
224
225/********** wxDbInf Destructor *************/
226wxDbInf::~wxDbInf()
227{
0cd121f9
MJ
228 if (pTableInf)
229 delete [] pTableInf;
230 pTableInf = NULL;
3ca6a5f0
BP
231} // wxDbInf::~wxDbInf()
232
233
234/*************************************************/
235
236
f6bcfd97 237int wxDbColFor::Format(int Nation,int dbDataType,SWORD sqlDataType,short columnSize,short decimalDigits)
67e9aaa3
GT
238{
239 // ----------------------------------------------------------------------------------------
0cd121f9 240 // -- 19991224 : mj10777 : Create
67e9aaa3
GT
241 // There is still a lot of work to do here, but it is a start
242 // It handles all the basic data-types that I have run into up to now
3ca6a5f0
BP
243 // The main work will have be with Dates and float Formatting
244 // (US 1,000.00 ; EU 1.000,00)
245 // There are wxWindow plans for locale support and the new wxDateTime. If
246 // they define some constants (wxEUROPEAN) that can be gloably used,
67e9aaa3
GT
247 // they should be used here.
248 // ----------------------------------------------------------------------------------------
3ca6a5f0 249 // There should also be a function to scan in a string to fill the variable
67e9aaa3
GT
250 // ----------------------------------------------------------------------------------------
251 wxString Temp0;
3ca6a5f0 252 i_Nation = Nation; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US
1e92909e 253 i_dbDataType = dbDataType;
67e9aaa3 254 i_sqlDataType = sqlDataType;
3ca6a5f0
BP
255 s_Field.Printf(wxT("%s%d"),s_Amount[1].c_str(),i_Amount[1]); // OK for VARCHAR, INTEGER and FLOAT
256 if (i_dbDataType == 0) // Filter unsupported dbDataTypes
67e9aaa3
GT
257 {
258 if ((i_sqlDataType == SQL_VARCHAR) || (i_sqlDataType == SQL_LONGVARCHAR))
259 i_dbDataType = DB_DATA_TYPE_VARCHAR;
260 if (i_sqlDataType == SQL_C_DATE)
261 i_dbDataType = DB_DATA_TYPE_DATE;
262 if (i_sqlDataType == SQL_C_BIT)
263 i_dbDataType = DB_DATA_TYPE_INTEGER;
264 if (i_sqlDataType == SQL_NUMERIC)
265 i_dbDataType = DB_DATA_TYPE_VARCHAR;
266 if (i_sqlDataType == SQL_REAL)
267 i_dbDataType = DB_DATA_TYPE_FLOAT;
268 }
269 if ((i_dbDataType == DB_DATA_TYPE_INTEGER) && (i_sqlDataType == SQL_C_DOUBLE))
270 { // DBASE Numeric
271 i_dbDataType = DB_DATA_TYPE_FLOAT;
272 }
273 switch(i_dbDataType) // -A-> Still a lot of proper formatting to do
274 {
275 case DB_DATA_TYPE_VARCHAR:
3ca6a5f0 276 s_Field = "%s";
67e9aaa3
GT
277 break;
278 case DB_DATA_TYPE_INTEGER:
3ca6a5f0 279 s_Field = "%d";
67e9aaa3
GT
280 break;
281 case DB_DATA_TYPE_FLOAT:
282 if (decimalDigits == 0)
283 decimalDigits = 2;
284 Temp0 = "%";
fbdcff4a 285 Temp0.Printf(wxT("%s%d.%d"),Temp0.c_str(),columnSize,decimalDigits);
3ca6a5f0 286 s_Field.Printf(wxT("%sf"),Temp0.c_str());
67e9aaa3
GT
287 break;
288 case DB_DATA_TYPE_DATE:
289 if (i_Nation == 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE)
290 {
291 s_Field = "%04d-%02d-%02d %02d:%02d:%02d.%03d";
292 }
293 if (i_Nation == 1) // European DD.MM.YYYY HH:MM:SS.SSS
294 {
295 s_Field = "%02d.%02d.%04d %02d:%02d:%02d.%03d";
296 }
297 if (i_Nation == 2) // UK DD/MM/YYYY HH:MM:SS.SSS
298 {
299 s_Field = "%02d/%02d/%04d %02d:%02d:%02d.%03d";
300 }
301 if (i_Nation == 3) // International YYYY-MM-DD HH:MM:SS.SSS
302 {
303 s_Field = "%04d-%02d-%02d %02d:%02d:%02d.%03d";
304 }
305 if (i_Nation == 4) // US MM/DD/YYYY HH:MM:SS.SSS
306 {
307 s_Field = "%02d/%02d/%04d %02d:%02d:%02d.%03d";
308 }
309 break;
310 default:
3ca6a5f0 311 s_Field.Printf(wxT("Unknown Format(%d)-SQL(%d)"),dbDataType,sqlDataType); //
67e9aaa3
GT
312 break;
313 };
314 return TRUE;
f6bcfd97 315} // wxDbColFor::Format()
67e9aaa3
GT
316
317
a8aa2258 318/********** wxDb Constructors **********/
f6bcfd97 319wxDb::wxDb(HENV &aHenv, bool FwdOnlyCursors)
a8aa2258
GT
320{
321 // Copy the HENV into the db class
322 henv = aHenv;
323 fwdOnlyCursors = FwdOnlyCursors;
324 initialize();
325} // wxDb::wxDb()
326
327
328void wxDb::initialize()
329/*
330 * Private member function that sets all wxDb member variables to
331 * known values at creation of the wxDb
332 */
108106cf 333{
1e92909e
GT
334 int i;
335
336 fpSqlLog = 0; // Sql Log file pointer
337 sqlLogState = sqlLogOFF; // By default, logging is turned off
338 nTables = 0;
a8aa2258 339 dbmsType = dbmsUNIDENTIFIED;
23f681ec 340
fbdcff4a
JS
341 wxStrcpy(sqlState,wxT(""));
342 wxStrcpy(errorMsg,wxT(""));
1e92909e
GT
343 nativeError = cbErrorMsg = 0;
344 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
fbdcff4a 345 wxStrcpy(errorList[i], wxT(""));
1e92909e
GT
346
347 // Init typeInf structures
fbdcff4a 348 wxStrcpy(typeInfVarchar.TypeName,wxT(""));
1e92909e
GT
349 typeInfVarchar.FsqlType = 0;
350 typeInfVarchar.Precision = 0;
351 typeInfVarchar.CaseSensitive = 0;
352 typeInfVarchar.MaximumScale = 0;
353
fbdcff4a 354 wxStrcpy(typeInfInteger.TypeName,wxT(""));
1e92909e
GT
355 typeInfInteger.FsqlType = 0;
356 typeInfInteger.Precision = 0;
357 typeInfInteger.CaseSensitive = 0;
358 typeInfInteger.MaximumScale = 0;
359
fbdcff4a 360 wxStrcpy(typeInfFloat.TypeName,wxT(""));
1e92909e
GT
361 typeInfFloat.FsqlType = 0;
362 typeInfFloat.Precision = 0;
363 typeInfFloat.CaseSensitive = 0;
364 typeInfFloat.MaximumScale = 0;
365
fbdcff4a 366 wxStrcpy(typeInfDate.TypeName,wxT(""));
1e92909e
GT
367 typeInfDate.FsqlType = 0;
368 typeInfDate.Precision = 0;
369 typeInfDate.CaseSensitive = 0;
370 typeInfDate.MaximumScale = 0;
23f681ec 371
1e92909e
GT
372 // Error reporting is turned OFF by default
373 silent = TRUE;
23f681ec 374
1e92909e
GT
375 // Allocate a data source connection handle
376 if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS)
377 DispAllErrors(henv);
378
379 // Initialize the db status flag
380 DB_STATUS = 0;
381
382 // Mark database as not open as of yet
383 dbIsOpen = FALSE;
a8aa2258 384} // wxDb::initialize()
108106cf 385
67e9aaa3 386
f6bcfd97
BP
387/********** wxDb::Open() **********/
388bool wxDb::Open(char *Dsn, char *Uid, char *AuthStr)
108106cf 389{
1e92909e
GT
390 assert(Dsn && wxStrlen(Dsn));
391 dsn = Dsn;
392 uid = Uid;
393 authStr = AuthStr;
108106cf 394
1e92909e 395 RETCODE retcode;
108106cf 396
1e92909e
GT
397 if (!FwdOnlyCursors())
398 {
399 // Specify that the ODBC cursor library be used, if needed. This must be
400 // specified before the connection is made.
401 retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED);
108106cf 402
6919c53f 403#ifdef DBDEBUG_CONSOLE
1e92909e
GT
404 if (retcode == SQL_SUCCESS)
405 cout << "SQLSetConnectOption(CURSOR_LIB) successful" << endl;
406 else
407 cout << "SQLSetConnectOption(CURSOR_LIB) failed" << endl;
6919c53f 408#endif
1e92909e 409 }
108106cf 410
1e92909e 411 // Connect to the data source
a8aa2258
GT
412 retcode = SQLConnect(hdbc, (UCHAR FAR *) dsn, SQL_NTS,
413 (UCHAR FAR *) uid, SQL_NTS,
414 (UCHAR FAR *) authStr,SQL_NTS);
f6bcfd97 415
a8aa2258 416/*
1e92909e
GT
417 if (retcode == SQL_SUCCESS_WITH_INFO)
418 DispAllErrors(henv, hdbc);
419 else if (retcode != SQL_SUCCESS)
420 return(DispAllErrors(henv, hdbc));
108106cf 421
a8aa2258
GT
422 if (retcode == SQL_ERROR)
423 return(DispAllErrors(henv, hdbc));
424*/
425 if ((retcode != SQL_SUCCESS) &&
426 (retcode != SQL_SUCCESS_WITH_INFO))
427 return(DispAllErrors(henv, hdbc));
428
a2115c88 429/*
1e92909e
GT
430 If using Intersolv branded ODBC drivers, this is the place where you would substitute
431 your branded driver license information
a2115c88 432
1e92909e
GT
433 SQLSetConnectOption(hdbc, 1041, (UDWORD) "");
434 SQLSetConnectOption(hdbc, 1042, (UDWORD) "");
a2115c88 435*/
67e9aaa3 436
1e92909e
GT
437 // Mark database as open
438 dbIsOpen = TRUE;
439
440 // Allocate a statement handle for the database connection
441 if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
442 return(DispAllErrors(henv, hdbc));
443
444 // Set Connection Options
a8aa2258 445 if (!setConnectionOptions())
1e92909e
GT
446 return(FALSE);
447
448 // Query the data source for inf. about itself
a8aa2258 449 if (!getDbInfo())
1e92909e
GT
450 return(FALSE);
451
452 // Query the data source regarding data type information
453
454 //
455 // The way I determined which SQL data types to use was by calling SQLGetInfo
456 // for all of the possible SQL data types to see which ones were supported. If
457 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
458 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
459 // types I've selected below will not alway's be what we want. These are just
460 // what happened to work against an Oracle 7/Intersolv combination. The following is
461 // a complete list of the results I got back against the Oracle 7 database:
462 //
463 // SQL_BIGINT SQL_NO_DATA_FOUND
464 // SQL_BINARY SQL_NO_DATA_FOUND
465 // SQL_BIT SQL_NO_DATA_FOUND
466 // SQL_CHAR type name = 'CHAR', Precision = 255
467 // SQL_DATE SQL_NO_DATA_FOUND
468 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
469 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
470 // SQL_FLOAT SQL_NO_DATA_FOUND
471 // SQL_INTEGER SQL_NO_DATA_FOUND
472 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
473 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
474 // SQL_NUMERIC SQL_NO_DATA_FOUND
475 // SQL_REAL SQL_NO_DATA_FOUND
476 // SQL_SMALLINT SQL_NO_DATA_FOUND
477 // SQL_TIME SQL_NO_DATA_FOUND
478 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
479 // SQL_VARBINARY type name = 'RAW', Precision = 255
480 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
481 // =====================================================================
482 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
483 //
484 // SQL_VARCHAR type name = 'TEXT', Precision = 255
485 // SQL_TIMESTAMP type name = 'DATETIME'
486 // SQL_DECIMAL SQL_NO_DATA_FOUND
487 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
488 // SQL_FLOAT SQL_NO_DATA_FOUND
489 // SQL_REAL type name = 'SINGLE', Precision = 7
490 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
491 // SQL_INTEGER type name = 'LONG', Precision = 10
492
493 // VARCHAR = Variable length character string
3ca6a5f0
BP
494 if (!getDataTypeInfo(SQL_VARCHAR, typeInfVarchar))
495 if (!getDataTypeInfo(SQL_CHAR, typeInfVarchar))
1e92909e
GT
496 return(FALSE);
497 else
498 typeInfVarchar.FsqlType = SQL_CHAR;
499 else
500 typeInfVarchar.FsqlType = SQL_VARCHAR;
501
502 // Float
3ca6a5f0 503 if (!getDataTypeInfo(SQL_DOUBLE,typeInfFloat))
f6bcfd97 504
3ca6a5f0
BP
505 if (!getDataTypeInfo(SQL_REAL,typeInfFloat))
506 if (!getDataTypeInfo(SQL_FLOAT,typeInfFloat))
507 if (!getDataTypeInfo(SQL_DECIMAL,typeInfFloat))
508 if (!getDataTypeInfo(SQL_NUMERIC,typeInfFloat))
1e92909e
GT
509 return(FALSE);
510 else
511 typeInfFloat.FsqlType = SQL_NUMERIC;
512 else
513 typeInfFloat.FsqlType = SQL_DECIMAL;
514 else
515 typeInfFloat.FsqlType = SQL_FLOAT;
516 else
517 typeInfFloat.FsqlType = SQL_REAL;
518 else
519 typeInfFloat.FsqlType = SQL_DOUBLE;
520
521 // Integer
3ca6a5f0
BP
522 if (!getDataTypeInfo(SQL_INTEGER, typeInfInteger))
523 {
524 // If SQL_INTEGER is not supported, use the floating point
525 // data type to store integers as well as floats
526 if (!getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger))
1e92909e
GT
527 return(FALSE);
528 else
529 typeInfInteger.FsqlType = typeInfFloat.FsqlType;
3ca6a5f0 530 }
1e92909e
GT
531 else
532 typeInfInteger.FsqlType = SQL_INTEGER;
533
534 // Date/Time
535 if (Dbms() != dbmsDBASE)
3ca6a5f0
BP
536 {
537 if (! getDataTypeInfo(SQL_TIMESTAMP,typeInfDate))
1e92909e
GT
538 return(FALSE);
539 else
540 typeInfDate.FsqlType = SQL_TIMESTAMP;
541 }
542 else
543 {
3ca6a5f0 544 if (!getDataTypeInfo(SQL_DATE,typeInfDate))
1e92909e
GT
545 return(FALSE);
546 else
547 typeInfDate.FsqlType = SQL_DATE;
548 }
108106cf 549
1fc5dd6f 550#ifdef DBDEBUG_CONSOLE
1e92909e
GT
551 cout << "VARCHAR DATA TYPE: " << typeInfVarchar.TypeName << endl;
552 cout << "INTEGER DATA TYPE: " << typeInfInteger.TypeName << endl;
553 cout << "FLOAT DATA TYPE: " << typeInfFloat.TypeName << endl;
554 cout << "DATE DATA TYPE: " << typeInfDate.TypeName << endl;
555 cout << endl;
108106cf
JS
556#endif
557
1e92909e
GT
558 // Completed Successfully
559 return(TRUE);
108106cf 560
f6bcfd97 561} // wxDb::Open()
108106cf 562
108106cf 563
a8aa2258
GT
564bool wxDb::Open(wxDb *copyDb)
565{
eb3b9dda 566 dsn = (char *)copyDb->GetDatasourceName();
a8aa2258
GT
567 uid = (char *)copyDb->GetUsername();
568 authStr = (char *)copyDb->GetPassword();
569
570 RETCODE retcode;
571
572 if (!FwdOnlyCursors())
573 {
574 // Specify that the ODBC cursor library be used, if needed. This must be
575 // specified before the connection is made.
576 retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED);
577
578#ifdef DBDEBUG_CONSOLE
579 if (retcode == SQL_SUCCESS)
580 cout << "SQLSetConnectOption(CURSOR_LIB) successful" << endl;
581 else
582 cout << "SQLSetConnectOption(CURSOR_LIB) failed" << endl;
583#endif
584 }
585
586 // Connect to the data source
587 retcode = SQLConnect(hdbc, (UCHAR FAR *) dsn, SQL_NTS,
588 (UCHAR FAR *) uid, SQL_NTS,
589 (UCHAR FAR *) authStr, SQL_NTS);
590
591 if (retcode == SQL_ERROR)
592 return(DispAllErrors(henv, hdbc));
593
594/*
595 If using Intersolv branded ODBC drivers, this is the place where you would substitute
596 your branded driver license information
597
598 SQLSetConnectOption(hdbc, 1041, (UDWORD) "");
599 SQLSetConnectOption(hdbc, 1042, (UDWORD) "");
600*/
601
602 // Mark database as open
603 dbIsOpen = TRUE;
604
605 // Allocate a statement handle for the database connection
606 if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
607 return(DispAllErrors(henv, hdbc));
608
609 // Set Connection Options
610 if (!setConnectionOptions())
611 return(FALSE);
612
613 // Instead of Querying the data source for info about itself, it can just be copied
614 // from the wxDb instance that was passed in (copyDb).
615 wxStrcpy(dbInf.serverName,copyDb->dbInf.serverName);
616 wxStrcpy(dbInf.databaseName,copyDb->dbInf.databaseName);
617 wxStrcpy(dbInf.dbmsName,copyDb->dbInf.dbmsName);
618 wxStrcpy(dbInf.dbmsVer,copyDb->dbInf.dbmsVer);
619 dbInf.maxConnections = copyDb->dbInf.maxConnections;
620 dbInf.maxStmts = copyDb->dbInf.maxStmts;
621 wxStrcpy(dbInf.driverName,copyDb->dbInf.driverName);
622 wxStrcpy(dbInf.odbcVer,copyDb->dbInf.odbcVer);
623 wxStrcpy(dbInf.drvMgrOdbcVer,copyDb->dbInf.drvMgrOdbcVer);
624 wxStrcpy(dbInf.driverVer,copyDb->dbInf.driverVer);
625 dbInf.apiConfLvl = copyDb->dbInf.apiConfLvl;
626 dbInf.cliConfLvl = copyDb->dbInf.cliConfLvl;
627 dbInf.sqlConfLvl = copyDb->dbInf.sqlConfLvl;
628 wxStrcpy(dbInf.outerJoins,copyDb->dbInf.outerJoins);
629 wxStrcpy(dbInf.procedureSupport,copyDb->dbInf.procedureSupport);
630 wxStrcpy(dbInf.accessibleTables,copyDb->dbInf.accessibleTables);
631 dbInf.cursorCommitBehavior = copyDb->dbInf.cursorCommitBehavior;
632 dbInf.cursorRollbackBehavior = copyDb->dbInf.cursorRollbackBehavior;
633 dbInf.supportNotNullClause = copyDb->dbInf.supportNotNullClause;
634 wxStrcpy(dbInf.supportIEF,copyDb->dbInf.supportIEF);
635 dbInf.txnIsolation = copyDb->dbInf.txnIsolation;
636 dbInf.txnIsolationOptions = copyDb->dbInf.txnIsolationOptions;
637 dbInf.fetchDirections = copyDb->dbInf.fetchDirections;
638 dbInf.lockTypes = copyDb->dbInf.lockTypes;
639 dbInf.posOperations = copyDb->dbInf.posOperations;
640 dbInf.posStmts = copyDb->dbInf.posStmts;
641 dbInf.scrollConcurrency = copyDb->dbInf.scrollConcurrency;
642 dbInf.scrollOptions = copyDb->dbInf.scrollOptions;
643 dbInf.staticSensitivity = copyDb->dbInf.staticSensitivity;
644 dbInf.txnCapable = copyDb->dbInf.txnCapable;
645 dbInf.loginTimeout = copyDb->dbInf.loginTimeout;
646
647 // VARCHAR = Variable length character string
648 typeInfVarchar.FsqlType = copyDb->typeInfVarchar.FsqlType;
d8a0a1c9
GT
649 wxStrcpy(typeInfVarchar.TypeName, copyDb->typeInfVarchar.TypeName);
650 typeInfVarchar.Precision = copyDb->typeInfVarchar.Precision;
651 typeInfVarchar.CaseSensitive = copyDb->typeInfVarchar.CaseSensitive;
652 typeInfVarchar.MaximumScale = copyDb->typeInfVarchar.MaximumScale;
a8aa2258
GT
653
654 // Float
655 typeInfFloat.FsqlType = copyDb->typeInfFloat.FsqlType;
d8a0a1c9
GT
656 wxStrcpy(typeInfFloat.TypeName, copyDb->typeInfFloat.TypeName);
657 typeInfFloat.Precision = copyDb->typeInfFloat.Precision;
658 typeInfFloat.CaseSensitive = copyDb->typeInfFloat.CaseSensitive;
659 typeInfFloat.MaximumScale = copyDb->typeInfFloat.MaximumScale;
a8aa2258
GT
660
661 // Integer
d8a0a1c9
GT
662 typeInfInteger.FsqlType = copyDb->typeInfInteger.FsqlType;
663 wxStrcpy(typeInfInteger.TypeName, copyDb->typeInfInteger.TypeName);
664 typeInfInteger.Precision = copyDb->typeInfInteger.Precision;
665 typeInfInteger.CaseSensitive = copyDb->typeInfInteger.CaseSensitive;
666 typeInfInteger.MaximumScale = copyDb->typeInfInteger.MaximumScale;
a8aa2258
GT
667
668 // Date/Time
669 typeInfDate.FsqlType = copyDb->typeInfDate.FsqlType;
d8a0a1c9
GT
670 wxStrcpy(typeInfDate.TypeName, copyDb->typeInfDate.TypeName);
671 typeInfDate.Precision = copyDb->typeInfDate.Precision;
672 typeInfDate.CaseSensitive = copyDb->typeInfDate.CaseSensitive;
673 typeInfDate.MaximumScale = copyDb->typeInfDate.MaximumScale;
a8aa2258
GT
674
675#ifdef DBDEBUG_CONSOLE
676 cout << "VARCHAR DATA TYPE: " << typeInfVarchar.TypeName << endl;
677 cout << "INTEGER DATA TYPE: " << typeInfInteger.TypeName << endl;
678 cout << "FLOAT DATA TYPE: " << typeInfFloat.TypeName << endl;
679 cout << "DATE DATA TYPE: " << typeInfDate.TypeName << endl;
680 cout << endl;
681#endif
682
683 // Completed Successfully
684 return(TRUE);
685} // wxDb::Open() 2
686
687
f6bcfd97
BP
688/********** wxDb::setConnectionOptions() **********/
689bool wxDb::setConnectionOptions(void)
67e9aaa3
GT
690/*
691 * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
692 */
108106cf 693{
a8aa2258
GT
694 SWORD cb;
695
696 // I need to get the DBMS name here, because some of the connection options
697 // are database specific and need to call the Dbms() function.
698 if (SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, 40, &cb) != SQL_SUCCESS)
699 return(DispAllErrors(henv, hdbc));
700
1e92909e
GT
701 SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
702 SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF);
a8aa2258
GT
703// SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads
704
705 // By default, MS Sql Server closes cursors on commit and rollback. The following
706 // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors
707 // after a transaction. This is a driver specific option and is not part of the
708 // ODBC standard. Note: this behavior is specific to the ODBC interface to SQL Server.
709 // The database settings don't have any effect one way or the other.
710 if (Dbms() == dbmsMS_SQL_SERVER)
711 {
712 const long SQL_PRESERVE_CURSORS = 1204L;
713 const long SQL_PC_ON = 1L;
714 SQLSetConnectOption(hdbc, SQL_PRESERVE_CURSORS, SQL_PC_ON);
715 }
108106cf 716
1e92909e 717 // Display the connection options to verify them
1fc5dd6f 718#ifdef DBDEBUG_CONSOLE
1e92909e 719 long l;
23f681ec
VZ
720 cout << "****** CONNECTION OPTIONS ******" << endl;
721
1e92909e
GT
722 if (SQLGetConnectOption(hdbc, SQL_AUTOCOMMIT, &l) != SQL_SUCCESS)
723 return(DispAllErrors(henv, hdbc));
724 cout << "AUTOCOMMIT: " << (l == SQL_AUTOCOMMIT_OFF ? "OFF" : "ON") << endl;
23f681ec 725
1e92909e
GT
726 if (SQLGetConnectOption(hdbc, SQL_ODBC_CURSORS, &l) != SQL_SUCCESS)
727 return(DispAllErrors(henv, hdbc));
728 cout << "ODBC CURSORS: ";
729 switch(l)
730 {
731 case(SQL_CUR_USE_IF_NEEDED):
732 cout << "SQL_CUR_USE_IF_NEEDED";
733 break;
734 case(SQL_CUR_USE_ODBC):
735 cout << "SQL_CUR_USE_ODBC";
736 break;
737 case(SQL_CUR_USE_DRIVER):
738 cout << "SQL_CUR_USE_DRIVER";
739 break;
740 }
741 cout << endl;
23f681ec 742
1e92909e
GT
743 if (SQLGetConnectOption(hdbc, SQL_OPT_TRACE, &l) != SQL_SUCCESS)
744 return(DispAllErrors(henv, hdbc));
745 cout << "TRACING: " << (l == SQL_OPT_TRACE_OFF ? "OFF" : "ON") << endl;
746
747 cout << endl;
108106cf
JS
748#endif
749
1e92909e
GT
750 // Completed Successfully
751 return(TRUE);
108106cf 752
f6bcfd97 753} // wxDb::setConnectionOptions()
108106cf 754
67e9aaa3 755
f6bcfd97
BP
756/********** wxDb::getDbInfo() **********/
757bool wxDb::getDbInfo(void)
108106cf 758{
1e92909e
GT
759 SWORD cb;
760 RETCODE retcode;
761
762 if (SQLGetInfo(hdbc, SQL_SERVER_NAME, (UCHAR*) dbInf.serverName, 80, &cb) != SQL_SUCCESS)
763 return(DispAllErrors(henv, hdbc));
108106cf 764
1e92909e
GT
765 if (SQLGetInfo(hdbc, SQL_DATABASE_NAME, (UCHAR*) dbInf.databaseName, 128, &cb) != SQL_SUCCESS)
766 return(DispAllErrors(henv, hdbc));
108106cf 767
1e92909e
GT
768 if (SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, 40, &cb) != SQL_SUCCESS)
769 return(DispAllErrors(henv, hdbc));
108106cf 770
1e92909e
GT
771 // 16-Mar-1999
772 // After upgrading to MSVC6, the original 20 char buffer below was insufficient,
773 // causing database connectivity to fail in some cases.
774 retcode = SQLGetInfo(hdbc, SQL_DBMS_VER, (UCHAR*) dbInf.dbmsVer, 64, &cb);
108106cf 775
1e92909e
GT
776 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO )
777 return(DispAllErrors(henv, hdbc));
108106cf 778
1e92909e
GT
779 if (SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, (UCHAR*) &dbInf.maxConnections, sizeof(dbInf.maxConnections), &cb) != SQL_SUCCESS)
780 return(DispAllErrors(henv, hdbc));
108106cf 781
1e92909e
GT
782 if (SQLGetInfo(hdbc, SQL_ACTIVE_STATEMENTS, (UCHAR*) &dbInf.maxStmts, sizeof(dbInf.maxStmts), &cb) != SQL_SUCCESS)
783 return(DispAllErrors(henv, hdbc));
108106cf 784
1e92909e
GT
785 if (SQLGetInfo(hdbc, SQL_DRIVER_NAME, (UCHAR*) dbInf.driverName, 40, &cb) != SQL_SUCCESS)
786 return(DispAllErrors(henv, hdbc));
108106cf 787
1e92909e
GT
788 if (SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, (UCHAR*) dbInf.odbcVer, 60, &cb) == SQL_ERROR)
789 return(DispAllErrors(henv, hdbc));
108106cf 790
1e92909e
GT
791 retcode = SQLGetInfo(hdbc, SQL_ODBC_VER, (UCHAR*) dbInf.drvMgrOdbcVer, 60, &cb);
792 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
793 return(DispAllErrors(henv, hdbc));
108106cf 794
1e92909e
GT
795 if (SQLGetInfo(hdbc, SQL_DRIVER_VER, (UCHAR*) dbInf.driverVer, 60, &cb) == SQL_ERROR)
796 return(DispAllErrors(henv, hdbc));
108106cf 797
1e92909e
GT
798 if (SQLGetInfo(hdbc, SQL_ODBC_API_CONFORMANCE, (UCHAR*) &dbInf.apiConfLvl, sizeof(dbInf.apiConfLvl), &cb) != SQL_SUCCESS)
799 return(DispAllErrors(henv, hdbc));
108106cf 800
1e92909e 801 if (SQLGetInfo(hdbc, SQL_ODBC_SAG_CLI_CONFORMANCE, (UCHAR*) &dbInf.cliConfLvl, sizeof(dbInf.cliConfLvl), &cb) != SQL_SUCCESS)
a8aa2258
GT
802// return(DispAllErrors(henv, hdbc));
803 {
804 // Not all drivers support this call - Nick Gorham(unixODBC)
805 dbInf.cliConfLvl = 0;
806 }
108106cf 807
1e92909e
GT
808 if (SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, (UCHAR*) &dbInf.sqlConfLvl, sizeof(dbInf.sqlConfLvl), &cb) != SQL_SUCCESS)
809 return(DispAllErrors(henv, hdbc));
108106cf 810
1e92909e
GT
811 if (SQLGetInfo(hdbc, SQL_OUTER_JOINS, (UCHAR*) dbInf.outerJoins, 2, &cb) != SQL_SUCCESS)
812 return(DispAllErrors(henv, hdbc));
108106cf 813
1e92909e
GT
814 if (SQLGetInfo(hdbc, SQL_PROCEDURES, (UCHAR*) dbInf.procedureSupport, 2, &cb) != SQL_SUCCESS)
815 return(DispAllErrors(henv, hdbc));
a8aa2258 816
3ca6a5f0
BP
817 if (SQLGetInfo(hdbc, SQL_ACCESSIBLE_TABLES, (UCHAR*) dbInf.accessibleTables, 2, &cb) != SQL_SUCCESS)
818 return(DispAllErrors(henv, hdbc));
a8aa2258 819
1e92909e
GT
820 if (SQLGetInfo(hdbc, SQL_CURSOR_COMMIT_BEHAVIOR, (UCHAR*) &dbInf.cursorCommitBehavior, sizeof(dbInf.cursorCommitBehavior), &cb) != SQL_SUCCESS)
821 return(DispAllErrors(henv, hdbc));
108106cf 822
1e92909e
GT
823 if (SQLGetInfo(hdbc, SQL_CURSOR_ROLLBACK_BEHAVIOR, (UCHAR*) &dbInf.cursorRollbackBehavior, sizeof(dbInf.cursorRollbackBehavior), &cb) != SQL_SUCCESS)
824 return(DispAllErrors(henv, hdbc));
108106cf 825
1e92909e
GT
826 if (SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, (UCHAR*) &dbInf.supportNotNullClause, sizeof(dbInf.supportNotNullClause), &cb) != SQL_SUCCESS)
827 return(DispAllErrors(henv, hdbc));
108106cf 828
1e92909e
GT
829 if (SQLGetInfo(hdbc, SQL_ODBC_SQL_OPT_IEF, (UCHAR*) dbInf.supportIEF, 2, &cb) != SQL_SUCCESS)
830 return(DispAllErrors(henv, hdbc));
108106cf 831
1e92909e
GT
832 if (SQLGetInfo(hdbc, SQL_DEFAULT_TXN_ISOLATION, (UCHAR*) &dbInf.txnIsolation, sizeof(dbInf.txnIsolation), &cb) != SQL_SUCCESS)
833 return(DispAllErrors(henv, hdbc));
108106cf 834
1e92909e
GT
835 if (SQLGetInfo(hdbc, SQL_TXN_ISOLATION_OPTION, (UCHAR*) &dbInf.txnIsolationOptions, sizeof(dbInf.txnIsolationOptions), &cb) != SQL_SUCCESS)
836 return(DispAllErrors(henv, hdbc));
108106cf 837
1e92909e
GT
838 if (SQLGetInfo(hdbc, SQL_FETCH_DIRECTION, (UCHAR*) &dbInf.fetchDirections, sizeof(dbInf.fetchDirections), &cb) != SQL_SUCCESS)
839 return(DispAllErrors(henv, hdbc));
108106cf 840
1e92909e
GT
841 if (SQLGetInfo(hdbc, SQL_LOCK_TYPES, (UCHAR*) &dbInf.lockTypes, sizeof(dbInf.lockTypes), &cb) != SQL_SUCCESS)
842 return(DispAllErrors(henv, hdbc));
108106cf 843
1e92909e
GT
844 if (SQLGetInfo(hdbc, SQL_POS_OPERATIONS, (UCHAR*) &dbInf.posOperations, sizeof(dbInf.posOperations), &cb) != SQL_SUCCESS)
845 return(DispAllErrors(henv, hdbc));
108106cf 846
1e92909e
GT
847 if (SQLGetInfo(hdbc, SQL_POSITIONED_STATEMENTS, (UCHAR*) &dbInf.posStmts, sizeof(dbInf.posStmts), &cb) != SQL_SUCCESS)
848 return(DispAllErrors(henv, hdbc));
108106cf 849
1e92909e
GT
850 if (SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, (UCHAR*) &dbInf.scrollConcurrency, sizeof(dbInf.scrollConcurrency), &cb) != SQL_SUCCESS)
851 return(DispAllErrors(henv, hdbc));
108106cf 852
1e92909e
GT
853 if (SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, (UCHAR*) &dbInf.scrollOptions, sizeof(dbInf.scrollOptions), &cb) != SQL_SUCCESS)
854 return(DispAllErrors(henv, hdbc));
108106cf 855
1e92909e
GT
856 if (SQLGetInfo(hdbc, SQL_STATIC_SENSITIVITY, (UCHAR*) &dbInf.staticSensitivity, sizeof(dbInf.staticSensitivity), &cb) != SQL_SUCCESS)
857 return(DispAllErrors(henv, hdbc));
108106cf 858
1e92909e
GT
859 if (SQLGetInfo(hdbc, SQL_TXN_CAPABLE, (UCHAR*) &dbInf.txnCapable, sizeof(dbInf.txnCapable), &cb) != SQL_SUCCESS)
860 return(DispAllErrors(henv, hdbc));
108106cf 861
1e92909e
GT
862 if (SQLGetInfo(hdbc, SQL_LOGIN_TIMEOUT, (UCHAR*) &dbInf.loginTimeout, sizeof(dbInf.loginTimeout), &cb) != SQL_SUCCESS)
863 return(DispAllErrors(henv, hdbc));
108106cf 864
1fc5dd6f 865#ifdef DBDEBUG_CONSOLE
23f681ec 866 cout << "***** DATA SOURCE INFORMATION *****" << endl;
1e92909e
GT
867 cout << "SERVER Name: " << dbInf.serverName << endl;
868 cout << "DBMS Name: " << dbInf.dbmsName << "; DBMS Version: " << dbInf.dbmsVer << endl;
869 cout << "ODBC Version: " << dbInf.odbcVer << "; Driver Version: " << dbInf.driverVer << endl;
870
871 cout << "API Conf. Level: ";
872 switch(dbInf.apiConfLvl)
873 {
874 case SQL_OAC_NONE: cout << "None"; break;
875 case SQL_OAC_LEVEL1: cout << "Level 1"; break;
876 case SQL_OAC_LEVEL2: cout << "Level 2"; break;
877 }
878 cout << endl;
879
880 cout << "SAG CLI Conf. Level: ";
881 switch(dbInf.cliConfLvl)
882 {
883 case SQL_OSCC_NOT_COMPLIANT: cout << "Not Compliant"; break;
884 case SQL_OSCC_COMPLIANT: cout << "Compliant"; break;
885 }
886 cout << endl;
887
888 cout << "SQL Conf. Level: ";
889 switch(dbInf.sqlConfLvl)
890 {
3ca6a5f0
BP
891 case SQL_OSC_MINIMUM: cout << "Minimum Grammar"; break;
892 case SQL_OSC_CORE: cout << "Core Grammar"; break;
893 case SQL_OSC_EXTENDED: cout << "Extended Grammar"; break;
1e92909e
GT
894 }
895 cout << endl;
896
897 cout << "Max. Connections: " << dbInf.maxConnections << endl;
898 cout << "Outer Joins: " << dbInf.outerJoins << endl;
899 cout << "Support for Procedures: " << dbInf.procedureSupport << endl;
3ca6a5f0 900 cout << "All tables accessible : " << dbInf.accessibleTables << endl;
1e92909e
GT
901 cout << "Cursor COMMIT Behavior: ";
902 switch(dbInf.cursorCommitBehavior)
903 {
904 case SQL_CB_DELETE: cout << "Delete cursors"; break;
905 case SQL_CB_CLOSE: cout << "Close cursors"; break;
906 case SQL_CB_PRESERVE: cout << "Preserve cursors"; break;
907 }
908 cout << endl;
909
910 cout << "Cursor ROLLBACK Behavior: ";
911 switch(dbInf.cursorRollbackBehavior)
912 {
913 case SQL_CB_DELETE: cout << "Delete cursors"; break;
914 case SQL_CB_CLOSE: cout << "Close cursors"; break;
915 case SQL_CB_PRESERVE: cout << "Preserve cursors"; break;
916 }
917 cout << endl;
918
919 cout << "Support NOT NULL clause: ";
920 switch(dbInf.supportNotNullClause)
921 {
922 case SQL_NNC_NULL: cout << "No"; break;
923 case SQL_NNC_NON_NULL: cout << "Yes"; break;
924 }
925 cout << endl;
926
927 cout << "Support IEF (Ref. Integrity): " << dbInf.supportIEF << endl;
928 cout << "Login Timeout: " << dbInf.loginTimeout << endl;
929
930 cout << endl << endl << "more ..." << endl;
931 getchar();
932
933 cout << "Default Transaction Isolation: ";
934 switch(dbInf.txnIsolation)
935 {
936 case SQL_TXN_READ_UNCOMMITTED: cout << "Read Uncommitted"; break;
937 case SQL_TXN_READ_COMMITTED: cout << "Read Committed"; break;
938 case SQL_TXN_REPEATABLE_READ: cout << "Repeatable Read"; break;
939 case SQL_TXN_SERIALIZABLE: cout << "Serializable"; break;
108106cf 940#ifdef ODBC_V20
1e92909e 941 case SQL_TXN_VERSIONING: cout << "Versioning"; break;
108106cf 942#endif
1e92909e
GT
943 }
944 cout << endl;
945
946 cout << "Transaction Isolation Options: ";
947 if (dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED)
948 cout << "Read Uncommitted, ";
949 if (dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED)
950 cout << "Read Committed, ";
951 if (dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ)
952 cout << "Repeatable Read, ";
953 if (dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE)
954 cout << "Serializable, ";
108106cf 955#ifdef ODBC_V20
1e92909e
GT
956 if (dbInf.txnIsolationOptions & SQL_TXN_VERSIONING)
957 cout << "Versioning";
108106cf 958#endif
1e92909e
GT
959 cout << endl;
960
961 cout << "Fetch Directions Supported:" << endl << " ";
962 if (dbInf.fetchDirections & SQL_FD_FETCH_NEXT)
963 cout << "Next, ";
964 if (dbInf.fetchDirections & SQL_FD_FETCH_PRIOR)
965 cout << "Prev, ";
966 if (dbInf.fetchDirections & SQL_FD_FETCH_FIRST)
967 cout << "First, ";
968 if (dbInf.fetchDirections & SQL_FD_FETCH_LAST)
969 cout << "Last, ";
970 if (dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE)
971 cout << "Absolute, ";
972 if (dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE)
973 cout << "Relative, ";
108106cf 974#ifdef ODBC_V20
1e92909e
GT
975 if (dbInf.fetchDirections & SQL_FD_FETCH_RESUME)
976 cout << "Resume, ";
108106cf 977#endif
1e92909e
GT
978 if (dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK)
979 cout << "Bookmark";
980 cout << endl;
981
982 cout << "Lock Types Supported (SQLSetPos): ";
983 if (dbInf.lockTypes & SQL_LCK_NO_CHANGE)
984 cout << "No Change, ";
985 if (dbInf.lockTypes & SQL_LCK_EXCLUSIVE)
986 cout << "Exclusive, ";
987 if (dbInf.lockTypes & SQL_LCK_UNLOCK)
988 cout << "UnLock";
989 cout << endl;
990
991 cout << "Position Operations Supported (SQLSetPos): ";
992 if (dbInf.posOperations & SQL_POS_POSITION)
993 cout << "Position, ";
994 if (dbInf.posOperations & SQL_POS_REFRESH)
995 cout << "Refresh, ";
996 if (dbInf.posOperations & SQL_POS_UPDATE)
997 cout << "Upd, ";
998 if (dbInf.posOperations & SQL_POS_DELETE)
999 cout << "Del, ";
1000 if (dbInf.posOperations & SQL_POS_ADD)
1001 cout << "Add";
1002 cout << endl;
1003
1004 cout << "Positioned Statements Supported: ";
1005 if (dbInf.posStmts & SQL_PS_POSITIONED_DELETE)
1006 cout << "Pos delete, ";
1007 if (dbInf.posStmts & SQL_PS_POSITIONED_UPDATE)
1008 cout << "Pos update, ";
1009 if (dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)
1010 cout << "Select for update";
1011 cout << endl;
1012
1013 cout << "Scroll Concurrency: ";
1014 if (dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY)
1015 cout << "Read Only, ";
1016 if (dbInf.scrollConcurrency & SQL_SCCO_LOCK)
1017 cout << "Lock, ";
1018 if (dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER)
1019 cout << "Opt. Rowver, ";
1020 if (dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES)
1021 cout << "Opt. Values";
1022 cout << endl;
1023
1024 cout << "Scroll Options: ";
1025 if (dbInf.scrollOptions & SQL_SO_FORWARD_ONLY)
1026 cout << "Fwd Only, ";
1027 if (dbInf.scrollOptions & SQL_SO_STATIC)
1028 cout << "Static, ";
1029 if (dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN)
1030 cout << "Keyset Driven, ";
1031 if (dbInf.scrollOptions & SQL_SO_DYNAMIC)
1032 cout << "Dynamic, ";
1033 if (dbInf.scrollOptions & SQL_SO_MIXED)
1034 cout << "Mixed";
1035 cout << endl;
1036
1037 cout << "Static Sensitivity: ";
1038 if (dbInf.staticSensitivity & SQL_SS_ADDITIONS)
1039 cout << "Additions, ";
1040 if (dbInf.staticSensitivity & SQL_SS_DELETIONS)
1041 cout << "Deletions, ";
1042 if (dbInf.staticSensitivity & SQL_SS_UPDATES)
1043 cout << "Updates";
1044 cout << endl;
1045
1046 cout << "Transaction Capable?: ";
1047 switch(dbInf.txnCapable)
1048 {
1049 case SQL_TC_NONE: cout << "No"; break;
1050 case SQL_TC_DML: cout << "DML Only"; break;
1051 case SQL_TC_DDL_COMMIT: cout << "DDL Commit"; break;
1052 case SQL_TC_DDL_IGNORE: cout << "DDL Ignore"; break;
1053 case SQL_TC_ALL: cout << "DDL & DML"; break;
1054 }
1055 cout << endl;
1056
1057 cout << endl;
108106cf
JS
1058#endif
1059
1e92909e
GT
1060 // Completed Successfully
1061 return(TRUE);
108106cf 1062
f6bcfd97 1063} // wxDb::getDbInfo()
108106cf 1064
67e9aaa3 1065
f6bcfd97
BP
1066/********** wxDb::getDataTypeInfo() **********/
1067bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo)
108106cf 1068{
67e9aaa3
GT
1069/*
1070 * fSqlType will be something like SQL_VARCHAR. This parameter determines
1071 * the data type inf. is gathered for.
1072 *
f6bcfd97 1073 * wxDbSqlTypeInfo is a structure that is filled in with data type information,
67e9aaa3 1074 */
1e92909e 1075 RETCODE retcode;
f6bcfd97
BP
1076 SDWORD cbRet;
1077
1e92909e
GT
1078 // Get information about the data type specified
1079 if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS)
1080 return(DispAllErrors(henv, hdbc, hstmt));
1081 // Fetch the record
1082 if ((retcode = SQLFetch(hstmt)) != SQL_SUCCESS)
3ca6a5f0 1083 {
1fc5dd6f 1084#ifdef DBDEBUG_CONSOLE
3ca6a5f0
BP
1085 if (retcode == SQL_NO_DATA_FOUND)
1086 cout << "SQL_NO_DATA_FOUND fetching inf. about data type." << endl;
108106cf 1087#endif
3ca6a5f0
BP
1088 DispAllErrors(henv, hdbc, hstmt);
1089 SQLFreeStmt(hstmt, SQL_CLOSE);
1090 return(FALSE);
1091 }
1e92909e
GT
1092 // Obtain columns from the record
1093 if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) structSQLTypeInfo.TypeName, DB_TYPE_NAME_LEN, &cbRet) != SQL_SUCCESS)
1094 return(DispAllErrors(henv, hdbc, hstmt));
67e9aaa3 1095
f6bcfd97
BP
1096 // BJO 20000503: no more needed with new GetColumns...
1097#if OLD_GETCOLUMNS
67e9aaa3
GT
1098 // BJO 991209
1099 if (Dbms() == dbmsMY_SQL)
3ca6a5f0 1100 {
f6bcfd97
BP
1101 if (!wxStrcmp(structSQLTypeInfo.TypeName, "middleint")) wxStrcpy(structSQLTypeInfo.TypeName, "mediumint");
1102 if (!wxStrcmp(structSQLTypeInfo.TypeName, "middleint unsigned")) wxStrcpy(structSQLTypeInfo.TypeName, "mediumint unsigned");
1103 if (!wxStrcmp(structSQLTypeInfo.TypeName, "integer")) wxStrcpy(structSQLTypeInfo.TypeName, "int");
1104 if (!wxStrcmp(structSQLTypeInfo.TypeName, "integer unsigned")) wxStrcpy(structSQLTypeInfo.TypeName, "int unsigned");
1105 if (!wxStrcmp(structSQLTypeInfo.TypeName, "middleint")) wxStrcpy(structSQLTypeInfo.TypeName, "mediumint");
1106 if (!wxStrcmp(structSQLTypeInfo.TypeName, "varchar")) wxStrcpy(structSQLTypeInfo.TypeName, "char");
3ca6a5f0 1107 }
f6bcfd97
BP
1108
1109 // BJO 20000427 : OpenLink driver
1110 if (!wxStrncmp(dbInf.driverName, "oplodbc", 7) ||
3ca6a5f0
BP
1111 !wxStrncmp(dbInf.driverName, "OLOD", 4))
1112 {
1113 if (!wxStrcmp(structSQLTypeInfo.TypeName, "double precision"))
1114 wxStrcpy(structSQLTypeInfo.TypeName, "real");
1115 }
f6bcfd97 1116#endif
67e9aaa3 1117
1e92909e
GT
1118 if (SQLGetData(hstmt, 3, SQL_C_LONG, (UCHAR*) &structSQLTypeInfo.Precision, 0, &cbRet) != SQL_SUCCESS)
1119 return(DispAllErrors(henv, hdbc, hstmt));
1120 if (SQLGetData(hstmt, 8, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.CaseSensitive, 0, &cbRet) != SQL_SUCCESS)
1121 return(DispAllErrors(henv, hdbc, hstmt));
1122// if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
1123// return(DispAllErrors(henv, hdbc, hstmt));
a2115c88 1124
1e92909e
GT
1125 if (SQLGetData(hstmt, 15, SQL_C_SHORT,(UCHAR*) &structSQLTypeInfo.MaximumScale, 0, &cbRet) != SQL_SUCCESS)
1126 return(DispAllErrors(henv, hdbc, hstmt));
108106cf 1127
1e92909e
GT
1128 if (structSQLTypeInfo.MaximumScale < 0)
1129 structSQLTypeInfo.MaximumScale = 0;
108106cf 1130
1e92909e
GT
1131 // Close the statement handle which closes open cursors
1132 if (SQLFreeStmt(hstmt, SQL_CLOSE) != SQL_SUCCESS)
1133 return(DispAllErrors(henv, hdbc, hstmt));
108106cf 1134
1e92909e
GT
1135 // Completed Successfully
1136 return(TRUE);
108106cf 1137
f6bcfd97 1138} // wxDb::getDataTypeInfo()
108106cf 1139
67e9aaa3 1140
f6bcfd97
BP
1141/********** wxDb::Close() **********/
1142void wxDb::Close(void)
108106cf 1143{
1e92909e
GT
1144 // Close the Sql Log file
1145 if (fpSqlLog)
1146 {
1147 fclose(fpSqlLog);
1148 fpSqlLog = 0;
1149 }
1150
1151 // Free statement handle
1152 if (dbIsOpen)
1153 {
1154 if (SQLFreeStmt(hstmt, SQL_DROP) != SQL_SUCCESS)
1155 DispAllErrors(henv, hdbc);
1156 }
1157
1158 // Disconnect from the datasource
1159 if (SQLDisconnect(hdbc) != SQL_SUCCESS)
1160 DispAllErrors(henv, hdbc);
1161
1162 // Free the connection to the datasource
1163 if (SQLFreeConnect(hdbc) != SQL_SUCCESS)
1164 DispAllErrors(henv, hdbc);
1165
1166 // There should be zero Ctable objects still connected to this db object
1167 assert(nTables == 0);
a2115c88 1168
e041ce57 1169#ifdef __WXDEBUG__
fdc03678 1170 wxTablesInUse *tiu;
1e92909e
GT
1171 wxNode *pNode;
1172 pNode = TablesInUse.First();
1173 wxString s,s2;
1174 while (pNode)
1175 {
fdc03678 1176 tiu = (wxTablesInUse *)pNode->Data();
1e92909e
GT
1177 if (tiu->pDb == this)
1178 {
fbdcff4a
JS
1179 s.sprintf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu->tableName,tiu->tableID,tiu->pDb);
1180 s2.sprintf(wxT("Orphaned found using pDb:[%p]"),this);
0efe4a98 1181 wxLogDebug (s.c_str(),s2.c_str());
1e92909e
GT
1182 }
1183 pNode = pNode->Next();
1184 }
a2115c88
GT
1185#endif
1186
1e92909e
GT
1187 // Copy the error messages to a global variable
1188 int i;
1189 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
1190 wxStrcpy(DBerrorList[i],errorList[i]);
a2115c88 1191
a8aa2258
GT
1192 dbmsType = dbmsUNIDENTIFIED;
1193 dbIsOpen = FALSE;
1194
f6bcfd97 1195} // wxDb::Close()
108106cf 1196
67e9aaa3 1197
f6bcfd97
BP
1198/********** wxDb::CommitTrans() **********/
1199bool wxDb::CommitTrans(void)
108106cf 1200{
1e92909e
GT
1201 if (this)
1202 {
1203 // Commit the transaction
1204 if (SQLTransact(henv, hdbc, SQL_COMMIT) != SQL_SUCCESS)
1205 return(DispAllErrors(henv, hdbc));
1206 }
108106cf 1207
1e92909e
GT
1208 // Completed successfully
1209 return(TRUE);
108106cf 1210
f6bcfd97 1211} // wxDb::CommitTrans()
108106cf 1212
67e9aaa3 1213
f6bcfd97
BP
1214/********** wxDb::RollbackTrans() **********/
1215bool wxDb::RollbackTrans(void)
108106cf 1216{
1e92909e
GT
1217 // Rollback the transaction
1218 if (SQLTransact(henv, hdbc, SQL_ROLLBACK) != SQL_SUCCESS)
1219 return(DispAllErrors(henv, hdbc));
108106cf 1220
1e92909e
GT
1221 // Completed successfully
1222 return(TRUE);
108106cf 1223
f6bcfd97 1224} // wxDb::RollbackTrans()
108106cf 1225
67e9aaa3 1226
f6bcfd97
BP
1227/********** wxDb::DispAllErrors() **********/
1228bool wxDb::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
a8aa2258
GT
1229/*
1230 * This function is called internally whenever an error condition prevents the user's
1231 * request from being executed. This function will query the datasource as to the
1232 * actual error(s) that just occured on the previous request of the datasource.
1233 *
1234 * The function will retrieve each error condition from the datasource and
1235 * sprintf the codes/text values into a string which it then logs via logError().
1236 * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
1237 * window and program execution will be paused until the user presses a key.
1238 *
1239 * This function always returns a FALSE, so that functions which call this function
1240 * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure
1241 * of the users request, so that the calling code can then process the error msg log
1242 */
108106cf 1243{
1e92909e
GT
1244 wxString odbcErrMsg;
1245
1246 while (SQLError(aHenv, aHdbc, aHstmt, (UCHAR FAR *) sqlState, &nativeError, (UCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
1247 {
1248 odbcErrMsg.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState, nativeError, errorMsg);
f6bcfd97 1249 logError(odbcErrMsg.c_str(), sqlState);
1e92909e
GT
1250 if (!silent)
1251 {
1fc5dd6f 1252#ifdef DBDEBUG_CONSOLE
1e92909e 1253 // When run in console mode, use standard out to display errors.
f6bcfd97 1254 cout << odbcErrMsg.c_str() << endl;
1e92909e
GT
1255 cout << "Press any key to continue..." << endl;
1256 getchar();
108106cf 1257#endif
a2115c88
GT
1258
1259#ifdef __WXDEBUG__
f6bcfd97 1260 wxLogDebug(odbcErrMsg.c_str(),wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
a2115c88 1261#endif
f6bcfd97 1262 }
1e92909e 1263 }
108106cf 1264
1e92909e 1265 return(FALSE); // This function always returns false.
108106cf 1266
f6bcfd97 1267} // wxDb::DispAllErrors()
108106cf 1268
67e9aaa3 1269
f6bcfd97
BP
1270/********** wxDb::GetNextError() **********/
1271bool wxDb::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
108106cf 1272{
1e92909e
GT
1273 if (SQLError(aHenv, aHdbc, aHstmt, (UCHAR FAR *) sqlState, &nativeError, (UCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
1274 return(TRUE);
1275 else
1276 return(FALSE);
108106cf 1277
f6bcfd97 1278} // wxDb::GetNextError()
108106cf 1279
67e9aaa3 1280
f6bcfd97
BP
1281/********** wxDb::DispNextError() **********/
1282void wxDb::DispNextError(void)
108106cf 1283{
1e92909e 1284 wxString odbcErrMsg;
108106cf 1285
1e92909e 1286 odbcErrMsg.sprintf("SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState, nativeError, errorMsg);
f6bcfd97 1287 logError(odbcErrMsg.c_str(), sqlState);
108106cf 1288
1e92909e
GT
1289 if (silent)
1290 return;
108106cf 1291
1fc5dd6f 1292#ifdef DBDEBUG_CONSOLE
1e92909e 1293 // When run in console mode, use standard out to display errors.
f6bcfd97 1294 cout << odbcErrMsg.c_str() << endl;
1e92909e
GT
1295 cout << "Press any key to continue..." << endl;
1296 getchar();
108106cf
JS
1297#endif
1298
f6bcfd97
BP
1299#ifdef __WXDEBUG__
1300 wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE"));
1301#endif // __WXDEBUG__
108106cf 1302
f6bcfd97
BP
1303} // wxDb::DispNextError()
1304
1305
1306/********** wxDb::logError() **********/
1307void wxDb::logError(const char *errMsg, const char *SQLState)
108106cf 1308{
1e92909e 1309 assert(errMsg && wxStrlen(errMsg));
108106cf 1310
1e92909e
GT
1311 static int pLast = -1;
1312 int dbStatus;
108106cf 1313
1e92909e
GT
1314 if (++pLast == DB_MAX_ERROR_HISTORY)
1315 {
1316 int i;
1317 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
1318 wxStrcpy(errorList[i], errorList[i+1]);
1319 pLast--;
1320 }
108106cf 1321
1e92909e 1322 wxStrcpy(errorList[pLast], errMsg);
108106cf 1323
1e92909e
GT
1324 if (SQLState && wxStrlen(SQLState))
1325 if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
1326 DB_STATUS = dbStatus;
108106cf 1327
1e92909e
GT
1328 // Add the errmsg to the sql log
1329 WriteSqlLog(errMsg);
a2115c88 1330
f6bcfd97 1331} // wxDb::logError()
108106cf 1332
67e9aaa3 1333
f6bcfd97
BP
1334/**********wxDb::TranslateSqlState() **********/
1335int wxDb::TranslateSqlState(const wxChar *SQLState)
108106cf 1336{
f6bcfd97 1337 if (!wxStrcmp(SQLState, wxT("01000")))
1e92909e 1338 return(DB_ERR_GENERAL_WARNING);
f6bcfd97 1339 if (!wxStrcmp(SQLState, wxT("01002")))
1e92909e 1340 return(DB_ERR_DISCONNECT_ERROR);
f6bcfd97 1341 if (!wxStrcmp(SQLState, wxT("01004")))
1e92909e 1342 return(DB_ERR_DATA_TRUNCATED);
f6bcfd97 1343 if (!wxStrcmp(SQLState, wxT("01006")))
1e92909e 1344 return(DB_ERR_PRIV_NOT_REVOKED);
f6bcfd97 1345 if (!wxStrcmp(SQLState, wxT("01S00")))
1e92909e 1346 return(DB_ERR_INVALID_CONN_STR_ATTR);
f6bcfd97 1347 if (!wxStrcmp(SQLState, wxT("01S01")))
1e92909e 1348 return(DB_ERR_ERROR_IN_ROW);
f6bcfd97 1349 if (!wxStrcmp(SQLState, wxT("01S02")))
1e92909e 1350 return(DB_ERR_OPTION_VALUE_CHANGED);
f6bcfd97 1351 if (!wxStrcmp(SQLState, wxT("01S03")))
1e92909e 1352 return(DB_ERR_NO_ROWS_UPD_OR_DEL);
f6bcfd97 1353 if (!wxStrcmp(SQLState, wxT("01S04")))
1e92909e 1354 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL);
f6bcfd97 1355 if (!wxStrcmp(SQLState, wxT("07001")))
1e92909e 1356 return(DB_ERR_WRONG_NO_OF_PARAMS);
f6bcfd97 1357 if (!wxStrcmp(SQLState, wxT("07006")))
1e92909e 1358 return(DB_ERR_DATA_TYPE_ATTR_VIOL);
f6bcfd97 1359 if (!wxStrcmp(SQLState, wxT("08001")))
1e92909e 1360 return(DB_ERR_UNABLE_TO_CONNECT);
f6bcfd97 1361 if (!wxStrcmp(SQLState, wxT("08002")))
1e92909e 1362 return(DB_ERR_CONNECTION_IN_USE);
f6bcfd97 1363 if (!wxStrcmp(SQLState, wxT("08003")))
1e92909e 1364 return(DB_ERR_CONNECTION_NOT_OPEN);
f6bcfd97 1365 if (!wxStrcmp(SQLState, wxT("08004")))
1e92909e 1366 return(DB_ERR_REJECTED_CONNECTION);
f6bcfd97 1367 if (!wxStrcmp(SQLState, wxT("08007")))
1e92909e 1368 return(DB_ERR_CONN_FAIL_IN_TRANS);
f6bcfd97 1369 if (!wxStrcmp(SQLState, wxT("08S01")))
1e92909e 1370 return(DB_ERR_COMM_LINK_FAILURE);
f6bcfd97 1371 if (!wxStrcmp(SQLState, wxT("21S01")))
1e92909e 1372 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH);
f6bcfd97 1373 if (!wxStrcmp(SQLState, wxT("21S02")))
1e92909e 1374 return(DB_ERR_DERIVED_TABLE_MISMATCH);
f6bcfd97 1375 if (!wxStrcmp(SQLState, wxT("22001")))
1e92909e 1376 return(DB_ERR_STRING_RIGHT_TRUNC);
f6bcfd97 1377 if (!wxStrcmp(SQLState, wxT("22003")))
1e92909e 1378 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG);
f6bcfd97 1379 if (!wxStrcmp(SQLState, wxT("22005")))
1e92909e 1380 return(DB_ERR_ERROR_IN_ASSIGNMENT);
f6bcfd97 1381 if (!wxStrcmp(SQLState, wxT("22008")))
1e92909e 1382 return(DB_ERR_DATETIME_FLD_OVERFLOW);
f6bcfd97 1383 if (!wxStrcmp(SQLState, wxT("22012")))
1e92909e 1384 return(DB_ERR_DIVIDE_BY_ZERO);
f6bcfd97 1385 if (!wxStrcmp(SQLState, wxT("22026")))
1e92909e 1386 return(DB_ERR_STR_DATA_LENGTH_MISMATCH);
f6bcfd97 1387 if (!wxStrcmp(SQLState, wxT("23000")))
1e92909e 1388 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL);
f6bcfd97 1389 if (!wxStrcmp(SQLState, wxT("24000")))
1e92909e 1390 return(DB_ERR_INVALID_CURSOR_STATE);
f6bcfd97 1391 if (!wxStrcmp(SQLState, wxT("25000")))
1e92909e 1392 return(DB_ERR_INVALID_TRANS_STATE);
f6bcfd97 1393 if (!wxStrcmp(SQLState, wxT("28000")))
1e92909e 1394 return(DB_ERR_INVALID_AUTH_SPEC);
f6bcfd97 1395 if (!wxStrcmp(SQLState, wxT("34000")))
1e92909e 1396 return(DB_ERR_INVALID_CURSOR_NAME);
f6bcfd97 1397 if (!wxStrcmp(SQLState, wxT("37000")))
1e92909e 1398 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL);
f6bcfd97 1399 if (!wxStrcmp(SQLState, wxT("3C000")))
1e92909e 1400 return(DB_ERR_DUPLICATE_CURSOR_NAME);
f6bcfd97 1401 if (!wxStrcmp(SQLState, wxT("40001")))
1e92909e 1402 return(DB_ERR_SERIALIZATION_FAILURE);
f6bcfd97 1403 if (!wxStrcmp(SQLState, wxT("42000")))
1e92909e 1404 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2);
f6bcfd97 1405 if (!wxStrcmp(SQLState, wxT("70100")))
1e92909e 1406 return(DB_ERR_OPERATION_ABORTED);
f6bcfd97 1407 if (!wxStrcmp(SQLState, wxT("IM001")))
1e92909e 1408 return(DB_ERR_UNSUPPORTED_FUNCTION);
f6bcfd97 1409 if (!wxStrcmp(SQLState, wxT("IM002")))
1e92909e 1410 return(DB_ERR_NO_DATA_SOURCE);
f6bcfd97 1411 if (!wxStrcmp(SQLState, wxT("IM003")))
1e92909e 1412 return(DB_ERR_DRIVER_LOAD_ERROR);
f6bcfd97 1413 if (!wxStrcmp(SQLState, wxT("IM004")))
1e92909e 1414 return(DB_ERR_SQLALLOCENV_FAILED);
f6bcfd97 1415 if (!wxStrcmp(SQLState, wxT("IM005")))
1e92909e 1416 return(DB_ERR_SQLALLOCCONNECT_FAILED);
f6bcfd97 1417 if (!wxStrcmp(SQLState, wxT("IM006")))
1e92909e 1418 return(DB_ERR_SQLSETCONNECTOPTION_FAILED);
f6bcfd97 1419 if (!wxStrcmp(SQLState, wxT("IM007")))
1e92909e 1420 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB);
f6bcfd97 1421 if (!wxStrcmp(SQLState, wxT("IM008")))
1e92909e 1422 return(DB_ERR_DIALOG_FAILED);
f6bcfd97 1423 if (!wxStrcmp(SQLState, wxT("IM009")))
1e92909e 1424 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL);
f6bcfd97 1425 if (!wxStrcmp(SQLState, wxT("IM010")))
1e92909e 1426 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG);
f6bcfd97 1427 if (!wxStrcmp(SQLState, wxT("IM011")))
1e92909e 1428 return(DB_ERR_DRIVER_NAME_TOO_LONG);
f6bcfd97 1429 if (!wxStrcmp(SQLState, wxT("IM012")))
1e92909e 1430 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR);
f6bcfd97 1431 if (!wxStrcmp(SQLState, wxT("IM013")))
1e92909e 1432 return(DB_ERR_TRACE_FILE_ERROR);
f6bcfd97 1433 if (!wxStrcmp(SQLState, wxT("S0001")))
1e92909e 1434 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS);
f6bcfd97 1435 if (!wxStrcmp(SQLState, wxT("S0002")))
1e92909e 1436 return(DB_ERR_TABLE_NOT_FOUND);
f6bcfd97 1437 if (!wxStrcmp(SQLState, wxT("S0011")))
1e92909e 1438 return(DB_ERR_INDEX_ALREADY_EXISTS);
f6bcfd97 1439 if (!wxStrcmp(SQLState, wxT("S0012")))
1e92909e 1440 return(DB_ERR_INDEX_NOT_FOUND);
f6bcfd97 1441 if (!wxStrcmp(SQLState, wxT("S0021")))
1e92909e 1442 return(DB_ERR_COLUMN_ALREADY_EXISTS);
f6bcfd97 1443 if (!wxStrcmp(SQLState, wxT("S0022")))
1e92909e 1444 return(DB_ERR_COLUMN_NOT_FOUND);
f6bcfd97 1445 if (!wxStrcmp(SQLState, wxT("S0023")))
1e92909e 1446 return(DB_ERR_NO_DEFAULT_FOR_COLUMN);
f6bcfd97 1447 if (!wxStrcmp(SQLState, wxT("S1000")))
1e92909e 1448 return(DB_ERR_GENERAL_ERROR);
f6bcfd97 1449 if (!wxStrcmp(SQLState, wxT("S1001")))
1e92909e 1450 return(DB_ERR_MEMORY_ALLOCATION_FAILURE);
f6bcfd97 1451 if (!wxStrcmp(SQLState, wxT("S1002")))
1e92909e 1452 return(DB_ERR_INVALID_COLUMN_NUMBER);
f6bcfd97 1453 if (!wxStrcmp(SQLState, wxT("S1003")))
1e92909e 1454 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE);
f6bcfd97 1455 if (!wxStrcmp(SQLState, wxT("S1004")))
1e92909e 1456 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE);
f6bcfd97 1457 if (!wxStrcmp(SQLState, wxT("S1008")))
1e92909e 1458 return(DB_ERR_OPERATION_CANCELLED);
f6bcfd97 1459 if (!wxStrcmp(SQLState, wxT("S1009")))
1e92909e 1460 return(DB_ERR_INVALID_ARGUMENT_VALUE);
f6bcfd97 1461 if (!wxStrcmp(SQLState, wxT("S1010")))
1e92909e 1462 return(DB_ERR_FUNCTION_SEQUENCE_ERROR);
f6bcfd97 1463 if (!wxStrcmp(SQLState, wxT("S1011")))
1e92909e 1464 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME);
f6bcfd97 1465 if (!wxStrcmp(SQLState, wxT("S1012")))
1e92909e 1466 return(DB_ERR_INVALID_TRANS_OPERATION_CODE);
f6bcfd97 1467 if (!wxStrcmp(SQLState, wxT("S1015")))
1e92909e 1468 return(DB_ERR_NO_CURSOR_NAME_AVAIL);
f6bcfd97 1469 if (!wxStrcmp(SQLState, wxT("S1090")))
1e92909e 1470 return(DB_ERR_INVALID_STR_OR_BUF_LEN);
f6bcfd97 1471 if (!wxStrcmp(SQLState, wxT("S1091")))
1e92909e 1472 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE);
f6bcfd97 1473 if (!wxStrcmp(SQLState, wxT("S1092")))
1e92909e 1474 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE);
f6bcfd97 1475 if (!wxStrcmp(SQLState, wxT("S1093")))
1e92909e 1476 return(DB_ERR_INVALID_PARAM_NO);
f6bcfd97 1477 if (!wxStrcmp(SQLState, wxT("S1094")))
1e92909e 1478 return(DB_ERR_INVALID_SCALE_VALUE);
f6bcfd97 1479 if (!wxStrcmp(SQLState, wxT("S1095")))
1e92909e 1480 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE);
f6bcfd97 1481 if (!wxStrcmp(SQLState, wxT("S1096")))
1e92909e 1482 return(DB_ERR_INF_TYPE_OUT_OF_RANGE);
f6bcfd97 1483 if (!wxStrcmp(SQLState, wxT("S1097")))
1e92909e 1484 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE);
f6bcfd97 1485 if (!wxStrcmp(SQLState, wxT("S1098")))
1e92909e 1486 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE);
f6bcfd97 1487 if (!wxStrcmp(SQLState, wxT("S1099")))
1e92909e 1488 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE);
f6bcfd97 1489 if (!wxStrcmp(SQLState, wxT("S1100")))
1e92909e 1490 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE);
f6bcfd97 1491 if (!wxStrcmp(SQLState, wxT("S1101")))
1e92909e 1492 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE);
f6bcfd97 1493 if (!wxStrcmp(SQLState, wxT("S1103")))
1e92909e 1494 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE);
f6bcfd97 1495 if (!wxStrcmp(SQLState, wxT("S1104")))
1e92909e 1496 return(DB_ERR_INVALID_PRECISION_VALUE);
f6bcfd97 1497 if (!wxStrcmp(SQLState, wxT("S1105")))
1e92909e 1498 return(DB_ERR_INVALID_PARAM_TYPE);
f6bcfd97 1499 if (!wxStrcmp(SQLState, wxT("S1106")))
1e92909e 1500 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE);
f6bcfd97 1501 if (!wxStrcmp(SQLState, wxT("S1107")))
1e92909e 1502 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE);
f6bcfd97 1503 if (!wxStrcmp(SQLState, wxT("S1108")))
1e92909e 1504 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE);
f6bcfd97 1505 if (!wxStrcmp(SQLState, wxT("S1109")))
1e92909e 1506 return(DB_ERR_INVALID_CURSOR_POSITION);
f6bcfd97 1507 if (!wxStrcmp(SQLState, wxT("S1110")))
1e92909e 1508 return(DB_ERR_INVALID_DRIVER_COMPLETION);
f6bcfd97 1509 if (!wxStrcmp(SQLState, wxT("S1111")))
1e92909e 1510 return(DB_ERR_INVALID_BOOKMARK_VALUE);
f6bcfd97 1511 if (!wxStrcmp(SQLState, wxT("S1C00")))
1e92909e 1512 return(DB_ERR_DRIVER_NOT_CAPABLE);
f6bcfd97 1513 if (!wxStrcmp(SQLState, wxT("S1T00")))
1e92909e
GT
1514 return(DB_ERR_TIMEOUT_EXPIRED);
1515
1516 // No match
1517 return(0);
108106cf 1518
f6bcfd97 1519} // wxDb::TranslateSqlState()
67e9aaa3 1520
23f681ec 1521
f6bcfd97
BP
1522/********** wxDb::Grant() **********/
1523bool wxDb::Grant(int privileges, const char *tableName, const char *userList)
108106cf 1524{
1e92909e
GT
1525 wxString sqlStmt;
1526
1527 // Build the grant statement
1528 sqlStmt = "GRANT ";
1529 if (privileges == DB_GRANT_ALL)
1530 sqlStmt += "ALL";
1531 else
1532 {
1533 int c = 0;
1534 if (privileges & DB_GRANT_SELECT)
1535 {
1536 sqlStmt += "SELECT";
1537 c++;
1538 }
1539 if (privileges & DB_GRANT_INSERT)
1540 {
1541 if (c++)
1542 sqlStmt += ", ";
1543 sqlStmt += "INSERT";
1544 }
1545 if (privileges & DB_GRANT_UPDATE)
1546 {
1547 if (c++)
1548 sqlStmt += ", ";
1549 sqlStmt += "UPDATE";
1550 }
1551 if (privileges & DB_GRANT_DELETE)
1552 {
1553 if (c++)
1554 sqlStmt += ", ";
1555 sqlStmt += "DELETE";
1556 }
1557 }
1558
1559 sqlStmt += " ON ";
1560 sqlStmt += tableName;
1561 sqlStmt += " TO ";
1562 sqlStmt += userList;
108106cf 1563
1fc5dd6f 1564#ifdef DBDEBUG_CONSOLE
f6bcfd97 1565 cout << endl << sqlStmt.c_str() << endl;
108106cf
JS
1566#endif
1567
f6bcfd97 1568 WriteSqlLog(sqlStmt.c_str());
1fc5dd6f 1569
f6bcfd97 1570 return(ExecSql(sqlStmt.c_str()));
108106cf 1571
f6bcfd97 1572} // wxDb::Grant()
108106cf 1573
67e9aaa3 1574
f6bcfd97
BP
1575/********** wxDb::CreateView() **********/
1576bool wxDb::CreateView(const char *viewName, const char *colList, const char *pSqlStmt, bool attemptDrop)
108106cf 1577{
1e92909e
GT
1578 wxString sqlStmt;
1579
1580 // Drop the view first
1581 if (attemptDrop && !DropView(viewName))
1582 return FALSE;
1583
1584 // Build the create view statement
1585 sqlStmt = "CREATE VIEW ";
1586 sqlStmt += viewName;
23f681ec 1587
1e92909e
GT
1588 if (wxStrlen(colList))
1589 {
1590 sqlStmt += " (";
1591 sqlStmt += colList;
1592 sqlStmt += ")";
1593 }
108106cf 1594
1e92909e
GT
1595 sqlStmt += " AS ";
1596 sqlStmt += pSqlStmt;
108106cf 1597
f6bcfd97 1598 WriteSqlLog(sqlStmt.c_str());
1fc5dd6f
JS
1599
1600#ifdef DBDEBUG_CONSOLE
f6bcfd97 1601 cout << sqlStmt.c_str() << endl;
108106cf
JS
1602#endif
1603
f6bcfd97 1604 return(ExecSql(sqlStmt.c_str()));
108106cf 1605
f6bcfd97 1606} // wxDb::CreateView()
108106cf 1607
67e9aaa3 1608
f6bcfd97
BP
1609/********** wxDb::DropView() **********/
1610bool wxDb::DropView(const char *viewName)
a2115c88 1611{
67e9aaa3
GT
1612/*
1613 * NOTE: This function returns TRUE if the View does not exist, but
1614 * only for identified databases. Code will need to be added
1e92909e 1615 * below for any other databases when those databases are defined
67e9aaa3
GT
1616 * to handle this situation consistently
1617 */
1e92909e
GT
1618// char sqlStmt[DB_MAX_STATEMENT_LEN];
1619 wxString sqlStmt;
a2115c88 1620
1e92909e 1621 sqlStmt.sprintf("DROP VIEW %s", viewName);
a2115c88 1622
f6bcfd97 1623 WriteSqlLog(sqlStmt.c_str());
a2115c88
GT
1624
1625#ifdef DBDEBUG_CONSOLE
f6bcfd97 1626 cout << endl << sqlStmt.c_str() << endl;
a2115c88
GT
1627#endif
1628
f6bcfd97 1629 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
1e92909e
GT
1630 {
1631 // Check for "Base table not found" error and ignore
1632 GetNextError(henv, hdbc, hstmt);
f6bcfd97 1633 if (wxStrcmp(sqlState,wxT("S0002"))) // "Base table not found"
1e92909e
GT
1634 {
1635 // Check for product specific error codes
f6bcfd97 1636 if (!((Dbms() == dbmsSYBASE_ASA && !wxStrcmp(sqlState,wxT("42000"))))) // 5.x (and lower?)
1e92909e
GT
1637 {
1638 DispNextError();
1639 DispAllErrors(henv, hdbc, hstmt);
1640 RollbackTrans();
1641 return(FALSE);
1642 }
1643 }
1644 }
1645
1646 // Commit the transaction
1647 if (! CommitTrans())
1648 return(FALSE);
1649
1650 return TRUE;
a2115c88 1651
f6bcfd97 1652} // wxDb::DropView()
a2115c88
GT
1653
1654
f6bcfd97
BP
1655/********** wxDb::ExecSql() **********/
1656bool wxDb::ExecSql(const char *pSqlStmt)
108106cf 1657{
1e92909e
GT
1658 SQLFreeStmt(hstmt, SQL_CLOSE);
1659 if (SQLExecDirect(hstmt, (UCHAR FAR *) pSqlStmt, SQL_NTS) == SQL_SUCCESS)
1660 return(TRUE);
1661 else
1662 {
1663 DispAllErrors(henv, hdbc, hstmt);
1664 return(FALSE);
1665 }
108106cf 1666
f6bcfd97 1667} // wxDb::ExecSql()
108106cf 1668
67e9aaa3 1669
f6bcfd97
BP
1670/********** wxDb::GetNext() **********/
1671bool wxDb::GetNext(void)
a2115c88 1672{
1e92909e
GT
1673 if (SQLFetch(hstmt) == SQL_SUCCESS)
1674 return(TRUE);
1675 else
1676 {
1677 DispAllErrors(henv, hdbc, hstmt);
1678 return(FALSE);
1679 }
a2115c88 1680
f6bcfd97 1681} // wxDb::GetNext()
a2115c88 1682
67e9aaa3 1683
f6bcfd97
BP
1684/********** wxDb::GetData() **********/
1685bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FAR *cbReturned)
a2115c88 1686{
1e92909e
GT
1687 assert(pData);
1688 assert(cbReturned);
a2115c88 1689
1e92909e
GT
1690 if (SQLGetData(hstmt, colNo, cType, pData, maxLen, cbReturned) == SQL_SUCCESS)
1691 return(TRUE);
1692 else
1693 {
1694 DispAllErrors(henv, hdbc, hstmt);
1695 return(FALSE);
1696 }
a2115c88 1697
f6bcfd97 1698} // wxDb::GetData()
a2115c88 1699
67e9aaa3 1700
f6bcfd97
BP
1701/********** wxDb::GetKeyFields() **********/
1702int wxDb::GetKeyFields(char *tableName, wxDbColInf* colInf, int noCols)
67e9aaa3
GT
1703{
1704 char szPkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Primary key table name */
1705 char szFkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Foreign key table name */
1706 short iKeySeq;
1707// SQLSMALLINT iKeySeq;
1708 char szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */
1709 char szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */
1710 SQLRETURN retcode;
1711 SDWORD cb;
1712 int i;
1713 wxString Temp0;
1714 /*
1715 * ---------------------------------------------------------------------
0cd121f9 1716 * -- 19991224 : mj10777 : Create ------
67e9aaa3
GT
1717 * -- : Three things are done and stored here : ------
1718 * -- : 1) which Column(s) is/are Primary Key(s) ------
1719 * -- : 2) which tables use this Key as a Foreign Key ------
1720 * -- : 3) which columns are Foreign Key and the name ------
1721 * -- : of the Table where the Key is the Primary Key -----
1722 * -- : Called from GetColumns(char *tableName, ------
1723 * -- int *numCols,const char *userID ) ------
1724 * ---------------------------------------------------------------------
1725 */
1726
1727 /*---------------------------------------------------------------------*/
1728 /* Get the names of the columns in the primary key. */
1729 /*---------------------------------------------------------------------*/
1730 retcode = SQLPrimaryKeys(hstmt,
1731 NULL, 0, /* Catalog name */
1732 NULL, 0, /* Schema name */
1733 (UCHAR *) tableName, SQL_NTS); /* Table name */
1734
1735 /*---------------------------------------------------------------------*/
1736 /* Fetch and display the result set. This will be a list of the */
1737 /* columns in the primary key of the tableName table. */
1738 /*---------------------------------------------------------------------*/
1739 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1740 {
1741 retcode = SQLFetch(hstmt);
1742 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1743 {
1744 GetData( 4, SQL_C_CHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1745 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
1746 //-------
1747 for (i=0;i<noCols;i++) // Find the Column name
1748 if (!wxStrcmp(colInf[i].colName,szPkCol)) // We have found the Column
1749 colInf[i].PkCol = iKeySeq; // Which Primary Key is this (first, second usw.) ?
3ca6a5f0
BP
1750 } // if
1751 } // while
67e9aaa3
GT
1752 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
1753
1754 /*---------------------------------------------------------------------*/
1755 /* Get all the foreign keys that refer to tableName primary key. */
1756 /*---------------------------------------------------------------------*/
1757 retcode = SQLForeignKeys(hstmt,
1e92909e
GT
1758 NULL, 0, /* Primary catalog */
1759 NULL, 0, /* Primary schema */
1760 (UCHAR *)tableName, SQL_NTS, /* Primary table */
1761 NULL, 0, /* Foreign catalog */
1762 NULL, 0, /* Foreign schema */
1763 NULL, 0); /* Foreign table */
67e9aaa3
GT
1764
1765 /*---------------------------------------------------------------------*/
1766 /* Fetch and display the result set. This will be all of the foreign */
1767 /* keys in other tables that refer to the tableName primary key. */
1768 /*---------------------------------------------------------------------*/
1769 Temp0.Empty();
1770 szPkCol[0] = 0;
1771 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1772 {
1773 retcode = SQLFetch(hstmt);
1774 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1775 {
1776 GetData( 3, SQL_C_CHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
1777 GetData( 4, SQL_C_CHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1778 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
1779 GetData( 7, SQL_C_CHAR, szFkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
1780 GetData( 8, SQL_C_CHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
f6bcfd97 1781 Temp0.Printf(wxT("%s[%s] "),Temp0.c_str(),szFkTable); // [ ] in case there is a blank in the Table name
3ca6a5f0
BP
1782 } // if
1783 } // while
67e9aaa3 1784 Temp0.Trim(); // Get rid of any unneeded blanks
f6bcfd97 1785 if (Temp0 != wxT(""))
67e9aaa3 1786 {
3ca6a5f0
BP
1787 for (i=0;i<noCols;i++)
1788 { // Find the Column name
1789 if (!wxStrcmp(colInf[i].colName,szPkCol)) // We have found the Column, store the Information
1790 wxStrcpy(colInf[i].PkTableName,Temp0.c_str()); // Name of the Tables where this Primary Key is used as a Foreign Key
1791 }
1792 } // if
67e9aaa3
GT
1793 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
1794
1795 /*---------------------------------------------------------------------*/
1796 /* Get all the foreign keys in the tablename table. */
1797 /*---------------------------------------------------------------------*/
1798 retcode = SQLForeignKeys(hstmt,
1799 NULL, 0, /* Primary catalog */
1800 NULL, 0, /* Primary schema */
1801 NULL, 0, /* Primary table */
1802 NULL, 0, /* Foreign catalog */
1803 NULL, 0, /* Foreign schema */
1804 (UCHAR *)tableName, SQL_NTS); /* Foreign table */
1805
1806 /*---------------------------------------------------------------------*/
1807 /* Fetch and display the result set. This will be all of the */
1808 /* primary keys in other tables that are referred to by foreign */
1809 /* keys in the tableName table. */
1810 /*---------------------------------------------------------------------*/
1811 i = 0;
1812 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
1813 {
1814 retcode = SQLFetch(hstmt);
1815 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1816 {
1817 GetData( 3, SQL_C_CHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
1818 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
1819 GetData( 8, SQL_C_CHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1820 //-------
1821 for (i=0;i<noCols;i++) // Find the Column name
1822 {
1823 if (!wxStrcmp(colInf[i].colName,szFkCol)) // We have found the (Foreign Key) Column
1824 {
1825 colInf[i].FkCol = iKeySeq; // Which Foreign Key is this (first, second usw.) ?
3ca6a5f0
BP
1826 wxStrcpy(colInf[i].FkTableName,szPkTable); // Name of the Table where this Foriegn is the Primary Key
1827 } // if
1828 } // for
1829 } // if
1830 } // while
67e9aaa3
GT
1831 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
1832
67e9aaa3 1833 return TRUE;
3ca6a5f0 1834
f6bcfd97 1835} // wxDb::GetKeyFields()
67e9aaa3
GT
1836
1837
f6bcfd97
BP
1838#if OLD_GETCOLUMNS
1839/********** wxDb::GetColumns() **********/
1840wxDbColInf *wxDb::GetColumns(char *tableName[], const char *userID)
108106cf 1841/*
1e92909e
GT
1842 * 1) The last array element of the tableName[] argument must be zero (null).
1843 * This is how the end of the array is detected.
f6bcfd97 1844 * 2) This function returns an array of wxDbColInf structures. If no columns
1e92909e
GT
1845 * were found, or an error occured, this pointer will be zero (null). THE
1846 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
1847 * IS FINISHED WITH IT. i.e.
108106cf 1848 *
f6bcfd97 1849 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
1e92909e
GT
1850 * if (colInf)
1851 * {
1852 * // Use the column inf
1853 * .......
1854 * // Destroy the memory
1855 * delete [] colInf;
1856 * }
67e9aaa3
GT
1857 *
1858 * userID is evaluated in the following manner:
1e92909e
GT
1859 * userID == NULL ... UserID is ignored
1860 * userID == "" ... UserID set equal to 'this->uid'
1861 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 1862 *
f6bcfd97
BP
1863 * NOTE: ALL column bindings associated with this wxDb instance are unbound
1864 * by this function. This function should use its own wxDb instance
ea5d599d 1865 * to avoid undesired unbinding of columns.
108106cf 1866 */
108106cf 1867{
1e92909e
GT
1868 int noCols = 0;
1869 int colNo = 0;
f6bcfd97 1870 wxDbColInf *colInf = 0;
1e92909e
GT
1871
1872 RETCODE retcode;
1873 SDWORD cb;
1874
1875 wxString UserID;
1876 wxString TableName;
1877
1878 if (userID)
1879 {
1880 if (!wxStrlen(userID))
1881 UserID = uid;
1882 else
1883 UserID = userID;
1884 }
1885 else
1886 UserID = "";
1887
1888 // dBase does not use user names, and some drivers fail if you try to pass one
1889 if (Dbms() == dbmsDBASE)
1890 UserID = "";
1891
d8a0a1c9 1892 // Oracle and Interbase user names may only be in uppercase, so force
1e92909e
GT
1893 // the name to uppercase
1894 if (Dbms() == dbmsORACLE)
1895 UserID = UserID.Upper();
1896
1897 // Pass 1 - Determine how many columns there are.
f6bcfd97 1898 // Pass 2 - Allocate the wxDbColInf array and fill in
1e92909e
GT
1899 // the array with the column information.
1900 int pass;
1901 for (pass = 1; pass <= 2; pass++)
1902 {
1903 if (pass == 2)
1904 {
1905 if (noCols == 0) // Probably a bogus table name(s)
1906 break;
f6bcfd97
BP
1907 // Allocate n wxDbColInf objects to hold the column information
1908 colInf = new wxDbColInf[noCols+1];
1e92909e
GT
1909 if (!colInf)
1910 break;
1911 // Mark the end of the array
f6bcfd97
BP
1912 wxStrcpy(colInf[noCols].tableName, wxT(""));
1913 wxStrcpy(colInf[noCols].colName, wxT(""));
1e92909e
GT
1914 colInf[noCols].sqlDataType = 0;
1915 }
1916 // Loop through each table name
1917 int tbl;
1918 for (tbl = 0; tableName[tbl]; tbl++)
1919 {
1920 TableName = tableName[tbl];
d8a0a1c9 1921 // Oracle and Interbase table names are uppercase only, so force
1e92909e 1922 // the name to uppercase just in case programmer forgot to do this
d8a0a1c9
GT
1923 if ((Dbms() == dbmsORACLE) ||
1924 (Dbms() == dbmsINTERBASE))
1e92909e
GT
1925 TableName = TableName.Upper();
1926
1927 SQLFreeStmt(hstmt, SQL_CLOSE);
1928
a8aa2258 1929 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
1e92909e 1930 // use the call below that leaves out the user name
f6bcfd97 1931 if (wxStrcmp(UserID.c_str(),wxT("")) &&
1e92909e 1932 Dbms() != dbmsMY_SQL &&
a8aa2258
GT
1933 Dbms() != dbmsACCESS &&
1934 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
1935 {
1936 retcode = SQLColumns(hstmt,
1937 NULL, 0, // All qualifiers
f6bcfd97
BP
1938 (UCHAR *) UserID.c_str(), SQL_NTS, // Owner
1939 (UCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
1940 NULL, 0); // All columns
1941 }
1942 else
1943 {
1944 retcode = SQLColumns(hstmt,
1945 NULL, 0, // All qualifiers
1946 NULL, 0, // Owner
f6bcfd97 1947 (UCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
1948 NULL, 0); // All columns
1949 }
1950 if (retcode != SQL_SUCCESS)
1951 { // Error occured, abort
1952 DispAllErrors(henv, hdbc, hstmt);
1953 if (colInf)
1954 delete [] colInf;
1955 SQLFreeStmt(hstmt, SQL_CLOSE);
1956 return(0);
1957 }
1958
1959 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
1960 {
1961 if (pass == 1) // First pass, just add up the number of columns
1962 noCols++;
1963 else // Pass 2; Fill in the array of structures
1964 {
1965 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
1966 {
1967 // NOTE: Only the ODBC 1.x fields are retrieved
1968 GetData( 1, SQL_C_CHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
1969 GetData( 2, SQL_C_CHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
1970 GetData( 3, SQL_C_CHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
1971 GetData( 4, SQL_C_CHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1972 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
1973 GetData( 6, SQL_C_CHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
1974 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnSize, 0, &cb);
1975 GetData( 8, SQL_C_SLONG, (UCHAR*) &colInf[colNo].bufferLength, 0, &cb);
1976 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
1977 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
1978 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
52a17fe5 1979 GetData(12, SQL_C_CHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
3ca6a5f0 1980
f6bcfd97 1981 // Determine the wxDb data type that is used to represent the native data type of this data source
1e92909e
GT
1982 colInf[colNo].dbDataType = 0;
1983 if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
52a17fe5 1984 {
a8aa2258
GT
1985#ifdef _IODBC_
1986 // IODBC does not return a correct columnSize, so we set
1987 // columnSize = bufferLength if no column size was returned
1988 // IODBC returns the columnSize in bufferLength.. (bug)
52a17fe5
GT
1989 if (colInf[colNo].columnSize < 1)
1990 {
52a17fe5
GT
1991 colInf[colNo].columnSize = colInf[colNo].bufferLength;
1992 }
a8aa2258 1993#endif
1e92909e 1994 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
52a17fe5 1995 }
1e92909e
GT
1996 else if (!wxStricmp(typeInfInteger.TypeName,colInf[colNo].typeName))
1997 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
1998 else if (!wxStricmp(typeInfFloat.TypeName,colInf[colNo].typeName))
1999 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
2000 else if (!wxStricmp(typeInfDate.TypeName,colInf[colNo].typeName))
2001 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
2002
2003 colNo++;
2004 }
2005 }
2006 }
2007 if (retcode != SQL_NO_DATA_FOUND)
2008 { // Error occured, abort
2009 DispAllErrors(henv, hdbc, hstmt);
2010 if (colInf)
2011 delete [] colInf;
2012 SQLFreeStmt(hstmt, SQL_CLOSE);
2013 return(0);
2014 }
2015 }
2016 }
2017
2018 SQLFreeStmt(hstmt, SQL_CLOSE);
2019 return colInf;
108106cf 2020
f6bcfd97 2021} // wxDb::GetColumns()
108106cf
JS
2022
2023
f6bcfd97
BP
2024/********** wxDb::GetColumns() **********/
2025
2026wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
2027//
2028// Same as the above GetColumns() function except this one gets columns
2029// only for a single table, and if 'numCols' is not NULL, the number of
2030// columns stored in the returned wxDbColInf is set in '*numCols'
2031//
2032// userID is evaluated in the following manner:
2033// userID == NULL ... UserID is ignored
2034// userID == "" ... UserID set equal to 'this->uid'
2035// userID != "" ... UserID set equal to 'userID'
2036//
2037// NOTE: ALL column bindings associated with this wxDb instance are unbound
2038// by this function. This function should use its own wxDb instance
2039// to avoid undesired unbinding of columns.
2040
67e9aaa3 2041{
1e92909e
GT
2042 int noCols = 0;
2043 int colNo = 0;
f6bcfd97 2044 wxDbColInf *colInf = 0;
1e92909e
GT
2045
2046 RETCODE retcode;
2047 SDWORD cb;
2048
2049 wxString UserID;
2050 wxString TableName;
2051
2052 if (userID)
2053 {
2054 if (!wxStrlen(userID))
2055 UserID = uid;
2056 else
2057 UserID = userID;
2058 }
2059 else
2060 UserID = "";
2061
2062 // dBase does not use user names, and some drivers fail if you try to pass one
2063 if (Dbms() == dbmsDBASE)
2064 UserID = "";
2065
23f681ec 2066 // Oracle user names may only be in uppercase, so force
1e92909e
GT
2067 // the name to uppercase
2068 if (Dbms() == dbmsORACLE)
2069 UserID = UserID.Upper();
2070
2071 // Pass 1 - Determine how many columns there are.
f6bcfd97 2072 // Pass 2 - Allocate the wxDbColInf array and fill in
1e92909e
GT
2073 // the array with the column information.
2074 int pass;
2075 for (pass = 1; pass <= 2; pass++)
2076 {
2077 if (pass == 2)
2078 {
2079 if (noCols == 0) // Probably a bogus table name(s)
2080 break;
f6bcfd97
BP
2081 // Allocate n wxDbColInf objects to hold the column information
2082 colInf = new wxDbColInf[noCols+1];
1e92909e
GT
2083 if (!colInf)
2084 break;
2085 // Mark the end of the array
f6bcfd97
BP
2086 wxStrcpy(colInf[noCols].tableName, wxT(""));
2087 wxStrcpy(colInf[noCols].colName, wxT(""));
1e92909e
GT
2088 colInf[noCols].sqlDataType = 0;
2089 }
2090
2091 TableName = tableName;
d8a0a1c9 2092 // Oracle and Interbase table names are uppercase only, so force
1e92909e 2093 // the name to uppercase just in case programmer forgot to do this
d8a0a1c9
GT
2094 if ((Dbms() == dbmsORACLE) ||
2095 (Dbms() == dbmsINTERBASE))
1e92909e
GT
2096 TableName = TableName.Upper();
2097
2098 SQLFreeStmt(hstmt, SQL_CLOSE);
2099
a8aa2258 2100 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
1e92909e 2101 // use the call below that leaves out the user name
f6bcfd97 2102 if (wxStrcmp(UserID.c_str(),wxT("")) &&
1e92909e 2103 Dbms() != dbmsMY_SQL &&
a8aa2258
GT
2104 Dbms() != dbmsACCESS &&
2105 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
2106 {
2107 retcode = SQLColumns(hstmt,
2108 NULL, 0, // All qualifiers
f6bcfd97
BP
2109 (UCHAR *) UserID.c_str(), SQL_NTS, // Owner
2110 (UCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2111 NULL, 0); // All columns
2112 }
2113 else
2114 {
2115 retcode = SQLColumns(hstmt,
2116 NULL, 0, // All qualifiers
2117 NULL, 0, // Owner
f6bcfd97 2118 (UCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2119 NULL, 0); // All columns
2120 }
2121 if (retcode != SQL_SUCCESS)
2122 { // Error occured, abort
2123 DispAllErrors(henv, hdbc, hstmt);
2124 if (colInf)
2125 delete [] colInf;
2126 SQLFreeStmt(hstmt, SQL_CLOSE);
2127 if (numCols)
2128 *numCols = 0;
2129 return(0);
2130 }
2131
2132 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2133 {
2134 if (pass == 1) // First pass, just add up the number of columns
2135 noCols++;
2136 else // Pass 2; Fill in the array of structures
2137 {
2138 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2139 {
2140 // NOTE: Only the ODBC 1.x fields are retrieved
2141 GetData( 1, SQL_C_CHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2142 GetData( 2, SQL_C_CHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2143 GetData( 3, SQL_C_CHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2144 GetData( 4, SQL_C_CHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2145 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
2146 GetData( 6, SQL_C_CHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
2147 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnSize, 0, &cb);
67e9aaa3 2148 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
23f681ec 2149 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferLength, 0, &cb);
1e92909e
GT
2150 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2151 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2152 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
2153 GetData(12, SQL_C_CHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
67e9aaa3
GT
2154 // Start Values for Primary/Foriegn Key (=No)
2155 colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2156 colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2157 colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2158 colInf[colNo].FkTableName[0] = 0; // Foreign key table name
2159
3ca6a5f0
BP
2160 // BJO 20000428 : Virtuoso returns type names with upper cases!
2161 if (Dbms() == dbmsVIRTUOSO)
2162 {
2163 wxString s = colInf[colNo].typeName;
2164 s = s.MakeLower();
2165 wxStrcmp(colInf[colNo].typeName, s.c_str());
2166 }
2167
2168 // Determine the wxDb data type that is used to represent the native data type of this data source
2169 colInf[colNo].dbDataType = 0;
2170 if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
2171 {
a8aa2258
GT
2172#ifdef _IODBC_
2173 // IODBC does not return a correct columnSize, so we set
2174 // columnSize = bufferLength if no column size was returned
2175 // IODBC returns the columnSize in bufferLength.. (bug)
3ca6a5f0
BP
2176 if (colInf[colNo].columnSize < 1)
2177 {
a8aa2258 2178 colInf[colNo].columnSize = colInf[colNo].bufferLength;
3ca6a5f0 2179 }
a8aa2258
GT
2180#endif
2181
3ca6a5f0
BP
2182 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
2183 }
2184 else if (!wxStricmp(typeInfInteger.TypeName,colInf[colNo].typeName))
2185 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
2186 else if (!wxStricmp(typeInfFloat.TypeName,colInf[colNo].typeName))
2187 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
2188 else if (!wxStricmp(typeInfDate.TypeName,colInf[colNo].typeName))
2189 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
2190
1e92909e
GT
2191 colNo++;
2192 }
2193 }
2194 }
2195 if (retcode != SQL_NO_DATA_FOUND)
3ca6a5f0 2196 { // Error occured, abort
1e92909e
GT
2197 DispAllErrors(henv, hdbc, hstmt);
2198 if (colInf)
3ca6a5f0 2199 delete [] colInf;
1e92909e
GT
2200 SQLFreeStmt(hstmt, SQL_CLOSE);
2201 if (numCols)
3ca6a5f0 2202 *numCols = 0;
1e92909e 2203 return(0);
3ca6a5f0 2204 }
1e92909e 2205 }
67e9aaa3
GT
2206
2207 SQLFreeStmt(hstmt, SQL_CLOSE);
2208
2209 // Store Primary and Foriegn Keys
2210 GetKeyFields(tableName,colInf,noCols);
2211
2212 if (numCols)
1e92909e
GT
2213 *numCols = noCols;
2214 return colInf;
67e9aaa3 2215
f6bcfd97
BP
2216} // wxDb::GetColumns()
2217
f6bcfd97 2218
3ca6a5f0 2219#else // New GetColumns
67e9aaa3
GT
2220
2221
f6bcfd97 2222/*
3ca6a5f0
BP
2223 BJO 20000503
2224 These are tentative new GetColumns members which should be more database
2225 independant and which always returns the columns in the order they were
2226 created.
2227
2228 - The first one (wxDbColInf *wxDb::GetColumns(char *tableName[], const
2229 char* userID)) calls the second implementation for each separate table
2230 before merging the results. This makes the code easier to maintain as
2231 only one member (the second) makes the real work
2232 - wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const
2233 char *userID) is a little bit improved
2234 - It doesn't anymore rely on the type-name to find out which database-type
2235 each column has
2236 - It ends by sorting the columns, so that they are returned in the same
2237 order they were created
f6bcfd97
BP
2238*/
2239
2240typedef struct
2241{
3ca6a5f0
BP
2242 int noCols;
2243 wxDbColInf *colInf;
f6bcfd97
BP
2244} _TableColumns;
2245
3ca6a5f0 2246
f6bcfd97
BP
2247wxDbColInf *wxDb::GetColumns(char *tableName[], const char* userID)
2248{
3ca6a5f0
BP
2249 int i, j;
2250 // The last array element of the tableName[] argument must be zero (null).
2251 // This is how the end of the array is detected.
2252
2253 int noCols = 0;
2254
2255 // How many tables ?
2256 int tbl;
2257 for (tbl = 0 ; tableName[tbl]; tbl++);
2258
2259 // Create a table to maintain the columns for each separate table
2260 _TableColumns *TableColumns = new _TableColumns[tbl];
2261
2262 // Fill the table
2263 for (i = 0 ; i < tbl ; i++)
2264
2265 {
2266 TableColumns[i].colInf = GetColumns(tableName[i], &TableColumns[i].noCols, userID);
2267 if (TableColumns[i].colInf == NULL)
2268 return NULL;
2269 noCols += TableColumns[i].noCols;
2270 }
2271
2272 // Now merge all the separate table infos
2273 wxDbColInf *colInf = new wxDbColInf[noCols+1];
2274
2275 // Mark the end of the array
2276 wxStrcpy(colInf[noCols].tableName, wxT(""));
2277 wxStrcpy(colInf[noCols].colName, wxT(""));
2278 colInf[noCols].sqlDataType = 0;
2279
2280 // Merge ...
2281 int offset = 0;
2282
2283 for (i = 0 ; i < tbl ; i++)
2284 {
2285 for (j = 0 ; j < TableColumns[i].noCols ; j++)
2286 {
2287 colInf[offset++] = TableColumns[i].colInf[j];
2288 }
2289 }
2290
2291 delete [] TableColumns;
2292
2293 return colInf;
2294} // wxDb::GetColumns() -- NEW
f6bcfd97
BP
2295
2296
2297wxDbColInf *wxDb::GetColumns(char *tableName, int *numCols, const char *userID)
3ca6a5f0
BP
2298//
2299// Same as the above GetColumns() function except this one gets columns
2300// only for a single table, and if 'numCols' is not NULL, the number of
2301// columns stored in the returned wxDbColInf is set in '*numCols'
2302//
2303// userID is evaluated in the following manner:
2304// userID == NULL ... UserID is ignored
2305// userID == "" ... UserID set equal to 'this->uid'
2306// userID != "" ... UserID set equal to 'userID'
2307//
2308// NOTE: ALL column bindings associated with this wxDb instance are unbound
2309// by this function. This function should use its own wxDb instance
2310// to avoid undesired unbinding of columns.
f6bcfd97 2311{
3ca6a5f0
BP
2312 SWORD noCols = 0;
2313 int colNo = 0;
2314 wxDbColInf *colInf = 0;
2315
2316 RETCODE retcode;
2317 SDWORD cb;
2318
2319 wxString UserID;
2320 wxString TableName;
2321
2322 if (userID)
2323 {
2324 if (!wxStrlen(userID))
2325 UserID = uid;
2326 else
2327 UserID = userID;
2328 }
2329 else
2330 UserID = "";
2331
2332 // dBase does not use user names, and some drivers fail if you try to pass one
2333 if (Dbms() == dbmsDBASE)
2334 UserID = "";
2335
2336 // Oracle user names may only be in uppercase, so force
2337 // the name to uppercase
2338 if (Dbms() == dbmsORACLE)
2339 UserID = UserID.Upper();
2340
2341 // Pass 1 - Determine how many columns there are.
2342 // Pass 2 - Allocate the wxDbColInf array and fill in
2343 // the array with the column information.
2344 int pass;
2345 for (pass = 1; pass <= 2; pass++)
2346 {
2347 if (pass == 2)
f6bcfd97 2348 {
3ca6a5f0
BP
2349 if (noCols == 0) // Probably a bogus table name(s)
2350 break;
2351 // Allocate n wxDbColInf objects to hold the column information
2352 colInf = new wxDbColInf[noCols+1];
2353 if (!colInf)
2354 break;
2355 // Mark the end of the array
2356 wxStrcpy(colInf[noCols].tableName, wxT(""));
2357 wxStrcpy(colInf[noCols].colName, wxT(""));
2358 colInf[noCols].sqlDataType = 0;
f6bcfd97 2359 }
3ca6a5f0
BP
2360
2361 TableName = tableName;
d8a0a1c9 2362 // Oracle and Interbase table names are uppercase only, so force
3ca6a5f0 2363 // the name to uppercase just in case programmer forgot to do this
d8a0a1c9
GT
2364 if ((Dbms() == dbmsORACLE) ||
2365 (Dbms() == dbmsINTERBASE))
3ca6a5f0
BP
2366 TableName = TableName.Upper();
2367
2368 SQLFreeStmt(hstmt, SQL_CLOSE);
2369
a8aa2258 2370 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
3ca6a5f0
BP
2371 // use the call below that leaves out the user name
2372 if (wxStrcmp(UserID.c_str(),wxT("")) &&
2373 Dbms() != dbmsMY_SQL &&
a8aa2258
GT
2374 Dbms() != dbmsACCESS &&
2375 Dbms() != dbmsMS_SQL_SERVER)
f6bcfd97 2376 {
3ca6a5f0
BP
2377 retcode = SQLColumns(hstmt,
2378 NULL, 0, // All qualifiers
2379 (UCHAR *) UserID.c_str(), SQL_NTS, // Owner
2380 (UCHAR *) TableName.c_str(), SQL_NTS,
2381 NULL, 0); // All columns
f6bcfd97 2382 }
3ca6a5f0 2383 else
f6bcfd97 2384 {
3ca6a5f0
BP
2385 retcode = SQLColumns(hstmt,
2386 NULL, 0, // All qualifiers
2387 NULL, 0, // Owner
2388 (UCHAR *) TableName.c_str(), SQL_NTS,
2389 NULL, 0); // All columns
f6bcfd97 2390 }
3ca6a5f0 2391 if (retcode != SQL_SUCCESS)
f6bcfd97 2392 { // Error occured, abort
3ca6a5f0
BP
2393 DispAllErrors(henv, hdbc, hstmt);
2394 if (colInf)
2395 delete [] colInf;
2396 SQLFreeStmt(hstmt, SQL_CLOSE);
2397 if (numCols)
2398 *numCols = 0;
2399 return(0);
f6bcfd97 2400 }
3ca6a5f0 2401
f6bcfd97
BP
2402 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2403 {
2404 if (pass == 1) // First pass, just add up the number of columns
2405 noCols++;
2406 else // Pass 2; Fill in the array of structures
2407 {
2408 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2409 {
2410 // NOTE: Only the ODBC 1.x fields are retrieved
2411 GetData( 1, SQL_C_CHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2412 GetData( 2, SQL_C_CHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2413 GetData( 3, SQL_C_CHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2414 GetData( 4, SQL_C_CHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2415 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
2416 GetData( 6, SQL_C_CHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
2417 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnSize, 0, &cb);
2418 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferLength, 0, &cb);
2419 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2420 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2421 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
2422 GetData(12, SQL_C_CHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
2423 // Start Values for Primary/Foriegn Key (=No)
2424 colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2425 colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2426 colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2427 colInf[colNo].FkTableName[0] = 0; // Foreign key table name
3ca6a5f0
BP
2428
2429#ifdef _IODBC_
a8aa2258
GT
2430 // IODBC does not return a correct columnSize, so we set
2431 // columnSize = bufferLength if no column size was returned
3ca6a5f0 2432 // IODBC returns the columnSize in bufferLength.. (bug)
a8aa2258
GT
2433 if (colInf[colNo].columnSize < 1)
2434 {
2435 colInf[colNo].columnSize = colInf[colNo].bufferLength;
2436 }
f6bcfd97 2437#endif
3ca6a5f0
BP
2438
2439 // Determine the wxDb data type that is used to represent the native data type of this data source
2440 colInf[colNo].dbDataType = 0;
2441 // Get the intern datatype
2442 switch (colInf[colNo].sqlDataType)
2443 {
2444 case SQL_VARCHAR:
2445 case SQL_CHAR:
2446 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
2447 break;
2448
2449 case SQL_TINYINT:
2450 case SQL_SMALLINT:
2451 case SQL_INTEGER:
2452 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
2453 break;
2454 case SQL_DOUBLE:
2455 case SQL_DECIMAL:
2456 case SQL_NUMERIC:
2457 case SQL_FLOAT:
2458 case SQL_REAL:
2459 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
2460 break;
2461 case SQL_DATE:
2462 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
2463 break;
f6bcfd97 2464#ifdef __WXDEBUG__
3ca6a5f0
BP
2465 default:
2466 wxString errMsg;
2467 errMsg.sprintf("SQL Data type %d currently not supported by wxWindows", colInf[colNo].sqlDataType);
2468 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
2469#endif
2470 }
f6bcfd97
BP
2471 colNo++;
2472 }
2473 }
2474 }
2475 if (retcode != SQL_NO_DATA_FOUND)
3ca6a5f0 2476 { // Error occured, abort
f6bcfd97
BP
2477 DispAllErrors(henv, hdbc, hstmt);
2478 if (colInf)
3ca6a5f0 2479 delete [] colInf;
f6bcfd97
BP
2480 SQLFreeStmt(hstmt, SQL_CLOSE);
2481 if (numCols)
3ca6a5f0 2482 *numCols = 0;
f6bcfd97 2483 return(0);
3ca6a5f0
BP
2484 }
2485 }
2486
2487 SQLFreeStmt(hstmt, SQL_CLOSE);
2488
2489 // Store Primary and Foreign Keys
2490 GetKeyFields(tableName,colInf,noCols);
2491
2492 ///////////////////////////////////////////////////////////////////////////
2493 // Now sort the the columns in order to make them appear in the right order
2494 ///////////////////////////////////////////////////////////////////////////
2495
2496 // Build a generic SELECT statement which returns 0 rows
2497 wxString Stmt;
2498
2499 Stmt.sprintf("select * from %s where 0=1", tableName);
2500
2501 // Execute query
2502 if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS)
2503 {
2504 DispAllErrors(henv, hdbc, hstmt);
2505 return NULL;
f6bcfd97 2506 }
3ca6a5f0
BP
2507
2508 // Get the number of result columns
2509 if (SQLNumResultCols (hstmt, &noCols) != SQL_SUCCESS)
2510 {
2511 DispAllErrors(henv, hdbc, hstmt);
2512 return NULL;
2513 }
2514
2515 if (noCols == 0) // Probably a bogus table name
2516 return NULL;
2517
2518 // Get the name
2519 int i;
2520 short colNum;
2521 UCHAR name[100];
2522 SWORD Sword;
2523 SDWORD Sdword;
2524 for (colNum = 0; colNum < noCols; colNum++)
f6bcfd97 2525 {
3ca6a5f0
BP
2526 if (SQLColAttributes(hstmt,colNum+1, SQL_COLUMN_NAME,
2527 name, sizeof(name),
2528 &Sword, &Sdword) != SQL_SUCCESS)
2529 {
2530 DispAllErrors(henv, hdbc, hstmt);
2531 return NULL;
2532 }
2533
2534 wxString Name1 = name;
2535 Name1 = Name1.Upper();
2536
2537 // Where is this name in the array ?
2538 for (i = colNum ; i < noCols ; i++)
2539 {
2540 wxString Name2 = colInf[i].colName;
2541 Name2 = Name2.Upper();
2542 if (Name2 == Name1)
2543 {
2544 if (colNum != i) // swap to sort
2545 {
2546 wxDbColInf tmpColInf = colInf[colNum];
2547 colInf[colNum] = colInf[i];
2548 colInf[i] = tmpColInf;
2549 }
2550 break;
2551 }
2552 }
f6bcfd97 2553 }
3ca6a5f0 2554 SQLFreeStmt(hstmt, SQL_CLOSE);
f6bcfd97 2555
3ca6a5f0
BP
2556 ///////////////////////////////////////////////////////////////////////////
2557 // End sorting
2558 ///////////////////////////////////////////////////////////////////////////
f6bcfd97 2559
3ca6a5f0
BP
2560 if (numCols)
2561 *numCols = noCols;
2562 return colInf;
2563
f6bcfd97
BP
2564} // wxDb::GetColumns()
2565
2566
3ca6a5f0 2567#endif // #else OLD_GETCOLUMNS
f6bcfd97
BP
2568
2569
2570/********** wxDb::GetColumnCount() **********/
2571int wxDb::GetColumnCount(char *tableName, const char *userID)
67e9aaa3
GT
2572/*
2573 * Returns a count of how many columns are in a table.
2574 * If an error occurs in computing the number of columns
2575 * this function will return a -1 for the count
2576 *
2577 * userID is evaluated in the following manner:
1e92909e
GT
2578 * userID == NULL ... UserID is ignored
2579 * userID == "" ... UserID set equal to 'this->uid'
2580 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 2581 *
f6bcfd97
BP
2582 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2583 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
2584 * to avoid undesired unbinding of columns.
2585 */
2586{
1e92909e
GT
2587 int noCols = 0;
2588
2589 RETCODE retcode;
2590
2591 wxString UserID;
2592 wxString TableName;
2593
2594 if (userID)
2595 {
2596 if (!wxStrlen(userID))
2597 UserID = uid;
2598 else
2599 UserID = userID;
2600 }
2601 else
f6bcfd97 2602 UserID = wxT("");
1e92909e
GT
2603
2604 // dBase does not use user names, and some drivers fail if you try to pass one
2605 if (Dbms() == dbmsDBASE)
f6bcfd97 2606 UserID = wxT("");
1e92909e 2607
23f681ec 2608 // Oracle user names may only be in uppercase, so force
1e92909e
GT
2609 // the name to uppercase
2610 if (Dbms() == dbmsORACLE)
2611 UserID = UserID.Upper();
2612
2613 {
2614 // Loop through each table name
2615 {
2616 TableName = tableName;
d8a0a1c9 2617 // Oracle and Interbase table names are uppercase only, so force
1e92909e 2618 // the name to uppercase just in case programmer forgot to do this
d8a0a1c9
GT
2619 if ((Dbms() == dbmsORACLE) ||
2620 (Dbms() == dbmsINTERBASE))
1e92909e
GT
2621 TableName = TableName.Upper();
2622
2623 SQLFreeStmt(hstmt, SQL_CLOSE);
2624
a8aa2258 2625 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
1e92909e 2626 // use the call below that leaves out the user name
f6bcfd97 2627 if (wxStrcmp(UserID.c_str(),wxT("")) &&
1e92909e 2628 Dbms() != dbmsMY_SQL &&
a8aa2258
GT
2629 Dbms() != dbmsACCESS &&
2630 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
2631 {
2632 retcode = SQLColumns(hstmt,
2633 NULL, 0, // All qualifiers
3ca6a5f0 2634 (UCHAR *) UserID.c_str(), SQL_NTS, // Owner
f6bcfd97 2635 (UCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2636 NULL, 0); // All columns
2637 }
2638 else
2639 {
2640 retcode = SQLColumns(hstmt,
2641 NULL, 0, // All qualifiers
2642 NULL, 0, // Owner
f6bcfd97 2643 (UCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2644 NULL, 0); // All columns
2645 }
2646 if (retcode != SQL_SUCCESS)
2647 { // Error occured, abort
2648 DispAllErrors(henv, hdbc, hstmt);
2649 SQLFreeStmt(hstmt, SQL_CLOSE);
2650 return(-1);
2651 }
2652
2653 // Count the columns
2654 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2655 noCols++;
2656
2657 if (retcode != SQL_NO_DATA_FOUND)
2658 { // Error occured, abort
2659 DispAllErrors(henv, hdbc, hstmt);
2660 SQLFreeStmt(hstmt, SQL_CLOSE);
2661 return(-1);
2662 }
2663 }
2664 }
2665
2666 SQLFreeStmt(hstmt, SQL_CLOSE);
2667 return noCols;
67e9aaa3 2668
f6bcfd97 2669} // wxDb::GetColumnCount()
67e9aaa3
GT
2670
2671
f6bcfd97
BP
2672/********** wxDb::GetCatalog() *******/
2673wxDbInf *wxDb::GetCatalog(char *userID)
67e9aaa3
GT
2674/*
2675 * ---------------------------------------------------------------------
0cd121f9 2676 * -- 19991203 : mj10777 : Create ------
67e9aaa3
GT
2677 * -- : Creates a wxDbInf with Tables / Cols Array ------
2678 * -- : uses SQLTables and fills pTableInf; ------
2679 * -- : pColInf is set to NULL and numCols to 0; ------
2680 * -- : returns pDbInf (wxDbInf) ------
2681 * -- - if unsuccesfull (pDbInf == NULL) ------
2682 * -- : pColInf can be filled with GetColumns(..); ------
2683 * -- : numCols can be filled with GetColumnCount(..); ------
2684 * ---------------------------------------------------------------------
2685 *
2686 * userID is evaluated in the following manner:
1e92909e
GT
2687 * userID == NULL ... UserID is ignored
2688 * userID == "" ... UserID set equal to 'this->uid'
2689 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 2690 *
f6bcfd97
BP
2691 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2692 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
2693 * to avoid undesired unbinding of columns.
2694 */
2695{
1e92909e
GT
2696 wxDbInf *pDbInf = NULL; // Array of catalog entries
2697 int noTab = 0; // Counter while filling table entries
2698 int pass;
2699 RETCODE retcode;
2700 SDWORD cb;
1e92909e
GT
2701 wxString tblNameSave;
2702
2703 wxString UserID;
2704
2705 if (userID)
2706 {
2707 if (!wxStrlen(userID))
2708 UserID = uid;
2709 else
2710 UserID = userID;
2711 }
2712 else
f6bcfd97 2713 UserID = wxT("");
1e92909e
GT
2714
2715 // dBase does not use user names, and some drivers fail if you try to pass one
2716 if (Dbms() == dbmsDBASE)
f6bcfd97 2717 UserID = wxT("");
1e92909e 2718
23f681ec 2719 // Oracle user names may only be in uppercase, so force
1e92909e
GT
2720 // the name to uppercase
2721 if (Dbms() == dbmsORACLE)
2722 UserID = UserID.Upper();
2723
2724 //-------------------------------------------------------------
2725 pDbInf = new wxDbInf; // Create the Database Arrray
1e92909e
GT
2726 //-------------------------------------------------------------
2727 // Table Information
2728 // Pass 1 - Determine how many Tables there are.
2729 // Pass 2 - Create the Table array and fill it
2730 // - Create the Cols array = NULL
2731 //-------------------------------------------------------------
f6bcfd97 2732
1e92909e
GT
2733 for (pass = 1; pass <= 2; pass++)
2734 {
2735 SQLFreeStmt(hstmt, SQL_CLOSE); // Close if Open
f6bcfd97 2736 tblNameSave = wxT("");
1e92909e 2737
f6bcfd97 2738 if (wxStrcmp(UserID.c_str(),wxT("")) &&
3ca6a5f0
BP
2739 Dbms() != dbmsMY_SQL &&
2740 Dbms() != dbmsACCESS)
1e92909e
GT
2741 {
2742 retcode = SQLTables(hstmt,
2743 NULL, 0, // All qualifiers
3ca6a5f0 2744 (UCHAR *) UserID.c_str(), SQL_NTS, // User specified
1e92909e
GT
2745 NULL, 0, // All tables
2746 NULL, 0); // All columns
2747 }
2748 else
2749 {
2750 retcode = SQLTables(hstmt,
2751 NULL, 0, // All qualifiers
2752 NULL, 0, // User specified
2753 NULL, 0, // All tables
2754 NULL, 0); // All columns
2755 }
f6bcfd97 2756
1e92909e
GT
2757 if (retcode != SQL_SUCCESS)
2758 {
2759 DispAllErrors(henv, hdbc, hstmt);
2760 pDbInf = NULL;
2761 SQLFreeStmt(hstmt, SQL_CLOSE);
2762 return pDbInf;
2763 }
3ca6a5f0 2764
1e92909e
GT
2765 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) // Table Information
2766 {
2767 if (pass == 1) // First pass, just count the Tables
2768 {
2769 if (pDbInf->numTables == 0)
2770 {
2771 GetData( 1, SQL_C_CHAR, (UCHAR*) pDbInf->catalog, 128+1, &cb);
2772 GetData( 2, SQL_C_CHAR, (UCHAR*) pDbInf->schema, 128+1, &cb);
2773 }
2774 pDbInf->numTables++; // Counter for Tables
2775 } // if (pass == 1)
2776 if (pass == 2) // Create and fill the Table entries
2777 {
2778 if (pDbInf->pTableInf == NULL) // Has the Table Array been created
2779 { // no, then create the Array
f6bcfd97 2780 pDbInf->pTableInf = new wxDbTableInf[pDbInf->numTables];
1e92909e 2781 noTab = 0;
3ca6a5f0 2782 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
f6bcfd97 2783
1e92909e
GT
2784 GetData( 3, SQL_C_CHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2785 GetData( 4, SQL_C_CHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableType, 30+1, &cb);
2786 GetData( 5, SQL_C_CHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableRemarks, 254+1, &cb);
3ca6a5f0 2787
1e92909e 2788 noTab++;
3ca6a5f0
BP
2789 } // if
2790 } // while
2791 } // for
1e92909e
GT
2792 SQLFreeStmt(hstmt, SQL_CLOSE);
2793
2794 // Query how many columns are in each table
2795 for (noTab=0;noTab<pDbInf->numTables;noTab++)
2796 {
2797 (pDbInf->pTableInf+noTab)->numCols = GetColumnCount((pDbInf->pTableInf+noTab)->tableName,UserID);
2798 }
3ca6a5f0 2799
1e92909e 2800 return pDbInf;
3ca6a5f0 2801
f6bcfd97 2802} // wxDb::GetCatalog()
67e9aaa3
GT
2803
2804
f6bcfd97
BP
2805/********** wxDb::Catalog() **********/
2806bool wxDb::Catalog(const char *userID, const char *fileName)
67e9aaa3
GT
2807/*
2808 * Creates the text file specified in 'filename' which will contain
2809 * a minimal data dictionary of all tables accessible by the user specified
2810 * in 'userID'
2811 *
2812 * userID is evaluated in the following manner:
1e92909e
GT
2813 * userID == NULL ... UserID is ignored
2814 * userID == "" ... UserID set equal to 'this->uid'
2815 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 2816 *
f6bcfd97
BP
2817 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2818 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
2819 * to avoid undesired unbinding of columns.
2820 */
1fc5dd6f 2821{
1e92909e
GT
2822 assert(fileName && wxStrlen(fileName));
2823
2824 RETCODE retcode;
2825 SDWORD cb;
2826 char tblName[DB_MAX_TABLE_NAME_LEN+1];
2827 wxString tblNameSave;
2828 char colName[DB_MAX_COLUMN_NAME_LEN+1];
2829 SWORD sqlDataType;
2830 char typeName[30+1];
2831 SWORD precision, length;
2832
2833 wxString UserID;
2834
2835 FILE *fp = fopen(fileName,"wt");
2836 if (fp == NULL)
2837 return(FALSE);
2838
2839 SQLFreeStmt(hstmt, SQL_CLOSE);
2840
2841 if (userID)
2842 {
2843 if (!wxStrlen(userID))
2844 UserID = uid;
2845 else
2846 UserID = userID;
2847 }
2848 else
f6bcfd97 2849 UserID = wxT("");
1e92909e
GT
2850
2851 // dBase does not use user names, and some drivers fail if you try to pass one
2852 if (Dbms() == dbmsDBASE)
f6bcfd97 2853 UserID = wxT("");
1e92909e 2854
23f681ec 2855 // Oracle user names may only be in uppercase, so force
1e92909e
GT
2856 // the name to uppercase
2857 if (Dbms() == dbmsORACLE)
2858 UserID = UserID.Upper();
2859
f6bcfd97 2860 if (wxStrcmp(UserID.c_str(),wxT("")) &&
1e92909e
GT
2861 Dbms() != dbmsMY_SQL &&
2862 Dbms() != dbmsACCESS)
2863 {
2864 retcode = SQLColumns(hstmt,
2865 NULL, 0, // All qualifiers
3ca6a5f0 2866 (UCHAR *) UserID.c_str(), SQL_NTS, // User specified
1e92909e
GT
2867 NULL, 0, // All tables
2868 NULL, 0); // All columns
2869 }
2870 else
2871 {
2872 retcode = SQLColumns(hstmt,
2873 NULL, 0, // All qualifiers
2874 NULL, 0, // User specified
2875 NULL, 0, // All tables
2876 NULL, 0); // All columns
2877 }
2878 if (retcode != SQL_SUCCESS)
2879 {
2880 DispAllErrors(henv, hdbc, hstmt);
2881 fclose(fp);
2882 return(FALSE);
2883 }
2884
2885 wxString outStr;
f6bcfd97 2886 tblNameSave = wxT("");
1e92909e
GT
2887 int cnt = 0;
2888
2889 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2890 {
f6bcfd97 2891 if (wxStrcmp(tblName,tblNameSave.c_str()))
1e92909e
GT
2892 {
2893 if (cnt)
2894 fputs("\n", fp);
2895 fputs("================================ ", fp);
2896 fputs("================================ ", fp);
2897 fputs("===================== ", fp);
2898 fputs("========= ", fp);
2899 fputs("=========\n", fp);
f6bcfd97
BP
2900 outStr.sprintf(wxT("%-32s %-32s %-21s %9s %9s\n"),
2901 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
2902 fputs(outStr.c_str(), fp);
1e92909e
GT
2903 fputs("================================ ", fp);
2904 fputs("================================ ", fp);
2905 fputs("===================== ", fp);
2906 fputs("========= ", fp);
2907 fputs("=========\n", fp);
2908 tblNameSave = tblName;
2909 }
67e9aaa3
GT
2910
2911 GetData(3,SQL_C_CHAR, (UCHAR *)tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2912 GetData(4,SQL_C_CHAR, (UCHAR *)colName, DB_MAX_COLUMN_NAME_LEN+1,&cb);
2913 GetData(5,SQL_C_SSHORT,(UCHAR *)&sqlDataType,0, &cb);
2914 GetData(6,SQL_C_CHAR, (UCHAR *)typeName, sizeof(typeName), &cb);
2915 GetData(7,SQL_C_SSHORT,(UCHAR *)&precision, 0, &cb);
2916 GetData(8,SQL_C_SSHORT,(UCHAR *)&length, 0, &cb);
2917
1e92909e
GT
2918 outStr.sprintf("%-32s %-32s (%04d)%-15s %9d %9d\n",
2919 tblName, colName, sqlDataType, typeName, precision, length);
f6bcfd97 2920 if (fputs(outStr.c_str(), fp) == EOF)
1e92909e
GT
2921 {
2922 SQLFreeStmt(hstmt, SQL_CLOSE);
2923 fclose(fp);
2924 return(FALSE);
2925 }
2926 cnt++;
2927 }
1fc5dd6f 2928
1e92909e
GT
2929 if (retcode != SQL_NO_DATA_FOUND)
2930 DispAllErrors(henv, hdbc, hstmt);
1fc5dd6f 2931
1e92909e 2932 SQLFreeStmt(hstmt, SQL_CLOSE);
a2115c88 2933
1e92909e
GT
2934 fclose(fp);
2935 return(retcode == SQL_NO_DATA_FOUND);
1fc5dd6f 2936
f6bcfd97 2937} // wxDb::Catalog()
1fc5dd6f
JS
2938
2939
f6bcfd97 2940bool wxDb::TableExists(const char *tableName, const char *userID, const char *tablePath)
67e9aaa3
GT
2941/*
2942 * Table name can refer to a table, view, alias or synonym. Returns true
2943 * if the object exists in the database. This function does not indicate
2944 * whether or not the user has privleges to query or perform other functions
2945 * on the table.
2946 *
2947 * userID is evaluated in the following manner:
1e92909e
GT
2948 * userID == NULL ... UserID is ignored
2949 * userID == "" ... UserID set equal to 'this->uid'
2950 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 2951 */
108106cf 2952{
1e92909e
GT
2953 wxString UserID;
2954 wxString TableName;
3ca6a5f0 2955
1e92909e 2956 assert(tableName && wxStrlen(tableName));
3ca6a5f0 2957
f6bcfd97 2958 if (Dbms() == dbmsDBASE)
1e92909e 2959 {
3ca6a5f0
BP
2960 wxString dbName;
2961 if (tablePath && wxStrlen(tablePath))
2962 dbName.sprintf("%s\\%s.dbf",tablePath,tableName);
2963 else
2964 dbName.sprintf("%s.dbf",tableName);
2965
2966 bool exists;
2967 exists = wxFileExists(dbName.c_str());
2968 return exists;
1e92909e 2969 }
3ca6a5f0 2970
1e92909e
GT
2971 if (userID)
2972 {
2973 if (!wxStrlen(userID))
2974 UserID = uid;
2975 else
2976 UserID = userID;
2977 }
2978 else
2979 UserID = "";
3ca6a5f0 2980
23f681ec 2981 // Oracle user names may only be in uppercase, so force
1e92909e
GT
2982 // the name to uppercase
2983 if (Dbms() == dbmsORACLE)
2984 UserID = UserID.Upper();
3ca6a5f0 2985
1e92909e 2986 TableName = tableName;
d8a0a1c9 2987 // Oracle and Interbase table names are uppercase only, so force
1e92909e 2988 // the name to uppercase just in case programmer forgot to do this
d8a0a1c9
GT
2989 if ((Dbms() == dbmsORACLE) ||
2990 (Dbms() == dbmsINTERBASE))
1e92909e 2991 TableName = TableName.Upper();
3ca6a5f0 2992
1e92909e
GT
2993 SQLFreeStmt(hstmt, SQL_CLOSE);
2994 RETCODE retcode;
3ca6a5f0 2995
a8aa2258
GT
2996 // Some databases cannot accept a user name when looking up table names,
2997 // so we use the call below that leaves out the user name
1e92909e 2998 if (wxStrcmp(UserID,"") &&
3ca6a5f0 2999 Dbms() != dbmsMY_SQL &&
a8aa2258
GT
3000 Dbms() != dbmsACCESS &&
3001 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
3002 {
3003 retcode = SQLTables(hstmt,
3ca6a5f0 3004 NULL, 0, // All qualifiers
a8aa2258 3005 (UCHAR *) UserID.c_str(), SQL_NTS, // Only tables owned by this user
f6bcfd97 3006 (UCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3007 NULL, 0); // All table types
1e92909e
GT
3008 }
3009 else
3010 {
3011 retcode = SQLTables(hstmt,
3ca6a5f0
BP
3012 NULL, 0, // All qualifiers
3013 NULL, 0, // All owners
f6bcfd97 3014 (UCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3015 NULL, 0); // All table types
1e92909e
GT
3016 }
3017 if (retcode != SQL_SUCCESS)
3018 return(DispAllErrors(henv, hdbc, hstmt));
3ca6a5f0 3019
1e92909e 3020 retcode = SQLFetch(hstmt);
a8aa2258 3021 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
1e92909e
GT
3022 {
3023 SQLFreeStmt(hstmt, SQL_CLOSE);
3024 return(DispAllErrors(henv, hdbc, hstmt));
3025 }
3ca6a5f0 3026
1e92909e 3027 SQLFreeStmt(hstmt, SQL_CLOSE);
108106cf 3028
3ca6a5f0
BP
3029 return(TRUE);
3030
f6bcfd97 3031} // wxDb::TableExists()
108106cf
JS
3032
3033
a8aa2258 3034/********** wxDb::TablePrivileges() **********/
eb3b9dda
GT
3035bool wxDb::TablePrivileges(const char *tableName, const char* priv, const char *userID,
3036 const char *schema, const char *tablePath)
3ca6a5f0
BP
3037{
3038 wxDbTablePrivilegeInfo result;
3039 SDWORD cbRetVal;
3040 RETCODE retcode;
3041
3042 //We probably need to be able to dynamically set this based on
3043 //the driver type, and state.
3044 char curRole[]="public";
3045
3046 //Prologue here similar to db::TableExists()
3047 wxString UserID;
3048 wxString TableName;
3049
eb3b9dda 3050 assert(userID);
3ca6a5f0
BP
3051 assert(tableName && wxStrlen(tableName));
3052
3053 if (userID)
3054 {
3055 if (!wxStrlen(userID))
3056 UserID = uid;
3057 else
3058 UserID = userID;
3059 }
3060 else
3061 UserID = "";
3062
3063 // Oracle user names may only be in uppercase, so force
3064 // the name to uppercase
3065 if (Dbms() == dbmsORACLE)
3066 UserID = UserID.Upper();
3067
3068 TableName = tableName;
d8a0a1c9 3069 // Oracle and Interbase table names are uppercase only, so force
3ca6a5f0 3070 // the name to uppercase just in case programmer forgot to do this
d8a0a1c9
GT
3071 if ((Dbms() == dbmsORACLE) ||
3072 (Dbms() == dbmsINTERBASE))
3ca6a5f0
BP
3073 TableName = TableName.Upper();
3074
3075 SQLFreeStmt(hstmt, SQL_CLOSE);
d8a0a1c9
GT
3076
3077 if (!schema)
3078 {
3079 retcode = SQLTablePrivileges(hstmt,
3080 NULL, 0, // Catalog
3081 NULL, 0, // Schema
3082 (UCHAR FAR *)TableName.c_str(), SQL_NTS);
3083 }
3084 else
3085 {
3086 retcode = SQLTablePrivileges(hstmt,
3087 NULL, 0, // Catalog
3088 (UCHAR FAR *)schema, SQL_NTS, // Schema
3089 (UCHAR FAR *)TableName.c_str(), SQL_NTS);
3090 }
a8aa2258 3091
3ca6a5f0
BP
3092#ifdef DBDEBUG_CONSOLE
3093 fprintf(stderr ,"SQLTablePrivileges() returned %i \n",retcode);
3094#endif
3ca6a5f0 3095
a8aa2258
GT
3096 if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
3097 return(DispAllErrors(henv, hdbc, hstmt));
3098
d8a0a1c9
GT
3099 retcode = SQLFetch(hstmt);
3100 while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
3101 {
3102 if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS)
3103 return(DispAllErrors(henv, hdbc, hstmt));
3ca6a5f0 3104
d8a0a1c9
GT
3105 if (SQLGetData(hstmt, 2, SQL_C_CHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS)
3106 return(DispAllErrors(henv, hdbc, hstmt));
3ca6a5f0 3107
d8a0a1c9
GT
3108 if (SQLGetData(hstmt, 3, SQL_C_CHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS)
3109 return(DispAllErrors(henv, hdbc, hstmt));
3ca6a5f0 3110
d8a0a1c9
GT
3111 if (SQLGetData(hstmt, 4, SQL_C_CHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS)
3112 return(DispAllErrors(henv, hdbc, hstmt));
3ca6a5f0 3113
d8a0a1c9
GT
3114 if (SQLGetData(hstmt, 5, SQL_C_CHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS)
3115 return(DispAllErrors(henv, hdbc, hstmt));
a8aa2258 3116
d8a0a1c9
GT
3117 if (SQLGetData(hstmt, 6, SQL_C_CHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS)
3118 return(DispAllErrors(henv, hdbc, hstmt));
3ca6a5f0 3119
d8a0a1c9
GT
3120 if (SQLGetData(hstmt, 7, SQL_C_CHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS)
3121 return(DispAllErrors(henv, hdbc, hstmt));
3122
3ca6a5f0 3123#ifdef DBDEBUG_CONSOLE
a8aa2258
GT
3124 fprintf(stderr,"Scanning %s privilege on table %s.%s granted by %s to %s\n",
3125 result.privilege,result.tableOwner,result.tableName,
3ca6a5f0
BP
3126 result.grantor, result.grantee);
3127#endif
d8a0a1c9 3128
a8aa2258
GT
3129 if (UserID.IsSameAs(result.tableOwner,false))
3130 {
3131 SQLFreeStmt(hstmt, SQL_CLOSE);
3ca6a5f0 3132 return TRUE;
a8aa2258 3133 }
3ca6a5f0
BP
3134
3135 if (UserID.IsSameAs(result.grantee,false) &&
a8aa2258
GT
3136 !wxStrcmp(result.privilege,priv))
3137 {
3138 SQLFreeStmt(hstmt, SQL_CLOSE);
3ca6a5f0 3139 return TRUE;
a8aa2258 3140 }
3ca6a5f0 3141
a8aa2258
GT
3142 if (!wxStrcmp(result.grantee,curRole) &&
3143 !wxStrcmp(result.privilege,priv))
3144 {
3145 SQLFreeStmt(hstmt, SQL_CLOSE);
3ca6a5f0 3146 return TRUE;
a8aa2258 3147 }
3ca6a5f0
BP
3148
3149 retcode = SQLFetch(hstmt);
3150 }
3151
a8aa2258 3152 SQLFreeStmt(hstmt, SQL_CLOSE);
3ca6a5f0
BP
3153 return FALSE;
3154
a8aa2258 3155} // wxDb::TablePrivileges
3ca6a5f0
BP
3156
3157
f6bcfd97
BP
3158/********** wxDb::SetSqlLogging() **********/
3159bool wxDb::SetSqlLogging(wxDbSqlLogState state, const char *filename, bool append)
1fc5dd6f 3160{
ea5d599d
GT
3161 assert(state == sqlLogON || state == sqlLogOFF);
3162 assert(state == sqlLogOFF || filename);
1e92909e 3163
ea5d599d
GT
3164 if (state == sqlLogON)
3165 {
3166 if (fpSqlLog == 0)
3167 {
3168 fpSqlLog = fopen(filename, (append ? "at" : "wt"));
3169 if (fpSqlLog == NULL)
3170 return(FALSE);
3171 }
3172 }
3173 else // sqlLogOFF
3174 {
3175 if (fpSqlLog)
3176 {
3177 if (fclose(fpSqlLog))
3178 return(FALSE);
3179 fpSqlLog = 0;
3180 }
3181 }
1e92909e 3182
ea5d599d
GT
3183 sqlLogState = state;
3184 return(TRUE);
1fc5dd6f 3185
f6bcfd97 3186} // wxDb::SetSqlLogging()
1fc5dd6f
JS
3187
3188
f6bcfd97
BP
3189/********** wxDb::WriteSqlLog() **********/
3190bool wxDb::WriteSqlLog(const wxChar *logMsg)
1fc5dd6f 3191{
1e92909e 3192 assert(logMsg);
1fc5dd6f 3193
1e92909e
GT
3194 if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
3195 return(FALSE);
1fc5dd6f 3196
1e92909e
GT
3197 if (fputs("\n", fpSqlLog) == EOF) return(FALSE);
3198 if (fputs(logMsg, fpSqlLog) == EOF) return(FALSE);
3199 if (fputs("\n", fpSqlLog) == EOF) return(FALSE);
1fc5dd6f 3200
1e92909e 3201 return(TRUE);
1fc5dd6f 3202
f6bcfd97 3203} // wxDb::WriteSqlLog()
1fc5dd6f
JS
3204
3205
f6bcfd97
BP
3206/********** wxDb::Dbms() **********/
3207wxDBMS wxDb::Dbms(void)
a2115c88
GT
3208/*
3209 * Be aware that not all database engines use the exact same syntax, and not
3210 * every ODBC compliant database is compliant to the same level of compliancy.
3211 * Some manufacturers support the minimum Level 1 compliancy, and others up
3212 * through Level 3. Others support subsets of features for levels above 1.
3213 *
f6bcfd97 3214 * If you find an inconsistency between the wxDb class and a specific database
a2115c88
GT
3215 * engine, and an identifier to this section, and special handle the database in
3216 * the area where behavior is non-conforming with the other databases.
3217 *
3218 *
3219 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3220 * ---------------------------------------------------
3221 *
3222 * ORACLE
1e92909e 3223 * - Currently the only database supported by the class to support VIEWS
a2115c88
GT
3224 *
3225 * DBASE
1e92909e
GT
3226 * - Does not support the SQL_TIMESTAMP structure
3227 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
fdc03678
GT
3228 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
3229 * is TRUE. The user must create ALL indexes from their program.
1e92909e
GT
3230 * - Table names can only be 8 characters long
3231 * - Column names can only be 10 characters long
a2115c88
GT
3232 *
3233 * SYBASE (all)
1e92909e
GT
3234 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3235 * after every table name involved in the query/join if that tables matching record(s)
3236 * are to be locked
3237 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
a2115c88
GT
3238 *
3239 * SYBASE (Enterprise)
1e92909e 3240 * - If a column is part of the Primary Key, the column cannot be NULL
3ca6a5f0 3241 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
a2115c88
GT
3242 *
3243 * MY_SQL
1e92909e
GT
3244 * - If a column is part of the Primary Key, the column cannot be NULL
3245 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3ca6a5f0
BP
3246 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3247 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3248 * column definition if it is not defined correctly, but it is experimental
3249 * - Does not support sub-queries in SQL statements
a2115c88
GT
3250 *
3251 * POSTGRES
23f681ec 3252 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3ca6a5f0 3253 * - Does not support sub-queries in SQL statements
a2115c88 3254 *
a8aa2258
GT
3255 * DB2
3256 * - Primary keys must be declared as NOT NULL
3257 *
a2115c88 3258 */
a2115c88 3259{
a8aa2258
GT
3260 // Should only need to do this once for each new database connection
3261 // so return the value we already determined it to be to save time
3262 // and lots of string comparisons
3263 if (dbmsType != dbmsUNIDENTIFIED)
3264 return(dbmsType);
3265
1e92909e 3266 wxChar baseName[25+1];
1e92909e 3267 wxStrncpy(baseName,dbInf.dbmsName,25);
3ca6a5f0 3268 baseName[25] = 0;
f6bcfd97 3269
d8a0a1c9
GT
3270 // RGG 20001025 : add support for Interbase
3271 // GT : Integrated to base classes on 20001121
3272 if (!wxStricmp(dbInf.dbmsName,"Interbase"))
3273 return((wxDBMS)(dbmsType = dbmsINTERBASE));
3274
f6bcfd97
BP
3275 // BJO 20000428 : add support for Virtuoso
3276 if (!wxStricmp(dbInf.dbmsName,"OpenLink Virtuoso VDBMS"))
a8aa2258 3277 return((wxDBMS)(dbmsType = dbmsVIRTUOSO));
f6bcfd97 3278
1e92909e 3279 if (!wxStricmp(dbInf.dbmsName,"Adaptive Server Anywhere"))
a8aa2258
GT
3280 return((wxDBMS)(dbmsType = dbmsSYBASE_ASA));
3281
f6bcfd97
BP
3282 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3283 // connected through an OpenLink driver.
3284 // Is it also returned by Sybase Adapatitve server?
3ca6a5f0 3285 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
f6bcfd97 3286 if (!wxStricmp(dbInf.dbmsName,"SQL Server"))
3ca6a5f0 3287 {
f6bcfd97
BP
3288 if (!wxStrncmp(dbInf.driverName, "oplodbc", 7) ||
3289 !wxStrncmp(dbInf.driverName, "OLOD", 4))
a8aa2258
GT
3290 return ((wxDBMS)(dbmsMS_SQL_SERVER));
3291 else
3292 return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
3ca6a5f0 3293 }
f6bcfd97 3294
1e92909e 3295 if (!wxStricmp(dbInf.dbmsName,"Microsoft SQL Server"))
a8aa2258 3296 return((wxDBMS)(dbmsType = dbmsMS_SQL_SERVER));
1e92909e 3297 if (!wxStricmp(dbInf.dbmsName,"MySQL"))
a8aa2258 3298 return((wxDBMS)(dbmsType = dbmsMY_SQL));
1e92909e 3299 if (!wxStricmp(dbInf.dbmsName,"PostgreSQL")) // v6.5.0
a8aa2258 3300 return((wxDBMS)(dbmsType = dbmsPOSTGRES));
1e92909e
GT
3301
3302 baseName[8] = 0;
3303 if (!wxStricmp(baseName,"Informix"))
a8aa2258 3304 return((wxDBMS)(dbmsType = dbmsINFORMIX));
1e92909e
GT
3305
3306 baseName[6] = 0;
3307 if (!wxStricmp(baseName,"Oracle"))
a8aa2258 3308 return((wxDBMS)(dbmsType = dbmsORACLE));
1e92909e 3309 if (!wxStricmp(dbInf.dbmsName,"ACCESS"))
a8aa2258 3310 return((wxDBMS)(dbmsType = dbmsACCESS));
1e92909e 3311 if (!wxStricmp(dbInf.dbmsName,"MySQL"))
a8aa2258 3312 return((wxDBMS)(dbmsType = dbmsMY_SQL));
f6bcfd97 3313 if (!wxStricmp(baseName,"Sybase"))
a8aa2258 3314 return((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
1e92909e
GT
3315
3316 baseName[5] = 0;
3317 if (!wxStricmp(baseName,"DBASE"))
a8aa2258 3318 return((wxDBMS)(dbmsType = dbmsDBASE));
1e92909e 3319
a8aa2258
GT
3320 baseName[3] = 0;
3321 if (!wxStricmp(baseName,"DB2"))
3322 return((wxDBMS)(dbmsType = dbmsDBASE));
3323
3324 return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
3ca6a5f0 3325
f6bcfd97 3326} // wxDb::Dbms()
a2115c88
GT
3327
3328
fdc03678 3329/********** wxDbGetConnection() **********/
f6bcfd97 3330wxDb WXDLLEXPORT *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors)
108106cf 3331{
fdc03678 3332 wxDbList *pList;
1e92909e 3333
a8aa2258
GT
3334 // Used to keep a pointer to a DB connection that matches the requested
3335 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
3336 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
3337 // rather than having to re-query the datasource to get all the values
3338 // using the wxDb::Open(Dsn,Uid,AuthStr) function
3339 wxDb *matchingDbConnection = NULL;
3340
1e92909e
GT
3341 // Scan the linked list searching for an available database connection
3342 // that's already been opened but is currently not in use.
3343 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3344 {
3345 // The database connection must be for the same datasource
3346 // name and must currently not be in use.
3ca6a5f0
BP
3347 if (pList->Free &&
3348 (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors) &&
3349 (!wxStrcmp(pDbConfig->Dsn, pList->Dsn))) // Found a free connection
1e92909e
GT
3350 {
3351 pList->Free = FALSE;
3352 return(pList->PtrDb);
3353 }
a8aa2258
GT
3354
3355 if (!wxStrcmp(pDbConfig->Dsn, pList->Dsn) &&
3356 !wxStrcmp(pDbConfig->Uid, pList->Uid) &&
3357 !wxStrcmp(pDbConfig->AuthStr, pList->AuthStr))
3358 matchingDbConnection = pList->PtrDb;
1e92909e
GT
3359 }
3360
3361 // No available connections. A new connection must be made and
3362 // appended to the end of the linked list.
3363 if (PtrBegDbList)
3364 {
3365 // Find the end of the list
3366 for (pList = PtrBegDbList; pList->PtrNext; pList = pList->PtrNext);
3367 // Append a new list item
fdc03678 3368 pList->PtrNext = new wxDbList;
1e92909e
GT
3369 pList->PtrNext->PtrPrev = pList;
3370 pList = pList->PtrNext;
3371 }
3ca6a5f0 3372 else // Empty list
1e92909e
GT
3373 {
3374 // Create the first node on the list
fdc03678 3375 pList = PtrBegDbList = new wxDbList;
1e92909e
GT
3376 pList->PtrPrev = 0;
3377 }
3378
3379 // Initialize new node in the linked list
3380 pList->PtrNext = 0;
3381 pList->Free = FALSE;
fdc03678 3382 wxStrcpy(pList->Dsn, pDbConfig->Dsn);
a8aa2258
GT
3383 wxStrcpy(pList->Uid, pDbConfig->Uid);
3384 wxStrcpy(pList->AuthStr, pDbConfig->AuthStr);
3385
f6bcfd97 3386 pList->PtrDb = new wxDb(pDbConfig->Henv,FwdOnlyCursors);
1e92909e 3387
a8aa2258
GT
3388 bool opened = FALSE;
3389
3390 if (!matchingDbConnection)
3391 opened = pList->PtrDb->Open(pDbConfig->Dsn, pDbConfig->Uid, pDbConfig->AuthStr);
3392 else
3393 opened = pList->PtrDb->Open(matchingDbConnection);
3394
1e92909e 3395 // Connect to the datasource
a8aa2258 3396 if (opened)
1e92909e 3397 {
f6bcfd97 3398 pList->PtrDb->SetSqlLogging(SQLLOGstate,SQLLOGfn,TRUE);
1e92909e
GT
3399 return(pList->PtrDb);
3400 }
3401 else // Unable to connect, destroy list item
3402 {
3403 if (pList->PtrPrev)
3404 pList->PtrPrev->PtrNext = 0;
3405 else
3406 PtrBegDbList = 0; // Empty list again
f6bcfd97
BP
3407 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
3408 pList->PtrDb->Close(); // Close the wxDb object
3409 delete pList->PtrDb; // Deletes the wxDb object
1e92909e
GT
3410 delete pList; // Deletes the linked list object
3411 return(0);
3412 }
108106cf 3413
fdc03678 3414} // wxDbGetConnection()
108106cf 3415
67e9aaa3 3416
fdc03678 3417/********** wxDbFreeConnection() **********/
f6bcfd97 3418bool WXDLLEXPORT wxDbFreeConnection(wxDb *pDb)
108106cf 3419{
fdc03678 3420 wxDbList *pList;
108106cf 3421
1e92909e
GT
3422 // Scan the linked list searching for the database connection
3423 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3424 {
3ca6a5f0
BP
3425 if (pList->PtrDb == pDb) // Found it, now free it!!!
3426 return (pList->Free = TRUE);
1e92909e 3427 }
108106cf 3428
1e92909e
GT
3429 // Never found the database object, return failure
3430 return(FALSE);
108106cf 3431
fdc03678 3432} // wxDbFreeConnection()
108106cf 3433
67e9aaa3 3434
fdc03678
GT
3435/********** wxDbCloseConnections() **********/
3436void WXDLLEXPORT wxDbCloseConnections(void)
108106cf 3437{
fdc03678 3438 wxDbList *pList, *pNext;
23f681ec 3439
1e92909e
GT
3440 // Traverse the linked list closing database connections and freeing memory as I go.
3441 for (pList = PtrBegDbList; pList; pList = pNext)
3442 {
3443 pNext = pList->PtrNext; // Save the pointer to next
f6bcfd97
BP
3444 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
3445 pList->PtrDb->Close(); // Close the wxDb object
3446 delete pList->PtrDb; // Deletes the wxDb object
1e92909e
GT
3447 delete pList; // Deletes the linked list object
3448 }
3449
3450 // Mark the list as empty
3451 PtrBegDbList = 0;
108106cf 3452
fdc03678 3453} // wxDbCloseConnections()
108106cf 3454
67e9aaa3 3455
eb3b9dda 3456/********** wxDbConnectionsInUse() **********/
fdc03678 3457int WXDLLEXPORT wxDbConnectionsInUse(void)
108106cf 3458{
fdc03678 3459 wxDbList *pList;
1e92909e 3460 int cnt = 0;
108106cf 3461
1e92909e
GT
3462 // Scan the linked list counting db connections that are currently in use
3463 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3464 {
3465 if (pList->Free == FALSE)
3466 cnt++;
3467 }
108106cf 3468
1e92909e 3469 return(cnt);
108106cf 3470
fdc03678 3471} // wxDbConnectionsInUse()
108106cf 3472
67e9aaa3 3473
fdc03678 3474/********** wxDbSqlLog() **********/
f6bcfd97 3475bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename)
a2115c88 3476{
1e92909e 3477 bool append = FALSE;
fdc03678 3478 wxDbList *pList;
a2115c88 3479
1e92909e
GT
3480 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3481 {
f6bcfd97 3482 if (!pList->PtrDb->SetSqlLogging(state,filename,append))
1e92909e
GT
3483 return(FALSE);
3484 append = TRUE;
3485 }
a2115c88 3486
1e92909e 3487 SQLLOGstate = state;
3ca6a5f0 3488 SQLLOGfn = filename;
a2115c88 3489
1e92909e 3490 return(TRUE);
a2115c88 3491
fdc03678 3492} // wxDbSqlLog()
a2115c88 3493
67e9aaa3 3494
a8aa2258 3495#if 0
fdc03678
GT
3496/********** wxDbCreateDataSource() **********/
3497int wxDbCreateDataSource(const char *driverName, const char *dsn, const char *description,
3498 bool sysDSN, const char *defDir, wxWindow *parent)
3499/*
3500 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3501 * Very rudimentary creation of an ODBC data source.
a8aa2258
GT
3502 *
3503 * ODBC driver must be ODBC 3.0 compliant to use this function
fdc03678
GT
3504 */
3505{
3506 int result = FALSE;
3507
a8aa2258
GT
3508//!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3509#ifdef __VISUALC__
fdc03678
GT
3510 int dsnLocation;
3511 wxString setupStr;
3512
3513 if (sysDSN)
3514 dsnLocation = ODBC_ADD_SYS_DSN;
3515 else
3516 dsnLocation = ODBC_ADD_DSN;
3517
3518 // NOTE: The decimal 2 is an invalid character in all keyword pairs
3519 // so that is why I used it, as wxString does not deal well with
3520 // embedded nulls in strings
3521 setupStr.sprintf("DSN=%s%cDescription=%s%cDefaultDir=%s%c",dsn,2,description,2,defDir,2);
3522
3523 // Replace the separator from above with the '\0' seperator needed
3524 // by the SQLConfigDataSource() function
3525 int k;
3526 do
3527 {
3528 k = setupStr.Find((wxChar)2,TRUE);
3529 if (k != wxNOT_FOUND)
3530 setupStr[(UINT)k] = '\0';
3531 }
3532 while (k != wxNOT_FOUND);
3533
3534 result = SQLConfigDataSource((HWND)parent->GetHWND(), dsnLocation,
f6bcfd97 3535 driverName, setupStr.c_str());
fdc03678 3536
a8aa2258 3537 if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
fdc03678
GT
3538 {
3539 // check for errors caused by ConfigDSN based functions
3540 DWORD retcode = 0;
3541 WORD cb;
a8aa2258 3542 wxChar errMsg[SQL_MAX_MESSAGE_LENGTH];
fdc03678
GT
3543 errMsg[0] = '\0';
3544
a8aa2258
GT
3545 // This function is only supported in ODBC drivers v3.0 compliant and above
3546 SQLInstallerError(1,&retcode,errMsg,SQL_MAX_MESSAGE_LENGTH-1,&cb);
fdc03678
GT
3547 if (retcode)
3548 {
fdc03678 3549#ifdef DBDEBUG_CONSOLE
f6bcfd97
BP
3550 // When run in console mode, use standard out to display errors.
3551 cout << errMsg << endl;
a8aa2258 3552 cout << wxT("Press any key to continue...") << endl;
f6bcfd97 3553 getchar();
fdc03678 3554#endif // DBDEBUG_CONSOLE
fdc03678
GT
3555
3556#ifdef __WXDEBUG__
f6bcfd97 3557 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
fdc03678
GT
3558#endif // __WXDEBUG__
3559 }
3560 }
3561 else
3562 result = TRUE;
a8aa2258
GT
3563#else
3564 // Using iODBC/unixODBC or some other compiler which does not support the APIs
3565 // necessary to use this function, so this function is not supported
fdc03678 3566#ifdef __WXDEBUG__
a8aa2258 3567 wxLogDebug("wxDbCreateDataSource() not available except under VC++/MSW",wxT("ODBC DEBUG MESSAGE"));
fdc03678 3568#endif
a8aa2258
GT
3569 result = FALSE;
3570#endif // __VISUALC__
fdc03678
GT
3571
3572 return result;
3573
3574} // wxDbCreateDataSource()
3575#endif
3576
3577
3578/********** wxDbGetDataSource() **********/
3579bool wxDbGetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
1e92909e 3580 UWORD direction)
67e9aaa3
GT
3581/*
3582 * Dsn and DsDesc will contain the data source name and data source
3583 * description upon return
3584 */
108106cf 3585{
1e92909e 3586 SWORD cb1,cb2;
108106cf 3587
1e92909e
GT
3588 if (SQLDataSources(henv, direction, (UCHAR FAR *) Dsn, DsnMax, &cb1,
3589 (UCHAR FAR *) DsDesc, DsDescMax, &cb2) == SQL_SUCCESS)
3590 return(TRUE);
3591 else
3592 return(FALSE);
108106cf 3593
fdc03678
GT
3594} // wxDbGetDataSource()
3595
3596
3597// Change this to 0 to remove use of all deprecated functions
f6bcfd97 3598#if wxODBC_BACKWARD_COMPATABILITY
fdc03678
GT
3599/********************************************************************
3600 ********************************************************************
3601 *
3602 * The following functions are all DEPRECATED and are included for
3603 * backward compatability reasons only
3604 *
3605 ********************************************************************
3606 ********************************************************************/
f6bcfd97 3607bool SqlLog(sqlLog state, const wxChar *filename)
fdc03678 3608{
f6bcfd97 3609 return wxDbSqlLog((enum wxDbSqlLogState)state, filename);
fdc03678
GT
3610}
3611/***** DEPRECATED: use wxGetDataSource() *****/
3612bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
3613 UWORD direction)
3614{
3615 return wxDbGetDataSource(henv, Dsn, DsnMax, DsDesc, DsDescMax, direction);
3616}
3617/***** DEPRECATED: use wxDbGetConnection() *****/
f6bcfd97 3618wxDb WXDLLEXPORT *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors)
fdc03678
GT
3619{
3620 return wxDbGetConnection((wxDbConnectInf *)pDbStuff, FwdOnlyCursors);
3621}
3622/***** DEPRECATED: use wxDbFreeConnection() *****/
f6bcfd97 3623bool WXDLLEXPORT FreeDbConnection(wxDb *pDb)
fdc03678
GT
3624{
3625 return wxDbFreeConnection(pDb);
3626}
3627/***** DEPRECATED: use wxDbCloseConnections() *****/
3628void WXDLLEXPORT CloseDbConnections(void)
3629{
3630 wxDbCloseConnections();
3631}
3632/***** DEPRECATED: use wxDbConnectionsInUse() *****/
3633int WXDLLEXPORT NumberDbConnectionsInUse(void)
3634{
3635 return wxDbConnectionsInUse();
3636}
3637#endif
3638
3639
108106cf 3640#endif
1fc5dd6f 3641 // wxUSE_ODBC