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