]> git.saurik.com Git - wxWidgets.git/blame - src/common/db.cpp
use type safe list instead of wxList for m_columns
[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];
1e92909e
GT
2983 SWORD precision, length;
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
3025 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
3026 {
4fdae997 3027 if (wxStrcmp(tblName, tblNameSave.c_str()))
1e92909e
GT
3028 {
3029 if (cnt)
4fdae997
GT
3030 fputs(wxT("\n"), fp);
3031 fputs(wxT("================================ "), fp);
3032 fputs(wxT("================================ "), fp);
3033 fputs(wxT("===================== "), fp);
3034 fputs(wxT("========= "), fp);
3035 fputs(wxT("=========\n"), fp);
3036 outStr.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
f6bcfd97
BP
3037 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
3038 fputs(outStr.c_str(), fp);
4fdae997
GT
3039 fputs(wxT("================================ "), fp);
3040 fputs(wxT("================================ "), fp);
3041 fputs(wxT("===================== "), fp);
3042 fputs(wxT("========= "), fp);
3043 fputs(wxT("=========\n"), fp);
1e92909e
GT
3044 tblNameSave = tblName;
3045 }
67e9aaa3
GT
3046
3047 GetData(3,SQL_C_CHAR, (UCHAR *)tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
3048 GetData(4,SQL_C_CHAR, (UCHAR *)colName, DB_MAX_COLUMN_NAME_LEN+1,&cb);
3049 GetData(5,SQL_C_SSHORT,(UCHAR *)&sqlDataType,0, &cb);
3050 GetData(6,SQL_C_CHAR, (UCHAR *)typeName, sizeof(typeName), &cb);
3051 GetData(7,SQL_C_SSHORT,(UCHAR *)&precision, 0, &cb);
3052 GetData(8,SQL_C_SSHORT,(UCHAR *)&length, 0, &cb);
3053
4fdae997 3054 outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9d %9d\n"),
1e92909e 3055 tblName, colName, sqlDataType, typeName, precision, length);
f6bcfd97 3056 if (fputs(outStr.c_str(), fp) == EOF)
1e92909e
GT
3057 {
3058 SQLFreeStmt(hstmt, SQL_CLOSE);
3059 fclose(fp);
a144affe 3060 return(FALSE);
1e92909e
GT
3061 }
3062 cnt++;
3063 }
1fc5dd6f 3064
1e92909e
GT
3065 if (retcode != SQL_NO_DATA_FOUND)
3066 DispAllErrors(henv, hdbc, hstmt);
1fc5dd6f 3067
1e92909e 3068 SQLFreeStmt(hstmt, SQL_CLOSE);
a2115c88 3069
1e92909e
GT
3070 fclose(fp);
3071 return(retcode == SQL_NO_DATA_FOUND);
1fc5dd6f 3072
f6bcfd97 3073} // wxDb::Catalog()
1fc5dd6f
JS
3074
3075
4fdae997 3076bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wxString &tablePath)
67e9aaa3 3077/*
a144affe 3078 * Table name can refer to a table, view, alias or synonym. Returns TRUE
67e9aaa3
GT
3079 * if the object exists in the database. This function does not indicate
3080 * whether or not the user has privleges to query or perform other functions
3081 * on the table.
3082 *
3083 * userID is evaluated in the following manner:
1e92909e
GT
3084 * userID == NULL ... UserID is ignored
3085 * userID == "" ... UserID set equal to 'this->uid'
3086 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3087 */
108106cf 3088{
4fdae997 3089 wxASSERT(tableName.Length());
eedb1543 3090
4fdae997 3091 wxString TableName;
eedb1543
DW
3092
3093 if (Dbms() == dbmsDBASE)
1e92909e 3094 {
3ca6a5f0 3095 wxString dbName;
4fdae997 3096 if (tablePath.Length())
942e67c3 3097 dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
3ca6a5f0 3098 else
942e67c3 3099 dbName.Printf(wxT("%s.dbf"), tableName.c_str());
eedb1543 3100
3ca6a5f0 3101 bool exists;
4fdae997 3102 exists = wxFileExists(dbName);
3ca6a5f0 3103 return exists;
1e92909e 3104 }
eedb1543 3105
4fdae997
GT
3106 wxString UserID;
3107 convertUserID(userID,UserID);
eedb1543 3108
1e92909e 3109 TableName = tableName;
d8a0a1c9 3110 // Oracle and Interbase table names are uppercase only, so force
1e92909e 3111 // the name to uppercase just in case programmer forgot to do this
eedb1543 3112 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 3113 (Dbms() == dbmsINTERBASE))
1e92909e 3114 TableName = TableName.Upper();
eedb1543 3115
1e92909e
GT
3116 SQLFreeStmt(hstmt, SQL_CLOSE);
3117 RETCODE retcode;
eedb1543 3118
a8aa2258
GT
3119 // Some databases cannot accept a user name when looking up table names,
3120 // so we use the call below that leaves out the user name
4fdae997 3121 if (!UserID.IsEmpty() &&
3ca6a5f0 3122 Dbms() != dbmsMY_SQL &&
a8aa2258 3123 Dbms() != dbmsACCESS &&
2beca662
GT
3124 Dbms() != dbmsMS_SQL_SERVER &&
3125 Dbms() != dbmsDB2 &&
081eb1b1 3126 Dbms() != dbmsINTERBASE &&
2beca662 3127 Dbms() != dbmsPERVASIVE_SQL)
1e92909e
GT
3128 {
3129 retcode = SQLTables(hstmt,
3ca6a5f0 3130 NULL, 0, // All qualifiers
a8aa2258 3131 (UCHAR *) UserID.c_str(), SQL_NTS, // Only tables owned by this user
f6bcfd97 3132 (UCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3133 NULL, 0); // All table types
1e92909e
GT
3134 }
3135 else
3136 {
3137 retcode = SQLTables(hstmt,
3ca6a5f0
BP
3138 NULL, 0, // All qualifiers
3139 NULL, 0, // All owners
f6bcfd97 3140 (UCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3141 NULL, 0); // All table types
1e92909e
GT
3142 }
3143 if (retcode != SQL_SUCCESS)
3144 return(DispAllErrors(henv, hdbc, hstmt));
eedb1543 3145
1e92909e 3146 retcode = SQLFetch(hstmt);
a8aa2258 3147 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
1e92909e
GT
3148 {
3149 SQLFreeStmt(hstmt, SQL_CLOSE);
3150 return(DispAllErrors(henv, hdbc, hstmt));
3151 }
eedb1543 3152
1e92909e 3153 SQLFreeStmt(hstmt, SQL_CLOSE);
108106cf 3154
a144affe 3155 return(TRUE);
eedb1543 3156
f6bcfd97 3157} // wxDb::TableExists()
108106cf
JS
3158
3159
a8aa2258 3160/********** wxDb::TablePrivileges() **********/
4fdae997
GT
3161bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
3162 const wxChar *schema, const wxString &tablePath)
3ca6a5f0 3163{
4fdae997
GT
3164 wxASSERT(tableName.Length());
3165
3ca6a5f0
BP
3166 wxDbTablePrivilegeInfo result;
3167 SDWORD cbRetVal;
3168 RETCODE retcode;
eedb1543 3169
4fdae997
GT
3170 // We probably need to be able to dynamically set this based on
3171 // the driver type, and state.
3172 wxChar curRole[]=wxT("public");
eedb1543 3173
3ca6a5f0 3174 wxString TableName;
eedb1543 3175
02cf6fdd 3176 wxString UserID,Schema;
4fdae997 3177 convertUserID(userID,UserID);
02cf6fdd 3178 convertUserID(schema,Schema);
eedb1543 3179
3ca6a5f0 3180 TableName = tableName;
d8a0a1c9 3181 // Oracle and Interbase table names are uppercase only, so force
3ca6a5f0 3182 // the name to uppercase just in case programmer forgot to do this
eedb1543 3183 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 3184 (Dbms() == dbmsINTERBASE))
3ca6a5f0 3185 TableName = TableName.Upper();
eedb1543 3186
3ca6a5f0 3187 SQLFreeStmt(hstmt, SQL_CLOSE);
d8a0a1c9 3188
02cf6fdd
GT
3189 // Some databases cannot accept a user name when looking up table names,
3190 // so we use the call below that leaves out the user name
3191 if (!Schema.IsEmpty() &&
3192 Dbms() != dbmsMY_SQL &&
3193 Dbms() != dbmsACCESS &&
3194 Dbms() != dbmsMS_SQL_SERVER)
d8a0a1c9
GT
3195 {
3196 retcode = SQLTablePrivileges(hstmt,
3197 NULL, 0, // Catalog
02cf6fdd 3198 (UCHAR FAR *)Schema.c_str(), SQL_NTS, // Schema
eedb1543 3199 (UCHAR FAR *)TableName.c_str(), SQL_NTS);
d8a0a1c9
GT
3200 }
3201 else
3202 {
3203 retcode = SQLTablePrivileges(hstmt,
3204 NULL, 0, // Catalog
02cf6fdd 3205 NULL, 0, // Schema
eedb1543 3206 (UCHAR FAR *)TableName.c_str(), SQL_NTS);
d8a0a1c9 3207 }
a8aa2258 3208
eedb1543 3209#ifdef DBDEBUG_CONSOLE
4fdae997 3210 fprintf(stderr ,wxT("SQLTablePrivileges() returned %i \n"),retcode);
3ca6a5f0 3211#endif
eedb1543 3212
a8aa2258
GT
3213 if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
3214 return(DispAllErrors(henv, hdbc, hstmt));
3215
a144affe 3216 bool failed = FALSE;
d8a0a1c9 3217 retcode = SQLFetch(hstmt);
eedb1543 3218 while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
d8a0a1c9
GT
3219 {
3220 if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS)
a144affe 3221 failed = TRUE;
eedb1543 3222
5a226de0 3223 if (!failed && SQLGetData(hstmt, 2, SQL_C_CHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS)
a144affe 3224 failed = TRUE;
eedb1543 3225
5a226de0 3226 if (!failed && SQLGetData(hstmt, 3, SQL_C_CHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS)
a144affe 3227 failed = TRUE;
eedb1543 3228
5a226de0 3229 if (!failed && SQLGetData(hstmt, 4, SQL_C_CHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS)
a144affe 3230 failed = TRUE;
eedb1543 3231
5a226de0 3232 if (!failed && SQLGetData(hstmt, 5, SQL_C_CHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS)
a144affe 3233 failed = TRUE;
eedb1543 3234
5a226de0 3235 if (!failed && SQLGetData(hstmt, 6, SQL_C_CHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS)
a144affe 3236 failed = TRUE;
eedb1543 3237
5a226de0 3238 if (!failed && SQLGetData(hstmt, 7, SQL_C_CHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS)
a144affe 3239 failed = TRUE;
d8a0a1c9 3240
5a226de0
GT
3241 if (failed)
3242 {
3243 return(DispAllErrors(henv, hdbc, hstmt));
3244 }
3ca6a5f0 3245#ifdef DBDEBUG_CONSOLE
4fdae997 3246 fprintf(stderr,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
a8aa2258 3247 result.privilege,result.tableOwner,result.tableName,
3ca6a5f0 3248 result.grantor, result.grantee);
eedb1543 3249#endif
d8a0a1c9 3250
a144affe 3251 if (UserID.IsSameAs(result.tableOwner,FALSE))
a8aa2258
GT
3252 {
3253 SQLFreeStmt(hstmt, SQL_CLOSE);
a144affe 3254 return TRUE;
a8aa2258 3255 }
eedb1543 3256
a144affe 3257 if (UserID.IsSameAs(result.grantee,FALSE) &&
a8aa2258
GT
3258 !wxStrcmp(result.privilege,priv))
3259 {
3260 SQLFreeStmt(hstmt, SQL_CLOSE);
a144affe 3261 return TRUE;
a8aa2258 3262 }
eedb1543 3263
a8aa2258
GT
3264 if (!wxStrcmp(result.grantee,curRole) &&
3265 !wxStrcmp(result.privilege,priv))
3266 {
3267 SQLFreeStmt(hstmt, SQL_CLOSE);
a144affe 3268 return TRUE;
a8aa2258 3269 }
eedb1543 3270
3ca6a5f0 3271 retcode = SQLFetch(hstmt);
eedb1543
DW
3272 }
3273
a8aa2258 3274 SQLFreeStmt(hstmt, SQL_CLOSE);
a144affe 3275 return FALSE;
3ca6a5f0 3276
a8aa2258 3277} // wxDb::TablePrivileges
3ca6a5f0
BP
3278
3279
f6bcfd97 3280/********** wxDb::SetSqlLogging() **********/
4fdae997 3281bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
1fc5dd6f 3282{
4fdae997
GT
3283 wxASSERT(state == sqlLogON || state == sqlLogOFF);
3284 wxASSERT(state == sqlLogOFF || filename.Length());
1e92909e 3285
ea5d599d
GT
3286 if (state == sqlLogON)
3287 {
3288 if (fpSqlLog == 0)
3289 {
4fdae997 3290 fpSqlLog = fopen(filename, (append ? wxT("at") : wxT("wt")));
ea5d599d 3291 if (fpSqlLog == NULL)
a144affe 3292 return(FALSE);
ea5d599d
GT
3293 }
3294 }
3295 else // sqlLogOFF
3296 {
3297 if (fpSqlLog)
3298 {
3299 if (fclose(fpSqlLog))
a144affe 3300 return(FALSE);
ea5d599d
GT
3301 fpSqlLog = 0;
3302 }
3303 }
1e92909e 3304
ea5d599d 3305 sqlLogState = state;
a144affe 3306 return(TRUE);
1fc5dd6f 3307
f6bcfd97 3308} // wxDb::SetSqlLogging()
1fc5dd6f
JS
3309
3310
f6bcfd97 3311/********** wxDb::WriteSqlLog() **********/
4fdae997 3312bool wxDb::WriteSqlLog(const wxString &logMsg)
1fc5dd6f 3313{
4fdae997 3314 wxASSERT(logMsg.Length());
1fc5dd6f 3315
1e92909e 3316 if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
a144affe 3317 return(FALSE);
1fc5dd6f 3318
4fdae997 3319 if (fputs(wxT("\n"), fpSqlLog) == EOF)
a144affe 3320 return(FALSE);
4fdae997 3321 if (fputs(logMsg, fpSqlLog) == EOF)
a144affe 3322 return(FALSE);
4fdae997 3323 if (fputs(wxT("\n"), fpSqlLog) == EOF)
a144affe 3324 return(FALSE);
1fc5dd6f 3325
a144affe 3326 return(TRUE);
1fc5dd6f 3327
f6bcfd97 3328} // wxDb::WriteSqlLog()
1fc5dd6f
JS
3329
3330
f6bcfd97
BP
3331/********** wxDb::Dbms() **********/
3332wxDBMS wxDb::Dbms(void)
a2115c88
GT
3333/*
3334 * Be aware that not all database engines use the exact same syntax, and not
3335 * every ODBC compliant database is compliant to the same level of compliancy.
3336 * Some manufacturers support the minimum Level 1 compliancy, and others up
3337 * through Level 3. Others support subsets of features for levels above 1.
3338 *
f6bcfd97 3339 * If you find an inconsistency between the wxDb class and a specific database
a2115c88
GT
3340 * engine, and an identifier to this section, and special handle the database in
3341 * the area where behavior is non-conforming with the other databases.
3342 *
3343 *
3344 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3345 * ---------------------------------------------------
3346 *
3347 * ORACLE
1e92909e 3348 * - Currently the only database supported by the class to support VIEWS
a2115c88
GT
3349 *
3350 * DBASE
1e92909e
GT
3351 * - Does not support the SQL_TIMESTAMP structure
3352 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
fdc03678 3353 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
a144affe 3354 * is TRUE. The user must create ALL indexes from their program.
1e92909e
GT
3355 * - Table names can only be 8 characters long
3356 * - Column names can only be 10 characters long
a2115c88
GT
3357 *
3358 * SYBASE (all)
1e92909e
GT
3359 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3360 * after every table name involved in the query/join if that tables matching record(s)
3361 * are to be locked
3362 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
a2115c88
GT
3363 *
3364 * SYBASE (Enterprise)
1e92909e 3365 * - If a column is part of the Primary Key, the column cannot be NULL
3ca6a5f0 3366 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
a2115c88
GT
3367 *
3368 * MY_SQL
1e92909e 3369 * - If a column is part of the Primary Key, the column cannot be NULL
a144affe 3370 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3ca6a5f0
BP
3371 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3372 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3373 * column definition if it is not defined correctly, but it is experimental
3374 * - Does not support sub-queries in SQL statements
a2115c88
GT
3375 *
3376 * POSTGRES
23f681ec 3377 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3ca6a5f0 3378 * - Does not support sub-queries in SQL statements
a2115c88 3379 *
a8aa2258
GT
3380 * DB2
3381 * - Primary keys must be declared as NOT NULL
2beca662
GT
3382 * - Table and index names must not be longer than 13 characters in length (technically
3383 * table names can be up to 18 characters, but the primary index is created using the
3384 * base table name plus "_PIDX", so the limit if the table has a primary index is 13.
3385 *
3386 * PERVASIVE SQL
a8aa2258 3387 *
081eb1b1
GT
3388 * INTERBASE
3389 * - Columns that are part of primary keys must be defined as being NOT NULL
3390 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3391 * column definition if it is not defined correctly, but it is experimental
a2115c88 3392 */
a2115c88 3393{
a8aa2258 3394 // Should only need to do this once for each new database connection
eedb1543 3395 // so return the value we already determined it to be to save time
a8aa2258
GT
3396 // and lots of string comparisons
3397 if (dbmsType != dbmsUNIDENTIFIED)
3398 return(dbmsType);
3399
1e92909e 3400 wxChar baseName[25+1];
1e92909e 3401 wxStrncpy(baseName,dbInf.dbmsName,25);
3ca6a5f0 3402 baseName[25] = 0;
f6bcfd97 3403
d8a0a1c9
GT
3404 // RGG 20001025 : add support for Interbase
3405 // GT : Integrated to base classes on 20001121
4fdae997 3406 if (!wxStricmp(dbInf.dbmsName,wxT("Interbase")))
d8a0a1c9
GT
3407 return((wxDBMS)(dbmsType = dbmsINTERBASE));
3408
f6bcfd97 3409 // BJO 20000428 : add support for Virtuoso
4fdae997 3410 if (!wxStricmp(dbInf.dbmsName,wxT("OpenLink Virtuoso VDBMS")))
a8aa2258 3411 return((wxDBMS)(dbmsType = dbmsVIRTUOSO));
f6bcfd97 3412
4fdae997 3413 if (!wxStricmp(dbInf.dbmsName,wxT("Adaptive Server Anywhere")))
a8aa2258
GT
3414 return((wxDBMS)(dbmsType = dbmsSYBASE_ASA));
3415
f6bcfd97
BP
3416 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3417 // connected through an OpenLink driver.
eedb1543
DW
3418 // Is it also returned by Sybase Adapatitve server?
3419 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
4fdae997 3420 if (!wxStricmp(dbInf.dbmsName,wxT("SQL Server")))
3ca6a5f0 3421 {
4fdae997
GT
3422 if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) ||
3423 !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4))
081eb1b1
GT
3424 return ((wxDBMS)(dbmsMS_SQL_SERVER));
3425 else
3426 return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
3ca6a5f0 3427 }
f6bcfd97 3428
4fdae997 3429 if (!wxStricmp(dbInf.dbmsName,wxT("Microsoft SQL Server")))
a8aa2258 3430 return((wxDBMS)(dbmsType = dbmsMS_SQL_SERVER));
4fdae997 3431 if (!wxStricmp(dbInf.dbmsName,wxT("MySQL")))
a8aa2258 3432 return((wxDBMS)(dbmsType = dbmsMY_SQL));
4fdae997 3433 if (!wxStricmp(dbInf.dbmsName,wxT("PostgreSQL"))) // v6.5.0
a8aa2258 3434 return((wxDBMS)(dbmsType = dbmsPOSTGRES));
1e92909e 3435
2beca662 3436 baseName[9] = 0;
081eb1b1
GT
3437 if (!wxStricmp(dbInf.dbmsName,wxT("Pervasive")))
3438 return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL));
2beca662 3439
1e92909e 3440 baseName[8] = 0;
4fdae997 3441 if (!wxStricmp(baseName,wxT("Informix")))
a8aa2258 3442 return((wxDBMS)(dbmsType = dbmsINFORMIX));
1e92909e
GT
3443
3444 baseName[6] = 0;
4fdae997 3445 if (!wxStricmp(baseName,wxT("Oracle")))
a8aa2258 3446 return((wxDBMS)(dbmsType = dbmsORACLE));
4fdae997 3447 if (!wxStricmp(dbInf.dbmsName,wxT("ACCESS")))
a8aa2258 3448 return((wxDBMS)(dbmsType = dbmsACCESS));
4fdae997 3449 if (!wxStricmp(dbInf.dbmsName,wxT("MySQL")))
a8aa2258 3450 return((wxDBMS)(dbmsType = dbmsMY_SQL));
4fdae997 3451 if (!wxStricmp(baseName,wxT("Sybase")))
a8aa2258 3452 return((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
1e92909e
GT
3453
3454 baseName[5] = 0;
4fdae997 3455 if (!wxStricmp(baseName,wxT("DBASE")))
a8aa2258 3456 return((wxDBMS)(dbmsType = dbmsDBASE));
1e92909e 3457
a8aa2258 3458 baseName[3] = 0;
4fdae997 3459 if (!wxStricmp(baseName,wxT("DB2")))
a8aa2258
GT
3460 return((wxDBMS)(dbmsType = dbmsDBASE));
3461
3462 return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
3ca6a5f0 3463
f6bcfd97 3464} // wxDb::Dbms()
a2115c88
GT
3465
3466
4fdae997
GT
3467bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
3468 int dataType, ULONG columnLength,
3469 const wxString &optionalParam)
3470{
3471 wxASSERT(tableName.Length());
3472 wxASSERT(columnName.Length());
3473 wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
3474 dataType != DB_DATA_TYPE_VARCHAR);
3475
3476 // Must specify a columnLength if modifying a VARCHAR type column
3477 if (dataType == DB_DATA_TYPE_VARCHAR && !columnLength)
a144affe 3478 return FALSE;
5600884a 3479
4fdae997 3480 wxString dataTypeName;
081eb1b1 3481 wxString sqlStmt;
4fdae997
GT
3482 wxString alterSlashModify;
3483
081eb1b1
GT
3484 switch(dataType)
3485 {
3486 case DB_DATA_TYPE_VARCHAR :
3487 dataTypeName = typeInfVarchar.TypeName;
3488 break;
3489 case DB_DATA_TYPE_INTEGER :
3490 dataTypeName = typeInfInteger.TypeName;
3491 break;
3492 case DB_DATA_TYPE_FLOAT :
3493 dataTypeName = typeInfFloat.TypeName;
3494 break;
3495 case DB_DATA_TYPE_DATE :
3496 dataTypeName = typeInfDate.TypeName;
3497 break;
3498 case DB_DATA_TYPE_BLOB :
3499 dataTypeName = typeInfBlob.TypeName;
3500 break;
3501 default:
a144affe 3502 return FALSE;
081eb1b1
GT
3503 }
3504
3505 // Set the modify or alter syntax depending on the type of database connected to
3506 switch (Dbms())
3507 {
3508 case dbmsORACLE :
3509 alterSlashModify = "MODIFY";
3510 break;
3511 case dbmsMS_SQL_SERVER :
3512 alterSlashModify = "ALTER COLUMN";
3513 break;
3514 case dbmsUNIDENTIFIED :
a144affe 3515 return FALSE;
081eb1b1
GT
3516 case dbmsSYBASE_ASA :
3517 case dbmsSYBASE_ASE :
3518 case dbmsMY_SQL :
3519 case dbmsPOSTGRES :
3520 case dbmsACCESS :
3521 case dbmsDBASE :
3522 default :
3523 alterSlashModify = "MODIFY";
3524 break;
3525 }
3526
3527 // create the SQL statement
3528 sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(),
3529 columnName.c_str(), dataTypeName.c_str());
4fdae997
GT
3530
3531 // For varchars only, append the size of the column
3532 if (dataType == DB_DATA_TYPE_VARCHAR)
3533 {
3534 wxString s;
3535 s.Printf(wxT("(%d)"), columnLength);
3536 sqlStmt += s;
3537 }
3538
3539 // for passing things like "NOT NULL"
3540 if (optionalParam.Length())
3541 {
3542 sqlStmt += wxT(" ");
3543 sqlStmt += optionalParam;
3544 }
3545
081eb1b1 3546 return ExecSql(sqlStmt);
4fdae997
GT
3547
3548} // wxDb::ModifyColumn()
3549
3550
fdc03678 3551/********** wxDbGetConnection() **********/
f6bcfd97 3552wxDb WXDLLEXPORT *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors)
108106cf 3553{
fdc03678 3554 wxDbList *pList;
1e92909e 3555
a8aa2258
GT
3556 // Used to keep a pointer to a DB connection that matches the requested
3557 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
3558 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
3559 // rather than having to re-query the datasource to get all the values
3560 // using the wxDb::Open(Dsn,Uid,AuthStr) function
3561 wxDb *matchingDbConnection = NULL;
3562
1e92909e
GT
3563 // Scan the linked list searching for an available database connection
3564 // that's already been opened but is currently not in use.
3565 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3566 {
3567 // The database connection must be for the same datasource
3568 // name and must currently not be in use.
3ca6a5f0
BP
3569 if (pList->Free &&
3570 (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors) &&
942e67c3 3571 (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn))) // Found a free connection
1e92909e 3572 {
a144affe 3573 pList->Free = FALSE;
1e92909e
GT
3574 return(pList->PtrDb);
3575 }
a8aa2258 3576
942e67c3
GT
3577 if (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn) &&
3578 !wxStrcmp(pDbConfig->GetUserID(), pList->Uid) &&
3579 !wxStrcmp(pDbConfig->GetPassword(), pList->AuthStr))
a8aa2258 3580 matchingDbConnection = pList->PtrDb;
1e92909e
GT
3581 }
3582
3583 // No available connections. A new connection must be made and
3584 // appended to the end of the linked list.
3585 if (PtrBegDbList)
3586 {
3587 // Find the end of the list
3588 for (pList = PtrBegDbList; pList->PtrNext; pList = pList->PtrNext);
3589 // Append a new list item
fdc03678 3590 pList->PtrNext = new wxDbList;
1e92909e
GT
3591 pList->PtrNext->PtrPrev = pList;
3592 pList = pList->PtrNext;
3593 }
3ca6a5f0 3594 else // Empty list
1e92909e
GT
3595 {
3596 // Create the first node on the list
fdc03678 3597 pList = PtrBegDbList = new wxDbList;
1e92909e
GT
3598 pList->PtrPrev = 0;
3599 }
3600
3601 // Initialize new node in the linked list
4fdae997 3602 pList->PtrNext = 0;
a144affe 3603 pList->Free = FALSE;
2c257434 3604 pList->Dsn = pDbConfig->GetDsn();
942e67c3
GT
3605 pList->Uid = pDbConfig->GetUserID();
3606 pList->AuthStr = pDbConfig->GetPassword();
a8aa2258 3607
9556da13 3608 pList->PtrDb = new wxDb(pDbConfig->GetHenv(), FwdOnlyCursors);
1e92909e 3609
a144affe 3610 bool opened = FALSE;
a8aa2258
GT
3611
3612 if (!matchingDbConnection)
942e67c3 3613 opened = pList->PtrDb->Open(pDbConfig->GetDsn(), pDbConfig->GetUserID(), pDbConfig->GetPassword());
a8aa2258
GT
3614 else
3615 opened = pList->PtrDb->Open(matchingDbConnection);
3616
1e92909e 3617 // Connect to the datasource
a8aa2258 3618 if (opened)
1e92909e 3619 {
a144affe
GT
3620 pList->PtrDb->setCached(TRUE); // Prevent a user from deleting a cached connection
3621 pList->PtrDb->SetSqlLogging(SQLLOGstate,SQLLOGfn,TRUE);
1e92909e
GT
3622 return(pList->PtrDb);
3623 }
3624 else // Unable to connect, destroy list item
3625 {
3626 if (pList->PtrPrev)
3627 pList->PtrPrev->PtrNext = 0;
3628 else
3629 PtrBegDbList = 0; // Empty list again
f6bcfd97
BP
3630 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
3631 pList->PtrDb->Close(); // Close the wxDb object
3632 delete pList->PtrDb; // Deletes the wxDb object
1e92909e
GT
3633 delete pList; // Deletes the linked list object
3634 return(0);
3635 }
108106cf 3636
fdc03678 3637} // wxDbGetConnection()
108106cf 3638
67e9aaa3 3639
fdc03678 3640/********** wxDbFreeConnection() **********/
f6bcfd97 3641bool WXDLLEXPORT wxDbFreeConnection(wxDb *pDb)
108106cf 3642{
fdc03678 3643 wxDbList *pList;
108106cf 3644
1e92909e
GT
3645 // Scan the linked list searching for the database connection
3646 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3647 {
3ca6a5f0 3648 if (pList->PtrDb == pDb) // Found it, now free it!!!
a144affe 3649 return (pList->Free = TRUE);
1e92909e 3650 }
108106cf 3651
1e92909e 3652 // Never found the database object, return failure
a144affe 3653 return(FALSE);
108106cf 3654
fdc03678 3655} // wxDbFreeConnection()
108106cf 3656
67e9aaa3 3657
fdc03678
GT
3658/********** wxDbCloseConnections() **********/
3659void WXDLLEXPORT wxDbCloseConnections(void)
108106cf 3660{
fdc03678 3661 wxDbList *pList, *pNext;
23f681ec 3662
1e92909e
GT
3663 // Traverse the linked list closing database connections and freeing memory as I go.
3664 for (pList = PtrBegDbList; pList; pList = pNext)
3665 {
3666 pNext = pList->PtrNext; // Save the pointer to next
f6bcfd97
BP
3667 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
3668 pList->PtrDb->Close(); // Close the wxDb object
a144affe 3669 pList->PtrDb->setCached(FALSE); // Allows deletion of the wxDb instance
f6bcfd97 3670 delete pList->PtrDb; // Deletes the wxDb object
1e92909e
GT
3671 delete pList; // Deletes the linked list object
3672 }
3673
3674 // Mark the list as empty
3675 PtrBegDbList = 0;
108106cf 3676
fdc03678 3677} // wxDbCloseConnections()
108106cf 3678
67e9aaa3 3679
eb3b9dda 3680/********** wxDbConnectionsInUse() **********/
fdc03678 3681int WXDLLEXPORT wxDbConnectionsInUse(void)
108106cf 3682{
fdc03678 3683 wxDbList *pList;
1e92909e 3684 int cnt = 0;
108106cf 3685
1e92909e
GT
3686 // Scan the linked list counting db connections that are currently in use
3687 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3688 {
a144affe 3689 if (pList->Free == FALSE)
1e92909e
GT
3690 cnt++;
3691 }
108106cf 3692
1e92909e 3693 return(cnt);
108106cf 3694
fdc03678 3695} // wxDbConnectionsInUse()
108106cf 3696
67e9aaa3 3697
2c257434
GT
3698
3699/********** wxDbLogExtendedErrorMsg() **********/
3700// DEBUG ONLY function
3701const wxChar WXDLLEXPORT *wxDbLogExtendedErrorMsg(const wxChar *userText, wxDb *pDb,
3702 char *ErrFile, int ErrLine)
3703{
3704 static wxString msg;
3705 msg = userText;
3706
3707 wxString tStr;
3708
3709 if (ErrFile || ErrLine)
3710 {
3711 msg += wxT("File: ");
3712 msg += ErrFile;
3713 msg += wxT(" Line: ");
3714 tStr.Printf(wxT("%d"),ErrLine);
3715 msg += tStr.c_str();
3716 msg += wxT("\n");
3717 }
3718
3719 msg.Append (wxT("\nODBC errors:\n"));
3720 msg += wxT("\n");
3721
3722 // Display errors for this connection
3723 int i;
3724 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
3725 {
3726 if (pDb->errorList[i])
3727 {
3728 msg.Append(pDb->errorList[i]);
3729 if (wxStrcmp(pDb->errorList[i],wxT("")) != 0)
3730 msg.Append(wxT("\n"));
3731 // Clear the errmsg buffer so the next error will not
3732 // end up showing the previous error that have occurred
3733 wxStrcpy(pDb->errorList[i],wxT(""));
3734 }
3735 }
3736 msg += wxT("\n");
3737
3738 wxLogDebug(msg.c_str());
3739
3740 return msg.c_str();
3741} // wxDbLogExtendedErrorMsg()
3742
3743
fdc03678 3744/********** wxDbSqlLog() **********/
f6bcfd97 3745bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename)
a2115c88 3746{
a144affe 3747 bool append = FALSE;
fdc03678 3748 wxDbList *pList;
a2115c88 3749
1e92909e
GT
3750 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3751 {
f6bcfd97 3752 if (!pList->PtrDb->SetSqlLogging(state,filename,append))
a144affe
GT
3753 return(FALSE);
3754 append = TRUE;
1e92909e 3755 }
a2115c88 3756
1e92909e 3757 SQLLOGstate = state;
3ca6a5f0 3758 SQLLOGfn = filename;
a2115c88 3759
a144affe 3760 return(TRUE);
a2115c88 3761
fdc03678 3762} // wxDbSqlLog()
a2115c88 3763
67e9aaa3 3764
a8aa2258 3765#if 0
fdc03678 3766/********** wxDbCreateDataSource() **********/
4fdae997
GT
3767int wxDbCreateDataSource(const wxString &driverName, const wxString &dsn, const wxString &description,
3768 bool sysDSN, const wxString &defDir, wxWindow *parent)
fdc03678
GT
3769/*
3770 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
eedb1543 3771 * Very rudimentary creation of an ODBC data source.
a8aa2258
GT
3772 *
3773 * ODBC driver must be ODBC 3.0 compliant to use this function
fdc03678
GT
3774 */
3775{
a144affe 3776 int result = FALSE;
fdc03678 3777
a8aa2258
GT
3778//!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
3779#ifdef __VISUALC__
fdc03678
GT
3780 int dsnLocation;
3781 wxString setupStr;
3782
3783 if (sysDSN)
3784 dsnLocation = ODBC_ADD_SYS_DSN;
3785 else
3786 dsnLocation = ODBC_ADD_DSN;
3787
3788 // NOTE: The decimal 2 is an invalid character in all keyword pairs
eedb1543 3789 // so that is why I used it, as wxString does not deal well with
fdc03678 3790 // embedded nulls in strings
4fdae997 3791 setupStr.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn,2,description,2,defDir,2);
fdc03678
GT
3792
3793 // Replace the separator from above with the '\0' seperator needed
3794 // by the SQLConfigDataSource() function
3795 int k;
3796 do
3797 {
a144affe 3798 k = setupStr.Find((wxChar)2,TRUE);
fdc03678 3799 if (k != wxNOT_FOUND)
4fdae997 3800 setupStr[(UINT)k] = wxT('\0');
fdc03678
GT
3801 }
3802 while (k != wxNOT_FOUND);
3803
3804 result = SQLConfigDataSource((HWND)parent->GetHWND(), dsnLocation,
f6bcfd97 3805 driverName, setupStr.c_str());
fdc03678 3806
a8aa2258 3807 if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
fdc03678
GT
3808 {
3809 // check for errors caused by ConfigDSN based functions
3810 DWORD retcode = 0;
3811 WORD cb;
a8aa2258 3812 wxChar errMsg[SQL_MAX_MESSAGE_LENGTH];
4fdae997 3813 errMsg[0] = wxT('\0');
fdc03678 3814
a8aa2258
GT
3815 // This function is only supported in ODBC drivers v3.0 compliant and above
3816 SQLInstallerError(1,&retcode,errMsg,SQL_MAX_MESSAGE_LENGTH-1,&cb);
fdc03678
GT
3817 if (retcode)
3818 {
fdc03678 3819#ifdef DBDEBUG_CONSOLE
f6bcfd97
BP
3820 // When run in console mode, use standard out to display errors.
3821 cout << errMsg << endl;
a8aa2258 3822 cout << wxT("Press any key to continue...") << endl;
f6bcfd97 3823 getchar();
fdc03678 3824#endif // DBDEBUG_CONSOLE
fdc03678
GT
3825
3826#ifdef __WXDEBUG__
f6bcfd97 3827 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
fdc03678
GT
3828#endif // __WXDEBUG__
3829 }
3830 }
3831 else
a144affe 3832 result = TRUE;
a8aa2258
GT
3833#else
3834 // Using iODBC/unixODBC or some other compiler which does not support the APIs
3835 // necessary to use this function, so this function is not supported
fdc03678 3836#ifdef __WXDEBUG__
4fdae997 3837 wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
fdc03678 3838#endif
a144affe 3839 result = FALSE;
a8aa2258 3840#endif // __VISUALC__
fdc03678
GT
3841
3842 return result;
3843
3844} // wxDbCreateDataSource()
3845#endif
3846
3847
3848/********** wxDbGetDataSource() **********/
4fdae997 3849bool wxDbGetDataSource(HENV henv, wxChar *Dsn, SWORD DsnMax, wxChar *DsDesc,
dba2120c 3850 SWORD DsDescMax, UWORD direction)
67e9aaa3
GT
3851/*
3852 * Dsn and DsDesc will contain the data source name and data source
3853 * description upon return
3854 */
108106cf 3855{
1e92909e 3856 SWORD cb1,cb2;
108106cf 3857
1e92909e
GT
3858 if (SQLDataSources(henv, direction, (UCHAR FAR *) Dsn, DsnMax, &cb1,
3859 (UCHAR FAR *) DsDesc, DsDescMax, &cb2) == SQL_SUCCESS)
a144affe 3860 return(TRUE);
1e92909e 3861 else
a144affe 3862 return(FALSE);
108106cf 3863
fdc03678
GT
3864} // wxDbGetDataSource()
3865
3866
3867// Change this to 0 to remove use of all deprecated functions
f6bcfd97 3868#if wxODBC_BACKWARD_COMPATABILITY
fdc03678
GT
3869/********************************************************************
3870 ********************************************************************
3871 *
3872 * The following functions are all DEPRECATED and are included for
3873 * backward compatability reasons only
3874 *
3875 ********************************************************************
3876 ********************************************************************/
f6bcfd97 3877bool SqlLog(sqlLog state, const wxChar *filename)
fdc03678 3878{
f6bcfd97 3879 return wxDbSqlLog((enum wxDbSqlLogState)state, filename);
fdc03678
GT
3880}
3881/***** DEPRECATED: use wxGetDataSource() *****/
3882bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
3883 UWORD direction)
3884{
3885 return wxDbGetDataSource(henv, Dsn, DsnMax, DsDesc, DsDescMax, direction);
3886}
3887/***** DEPRECATED: use wxDbGetConnection() *****/
f6bcfd97 3888wxDb WXDLLEXPORT *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors)
fdc03678
GT
3889{
3890 return wxDbGetConnection((wxDbConnectInf *)pDbStuff, FwdOnlyCursors);
3891}
3892/***** DEPRECATED: use wxDbFreeConnection() *****/
f6bcfd97 3893bool WXDLLEXPORT FreeDbConnection(wxDb *pDb)
fdc03678
GT
3894{
3895 return wxDbFreeConnection(pDb);
3896}
3897/***** DEPRECATED: use wxDbCloseConnections() *****/
3898void WXDLLEXPORT CloseDbConnections(void)
3899{
3900 wxDbCloseConnections();
3901}
3902/***** DEPRECATED: use wxDbConnectionsInUse() *****/
3903int WXDLLEXPORT NumberDbConnectionsInUse(void)
3904{
3905 return wxDbConnectionsInUse();
3906}
3907#endif
3908
3909
108106cf 3910#endif
1fc5dd6f 3911 // wxUSE_ODBC