]> git.saurik.com Git - wxWidgets.git/blame - src/common/db.cpp
final cleanup of string conversion with null characters (hopefully :))
[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
e4e45573
GT
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;
e4e45573 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
f6bcfd97
BP
2166/********** wxDb::GetNext() **********/
2167bool wxDb::GetNext(void)
a2115c88 2168{
1e92909e 2169 if (SQLFetch(hstmt) == SQL_SUCCESS)
68379eaf 2170 return true;
1e92909e
GT
2171 else
2172 {
2173 DispAllErrors(henv, hdbc, hstmt);
68379eaf 2174 return false;
1e92909e 2175 }
a2115c88 2176
f6bcfd97 2177} // wxDb::GetNext()
a2115c88 2178
67e9aaa3 2179
f6bcfd97
BP
2180/********** wxDb::GetData() **********/
2181bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FAR *cbReturned)
a2115c88 2182{
4fdae997
GT
2183 wxASSERT(pData);
2184 wxASSERT(cbReturned);
a2115c88 2185
e4e45573
GT
2186 long bufferSize = maxLen;
2187
2188 if (cType == SQL_C_WXCHAR)
2189 bufferSize = maxLen * sizeof(wxChar);
2190
2191 if (SQLGetData(hstmt, colNo, cType, pData, bufferSize, cbReturned) == SQL_SUCCESS)
68379eaf 2192 return true;
1e92909e
GT
2193 else
2194 {
2195 DispAllErrors(henv, hdbc, hstmt);
68379eaf 2196 return false;
1e92909e 2197 }
a2115c88 2198
f6bcfd97 2199} // wxDb::GetData()
a2115c88 2200
67e9aaa3 2201
f6bcfd97 2202/********** wxDb::GetKeyFields() **********/
02cf6fdd 2203int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCols)
67e9aaa3 2204{
4fdae997
GT
2205 wxChar szPkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Primary key table name */
2206 wxChar szFkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Foreign key table name */
564c92d9 2207 SWORD iKeySeq;
67e9aaa3 2208// SQLSMALLINT iKeySeq;
4fdae997
GT
2209 wxChar szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */
2210 wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */
67e9aaa3
GT
2211 SQLRETURN retcode;
2212 SDWORD cb;
02cf6fdd 2213 SWORD i;
4fdae997 2214 wxString tempStr;
67e9aaa3 2215 /*
4fdae997
GT
2216 * -----------------------------------------------------------------------
2217 * -- 19991224 : mj10777 : Create ------
2218 * -- : Three things are done and stored here : ------
2219 * -- : 1) which Column(s) is/are Primary Key(s) ------
2220 * -- : 2) which tables use this Key as a Foreign Key ------
2221 * -- : 3) which columns are Foreign Key and the name ------
2222 * -- : of the Table where the Key is the Primary Key -----
2223 * -- : Called from GetColumns(const wxString &tableName, ------
2224 * -- int *numCols,const wxChar *userID ) ------
2225 * -----------------------------------------------------------------------
67e9aaa3
GT
2226 */
2227
2228 /*---------------------------------------------------------------------*/
2229 /* Get the names of the columns in the primary key. */
2230 /*---------------------------------------------------------------------*/
2231 retcode = SQLPrimaryKeys(hstmt,
4fdae997
GT
2232 NULL, 0, /* Catalog name */
2233 NULL, 0, /* Schema name */
8a39593e 2234 (SQLTCHAR FAR *) tableName.c_str(), SQL_NTS); /* Table name */
67e9aaa3
GT
2235
2236 /*---------------------------------------------------------------------*/
2237 /* Fetch and display the result set. This will be a list of the */
2238 /* columns in the primary key of the tableName table. */
2239 /*---------------------------------------------------------------------*/
2240 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
2241 {
2242 retcode = SQLFetch(hstmt);
2243 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
2244 {
e4e45573 2245 GetData( 4, SQL_C_WXCHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
67e9aaa3
GT
2246 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
2247 //-------
2248 for (i=0;i<noCols;i++) // Find the Column name
2249 if (!wxStrcmp(colInf[i].colName,szPkCol)) // We have found the Column
2250 colInf[i].PkCol = iKeySeq; // Which Primary Key is this (first, second usw.) ?
3ca6a5f0
BP
2251 } // if
2252 } // while
67e9aaa3
GT
2253 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
2254
2255 /*---------------------------------------------------------------------*/
2256 /* Get all the foreign keys that refer to tableName primary key. */
2257 /*---------------------------------------------------------------------*/
2258 retcode = SQLForeignKeys(hstmt,
4fdae997
GT
2259 NULL, 0, /* Primary catalog */
2260 NULL, 0, /* Primary schema */
8a39593e 2261 (SQLTCHAR FAR *)tableName.c_str(), SQL_NTS,/* Primary table */
4fdae997
GT
2262 NULL, 0, /* Foreign catalog */
2263 NULL, 0, /* Foreign schema */
2264 NULL, 0); /* Foreign table */
67e9aaa3
GT
2265
2266 /*---------------------------------------------------------------------*/
2267 /* Fetch and display the result set. This will be all of the foreign */
2268 /* keys in other tables that refer to the tableName primary key. */
2269 /*---------------------------------------------------------------------*/
4fdae997 2270 tempStr.Empty();
67e9aaa3
GT
2271 szPkCol[0] = 0;
2272 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
2273 {
2274 retcode = SQLFetch(hstmt);
2275 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
2276 {
e4e45573
GT
2277 GetData( 3, SQL_C_WXCHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
2278 GetData( 4, SQL_C_WXCHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2279 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
2280 GetData( 7, SQL_C_WXCHAR, szFkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
2281 GetData( 8, SQL_C_WXCHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
4fdae997 2282 tempStr.Printf(wxT("%s[%s] "),tempStr.c_str(),szFkTable); // [ ] in case there is a blank in the Table name
3ca6a5f0
BP
2283 } // if
2284 } // while
4fdae997
GT
2285
2286 tempStr.Trim(); // Get rid of any unneeded blanks
2287 if (!tempStr.IsEmpty())
67e9aaa3 2288 {
4fdae997 2289 for (i=0; i<noCols; i++)
3ca6a5f0 2290 { // Find the Column name
4fdae997
GT
2291 if (!wxStrcmp(colInf[i].colName, szPkCol)) // We have found the Column, store the Information
2292 wxStrcpy(colInf[i].PkTableName, tempStr.c_str()); // Name of the Tables where this Primary Key is used as a Foreign Key
3ca6a5f0
BP
2293 }
2294 } // if
4fdae997 2295
67e9aaa3
GT
2296 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
2297
2298 /*---------------------------------------------------------------------*/
2299 /* Get all the foreign keys in the tablename table. */
2300 /*---------------------------------------------------------------------*/
2301 retcode = SQLForeignKeys(hstmt,
4fdae997
GT
2302 NULL, 0, /* Primary catalog */
2303 NULL, 0, /* Primary schema */
2304 NULL, 0, /* Primary table */
2305 NULL, 0, /* Foreign catalog */
2306 NULL, 0, /* Foreign schema */
8a39593e 2307 (SQLTCHAR *)tableName.c_str(), SQL_NTS);/* Foreign table */
67e9aaa3
GT
2308
2309 /*---------------------------------------------------------------------*/
2310 /* Fetch and display the result set. This will be all of the */
2311 /* primary keys in other tables that are referred to by foreign */
2312 /* keys in the tableName table. */
2313 /*---------------------------------------------------------------------*/
67e9aaa3
GT
2314 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
2315 {
2316 retcode = SQLFetch(hstmt);
2317 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
2318 {
e4e45573
GT
2319 GetData( 3, SQL_C_WXCHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
2320 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
2321 GetData( 8, SQL_C_WXCHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
67e9aaa3 2322 //-------
4fdae997 2323 for (i=0; i<noCols; i++) // Find the Column name
67e9aaa3
GT
2324 {
2325 if (!wxStrcmp(colInf[i].colName,szFkCol)) // We have found the (Foreign Key) Column
2326 {
2327 colInf[i].FkCol = iKeySeq; // Which Foreign Key is this (first, second usw.) ?
3ca6a5f0
BP
2328 wxStrcpy(colInf[i].FkTableName,szPkTable); // Name of the Table where this Foriegn is the Primary Key
2329 } // if
2330 } // for
2331 } // if
2332 } // while
67e9aaa3
GT
2333 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
2334
a144affe 2335 return TRUE;
3ca6a5f0 2336
f6bcfd97 2337} // wxDb::GetKeyFields()
67e9aaa3
GT
2338
2339
f6bcfd97
BP
2340#if OLD_GETCOLUMNS
2341/********** wxDb::GetColumns() **********/
4fdae997 2342wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
108106cf 2343/*
1e92909e
GT
2344 * 1) The last array element of the tableName[] argument must be zero (null).
2345 * This is how the end of the array is detected.
f6bcfd97 2346 * 2) This function returns an array of wxDbColInf structures. If no columns
1e92909e
GT
2347 * were found, or an error occured, this pointer will be zero (null). THE
2348 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
2349 * IS FINISHED WITH IT. i.e.
108106cf 2350 *
f6bcfd97 2351 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
1e92909e
GT
2352 * if (colInf)
2353 * {
2354 * // Use the column inf
2355 * .......
2356 * // Destroy the memory
2357 * delete [] colInf;
2358 * }
67e9aaa3
GT
2359 *
2360 * userID is evaluated in the following manner:
1e92909e
GT
2361 * userID == NULL ... UserID is ignored
2362 * userID == "" ... UserID set equal to 'this->uid'
2363 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 2364 *
f6bcfd97
BP
2365 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2366 * by this function. This function should use its own wxDb instance
ea5d599d 2367 * to avoid undesired unbinding of columns.
108106cf 2368 */
108106cf 2369{
081eb1b1 2370 UWORD noCols = 0;
2c257434 2371 UWORD colNo = 0;
f6bcfd97 2372 wxDbColInf *colInf = 0;
1e92909e
GT
2373
2374 RETCODE retcode;
2375 SDWORD cb;
2376
1e92909e
GT
2377 wxString TableName;
2378
4fdae997
GT
2379 wxString UserID;
2380 convertUserID(userID,UserID);
1e92909e
GT
2381
2382 // Pass 1 - Determine how many columns there are.
f6bcfd97 2383 // Pass 2 - Allocate the wxDbColInf array and fill in
1e92909e
GT
2384 // the array with the column information.
2385 int pass;
2386 for (pass = 1; pass <= 2; pass++)
2387 {
2388 if (pass == 2)
2389 {
2390 if (noCols == 0) // Probably a bogus table name(s)
2391 break;
f6bcfd97
BP
2392 // Allocate n wxDbColInf objects to hold the column information
2393 colInf = new wxDbColInf[noCols+1];
1e92909e
GT
2394 if (!colInf)
2395 break;
2396 // Mark the end of the array
da99271d
GT
2397 wxStrcpy(colInf[noCols].tableName,wxEmptyString);
2398 wxStrcpy(colInf[noCols].colName,wxEmptyString);
1e92909e
GT
2399 colInf[noCols].sqlDataType = 0;
2400 }
2401 // Loop through each table name
2402 int tbl;
2403 for (tbl = 0; tableName[tbl]; tbl++)
2404 {
2405 TableName = tableName[tbl];
d8a0a1c9 2406 // Oracle and Interbase table names are uppercase only, so force
1e92909e 2407 // the name to uppercase just in case programmer forgot to do this
eedb1543 2408 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 2409 (Dbms() == dbmsINTERBASE))
1e92909e
GT
2410 TableName = TableName.Upper();
2411
2412 SQLFreeStmt(hstmt, SQL_CLOSE);
2413
a8aa2258 2414 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
1e92909e 2415 // use the call below that leaves out the user name
4fdae997
GT
2416 if (!UserID.IsEmpty() &&
2417 Dbms() != dbmsMY_SQL &&
2418 Dbms() != dbmsACCESS &&
2419 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
2420 {
2421 retcode = SQLColumns(hstmt,
2422 NULL, 0, // All qualifiers
8a39593e
JS
2423 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner
2424 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2425 NULL, 0); // All columns
2426 }
2427 else
2428 {
2429 retcode = SQLColumns(hstmt,
2430 NULL, 0, // All qualifiers
2431 NULL, 0, // Owner
8a39593e 2432 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2433 NULL, 0); // All columns
2434 }
2435 if (retcode != SQL_SUCCESS)
2436 { // Error occured, abort
2437 DispAllErrors(henv, hdbc, hstmt);
2438 if (colInf)
2439 delete [] colInf;
2440 SQLFreeStmt(hstmt, SQL_CLOSE);
2441 return(0);
2442 }
2443
2444 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2445 {
2446 if (pass == 1) // First pass, just add up the number of columns
2447 noCols++;
2448 else // Pass 2; Fill in the array of structures
2449 {
2450 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2451 {
2452 // NOTE: Only the ODBC 1.x fields are retrieved
e4e45573
GT
2453 GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2454 GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2455 GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2456 GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1e92909e 2457 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
e4e45573
GT
2458 GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
2459 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb);
2460 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb);
1e92909e
GT
2461 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2462 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2463 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
e4e45573 2464 GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
eedb1543 2465
f6bcfd97 2466 // Determine the wxDb data type that is used to represent the native data type of this data source
1e92909e
GT
2467 colInf[colNo].dbDataType = 0;
2468 if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
52a17fe5 2469 {
eedb1543 2470#ifdef _IODBC_
e4e45573
GT
2471 // IODBC does not return a correct columnLength, so we set
2472 // columnLength = bufferSize if no column length was returned
2473 // IODBC returns the columnLength in bufferSize. (bug)
2474 if (colInf[colNo].columnLength < 1)
52a17fe5 2475 {
e4e45573 2476 colInf[colNo].columnLength = colInf[colNo].bufferSize;
52a17fe5 2477 }
a8aa2258 2478#endif
1e92909e 2479 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
52a17fe5 2480 }
bf5423ea 2481 else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName))
1e92909e 2482 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
bf5423ea 2483 else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName))
1e92909e 2484 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
bf5423ea 2485 else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName))
1e92909e 2486 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
bf5423ea
GT
2487 else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName))
2488 colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
1e92909e
GT
2489 colNo++;
2490 }
2491 }
2492 }
2493 if (retcode != SQL_NO_DATA_FOUND)
2494 { // Error occured, abort
2495 DispAllErrors(henv, hdbc, hstmt);
2496 if (colInf)
2497 delete [] colInf;
2498 SQLFreeStmt(hstmt, SQL_CLOSE);
2499 return(0);
2500 }
2501 }
2502 }
2503
2504 SQLFreeStmt(hstmt, SQL_CLOSE);
2505 return colInf;
108106cf 2506
f6bcfd97 2507} // wxDb::GetColumns()
108106cf
JS
2508
2509
f6bcfd97
BP
2510/********** wxDb::GetColumns() **********/
2511
02cf6fdd 2512wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wxChar *userID)
f6bcfd97
BP
2513//
2514// Same as the above GetColumns() function except this one gets columns
2515// only for a single table, and if 'numCols' is not NULL, the number of
2516// columns stored in the returned wxDbColInf is set in '*numCols'
2517//
2518// userID is evaluated in the following manner:
2519// userID == NULL ... UserID is ignored
2520// userID == "" ... UserID set equal to 'this->uid'
2521// userID != "" ... UserID set equal to 'userID'
2522//
2523// NOTE: ALL column bindings associated with this wxDb instance are unbound
2524// by this function. This function should use its own wxDb instance
2525// to avoid undesired unbinding of columns.
2526
67e9aaa3 2527{
02cf6fdd 2528 UWORD noCols = 0;
e938ff5e 2529 UWORD colNo = 0;
f6bcfd97 2530 wxDbColInf *colInf = 0;
1e92909e
GT
2531
2532 RETCODE retcode;
2533 SDWORD cb;
2534
1e92909e
GT
2535 wxString TableName;
2536
4fdae997
GT
2537 wxString UserID;
2538 convertUserID(userID,UserID);
1e92909e
GT
2539
2540 // Pass 1 - Determine how many columns there are.
f6bcfd97 2541 // Pass 2 - Allocate the wxDbColInf array and fill in
1e92909e
GT
2542 // the array with the column information.
2543 int pass;
2544 for (pass = 1; pass <= 2; pass++)
2545 {
2546 if (pass == 2)
2547 {
2548 if (noCols == 0) // Probably a bogus table name(s)
2549 break;
f6bcfd97
BP
2550 // Allocate n wxDbColInf objects to hold the column information
2551 colInf = new wxDbColInf[noCols+1];
1e92909e
GT
2552 if (!colInf)
2553 break;
2554 // Mark the end of the array
da99271d
GT
2555 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
2556 wxStrcpy(colInf[noCols].colName, wxEmptyString);
4fdae997 2557 colInf[noCols].sqlDataType = 0;
1e92909e
GT
2558 }
2559
2560 TableName = tableName;
d8a0a1c9 2561 // Oracle and Interbase table names are uppercase only, so force
1e92909e 2562 // the name to uppercase just in case programmer forgot to do this
eedb1543 2563 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 2564 (Dbms() == dbmsINTERBASE))
1e92909e
GT
2565 TableName = TableName.Upper();
2566
2567 SQLFreeStmt(hstmt, SQL_CLOSE);
2568
a8aa2258 2569 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
1e92909e 2570 // use the call below that leaves out the user name
4fdae997
GT
2571 if (!UserID.IsEmpty() &&
2572 Dbms() != dbmsMY_SQL &&
2573 Dbms() != dbmsACCESS &&
2574 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
2575 {
2576 retcode = SQLColumns(hstmt,
2577 NULL, 0, // All qualifiers
8a39593e
JS
2578 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner
2579 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2580 NULL, 0); // All columns
2581 }
2582 else
2583 {
2584 retcode = SQLColumns(hstmt,
2585 NULL, 0, // All qualifiers
2586 NULL, 0, // Owner
8a39593e 2587 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2588 NULL, 0); // All columns
2589 }
2590 if (retcode != SQL_SUCCESS)
2591 { // Error occured, abort
2592 DispAllErrors(henv, hdbc, hstmt);
2593 if (colInf)
2594 delete [] colInf;
2595 SQLFreeStmt(hstmt, SQL_CLOSE);
2596 if (numCols)
2597 *numCols = 0;
2598 return(0);
2599 }
2600
2601 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2602 {
2603 if (pass == 1) // First pass, just add up the number of columns
2604 noCols++;
2605 else // Pass 2; Fill in the array of structures
2606 {
2607 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2608 {
2609 // NOTE: Only the ODBC 1.x fields are retrieved
e4e45573
GT
2610 GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2611 GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2612 GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2613 GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2614 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
2615 GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
2616 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb);
67e9aaa3 2617 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
e4e45573
GT
2618 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb);
2619 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2620 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2621 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
2622 GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
67e9aaa3
GT
2623 // Start Values for Primary/Foriegn Key (=No)
2624 colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2625 colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2626 colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2627 colInf[colNo].FkTableName[0] = 0; // Foreign key table name
2628
3ca6a5f0
BP
2629 // BJO 20000428 : Virtuoso returns type names with upper cases!
2630 if (Dbms() == dbmsVIRTUOSO)
2631 {
4fdae997 2632 wxString s = colInf[colNo].typeName;
3ca6a5f0 2633 s = s.MakeLower();
eedb1543 2634 wxStrcmp(colInf[colNo].typeName, s.c_str());
3ca6a5f0 2635 }
eedb1543 2636
3ca6a5f0
BP
2637 // Determine the wxDb data type that is used to represent the native data type of this data source
2638 colInf[colNo].dbDataType = 0;
bf5423ea 2639 if (!wxStricmp(typeInfVarchar.TypeName, colInf[colNo].typeName))
3ca6a5f0 2640 {
eedb1543 2641#ifdef _IODBC_
e4e45573
GT
2642 // IODBC does not return a correct columnLength, so we set
2643 // columnLength = bufferSize if no column length was returned
2644 // IODBC returns the columnLength in bufferSize. (bug)
2645 if (colInf[colNo].columnLength < 1)
3ca6a5f0 2646 {
e4e45573 2647 colInf[colNo].columnLength = colInf[colNo].bufferSize;
3ca6a5f0 2648 }
a8aa2258
GT
2649#endif
2650
3ca6a5f0
BP
2651 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
2652 }
bf5423ea 2653 else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName))
3ca6a5f0 2654 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
bf5423ea 2655 else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName))
3ca6a5f0 2656 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
bf5423ea 2657 else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName))
eedb1543 2658 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
bf5423ea
GT
2659 else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName))
2660 colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
eedb1543 2661
1e92909e
GT
2662 colNo++;
2663 }
2664 }
2665 }
2666 if (retcode != SQL_NO_DATA_FOUND)
3ca6a5f0 2667 { // Error occured, abort
1e92909e
GT
2668 DispAllErrors(henv, hdbc, hstmt);
2669 if (colInf)
3ca6a5f0 2670 delete [] colInf;
1e92909e
GT
2671 SQLFreeStmt(hstmt, SQL_CLOSE);
2672 if (numCols)
3ca6a5f0 2673 *numCols = 0;
1e92909e 2674 return(0);
3ca6a5f0 2675 }
1e92909e 2676 }
67e9aaa3
GT
2677
2678 SQLFreeStmt(hstmt, SQL_CLOSE);
2679
2680 // Store Primary and Foriegn Keys
2681 GetKeyFields(tableName,colInf,noCols);
2682
2683 if (numCols)
1e92909e
GT
2684 *numCols = noCols;
2685 return colInf;
67e9aaa3 2686
f6bcfd97
BP
2687} // wxDb::GetColumns()
2688
f6bcfd97 2689
3ca6a5f0 2690#else // New GetColumns
67e9aaa3
GT
2691
2692
f6bcfd97 2693/*
3ca6a5f0
BP
2694 BJO 20000503
2695 These are tentative new GetColumns members which should be more database
eedb1543 2696 independant and which always returns the columns in the order they were
3ca6a5f0
BP
2697 created.
2698
4fdae997
GT
2699 - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const
2700 wxChar* userID)) calls the second implementation for each separate table
eedb1543 2701 before merging the results. This makes the code easier to maintain as
3ca6a5f0 2702 only one member (the second) makes the real work
4fdae997
GT
2703 - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const
2704 wxChar *userID) is a little bit improved
eedb1543 2705 - It doesn't anymore rely on the type-name to find out which database-type
3ca6a5f0 2706 each column has
eedb1543 2707 - It ends by sorting the columns, so that they are returned in the same
3ca6a5f0 2708 order they were created
f6bcfd97
BP
2709*/
2710
2711typedef struct
2712{
02cf6fdd 2713 UWORD noCols;
3ca6a5f0 2714 wxDbColInf *colInf;
f6bcfd97
BP
2715} _TableColumns;
2716
3ca6a5f0 2717
4fdae997 2718wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
f6bcfd97 2719{
3ca6a5f0
BP
2720 int i, j;
2721 // The last array element of the tableName[] argument must be zero (null).
2722 // This is how the end of the array is detected.
2723
02cf6fdd 2724 UWORD noCols = 0;
3ca6a5f0
BP
2725
2726 // How many tables ?
2727 int tbl;
eedb1543
DW
2728 for (tbl = 0 ; tableName[tbl]; tbl++);
2729
3ca6a5f0
BP
2730 // Create a table to maintain the columns for each separate table
2731 _TableColumns *TableColumns = new _TableColumns[tbl];
eedb1543 2732
3ca6a5f0
BP
2733 // Fill the table
2734 for (i = 0 ; i < tbl ; i++)
eedb1543 2735
3ca6a5f0
BP
2736 {
2737 TableColumns[i].colInf = GetColumns(tableName[i], &TableColumns[i].noCols, userID);
eedb1543 2738 if (TableColumns[i].colInf == NULL)
3ca6a5f0
BP
2739 return NULL;
2740 noCols += TableColumns[i].noCols;
2741 }
eedb1543 2742
3ca6a5f0
BP
2743 // Now merge all the separate table infos
2744 wxDbColInf *colInf = new wxDbColInf[noCols+1];
eedb1543 2745
3ca6a5f0 2746 // Mark the end of the array
da99271d
GT
2747 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
2748 wxStrcpy(colInf[noCols].colName, wxEmptyString);
4fdae997 2749 colInf[noCols].sqlDataType = 0;
eedb1543 2750
3ca6a5f0
BP
2751 // Merge ...
2752 int offset = 0;
eedb1543 2753
3ca6a5f0
BP
2754 for (i = 0 ; i < tbl ; i++)
2755 {
2756 for (j = 0 ; j < TableColumns[i].noCols ; j++)
2757 {
eedb1543 2758 colInf[offset++] = TableColumns[i].colInf[j];
3ca6a5f0
BP
2759 }
2760 }
eedb1543 2761
3ca6a5f0 2762 delete [] TableColumns;
eedb1543 2763
3ca6a5f0
BP
2764 return colInf;
2765} // wxDb::GetColumns() -- NEW
f6bcfd97
BP
2766
2767
4fdae997 2768wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxChar *userID)
3ca6a5f0
BP
2769//
2770// Same as the above GetColumns() function except this one gets columns
2771// only for a single table, and if 'numCols' is not NULL, the number of
2772// columns stored in the returned wxDbColInf is set in '*numCols'
2773//
2774// userID is evaluated in the following manner:
2775// userID == NULL ... UserID is ignored
2776// userID == "" ... UserID set equal to 'this->uid'
2777// userID != "" ... UserID set equal to 'userID'
2778//
2779// NOTE: ALL column bindings associated with this wxDb instance are unbound
2780// by this function. This function should use its own wxDb instance
2781// to avoid undesired unbinding of columns.
f6bcfd97 2782{
02cf6fdd 2783 UWORD noCols = 0;
e938ff5e 2784 UWORD colNo = 0;
3ca6a5f0 2785 wxDbColInf *colInf = 0;
eedb1543 2786
3ca6a5f0
BP
2787 RETCODE retcode;
2788 SDWORD cb;
eedb1543 2789
3ca6a5f0 2790 wxString TableName;
eedb1543 2791
4fdae997
GT
2792 wxString UserID;
2793 convertUserID(userID,UserID);
eedb1543 2794
3ca6a5f0
BP
2795 // Pass 1 - Determine how many columns there are.
2796 // Pass 2 - Allocate the wxDbColInf array and fill in
2797 // the array with the column information.
2798 int pass;
2799 for (pass = 1; pass <= 2; pass++)
2800 {
2801 if (pass == 2)
f6bcfd97 2802 {
3ca6a5f0
BP
2803 if (noCols == 0) // Probably a bogus table name(s)
2804 break;
2805 // Allocate n wxDbColInf objects to hold the column information
2806 colInf = new wxDbColInf[noCols+1];
2807 if (!colInf)
2808 break;
2809 // Mark the end of the array
da99271d
GT
2810 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
2811 wxStrcpy(colInf[noCols].colName, wxEmptyString);
3ca6a5f0 2812 colInf[noCols].sqlDataType = 0;
f6bcfd97 2813 }
eedb1543 2814
3ca6a5f0 2815 TableName = tableName;
d8a0a1c9 2816 // Oracle and Interbase table names are uppercase only, so force
3ca6a5f0 2817 // the name to uppercase just in case programmer forgot to do this
eedb1543 2818 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 2819 (Dbms() == dbmsINTERBASE))
3ca6a5f0 2820 TableName = TableName.Upper();
eedb1543 2821
3ca6a5f0 2822 SQLFreeStmt(hstmt, SQL_CLOSE);
eedb1543 2823
a8aa2258 2824 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
3ca6a5f0 2825 // use the call below that leaves out the user name
4fdae997 2826 if (!UserID.IsEmpty() &&
3ca6a5f0 2827 Dbms() != dbmsMY_SQL &&
a8aa2258
GT
2828 Dbms() != dbmsACCESS &&
2829 Dbms() != dbmsMS_SQL_SERVER)
f6bcfd97 2830 {
3ca6a5f0
BP
2831 retcode = SQLColumns(hstmt,
2832 NULL, 0, // All qualifiers
2833 (UCHAR *) UserID.c_str(), SQL_NTS, // Owner
2834 (UCHAR *) TableName.c_str(), SQL_NTS,
2835 NULL, 0); // All columns
f6bcfd97 2836 }
3ca6a5f0 2837 else
f6bcfd97 2838 {
3ca6a5f0
BP
2839 retcode = SQLColumns(hstmt,
2840 NULL, 0, // All qualifiers
2841 NULL, 0, // Owner
2842 (UCHAR *) TableName.c_str(), SQL_NTS,
2843 NULL, 0); // All columns
f6bcfd97 2844 }
3ca6a5f0 2845 if (retcode != SQL_SUCCESS)
f6bcfd97 2846 { // Error occured, abort
3ca6a5f0
BP
2847 DispAllErrors(henv, hdbc, hstmt);
2848 if (colInf)
2849 delete [] colInf;
2850 SQLFreeStmt(hstmt, SQL_CLOSE);
2851 if (numCols)
2852 *numCols = 0;
2853 return(0);
f6bcfd97 2854 }
eedb1543 2855
f6bcfd97
BP
2856 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2857 {
2858 if (pass == 1) // First pass, just add up the number of columns
2859 noCols++;
2860 else // Pass 2; Fill in the array of structures
2861 {
2862 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2863 {
2864 // NOTE: Only the ODBC 1.x fields are retrieved
e4e45573
GT
2865 GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2866 GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2867 GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2868 GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2869 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
2870 GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
2871 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb);
2872 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb);
2873 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2874 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2875 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
2876 GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
f6bcfd97
BP
2877 // Start Values for Primary/Foriegn Key (=No)
2878 colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2879 colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2880 colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2881 colInf[colNo].FkTableName[0] = 0; // Foreign key table name
eedb1543
DW
2882
2883#ifdef _IODBC_
e4e45573
GT
2884 // IODBC does not return a correct columnLength, so we set
2885 // columnLength = bufferSize if no column length was returned
2886 // IODBC returns the columnLength in bufferSize. (bug)
2887 if (colInf[colNo].columnLength < 1)
a8aa2258 2888 {
e4e45573 2889 colInf[colNo].columnLength = colInf[colNo].bufferSize;
a8aa2258 2890 }
f6bcfd97 2891#endif
eedb1543 2892
3ca6a5f0
BP
2893 // Determine the wxDb data type that is used to represent the native data type of this data source
2894 colInf[colNo].dbDataType = 0;
2895 // Get the intern datatype
2896 switch (colInf[colNo].sqlDataType)
2897 {
2898 case SQL_VARCHAR:
2899 case SQL_CHAR:
eedb1543 2900 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
3ca6a5f0 2901 break;
eedb1543 2902
3ca6a5f0
BP
2903 case SQL_TINYINT:
2904 case SQL_SMALLINT:
2905 case SQL_INTEGER:
eedb1543 2906 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
3ca6a5f0
BP
2907 break;
2908 case SQL_DOUBLE:
2909 case SQL_DECIMAL:
2910 case SQL_NUMERIC:
2911 case SQL_FLOAT:
2912 case SQL_REAL:
eedb1543 2913 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
3ca6a5f0
BP
2914 break;
2915 case SQL_DATE:
eedb1543 2916 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
3ca6a5f0 2917 break;
bf5423ea
GT
2918 case SQL_BINARY:
2919 colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
2920 break;
f6bcfd97 2921#ifdef __WXDEBUG__
3ca6a5f0
BP
2922 default:
2923 wxString errMsg;
77ffb593 2924 errMsg.Printf(wxT("SQL Data type %d currently not supported by wxWidgets"), colInf[colNo].sqlDataType);
3ca6a5f0 2925 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
eedb1543 2926#endif
3ca6a5f0 2927 }
f6bcfd97
BP
2928 colNo++;
2929 }
2930 }
2931 }
2932 if (retcode != SQL_NO_DATA_FOUND)
3ca6a5f0 2933 { // Error occured, abort
f6bcfd97
BP
2934 DispAllErrors(henv, hdbc, hstmt);
2935 if (colInf)
3ca6a5f0 2936 delete [] colInf;
f6bcfd97
BP
2937 SQLFreeStmt(hstmt, SQL_CLOSE);
2938 if (numCols)
3ca6a5f0 2939 *numCols = 0;
f6bcfd97 2940 return(0);
3ca6a5f0
BP
2941 }
2942 }
eedb1543 2943
3ca6a5f0 2944 SQLFreeStmt(hstmt, SQL_CLOSE);
eedb1543 2945
3ca6a5f0
BP
2946 // Store Primary and Foreign Keys
2947 GetKeyFields(tableName,colInf,noCols);
2948
2949 ///////////////////////////////////////////////////////////////////////////
2950 // Now sort the the columns in order to make them appear in the right order
2951 ///////////////////////////////////////////////////////////////////////////
eedb1543 2952
3ca6a5f0
BP
2953 // Build a generic SELECT statement which returns 0 rows
2954 wxString Stmt;
eedb1543 2955
243d4b36 2956 Stmt.Printf(wxT("select * from \"%s\" where 0=1"), tableName);
eedb1543
DW
2957
2958 // Execute query
3ca6a5f0
BP
2959 if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS)
2960 {
2961 DispAllErrors(henv, hdbc, hstmt);
2962 return NULL;
eedb1543
DW
2963 }
2964
3ca6a5f0
BP
2965 // Get the number of result columns
2966 if (SQLNumResultCols (hstmt, &noCols) != SQL_SUCCESS)
2967 {
2968 DispAllErrors(henv, hdbc, hstmt);
2969 return NULL;
2970 }
eedb1543 2971
3ca6a5f0
BP
2972 if (noCols == 0) // Probably a bogus table name
2973 return NULL;
eedb1543
DW
2974
2975 // Get the name
3ca6a5f0
BP
2976 int i;
2977 short colNum;
2978 UCHAR name[100];
2979 SWORD Sword;
2980 SDWORD Sdword;
2981 for (colNum = 0; colNum < noCols; colNum++)
eedb1543
DW
2982 {
2983 if (SQLColAttributes(hstmt,colNum+1, SQL_COLUMN_NAME,
2984 name, sizeof(name),
3ca6a5f0
BP
2985 &Sword, &Sdword) != SQL_SUCCESS)
2986 {
2987 DispAllErrors(henv, hdbc, hstmt);
2988 return NULL;
eedb1543
DW
2989 }
2990
3ca6a5f0
BP
2991 wxString Name1 = name;
2992 Name1 = Name1.Upper();
eedb1543 2993
3ca6a5f0
BP
2994 // Where is this name in the array ?
2995 for (i = colNum ; i < noCols ; i++)
2996 {
2997 wxString Name2 = colInf[i].colName;
2998 Name2 = Name2.Upper();
2999 if (Name2 == Name1)
3000 {
3001 if (colNum != i) // swap to sort
3002 {
3003 wxDbColInf tmpColInf = colInf[colNum];
3004 colInf[colNum] = colInf[i];
3005 colInf[i] = tmpColInf;
3006 }
3007 break;
eedb1543
DW
3008 }
3009 }
3010 }
3ca6a5f0 3011 SQLFreeStmt(hstmt, SQL_CLOSE);
f6bcfd97 3012
3ca6a5f0
BP
3013 ///////////////////////////////////////////////////////////////////////////
3014 // End sorting
3015 ///////////////////////////////////////////////////////////////////////////
f6bcfd97 3016
3ca6a5f0
BP
3017 if (numCols)
3018 *numCols = noCols;
3019 return colInf;
eedb1543 3020
f6bcfd97
BP
3021} // wxDb::GetColumns()
3022
3023
3ca6a5f0 3024#endif // #else OLD_GETCOLUMNS
f6bcfd97
BP
3025
3026
3027/********** wxDb::GetColumnCount() **********/
dba2120c 3028int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID)
67e9aaa3
GT
3029/*
3030 * Returns a count of how many columns are in a table.
3031 * If an error occurs in computing the number of columns
3032 * this function will return a -1 for the count
3033 *
3034 * userID is evaluated in the following manner:
1e92909e
GT
3035 * userID == NULL ... UserID is ignored
3036 * userID == "" ... UserID set equal to 'this->uid'
3037 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3038 *
f6bcfd97
BP
3039 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3040 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
3041 * to avoid undesired unbinding of columns.
3042 */
3043{
02cf6fdd 3044 UWORD noCols = 0;
1e92909e
GT
3045
3046 RETCODE retcode;
3047
1e92909e
GT
3048 wxString TableName;
3049
4fdae997
GT
3050 wxString UserID;
3051 convertUserID(userID,UserID);
1e92909e 3052
4fdae997
GT
3053 TableName = tableName;
3054 // Oracle and Interbase table names are uppercase only, so force
3055 // the name to uppercase just in case programmer forgot to do this
3056 if ((Dbms() == dbmsORACLE) ||
3057 (Dbms() == dbmsINTERBASE))
3058 TableName = TableName.Upper();
1e92909e 3059
4fdae997 3060 SQLFreeStmt(hstmt, SQL_CLOSE);
1e92909e 3061
4fdae997
GT
3062 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
3063 // use the call below that leaves out the user name
3064 if (!UserID.IsEmpty() &&
3065 Dbms() != dbmsMY_SQL &&
3066 Dbms() != dbmsACCESS &&
3067 Dbms() != dbmsMS_SQL_SERVER)
1e92909e 3068 {
4fdae997
GT
3069 retcode = SQLColumns(hstmt,
3070 NULL, 0, // All qualifiers
8a39593e
JS
3071 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner
3072 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
4fdae997
GT
3073 NULL, 0); // All columns
3074 }
3075 else
3076 {
3077 retcode = SQLColumns(hstmt,
3078 NULL, 0, // All qualifiers
3079 NULL, 0, // Owner
8a39593e 3080 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
4fdae997
GT
3081 NULL, 0); // All columns
3082 }
3083 if (retcode != SQL_SUCCESS)
3084 { // Error occured, abort
3085 DispAllErrors(henv, hdbc, hstmt);
3086 SQLFreeStmt(hstmt, SQL_CLOSE);
3087 return(-1);
3088 }
1e92909e 3089
4fdae997
GT
3090 // Count the columns
3091 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
3092 noCols++;
1e92909e 3093
4fdae997
GT
3094 if (retcode != SQL_NO_DATA_FOUND)
3095 { // Error occured, abort
3096 DispAllErrors(henv, hdbc, hstmt);
3097 SQLFreeStmt(hstmt, SQL_CLOSE);
3098 return(-1);
1e92909e
GT
3099 }
3100
3101 SQLFreeStmt(hstmt, SQL_CLOSE);
3102 return noCols;
67e9aaa3 3103
f6bcfd97 3104} // wxDb::GetColumnCount()
67e9aaa3
GT
3105
3106
f6bcfd97 3107/********** wxDb::GetCatalog() *******/
4fdae997 3108wxDbInf *wxDb::GetCatalog(const wxChar *userID)
67e9aaa3
GT
3109/*
3110 * ---------------------------------------------------------------------
0cd121f9 3111 * -- 19991203 : mj10777 : Create ------
67e9aaa3
GT
3112 * -- : Creates a wxDbInf with Tables / Cols Array ------
3113 * -- : uses SQLTables and fills pTableInf; ------
3114 * -- : pColInf is set to NULL and numCols to 0; ------
3115 * -- : returns pDbInf (wxDbInf) ------
3116 * -- - if unsuccesfull (pDbInf == NULL) ------
3117 * -- : pColInf can be filled with GetColumns(..); ------
3118 * -- : numCols can be filled with GetColumnCount(..); ------
3119 * ---------------------------------------------------------------------
3120 *
3121 * userID is evaluated in the following manner:
1e92909e
GT
3122 * userID == NULL ... UserID is ignored
3123 * userID == "" ... UserID set equal to 'this->uid'
3124 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3125 *
f6bcfd97
BP
3126 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3127 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
3128 * to avoid undesired unbinding of columns.
3129 */
3130{
1e92909e
GT
3131 int noTab = 0; // Counter while filling table entries
3132 int pass;
3133 RETCODE retcode;
3134 SDWORD cb;
1e92909e
GT
3135 wxString tblNameSave;
3136
3137 wxString UserID;
4fdae997 3138 convertUserID(userID,UserID);
1e92909e
GT
3139
3140 //-------------------------------------------------------------
caf412d6
DS
3141 // Create the Database Array of catalog entries
3142
3143 wxDbInf *pDbInf = new wxDbInf;
3144
1e92909e
GT
3145 //-------------------------------------------------------------
3146 // Table Information
3147 // Pass 1 - Determine how many Tables there are.
3148 // Pass 2 - Create the Table array and fill it
3149 // - Create the Cols array = NULL
3150 //-------------------------------------------------------------
f6bcfd97 3151
1e92909e
GT
3152 for (pass = 1; pass <= 2; pass++)
3153 {
3154 SQLFreeStmt(hstmt, SQL_CLOSE); // Close if Open
4fdae997 3155 tblNameSave.Empty();
1e92909e 3156
4fdae997 3157 if (!UserID.IsEmpty() &&
3ca6a5f0 3158 Dbms() != dbmsMY_SQL &&
4fdae997
GT
3159 Dbms() != dbmsACCESS &&
3160 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
3161 {
3162 retcode = SQLTables(hstmt,
3163 NULL, 0, // All qualifiers
8a39593e 3164 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified
1e92909e
GT
3165 NULL, 0, // All tables
3166 NULL, 0); // All columns
3167 }
3168 else
3169 {
3170 retcode = SQLTables(hstmt,
3171 NULL, 0, // All qualifiers
3172 NULL, 0, // User specified
3173 NULL, 0, // All tables
3174 NULL, 0); // All columns
3175 }
f6bcfd97 3176
1e92909e
GT
3177 if (retcode != SQL_SUCCESS)
3178 {
3179 DispAllErrors(henv, hdbc, hstmt);
3180 pDbInf = NULL;
3181 SQLFreeStmt(hstmt, SQL_CLOSE);
3182 return pDbInf;
3183 }
eedb1543 3184
1e92909e
GT
3185 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) // Table Information
3186 {
3187 if (pass == 1) // First pass, just count the Tables
3188 {
3189 if (pDbInf->numTables == 0)
3190 {
e4e45573
GT
3191 GetData( 1, SQL_C_WXCHAR, (UCHAR*) pDbInf->catalog, 128+1, &cb);
3192 GetData( 2, SQL_C_WXCHAR, (UCHAR*) pDbInf->schema, 128+1, &cb);
1e92909e
GT
3193 }
3194 pDbInf->numTables++; // Counter for Tables
3195 } // if (pass == 1)
3196 if (pass == 2) // Create and fill the Table entries
3197 {
3198 if (pDbInf->pTableInf == NULL) // Has the Table Array been created
3199 { // no, then create the Array
f6bcfd97 3200 pDbInf->pTableInf = new wxDbTableInf[pDbInf->numTables];
1e92909e 3201 noTab = 0;
eedb1543 3202 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
f6bcfd97 3203
e4e45573
GT
3204 GetData( 3, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
3205 GetData( 4, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableType, 30+1, &cb);
3206 GetData( 5, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableRemarks, 254+1, &cb);
3ca6a5f0 3207
1e92909e 3208 noTab++;
3ca6a5f0
BP
3209 } // if
3210 } // while
3211 } // for
1e92909e
GT
3212 SQLFreeStmt(hstmt, SQL_CLOSE);
3213
3214 // Query how many columns are in each table
3215 for (noTab=0;noTab<pDbInf->numTables;noTab++)
3216 {
564c92d9 3217 (pDbInf->pTableInf+noTab)->numCols = (UWORD)GetColumnCount((pDbInf->pTableInf+noTab)->tableName,UserID);
1e92909e 3218 }
3ca6a5f0 3219
1e92909e 3220 return pDbInf;
3ca6a5f0 3221
f6bcfd97 3222} // wxDb::GetCatalog()
67e9aaa3
GT
3223
3224
f6bcfd97 3225/********** wxDb::Catalog() **********/
4fdae997 3226bool wxDb::Catalog(const wxChar *userID, const wxString &fileName)
67e9aaa3
GT
3227/*
3228 * Creates the text file specified in 'filename' which will contain
3229 * a minimal data dictionary of all tables accessible by the user specified
3230 * in 'userID'
3231 *
3232 * userID is evaluated in the following manner:
1e92909e
GT
3233 * userID == NULL ... UserID is ignored
3234 * userID == "" ... UserID set equal to 'this->uid'
3235 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3236 *
f6bcfd97
BP
3237 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3238 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
3239 * to avoid undesired unbinding of columns.
3240 */
1fc5dd6f 3241{
4fdae997 3242 wxASSERT(fileName.Length());
1e92909e
GT
3243
3244 RETCODE retcode;
3245 SDWORD cb;
4fdae997 3246 wxChar tblName[DB_MAX_TABLE_NAME_LEN+1];
1e92909e 3247 wxString tblNameSave;
4fdae997 3248 wxChar colName[DB_MAX_COLUMN_NAME_LEN+1];
1e92909e 3249 SWORD sqlDataType;
4fdae997 3250 wxChar typeName[30+1];
e262868d 3251 SDWORD precision, length;
1e92909e 3252
8a39593e 3253 FILE *fp = wxFopen(fileName.c_str(),wxT("wt"));
1e92909e 3254 if (fp == NULL)
68379eaf 3255 return false;
1e92909e
GT
3256
3257 SQLFreeStmt(hstmt, SQL_CLOSE);
3258
4fdae997
GT
3259 wxString UserID;
3260 convertUserID(userID,UserID);
1e92909e 3261
4fdae997
GT
3262 if (!UserID.IsEmpty() &&
3263 Dbms() != dbmsMY_SQL &&
3264 Dbms() != dbmsACCESS &&
081eb1b1 3265 Dbms() != dbmsINTERBASE &&
4fdae997 3266 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
3267 {
3268 retcode = SQLColumns(hstmt,
3269 NULL, 0, // All qualifiers
8a39593e 3270 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified
1e92909e
GT
3271 NULL, 0, // All tables
3272 NULL, 0); // All columns
3273 }
3274 else
3275 {
3276 retcode = SQLColumns(hstmt,
3277 NULL, 0, // All qualifiers
3278 NULL, 0, // User specified
3279 NULL, 0, // All tables
3280 NULL, 0); // All columns
3281 }
3282 if (retcode != SQL_SUCCESS)
3283 {
3284 DispAllErrors(henv, hdbc, hstmt);
3285 fclose(fp);
68379eaf 3286 return false;
1e92909e
GT
3287 }
3288
3289 wxString outStr;
4fdae997 3290 tblNameSave.Empty();
1e92909e
GT
3291 int cnt = 0;
3292
68379eaf 3293 while (true)
1e92909e 3294 {
e262868d
GT
3295 retcode = SQLFetch(hstmt);
3296 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
3297 break;
3298
e4e45573
GT
3299 GetData(3,SQL_C_WXCHAR, (UCHAR *) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
3300 GetData(4,SQL_C_WXCHAR, (UCHAR *) colName, DB_MAX_COLUMN_NAME_LEN+1,&cb);
3301 GetData(5,SQL_C_SSHORT, (UCHAR *)&sqlDataType, 0, &cb);
3302 GetData(6,SQL_C_WXCHAR, (UCHAR *) typeName, sizeof(typeName), &cb);
3303 GetData(7,SQL_C_SLONG, (UCHAR *)&precision, 0, &cb);
3304 GetData(8,SQL_C_SLONG, (UCHAR *)&length, 0, &cb);
b26e2b55 3305
4fdae997 3306 if (wxStrcmp(tblName, tblNameSave.c_str()))
1e92909e
GT
3307 {
3308 if (cnt)
8a39593e
JS
3309 wxFputs(wxT("\n"), fp);
3310 wxFputs(wxT("================================ "), fp);
3311 wxFputs(wxT("================================ "), fp);
3312 wxFputs(wxT("===================== "), fp);
3313 wxFputs(wxT("========= "), fp);
3314 wxFputs(wxT("=========\n"), fp);
4fdae997 3315 outStr.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
f6bcfd97 3316 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
8a39593e
JS
3317 wxFputs(outStr.c_str(), fp);
3318 wxFputs(wxT("================================ "), fp);
3319 wxFputs(wxT("================================ "), fp);
3320 wxFputs(wxT("===================== "), fp);
3321 wxFputs(wxT("========= "), fp);
3322 wxFputs(wxT("=========\n"), fp);
1e92909e
GT
3323 tblNameSave = tblName;
3324 }
67e9aaa3 3325
7fd4e7e1 3326 outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9ld %9ld\n"),
1e92909e 3327 tblName, colName, sqlDataType, typeName, precision, length);
8a39593e 3328 if (wxFputs(outStr.c_str(), fp) == EOF)
1e92909e
GT
3329 {
3330 SQLFreeStmt(hstmt, SQL_CLOSE);
3331 fclose(fp);
68379eaf 3332 return false;
1e92909e
GT
3333 }
3334 cnt++;
3335 }
1fc5dd6f 3336
1e92909e
GT
3337 if (retcode != SQL_NO_DATA_FOUND)
3338 DispAllErrors(henv, hdbc, hstmt);
1fc5dd6f 3339
1e92909e 3340 SQLFreeStmt(hstmt, SQL_CLOSE);
a2115c88 3341
1e92909e
GT
3342 fclose(fp);
3343 return(retcode == SQL_NO_DATA_FOUND);
1fc5dd6f 3344
f6bcfd97 3345} // wxDb::Catalog()
1fc5dd6f
JS
3346
3347
4fdae997 3348bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wxString &tablePath)
67e9aaa3 3349/*
68379eaf 3350 * Table name can refer to a table, view, alias or synonym. Returns true
67e9aaa3
GT
3351 * if the object exists in the database. This function does not indicate
3352 * whether or not the user has privleges to query or perform other functions
3353 * on the table.
3354 *
3355 * userID is evaluated in the following manner:
1e92909e
GT
3356 * userID == NULL ... UserID is ignored
3357 * userID == "" ... UserID set equal to 'this->uid'
3358 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3359 */
108106cf 3360{
4fdae997 3361 wxASSERT(tableName.Length());
eedb1543 3362
4fdae997 3363 wxString TableName;
eedb1543
DW
3364
3365 if (Dbms() == dbmsDBASE)
1e92909e 3366 {
3ca6a5f0 3367 wxString dbName;
4fdae997 3368 if (tablePath.Length())
942e67c3 3369 dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
3ca6a5f0 3370 else
942e67c3 3371 dbName.Printf(wxT("%s.dbf"), tableName.c_str());
eedb1543 3372
3ca6a5f0 3373 bool exists;
4fdae997 3374 exists = wxFileExists(dbName);
3ca6a5f0 3375 return exists;
1e92909e 3376 }
eedb1543 3377
4fdae997
GT
3378 wxString UserID;
3379 convertUserID(userID,UserID);
eedb1543 3380
1e92909e 3381 TableName = tableName;
d8a0a1c9 3382 // Oracle and Interbase table names are uppercase only, so force
1e92909e 3383 // the name to uppercase just in case programmer forgot to do this
eedb1543 3384 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 3385 (Dbms() == dbmsINTERBASE))
1e92909e 3386 TableName = TableName.Upper();
eedb1543 3387
1e92909e
GT
3388 SQLFreeStmt(hstmt, SQL_CLOSE);
3389 RETCODE retcode;
eedb1543 3390
a8aa2258
GT
3391 // Some databases cannot accept a user name when looking up table names,
3392 // so we use the call below that leaves out the user name
4fdae997 3393 if (!UserID.IsEmpty() &&
3ca6a5f0 3394 Dbms() != dbmsMY_SQL &&
a8aa2258 3395 Dbms() != dbmsACCESS &&
2beca662
GT
3396 Dbms() != dbmsMS_SQL_SERVER &&
3397 Dbms() != dbmsDB2 &&
081eb1b1 3398 Dbms() != dbmsINTERBASE &&
2beca662 3399 Dbms() != dbmsPERVASIVE_SQL)
1e92909e
GT
3400 {
3401 retcode = SQLTables(hstmt,
3ca6a5f0 3402 NULL, 0, // All qualifiers
8a39593e
JS
3403 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Only tables owned by this user
3404 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3405 NULL, 0); // All table types
1e92909e
GT
3406 }
3407 else
3408 {
3409 retcode = SQLTables(hstmt,
3ca6a5f0
BP
3410 NULL, 0, // All qualifiers
3411 NULL, 0, // All owners
8a39593e 3412 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3413 NULL, 0); // All table types
1e92909e
GT
3414 }
3415 if (retcode != SQL_SUCCESS)
3416 return(DispAllErrors(henv, hdbc, hstmt));
eedb1543 3417
1e92909e 3418 retcode = SQLFetch(hstmt);
a8aa2258 3419 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
1e92909e
GT
3420 {
3421 SQLFreeStmt(hstmt, SQL_CLOSE);
3422 return(DispAllErrors(henv, hdbc, hstmt));
3423 }
eedb1543 3424
1e92909e 3425 SQLFreeStmt(hstmt, SQL_CLOSE);
108106cf 3426
68379eaf 3427 return true;
eedb1543 3428
f6bcfd97 3429} // wxDb::TableExists()
108106cf
JS
3430
3431
a8aa2258 3432/********** wxDb::TablePrivileges() **********/
4fdae997 3433bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
8a39593e 3434 const wxChar *schema, const wxString &WXUNUSED(tablePath))
3ca6a5f0 3435{
4fdae997
GT
3436 wxASSERT(tableName.Length());
3437
3ca6a5f0
BP
3438 wxDbTablePrivilegeInfo result;
3439 SDWORD cbRetVal;
3440 RETCODE retcode;
eedb1543 3441
4fdae997
GT
3442 // We probably need to be able to dynamically set this based on
3443 // the driver type, and state.
3444 wxChar curRole[]=wxT("public");
eedb1543 3445
3ca6a5f0 3446 wxString TableName;
eedb1543 3447
02cf6fdd 3448 wxString UserID,Schema;
4fdae997 3449 convertUserID(userID,UserID);
02cf6fdd 3450 convertUserID(schema,Schema);
eedb1543 3451
3ca6a5f0 3452 TableName = tableName;
d8a0a1c9 3453 // Oracle and Interbase table names are uppercase only, so force
3ca6a5f0 3454 // the name to uppercase just in case programmer forgot to do this
eedb1543 3455 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 3456 (Dbms() == dbmsINTERBASE))
3ca6a5f0 3457 TableName = TableName.Upper();
eedb1543 3458
3ca6a5f0 3459 SQLFreeStmt(hstmt, SQL_CLOSE);
d8a0a1c9 3460
02cf6fdd
GT
3461 // Some databases cannot accept a user name when looking up table names,
3462 // so we use the call below that leaves out the user name
3463 if (!Schema.IsEmpty() &&
3464 Dbms() != dbmsMY_SQL &&
3465 Dbms() != dbmsACCESS &&
3466 Dbms() != dbmsMS_SQL_SERVER)
d8a0a1c9
GT
3467 {
3468 retcode = SQLTablePrivileges(hstmt,
3469 NULL, 0, // Catalog
8a39593e
JS
3470 (SQLTCHAR FAR *)Schema.c_str(), SQL_NTS, // Schema
3471 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
d8a0a1c9
GT
3472 }
3473 else
3474 {
3475 retcode = SQLTablePrivileges(hstmt,
3476 NULL, 0, // Catalog
02cf6fdd 3477 NULL, 0, // Schema
8a39593e 3478 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
d8a0a1c9 3479 }
a8aa2258 3480
eedb1543 3481#ifdef DBDEBUG_CONSOLE
8a39593e 3482 wxFprintf(stderr ,wxT("SQLTablePrivileges() returned %i \n"),retcode);
3ca6a5f0 3483#endif
eedb1543 3484
a8aa2258 3485 if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
e4e45573 3486 return (DispAllErrors(henv, hdbc, hstmt));
a8aa2258 3487
68379eaf 3488 bool failed = false;
d8a0a1c9 3489 retcode = SQLFetch(hstmt);
eedb1543 3490 while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
d8a0a1c9 3491 {
e4e45573 3492 if (SQLGetData(hstmt, 1, SQL_C_WXCHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS)
68379eaf 3493 failed = true;
eedb1543 3494
e4e45573 3495 if (!failed && SQLGetData(hstmt, 2, SQL_C_WXCHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS)
68379eaf 3496 failed = true;
eedb1543 3497
e4e45573 3498 if (!failed && SQLGetData(hstmt, 3, SQL_C_WXCHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS)
68379eaf 3499 failed = true;
eedb1543 3500
e4e45573 3501 if (!failed && SQLGetData(hstmt, 4, SQL_C_WXCHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS)
68379eaf 3502 failed = true;
eedb1543 3503
e4e45573 3504 if (!failed && SQLGetData(hstmt, 5, SQL_C_WXCHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS)
68379eaf 3505 failed = true;
eedb1543 3506
e4e45573 3507 if (!failed && SQLGetData(hstmt, 6, SQL_C_WXCHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS)
68379eaf 3508 failed = true;
eedb1543 3509
e4e45573 3510 if (!failed && SQLGetData(hstmt, 7, SQL_C_WXCHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS)
68379eaf 3511 failed = true;
d8a0a1c9 3512
5a226de0
GT
3513 if (failed)
3514 {
3515 return(DispAllErrors(henv, hdbc, hstmt));
3516 }
3ca6a5f0 3517#ifdef DBDEBUG_CONSOLE
8a39593e 3518 wxFprintf(stderr,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
a8aa2258 3519 result.privilege,result.tableOwner,result.tableName,
3ca6a5f0 3520 result.grantor, result.grantee);
eedb1543 3521#endif
d8a0a1c9 3522
68379eaf 3523 if (UserID.IsSameAs(result.tableOwner,false))
a8aa2258
GT
3524 {
3525 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3526 return true;
a8aa2258 3527 }
eedb1543 3528
68379eaf 3529 if (UserID.IsSameAs(result.grantee,false) &&
a8aa2258
GT
3530 !wxStrcmp(result.privilege,priv))
3531 {
3532 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3533 return true;
a8aa2258 3534 }
eedb1543 3535
a8aa2258
GT
3536 if (!wxStrcmp(result.grantee,curRole) &&
3537 !wxStrcmp(result.privilege,priv))
3538 {
3539 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3540 return true;
a8aa2258 3541 }
eedb1543 3542
3ca6a5f0 3543 retcode = SQLFetch(hstmt);
eedb1543
DW
3544 }
3545
a8aa2258 3546 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3547 return false;
3ca6a5f0 3548
a8aa2258 3549} // wxDb::TablePrivileges
3ca6a5f0
BP
3550
3551
5bdad317 3552const wxString wxDb::SQLTableName(const wxChar *tableName)
243d4b36
GT
3553{
3554 wxString TableName;
3555
3556 if (Dbms() == dbmsACCESS)
8a39593e 3557 TableName = _T("\"");
243d4b36
GT
3558 TableName += tableName;
3559 if (Dbms() == dbmsACCESS)
8a39593e 3560 TableName += _T("\"");
243d4b36
GT
3561
3562 return TableName;
3563} // wxDb::SQLTableName()
3564
3565
5bdad317 3566const wxString wxDb::SQLColumnName(const wxChar *colName)
243d4b36
GT
3567{
3568 wxString ColName;
3569
3570 if (Dbms() == dbmsACCESS)
8a39593e 3571 ColName = _T("\"");
243d4b36
GT
3572 ColName += colName;
3573 if (Dbms() == dbmsACCESS)
8a39593e 3574 ColName += _T("\"");
243d4b36
GT
3575
3576 return ColName;
3577} // wxDb::SQLColumnName()
3578
3579
f6bcfd97 3580/********** wxDb::SetSqlLogging() **********/
4fdae997 3581bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
1fc5dd6f 3582{
4fdae997
GT
3583 wxASSERT(state == sqlLogON || state == sqlLogOFF);
3584 wxASSERT(state == sqlLogOFF || filename.Length());
1e92909e 3585
ea5d599d
GT
3586 if (state == sqlLogON)
3587 {
3588 if (fpSqlLog == 0)
3589 {
8a39593e 3590 fpSqlLog = wxFopen(filename, (append ? wxT("at") : wxT("wt")));
ea5d599d 3591 if (fpSqlLog == NULL)
68379eaf 3592 return false;
ea5d599d
GT
3593 }
3594 }
3595 else // sqlLogOFF
3596 {
3597 if (fpSqlLog)
3598 {
3599 if (fclose(fpSqlLog))
68379eaf 3600 return false;
ea5d599d
GT
3601 fpSqlLog = 0;
3602 }
3603 }
1e92909e 3604
ea5d599d 3605 sqlLogState = state;
68379eaf 3606 return true;
1fc5dd6f 3607
f6bcfd97 3608} // wxDb::SetSqlLogging()
1fc5dd6f
JS
3609
3610
f6bcfd97 3611/********** wxDb::WriteSqlLog() **********/
4fdae997 3612bool wxDb::WriteSqlLog(const wxString &logMsg)
1fc5dd6f 3613{
4fdae997 3614 wxASSERT(logMsg.Length());
1fc5dd6f 3615
1e92909e 3616 if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
68379eaf 3617 return false;
1fc5dd6f 3618
8a39593e 3619 if (wxFputs(wxT("\n"), fpSqlLog) == EOF)
68379eaf 3620 return false;
8a39593e 3621 if (wxFputs(logMsg, fpSqlLog) == EOF)
68379eaf 3622 return false;
8a39593e 3623 if (wxFputs(wxT("\n"), fpSqlLog) == EOF)
68379eaf 3624 return false;
1fc5dd6f 3625
68379eaf 3626 return true;
1fc5dd6f 3627
f6bcfd97 3628} // wxDb::WriteSqlLog()
1fc5dd6f
JS
3629
3630
f6bcfd97
BP
3631/********** wxDb::Dbms() **********/
3632wxDBMS wxDb::Dbms(void)
a2115c88
GT
3633/*
3634 * Be aware that not all database engines use the exact same syntax, and not
3635 * every ODBC compliant database is compliant to the same level of compliancy.
3636 * Some manufacturers support the minimum Level 1 compliancy, and others up
3637 * through Level 3. Others support subsets of features for levels above 1.
3638 *
f6bcfd97 3639 * If you find an inconsistency between the wxDb class and a specific database
a2115c88
GT
3640 * engine, and an identifier to this section, and special handle the database in
3641 * the area where behavior is non-conforming with the other databases.
3642 *
3643 *
3644 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3645 * ---------------------------------------------------
3646 *
3647 * ORACLE
1e92909e 3648 * - Currently the only database supported by the class to support VIEWS
a2115c88
GT
3649 *
3650 * DBASE
1e92909e
GT
3651 * - Does not support the SQL_TIMESTAMP structure
3652 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
fdc03678 3653 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
68379eaf 3654 * is true. The user must create ALL indexes from their program.
1e92909e
GT
3655 * - Table names can only be 8 characters long
3656 * - Column names can only be 10 characters long
a2115c88
GT
3657 *
3658 * SYBASE (all)
1e92909e
GT
3659 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3660 * after every table name involved in the query/join if that tables matching record(s)
3661 * are to be locked
3662 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
a2115c88
GT
3663 *
3664 * SYBASE (Enterprise)
1e92909e 3665 * - If a column is part of the Primary Key, the column cannot be NULL
3ca6a5f0 3666 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
a2115c88
GT
3667 *
3668 * MY_SQL
1e92909e 3669 * - If a column is part of the Primary Key, the column cannot be NULL
a144affe 3670 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3ca6a5f0
BP
3671 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3672 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3673 * column definition if it is not defined correctly, but it is experimental
3674 * - Does not support sub-queries in SQL statements
a2115c88
GT
3675 *
3676 * POSTGRES
23f681ec 3677 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3ca6a5f0 3678 * - Does not support sub-queries in SQL statements
a2115c88 3679 *
a8aa2258
GT
3680 * DB2
3681 * - Primary keys must be declared as NOT NULL
2beca662
GT
3682 * - Table and index names must not be longer than 13 characters in length (technically
3683 * table names can be up to 18 characters, but the primary index is created using the
3684 * base table name plus "_PIDX", so the limit if the table has a primary index is 13.
3685 *
3686 * PERVASIVE SQL
a8aa2258 3687 *
081eb1b1
GT
3688 * INTERBASE
3689 * - Columns that are part of primary keys must be defined as being NOT NULL
3690 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3691 * column definition if it is not defined correctly, but it is experimental
a2115c88 3692 */
a2115c88 3693{
a8aa2258 3694 // Should only need to do this once for each new database connection
eedb1543 3695 // so return the value we already determined it to be to save time
a8aa2258
GT
3696 // and lots of string comparisons
3697 if (dbmsType != dbmsUNIDENTIFIED)
3698 return(dbmsType);
3699
1e92909e 3700 wxChar baseName[25+1];
1e92909e 3701 wxStrncpy(baseName,dbInf.dbmsName,25);
3ca6a5f0 3702 baseName[25] = 0;
f6bcfd97 3703
d8a0a1c9
GT
3704 // RGG 20001025 : add support for Interbase
3705 // GT : Integrated to base classes on 20001121
4fdae997 3706 if (!wxStricmp(dbInf.dbmsName,wxT("Interbase")))
d8a0a1c9
GT
3707 return((wxDBMS)(dbmsType = dbmsINTERBASE));
3708
f6bcfd97 3709 // BJO 20000428 : add support for Virtuoso
4fdae997 3710 if (!wxStricmp(dbInf.dbmsName,wxT("OpenLink Virtuoso VDBMS")))
a8aa2258 3711 return((wxDBMS)(dbmsType = dbmsVIRTUOSO));
f6bcfd97 3712
4fdae997 3713 if (!wxStricmp(dbInf.dbmsName,wxT("Adaptive Server Anywhere")))
a8aa2258
GT
3714 return((wxDBMS)(dbmsType = dbmsSYBASE_ASA));
3715
f6bcfd97
BP
3716 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3717 // connected through an OpenLink driver.
eedb1543
DW
3718 // Is it also returned by Sybase Adapatitve server?
3719 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
4fdae997 3720 if (!wxStricmp(dbInf.dbmsName,wxT("SQL Server")))
3ca6a5f0 3721 {
4fdae997
GT
3722 if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) ||
3723 !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4))
081eb1b1
GT
3724 return ((wxDBMS)(dbmsMS_SQL_SERVER));
3725 else
3726 return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
3ca6a5f0 3727 }
f6bcfd97 3728
4fdae997 3729 if (!wxStricmp(dbInf.dbmsName,wxT("Microsoft SQL Server")))
a8aa2258 3730 return((wxDBMS)(dbmsType = dbmsMS_SQL_SERVER));
9af163d7
GT
3731
3732 baseName[10] = 0;
3733 if (!wxStricmp(baseName,wxT("PostgreSQL"))) // v6.5.0
a8aa2258 3734 return((wxDBMS)(dbmsType = dbmsPOSTGRES));
1e92909e 3735
2beca662 3736 baseName[9] = 0;
9af163d7 3737 if (!wxStricmp(baseName,wxT("Pervasive")))
081eb1b1 3738 return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL));
2beca662 3739
1e92909e 3740 baseName[8] = 0;
4fdae997 3741 if (!wxStricmp(baseName,wxT("Informix")))
a8aa2258 3742 return((wxDBMS)(dbmsType = dbmsINFORMIX));
1e92909e
GT
3743
3744 baseName[6] = 0;
4fdae997 3745 if (!wxStricmp(baseName,wxT("Oracle")))
a8aa2258 3746 return((wxDBMS)(dbmsType = dbmsORACLE));
9af163d7 3747 if (!wxStricmp(baseName,wxT("ACCESS")))
a8aa2258 3748 return((wxDBMS)(dbmsType = dbmsACCESS));
4fdae997 3749 if (!wxStricmp(baseName,wxT("Sybase")))
a8aa2258 3750 return((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
1e92909e
GT
3751
3752 baseName[5] = 0;
4fdae997 3753 if (!wxStricmp(baseName,wxT("DBASE")))
a8aa2258 3754 return((wxDBMS)(dbmsType = dbmsDBASE));
9f4de2dc
JS
3755 if (!wxStricmp(baseName,wxT("xBase")))
3756 return((wxDBMS)(dbmsType = dbmsXBASE_SEQUITER));
e25cdb86
GT
3757 if (!wxStricmp(baseName,wxT("MySQL")))
3758 return((wxDBMS)(dbmsType = dbmsMY_SQL));
3759
a8aa2258 3760 baseName[3] = 0;
4fdae997 3761 if (!wxStricmp(baseName,wxT("DB2")))
a8aa2258
GT
3762 return((wxDBMS)(dbmsType = dbmsDBASE));
3763
3764 return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
3ca6a5f0 3765
f6bcfd97 3766} // wxDb::Dbms()
a2115c88
GT
3767
3768
4fdae997
GT
3769bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
3770 int dataType, ULONG columnLength,
3771 const wxString &optionalParam)
3772{
3773 wxASSERT(tableName.Length());
3774 wxASSERT(columnName.Length());
3775 wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
3776 dataType != DB_DATA_TYPE_VARCHAR);
3777
3778 // Must specify a columnLength if modifying a VARCHAR type column
3779 if (dataType == DB_DATA_TYPE_VARCHAR && !columnLength)
68379eaf 3780 return false;
5600884a 3781
4fdae997 3782 wxString dataTypeName;
081eb1b1 3783 wxString sqlStmt;
4fdae997
GT
3784 wxString alterSlashModify;
3785
081eb1b1
GT
3786 switch(dataType)
3787 {
3788 case DB_DATA_TYPE_VARCHAR :
3789 dataTypeName = typeInfVarchar.TypeName;
3790 break;
3791 case DB_DATA_TYPE_INTEGER :
3792 dataTypeName = typeInfInteger.TypeName;
3793 break;
3794 case DB_DATA_TYPE_FLOAT :
3795 dataTypeName = typeInfFloat.TypeName;
3796 break;
3797 case DB_DATA_TYPE_DATE :
3798 dataTypeName = typeInfDate.TypeName;
3799 break;
3800 case DB_DATA_TYPE_BLOB :
3801 dataTypeName = typeInfBlob.TypeName;
3802 break;
3803 default:
68379eaf 3804 return false;
081eb1b1
GT
3805 }
3806
3807 // Set the modify or alter syntax depending on the type of database connected to
3808 switch (Dbms())
3809 {
3810 case dbmsORACLE :
8a39593e 3811 alterSlashModify = _T("MODIFY");
081eb1b1
GT
3812 break;
3813 case dbmsMS_SQL_SERVER :
8a39593e 3814 alterSlashModify = _T("ALTER COLUMN");
081eb1b1
GT
3815 break;
3816 case dbmsUNIDENTIFIED :
68379eaf 3817 return false;
081eb1b1
GT
3818 case dbmsSYBASE_ASA :
3819 case dbmsSYBASE_ASE :
3820 case dbmsMY_SQL :
3821 case dbmsPOSTGRES :
3822 case dbmsACCESS :
3823 case dbmsDBASE :
9f4de2dc 3824 case dbmsXBASE_SEQUITER :
081eb1b1 3825 default :
8a39593e 3826 alterSlashModify = _T("MODIFY");
081eb1b1
GT
3827 break;
3828 }
3829
3830 // create the SQL statement
9c136858
JS
3831 if ( Dbms() == dbmsMY_SQL )
3832 {
3833 sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(),
3834 columnName.c_str(), dataTypeName.c_str());
3835 }
3836 else
3837 {
3838 sqlStmt.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName.c_str(), alterSlashModify.c_str(),
081eb1b1 3839 columnName.c_str(), dataTypeName.c_str());
9c136858 3840 }
4fdae997
GT
3841
3842 // For varchars only, append the size of the column
e25cdb86 3843 if (dataType == DB_DATA_TYPE_VARCHAR &&
8a39593e 3844 (Dbms() != dbmsMY_SQL || dataTypeName != _T("text")))
4fdae997
GT
3845 {
3846 wxString s;
7fd4e7e1 3847 s.Printf(wxT("(%lu)"), columnLength);
4fdae997
GT
3848 sqlStmt += s;
3849 }
3850
3851 // for passing things like "NOT NULL"
3852 if (optionalParam.Length())
3853 {
3854 sqlStmt += wxT(" ");
3855 sqlStmt += optionalParam;
3856 }
3857
081eb1b1 3858 return ExecSql(sqlStmt);
4fdae997
GT
3859
3860} // wxDb::ModifyColumn()
3861
3862
fdc03678 3863/********** wxDbGetConnection() **********/
bb41dcbe 3864wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors)
108106cf 3865{
fdc03678 3866 wxDbList *pList;
1e92909e 3867
a8aa2258
GT
3868 // Used to keep a pointer to a DB connection that matches the requested
3869 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
3870 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
3871 // rather than having to re-query the datasource to get all the values
3872 // using the wxDb::Open(Dsn,Uid,AuthStr) function
3873 wxDb *matchingDbConnection = NULL;
3874
1e92909e
GT
3875 // Scan the linked list searching for an available database connection
3876 // that's already been opened but is currently not in use.
3877 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3878 {
3879 // The database connection must be for the same datasource
3880 // name and must currently not be in use.
3ca6a5f0 3881 if (pList->Free &&
0907ea9c 3882 (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors))
1e92909e 3883 {
0907ea9c
GT
3884 if (pDbConfig->UseConnectionStr())
3885 {
68379eaf 3886 if (pList->PtrDb->OpenedWithConnectionString() &&
0907ea9c
GT
3887 (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr)))
3888 {
3889 // Found a free connection
68379eaf 3890 pList->Free = false;
0907ea9c
GT
3891 return(pList->PtrDb);
3892 }
3893 }
3894 else
3895 {
3896 if (!pList->PtrDb->OpenedWithConnectionString() &&
3897 (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn)))
3898 {
3899 // Found a free connection
68379eaf 3900 pList->Free = false;
0907ea9c
GT
3901 return(pList->PtrDb);
3902 }
3903 }
1e92909e 3904 }
a8aa2258 3905
0907ea9c
GT
3906 if (pDbConfig->UseConnectionStr())
3907 {
3908 if (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr))
3909 matchingDbConnection = pList->PtrDb;
3910 }
3911 else
3912 {
3913 if (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn) &&
3914 !wxStrcmp(pDbConfig->GetUserID(), pList->Uid) &&
3915 !wxStrcmp(pDbConfig->GetPassword(), pList->AuthStr))
3916 matchingDbConnection = pList->PtrDb;
3917 }
1e92909e
GT
3918 }
3919
3920 // No available connections. A new connection must be made and
3921 // appended to the end of the linked list.
3922 if (PtrBegDbList)
3923 {
3924 // Find the end of the list
3925 for (pList = PtrBegDbList; pList->PtrNext; pList = pList->PtrNext);
3926 // Append a new list item
fdc03678 3927 pList->PtrNext = new wxDbList;
1e92909e
GT
3928 pList->PtrNext->PtrPrev = pList;
3929 pList = pList->PtrNext;
3930 }
3ca6a5f0 3931 else // Empty list
1e92909e
GT
3932 {
3933 // Create the first node on the list
fdc03678 3934 pList = PtrBegDbList = new wxDbList;
1e92909e
GT
3935 pList->PtrPrev = 0;
3936 }
3937
3938 // Initialize new node in the linked list
0907ea9c 3939 pList->PtrNext = 0;
68379eaf 3940 pList->Free = false;
0907ea9c
GT
3941 pList->Dsn = pDbConfig->GetDsn();
3942 pList->Uid = pDbConfig->GetUserID();
3943 pList->AuthStr = pDbConfig->GetPassword();
3944 pList->ConnectionStr = pDbConfig->GetConnectionStr();
a8aa2258 3945
9556da13 3946 pList->PtrDb = new wxDb(pDbConfig->GetHenv(), FwdOnlyCursors);
1e92909e 3947
caf412d6 3948 bool opened;
a8aa2258
GT
3949
3950 if (!matchingDbConnection)
0907ea9c
GT
3951 {
3952 if (pDbConfig->UseConnectionStr())
3953 {
3954 opened = pList->PtrDb->Open(pDbConfig->GetConnectionStr());
3955 }
3956 else
3957 {
3958 opened = pList->PtrDb->Open(pDbConfig->GetDsn(), pDbConfig->GetUserID(), pDbConfig->GetPassword());
3959 }
3960 }
a8aa2258
GT
3961 else
3962 opened = pList->PtrDb->Open(matchingDbConnection);
3963
1e92909e 3964 // Connect to the datasource
a8aa2258 3965 if (opened)
1e92909e 3966 {
68379eaf
WS
3967 pList->PtrDb->setCached(true); // Prevent a user from deleting a cached connection
3968 pList->PtrDb->SetSqlLogging(SQLLOGstate, SQLLOGfn, true);
1e92909e
GT
3969 return(pList->PtrDb);
3970 }
3971 else // Unable to connect, destroy list item
3972 {
3973 if (pList->PtrPrev)
3974 pList->PtrPrev->PtrNext = 0;
3975 else
0907ea9c
GT
3976 PtrBegDbList = 0; // Empty list again
3977
3978 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
3979 pList->PtrDb->Close(); // Close the wxDb object
3980 delete pList->PtrDb; // Deletes the wxDb object
3981 delete pList; // Deletes the linked list object
1e92909e
GT
3982 return(0);
3983 }
108106cf 3984
fdc03678 3985} // wxDbGetConnection()
108106cf 3986
67e9aaa3 3987
fdc03678 3988/********** wxDbFreeConnection() **********/
bb41dcbe 3989bool WXDLLIMPEXP_ODBC wxDbFreeConnection(wxDb *pDb)
108106cf 3990{
fdc03678 3991 wxDbList *pList;
108106cf 3992
1e92909e
GT
3993 // Scan the linked list searching for the database connection
3994 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3995 {
3ca6a5f0 3996 if (pList->PtrDb == pDb) // Found it, now free it!!!
68379eaf 3997 return (pList->Free = true);
1e92909e 3998 }
108106cf 3999
1e92909e 4000 // Never found the database object, return failure
68379eaf 4001 return false;
108106cf 4002
fdc03678 4003} // wxDbFreeConnection()
108106cf 4004
67e9aaa3 4005
fdc03678 4006/********** wxDbCloseConnections() **********/
bb41dcbe 4007void WXDLLIMPEXP_ODBC wxDbCloseConnections(void)
108106cf 4008{
fdc03678 4009 wxDbList *pList, *pNext;
23f681ec 4010
1e92909e
GT
4011 // Traverse the linked list closing database connections and freeing memory as I go.
4012 for (pList = PtrBegDbList; pList; pList = pNext)
4013 {
4014 pNext = pList->PtrNext; // Save the pointer to next
f6bcfd97
BP
4015 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
4016 pList->PtrDb->Close(); // Close the wxDb object
68379eaf 4017 pList->PtrDb->setCached(false); // Allows deletion of the wxDb instance
f6bcfd97 4018 delete pList->PtrDb; // Deletes the wxDb object
1e92909e
GT
4019 delete pList; // Deletes the linked list object
4020 }
4021
4022 // Mark the list as empty
4023 PtrBegDbList = 0;
108106cf 4024
fdc03678 4025} // wxDbCloseConnections()
108106cf 4026
67e9aaa3 4027
eb3b9dda 4028/********** wxDbConnectionsInUse() **********/
bb41dcbe 4029int WXDLLIMPEXP_ODBC wxDbConnectionsInUse(void)
108106cf 4030{
fdc03678 4031 wxDbList *pList;
1e92909e 4032 int cnt = 0;
108106cf 4033
1e92909e
GT
4034 // Scan the linked list counting db connections that are currently in use
4035 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
4036 {
68379eaf 4037 if (pList->Free == false)
1e92909e
GT
4038 cnt++;
4039 }
108106cf 4040
1e92909e 4041 return(cnt);
108106cf 4042
fdc03678 4043} // wxDbConnectionsInUse()
108106cf 4044
67e9aaa3 4045
2c257434
GT
4046
4047/********** wxDbLogExtendedErrorMsg() **********/
4048// DEBUG ONLY function
f9ebf98b 4049const wxChar WXDLLIMPEXP_ODBC *wxDbLogExtendedErrorMsg(const wxChar *userText,
90350682
VZ
4050 wxDb *pDb,
4051 const wxChar *ErrFile,
4052 int ErrLine)
2c257434
GT
4053{
4054 static wxString msg;
4055 msg = userText;
4056
4057 wxString tStr;
4058
4059 if (ErrFile || ErrLine)
4060 {
4061 msg += wxT("File: ");
4062 msg += ErrFile;
4063 msg += wxT(" Line: ");
4064 tStr.Printf(wxT("%d"),ErrLine);
4065 msg += tStr.c_str();
4066 msg += wxT("\n");
4067 }
4068
4069 msg.Append (wxT("\nODBC errors:\n"));
4070 msg += wxT("\n");
2e57a9ef 4071
2c257434
GT
4072 // Display errors for this connection
4073 int i;
4074 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
4075 {
4076 if (pDb->errorList[i])
4077 {
4078 msg.Append(pDb->errorList[i]);
4079 if (wxStrcmp(pDb->errorList[i],wxT("")) != 0)
4080 msg.Append(wxT("\n"));
4081 // Clear the errmsg buffer so the next error will not
4082 // end up showing the previous error that have occurred
4083 wxStrcpy(pDb->errorList[i],wxT(""));
4084 }
4085 }
4086 msg += wxT("\n");
4087
4088 wxLogDebug(msg.c_str());
4089
4090 return msg.c_str();
4091} // wxDbLogExtendedErrorMsg()
4092
4093
fdc03678 4094/********** wxDbSqlLog() **********/
f6bcfd97 4095bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename)
a2115c88 4096{
68379eaf 4097 bool append = false;
fdc03678 4098 wxDbList *pList;
a2115c88 4099
1e92909e
GT
4100 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
4101 {
f6bcfd97 4102 if (!pList->PtrDb->SetSqlLogging(state,filename,append))
68379eaf
WS
4103 return false;
4104 append = true;
1e92909e 4105 }
a2115c88 4106
1e92909e 4107 SQLLOGstate = state;
3ca6a5f0 4108 SQLLOGfn = filename;
a2115c88 4109
68379eaf 4110 return true;
a2115c88 4111
fdc03678 4112} // wxDbSqlLog()
a2115c88 4113
67e9aaa3 4114
a8aa2258 4115#if 0
fdc03678 4116/********** wxDbCreateDataSource() **********/
4fdae997
GT
4117int wxDbCreateDataSource(const wxString &driverName, const wxString &dsn, const wxString &description,
4118 bool sysDSN, const wxString &defDir, wxWindow *parent)
fdc03678
GT
4119/*
4120 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
eedb1543 4121 * Very rudimentary creation of an ODBC data source.
a8aa2258
GT
4122 *
4123 * ODBC driver must be ODBC 3.0 compliant to use this function
fdc03678
GT
4124 */
4125{
a144affe 4126 int result = FALSE;
fdc03678 4127
a8aa2258
GT
4128//!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
4129#ifdef __VISUALC__
fdc03678
GT
4130 int dsnLocation;
4131 wxString setupStr;
4132
4133 if (sysDSN)
4134 dsnLocation = ODBC_ADD_SYS_DSN;
4135 else
4136 dsnLocation = ODBC_ADD_DSN;
4137
4138 // NOTE: The decimal 2 is an invalid character in all keyword pairs
eedb1543 4139 // so that is why I used it, as wxString does not deal well with
fdc03678 4140 // embedded nulls in strings
4fdae997 4141 setupStr.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn,2,description,2,defDir,2);
fdc03678
GT
4142
4143 // Replace the separator from above with the '\0' seperator needed
4144 // by the SQLConfigDataSource() function
4145 int k;
4146 do
4147 {
68379eaf 4148 k = setupStr.Find((wxChar)2,true);
fdc03678 4149 if (k != wxNOT_FOUND)
4fdae997 4150 setupStr[(UINT)k] = wxT('\0');
fdc03678
GT
4151 }
4152 while (k != wxNOT_FOUND);
4153
4154 result = SQLConfigDataSource((HWND)parent->GetHWND(), dsnLocation,
f6bcfd97 4155 driverName, setupStr.c_str());
fdc03678 4156
a8aa2258 4157 if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
fdc03678
GT
4158 {
4159 // check for errors caused by ConfigDSN based functions
4160 DWORD retcode = 0;
4161 WORD cb;
a8aa2258 4162 wxChar errMsg[SQL_MAX_MESSAGE_LENGTH];
4fdae997 4163 errMsg[0] = wxT('\0');
fdc03678 4164
a8aa2258
GT
4165 // This function is only supported in ODBC drivers v3.0 compliant and above
4166 SQLInstallerError(1,&retcode,errMsg,SQL_MAX_MESSAGE_LENGTH-1,&cb);
fdc03678
GT
4167 if (retcode)
4168 {
fdc03678 4169#ifdef DBDEBUG_CONSOLE
f6bcfd97
BP
4170 // When run in console mode, use standard out to display errors.
4171 cout << errMsg << endl;
a8aa2258 4172 cout << wxT("Press any key to continue...") << endl;
f6bcfd97 4173 getchar();
fdc03678 4174#endif // DBDEBUG_CONSOLE
fdc03678
GT
4175
4176#ifdef __WXDEBUG__
f6bcfd97 4177 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
fdc03678
GT
4178#endif // __WXDEBUG__
4179 }
4180 }
4181 else
a144affe 4182 result = TRUE;
a8aa2258
GT
4183#else
4184 // Using iODBC/unixODBC or some other compiler which does not support the APIs
4185 // necessary to use this function, so this function is not supported
fdc03678 4186#ifdef __WXDEBUG__
4fdae997 4187 wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
fdc03678 4188#endif
a144affe 4189 result = FALSE;
a8aa2258 4190#endif // __VISUALC__
fdc03678
GT
4191
4192 return result;
4193
4194} // wxDbCreateDataSource()
4195#endif
4196
4197
4198/********** wxDbGetDataSource() **********/
e4e45573
GT
4199bool wxDbGetDataSource(HENV henv, wxChar *Dsn, SWORD DsnMaxLength, wxChar *DsDesc,
4200 SWORD DsDescMaxLength, UWORD direction)
67e9aaa3
GT
4201/*
4202 * Dsn and DsDesc will contain the data source name and data source
4203 * description upon return
4204 */
108106cf 4205{
1e92909e 4206 SWORD cb1,cb2;
108106cf 4207
e4e45573
GT
4208 if (SQLDataSources(henv, direction, (SQLTCHAR FAR *) Dsn, DsnMaxLength*sizeof(wxChar), &cb1,
4209 (SQLTCHAR FAR *) DsDesc, DsDescMaxLength*sizeof(wxChar), &cb2) == SQL_SUCCESS)
68379eaf 4210 return true;
1e92909e 4211 else
68379eaf 4212 return false;
108106cf 4213
fdc03678
GT
4214} // wxDbGetDataSource()
4215
4216
4217// Change this to 0 to remove use of all deprecated functions
f6bcfd97 4218#if wxODBC_BACKWARD_COMPATABILITY
fdc03678
GT
4219/********************************************************************
4220 ********************************************************************
4221 *
4222 * The following functions are all DEPRECATED and are included for
4223 * backward compatability reasons only
4224 *
4225 ********************************************************************
4226 ********************************************************************/
f6bcfd97 4227bool SqlLog(sqlLog state, const wxChar *filename)
fdc03678 4228{
f6bcfd97 4229 return wxDbSqlLog((enum wxDbSqlLogState)state, filename);
fdc03678
GT
4230}
4231/***** DEPRECATED: use wxGetDataSource() *****/
4232bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
4233 UWORD direction)
4234{
4235 return wxDbGetDataSource(henv, Dsn, DsnMax, DsDesc, DsDescMax, direction);
4236}
4237/***** DEPRECATED: use wxDbGetConnection() *****/
bb41dcbe 4238wxDb WXDLLIMPEXP_ODBC *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors)
fdc03678
GT
4239{
4240 return wxDbGetConnection((wxDbConnectInf *)pDbStuff, FwdOnlyCursors);
4241}
4242/***** DEPRECATED: use wxDbFreeConnection() *****/
bb41dcbe 4243bool WXDLLIMPEXP_ODBC FreeDbConnection(wxDb *pDb)
fdc03678
GT
4244{
4245 return wxDbFreeConnection(pDb);
4246}
4247/***** DEPRECATED: use wxDbCloseConnections() *****/
bb41dcbe 4248void WXDLLIMPEXP_ODBC CloseDbConnections(void)
fdc03678
GT
4249{
4250 wxDbCloseConnections();
4251}
4252/***** DEPRECATED: use wxDbConnectionsInUse() *****/
bb41dcbe 4253int WXDLLIMPEXP_ODBC NumberDbConnectionsInUse(void)
fdc03678
GT
4254{
4255 return wxDbConnectionsInUse();
4256}
4257#endif
4258
4259
108106cf 4260#endif
1fc5dd6f 4261 // wxUSE_ODBC