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