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