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