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