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