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