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