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