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