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