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