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