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