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