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