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