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