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