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