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