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