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