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