]> git.saurik.com Git - wxWidgets.git/blame - src/common/db.cpp
Better alphabetized the event handler macros
[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
815cb839 1722 while (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, (long*) &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
1e92909e 1723 {
4fdae997
GT
1724 odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState, nativeError, errorMsg);
1725 logError(odbcErrMsg, sqlState);
1e92909e
GT
1726 if (!silent)
1727 {
1fc5dd6f 1728#ifdef DBDEBUG_CONSOLE
1e92909e 1729 // When run in console mode, use standard out to display errors.
f6bcfd97 1730 cout << odbcErrMsg.c_str() << endl;
4fdae997 1731 cout << wxT("Press any key to continue...") << endl;
1e92909e 1732 getchar();
108106cf 1733#endif
a2115c88
GT
1734
1735#ifdef __WXDEBUG__
4fdae997 1736 wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
a2115c88 1737#endif
f6bcfd97 1738 }
1e92909e 1739 }
108106cf 1740
68379eaf 1741 return false; // This function always returns false.
108106cf 1742
f6bcfd97 1743} // wxDb::DispAllErrors()
108106cf 1744
67e9aaa3 1745
f6bcfd97
BP
1746/********** wxDb::GetNextError() **********/
1747bool wxDb::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
108106cf 1748{
815cb839 1749 if (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, (long*) &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
68379eaf 1750 return true;
1e92909e 1751 else
68379eaf 1752 return false;
108106cf 1753
f6bcfd97 1754} // wxDb::GetNextError()
108106cf 1755
67e9aaa3 1756
f6bcfd97
BP
1757/********** wxDb::DispNextError() **********/
1758void wxDb::DispNextError(void)
108106cf 1759{
1e92909e 1760 wxString odbcErrMsg;
108106cf 1761
4fdae997
GT
1762 odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState, nativeError, errorMsg);
1763 logError(odbcErrMsg, sqlState);
108106cf 1764
1e92909e
GT
1765 if (silent)
1766 return;
108106cf 1767
1fc5dd6f 1768#ifdef DBDEBUG_CONSOLE
1e92909e 1769 // When run in console mode, use standard out to display errors.
f6bcfd97 1770 cout << odbcErrMsg.c_str() << endl;
4fdae997 1771 cout << wxT("Press any key to continue...") << endl;
1e92909e 1772 getchar();
108106cf
JS
1773#endif
1774
f6bcfd97
BP
1775#ifdef __WXDEBUG__
1776 wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE"));
1777#endif // __WXDEBUG__
108106cf 1778
f6bcfd97
BP
1779} // wxDb::DispNextError()
1780
1781
1782/********** wxDb::logError() **********/
4fdae997 1783void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
108106cf 1784{
4fdae997 1785 wxASSERT(errMsg.Length());
108106cf 1786
1e92909e
GT
1787 static int pLast = -1;
1788 int dbStatus;
108106cf 1789
1e92909e
GT
1790 if (++pLast == DB_MAX_ERROR_HISTORY)
1791 {
1792 int i;
1793 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
1794 wxStrcpy(errorList[i], errorList[i+1]);
1795 pLast--;
1796 }
108106cf 1797
1e92909e 1798 wxStrcpy(errorList[pLast], errMsg);
108106cf 1799
4fdae997 1800 if (SQLState.Length())
1e92909e
GT
1801 if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
1802 DB_STATUS = dbStatus;
108106cf 1803
1e92909e
GT
1804 // Add the errmsg to the sql log
1805 WriteSqlLog(errMsg);
a2115c88 1806
f6bcfd97 1807} // wxDb::logError()
108106cf 1808
67e9aaa3 1809
f6bcfd97 1810/**********wxDb::TranslateSqlState() **********/
4fdae997 1811int wxDb::TranslateSqlState(const wxString &SQLState)
108106cf 1812{
f6bcfd97 1813 if (!wxStrcmp(SQLState, wxT("01000")))
1e92909e 1814 return(DB_ERR_GENERAL_WARNING);
f6bcfd97 1815 if (!wxStrcmp(SQLState, wxT("01002")))
1e92909e 1816 return(DB_ERR_DISCONNECT_ERROR);
f6bcfd97 1817 if (!wxStrcmp(SQLState, wxT("01004")))
1e92909e 1818 return(DB_ERR_DATA_TRUNCATED);
f6bcfd97 1819 if (!wxStrcmp(SQLState, wxT("01006")))
1e92909e 1820 return(DB_ERR_PRIV_NOT_REVOKED);
f6bcfd97 1821 if (!wxStrcmp(SQLState, wxT("01S00")))
1e92909e 1822 return(DB_ERR_INVALID_CONN_STR_ATTR);
f6bcfd97 1823 if (!wxStrcmp(SQLState, wxT("01S01")))
1e92909e 1824 return(DB_ERR_ERROR_IN_ROW);
f6bcfd97 1825 if (!wxStrcmp(SQLState, wxT("01S02")))
1e92909e 1826 return(DB_ERR_OPTION_VALUE_CHANGED);
f6bcfd97 1827 if (!wxStrcmp(SQLState, wxT("01S03")))
1e92909e 1828 return(DB_ERR_NO_ROWS_UPD_OR_DEL);
f6bcfd97 1829 if (!wxStrcmp(SQLState, wxT("01S04")))
1e92909e 1830 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL);
f6bcfd97 1831 if (!wxStrcmp(SQLState, wxT("07001")))
1e92909e 1832 return(DB_ERR_WRONG_NO_OF_PARAMS);
f6bcfd97 1833 if (!wxStrcmp(SQLState, wxT("07006")))
1e92909e 1834 return(DB_ERR_DATA_TYPE_ATTR_VIOL);
f6bcfd97 1835 if (!wxStrcmp(SQLState, wxT("08001")))
1e92909e 1836 return(DB_ERR_UNABLE_TO_CONNECT);
f6bcfd97 1837 if (!wxStrcmp(SQLState, wxT("08002")))
1e92909e 1838 return(DB_ERR_CONNECTION_IN_USE);
f6bcfd97 1839 if (!wxStrcmp(SQLState, wxT("08003")))
1e92909e 1840 return(DB_ERR_CONNECTION_NOT_OPEN);
f6bcfd97 1841 if (!wxStrcmp(SQLState, wxT("08004")))
1e92909e 1842 return(DB_ERR_REJECTED_CONNECTION);
f6bcfd97 1843 if (!wxStrcmp(SQLState, wxT("08007")))
1e92909e 1844 return(DB_ERR_CONN_FAIL_IN_TRANS);
f6bcfd97 1845 if (!wxStrcmp(SQLState, wxT("08S01")))
1e92909e 1846 return(DB_ERR_COMM_LINK_FAILURE);
f6bcfd97 1847 if (!wxStrcmp(SQLState, wxT("21S01")))
1e92909e 1848 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH);
f6bcfd97 1849 if (!wxStrcmp(SQLState, wxT("21S02")))
1e92909e 1850 return(DB_ERR_DERIVED_TABLE_MISMATCH);
f6bcfd97 1851 if (!wxStrcmp(SQLState, wxT("22001")))
1e92909e 1852 return(DB_ERR_STRING_RIGHT_TRUNC);
f6bcfd97 1853 if (!wxStrcmp(SQLState, wxT("22003")))
1e92909e 1854 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG);
f6bcfd97 1855 if (!wxStrcmp(SQLState, wxT("22005")))
1e92909e 1856 return(DB_ERR_ERROR_IN_ASSIGNMENT);
f6bcfd97 1857 if (!wxStrcmp(SQLState, wxT("22008")))
1e92909e 1858 return(DB_ERR_DATETIME_FLD_OVERFLOW);
f6bcfd97 1859 if (!wxStrcmp(SQLState, wxT("22012")))
1e92909e 1860 return(DB_ERR_DIVIDE_BY_ZERO);
f6bcfd97 1861 if (!wxStrcmp(SQLState, wxT("22026")))
1e92909e 1862 return(DB_ERR_STR_DATA_LENGTH_MISMATCH);
f6bcfd97 1863 if (!wxStrcmp(SQLState, wxT("23000")))
1e92909e 1864 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL);
f6bcfd97 1865 if (!wxStrcmp(SQLState, wxT("24000")))
1e92909e 1866 return(DB_ERR_INVALID_CURSOR_STATE);
f6bcfd97 1867 if (!wxStrcmp(SQLState, wxT("25000")))
1e92909e 1868 return(DB_ERR_INVALID_TRANS_STATE);
f6bcfd97 1869 if (!wxStrcmp(SQLState, wxT("28000")))
1e92909e 1870 return(DB_ERR_INVALID_AUTH_SPEC);
f6bcfd97 1871 if (!wxStrcmp(SQLState, wxT("34000")))
1e92909e 1872 return(DB_ERR_INVALID_CURSOR_NAME);
f6bcfd97 1873 if (!wxStrcmp(SQLState, wxT("37000")))
1e92909e 1874 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL);
f6bcfd97 1875 if (!wxStrcmp(SQLState, wxT("3C000")))
1e92909e 1876 return(DB_ERR_DUPLICATE_CURSOR_NAME);
f6bcfd97 1877 if (!wxStrcmp(SQLState, wxT("40001")))
1e92909e 1878 return(DB_ERR_SERIALIZATION_FAILURE);
f6bcfd97 1879 if (!wxStrcmp(SQLState, wxT("42000")))
1e92909e 1880 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2);
f6bcfd97 1881 if (!wxStrcmp(SQLState, wxT("70100")))
1e92909e 1882 return(DB_ERR_OPERATION_ABORTED);
f6bcfd97 1883 if (!wxStrcmp(SQLState, wxT("IM001")))
1e92909e 1884 return(DB_ERR_UNSUPPORTED_FUNCTION);
f6bcfd97 1885 if (!wxStrcmp(SQLState, wxT("IM002")))
1e92909e 1886 return(DB_ERR_NO_DATA_SOURCE);
f6bcfd97 1887 if (!wxStrcmp(SQLState, wxT("IM003")))
1e92909e 1888 return(DB_ERR_DRIVER_LOAD_ERROR);
f6bcfd97 1889 if (!wxStrcmp(SQLState, wxT("IM004")))
1e92909e 1890 return(DB_ERR_SQLALLOCENV_FAILED);
f6bcfd97 1891 if (!wxStrcmp(SQLState, wxT("IM005")))
1e92909e 1892 return(DB_ERR_SQLALLOCCONNECT_FAILED);
f6bcfd97 1893 if (!wxStrcmp(SQLState, wxT("IM006")))
1e92909e 1894 return(DB_ERR_SQLSETCONNECTOPTION_FAILED);
f6bcfd97 1895 if (!wxStrcmp(SQLState, wxT("IM007")))
1e92909e 1896 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB);
f6bcfd97 1897 if (!wxStrcmp(SQLState, wxT("IM008")))
1e92909e 1898 return(DB_ERR_DIALOG_FAILED);
f6bcfd97 1899 if (!wxStrcmp(SQLState, wxT("IM009")))
1e92909e 1900 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL);
f6bcfd97 1901 if (!wxStrcmp(SQLState, wxT("IM010")))
1e92909e 1902 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG);
f6bcfd97 1903 if (!wxStrcmp(SQLState, wxT("IM011")))
1e92909e 1904 return(DB_ERR_DRIVER_NAME_TOO_LONG);
f6bcfd97 1905 if (!wxStrcmp(SQLState, wxT("IM012")))
1e92909e 1906 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR);
f6bcfd97 1907 if (!wxStrcmp(SQLState, wxT("IM013")))
1e92909e 1908 return(DB_ERR_TRACE_FILE_ERROR);
f6bcfd97 1909 if (!wxStrcmp(SQLState, wxT("S0001")))
1e92909e 1910 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS);
f6bcfd97 1911 if (!wxStrcmp(SQLState, wxT("S0002")))
1e92909e 1912 return(DB_ERR_TABLE_NOT_FOUND);
f6bcfd97 1913 if (!wxStrcmp(SQLState, wxT("S0011")))
1e92909e 1914 return(DB_ERR_INDEX_ALREADY_EXISTS);
f6bcfd97 1915 if (!wxStrcmp(SQLState, wxT("S0012")))
1e92909e 1916 return(DB_ERR_INDEX_NOT_FOUND);
f6bcfd97 1917 if (!wxStrcmp(SQLState, wxT("S0021")))
1e92909e 1918 return(DB_ERR_COLUMN_ALREADY_EXISTS);
f6bcfd97 1919 if (!wxStrcmp(SQLState, wxT("S0022")))
1e92909e 1920 return(DB_ERR_COLUMN_NOT_FOUND);
f6bcfd97 1921 if (!wxStrcmp(SQLState, wxT("S0023")))
1e92909e 1922 return(DB_ERR_NO_DEFAULT_FOR_COLUMN);
f6bcfd97 1923 if (!wxStrcmp(SQLState, wxT("S1000")))
1e92909e 1924 return(DB_ERR_GENERAL_ERROR);
f6bcfd97 1925 if (!wxStrcmp(SQLState, wxT("S1001")))
1e92909e 1926 return(DB_ERR_MEMORY_ALLOCATION_FAILURE);
f6bcfd97 1927 if (!wxStrcmp(SQLState, wxT("S1002")))
1e92909e 1928 return(DB_ERR_INVALID_COLUMN_NUMBER);
f6bcfd97 1929 if (!wxStrcmp(SQLState, wxT("S1003")))
1e92909e 1930 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE);
f6bcfd97 1931 if (!wxStrcmp(SQLState, wxT("S1004")))
1e92909e 1932 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE);
f6bcfd97 1933 if (!wxStrcmp(SQLState, wxT("S1008")))
1e92909e 1934 return(DB_ERR_OPERATION_CANCELLED);
f6bcfd97 1935 if (!wxStrcmp(SQLState, wxT("S1009")))
1e92909e 1936 return(DB_ERR_INVALID_ARGUMENT_VALUE);
f6bcfd97 1937 if (!wxStrcmp(SQLState, wxT("S1010")))
1e92909e 1938 return(DB_ERR_FUNCTION_SEQUENCE_ERROR);
f6bcfd97 1939 if (!wxStrcmp(SQLState, wxT("S1011")))
1e92909e 1940 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME);
f6bcfd97 1941 if (!wxStrcmp(SQLState, wxT("S1012")))
1e92909e 1942 return(DB_ERR_INVALID_TRANS_OPERATION_CODE);
f6bcfd97 1943 if (!wxStrcmp(SQLState, wxT("S1015")))
1e92909e 1944 return(DB_ERR_NO_CURSOR_NAME_AVAIL);
f6bcfd97 1945 if (!wxStrcmp(SQLState, wxT("S1090")))
1e92909e 1946 return(DB_ERR_INVALID_STR_OR_BUF_LEN);
f6bcfd97 1947 if (!wxStrcmp(SQLState, wxT("S1091")))
1e92909e 1948 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE);
f6bcfd97 1949 if (!wxStrcmp(SQLState, wxT("S1092")))
1e92909e 1950 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE);
f6bcfd97 1951 if (!wxStrcmp(SQLState, wxT("S1093")))
1e92909e 1952 return(DB_ERR_INVALID_PARAM_NO);
f6bcfd97 1953 if (!wxStrcmp(SQLState, wxT("S1094")))
1e92909e 1954 return(DB_ERR_INVALID_SCALE_VALUE);
f6bcfd97 1955 if (!wxStrcmp(SQLState, wxT("S1095")))
1e92909e 1956 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE);
f6bcfd97 1957 if (!wxStrcmp(SQLState, wxT("S1096")))
1e92909e 1958 return(DB_ERR_INF_TYPE_OUT_OF_RANGE);
f6bcfd97 1959 if (!wxStrcmp(SQLState, wxT("S1097")))
1e92909e 1960 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE);
f6bcfd97 1961 if (!wxStrcmp(SQLState, wxT("S1098")))
1e92909e 1962 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE);
f6bcfd97 1963 if (!wxStrcmp(SQLState, wxT("S1099")))
1e92909e 1964 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE);
f6bcfd97 1965 if (!wxStrcmp(SQLState, wxT("S1100")))
1e92909e 1966 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE);
f6bcfd97 1967 if (!wxStrcmp(SQLState, wxT("S1101")))
1e92909e 1968 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE);
f6bcfd97 1969 if (!wxStrcmp(SQLState, wxT("S1103")))
1e92909e 1970 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE);
f6bcfd97 1971 if (!wxStrcmp(SQLState, wxT("S1104")))
1e92909e 1972 return(DB_ERR_INVALID_PRECISION_VALUE);
f6bcfd97 1973 if (!wxStrcmp(SQLState, wxT("S1105")))
1e92909e 1974 return(DB_ERR_INVALID_PARAM_TYPE);
f6bcfd97 1975 if (!wxStrcmp(SQLState, wxT("S1106")))
1e92909e 1976 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE);
f6bcfd97 1977 if (!wxStrcmp(SQLState, wxT("S1107")))
1e92909e 1978 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE);
f6bcfd97 1979 if (!wxStrcmp(SQLState, wxT("S1108")))
1e92909e 1980 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE);
f6bcfd97 1981 if (!wxStrcmp(SQLState, wxT("S1109")))
1e92909e 1982 return(DB_ERR_INVALID_CURSOR_POSITION);
f6bcfd97 1983 if (!wxStrcmp(SQLState, wxT("S1110")))
1e92909e 1984 return(DB_ERR_INVALID_DRIVER_COMPLETION);
f6bcfd97 1985 if (!wxStrcmp(SQLState, wxT("S1111")))
1e92909e 1986 return(DB_ERR_INVALID_BOOKMARK_VALUE);
f6bcfd97 1987 if (!wxStrcmp(SQLState, wxT("S1C00")))
1e92909e 1988 return(DB_ERR_DRIVER_NOT_CAPABLE);
f6bcfd97 1989 if (!wxStrcmp(SQLState, wxT("S1T00")))
1e92909e
GT
1990 return(DB_ERR_TIMEOUT_EXPIRED);
1991
1992 // No match
1993 return(0);
108106cf 1994
f6bcfd97 1995} // wxDb::TranslateSqlState()
67e9aaa3 1996
23f681ec 1997
f6bcfd97 1998/********** wxDb::Grant() **********/
4fdae997 1999bool wxDb::Grant(int privileges, const wxString &tableName, const wxString &userList)
108106cf 2000{
1e92909e
GT
2001 wxString sqlStmt;
2002
2003 // Build the grant statement
4fdae997 2004 sqlStmt = wxT("GRANT ");
1e92909e 2005 if (privileges == DB_GRANT_ALL)
4fdae997 2006 sqlStmt += wxT("ALL");
1e92909e
GT
2007 else
2008 {
2009 int c = 0;
2010 if (privileges & DB_GRANT_SELECT)
2011 {
4fdae997 2012 sqlStmt += wxT("SELECT");
1e92909e
GT
2013 c++;
2014 }
2015 if (privileges & DB_GRANT_INSERT)
2016 {
2017 if (c++)
4fdae997
GT
2018 sqlStmt += wxT(", ");
2019 sqlStmt += wxT("INSERT");
1e92909e
GT
2020 }
2021 if (privileges & DB_GRANT_UPDATE)
2022 {
2023 if (c++)
4fdae997
GT
2024 sqlStmt += wxT(", ");
2025 sqlStmt += wxT("UPDATE");
1e92909e
GT
2026 }
2027 if (privileges & DB_GRANT_DELETE)
2028 {
2029 if (c++)
4fdae997
GT
2030 sqlStmt += wxT(", ");
2031 sqlStmt += wxT("DELETE");
1e92909e
GT
2032 }
2033 }
2034
4fdae997 2035 sqlStmt += wxT(" ON ");
243d4b36 2036 sqlStmt += SQLTableName(tableName);
4fdae997 2037 sqlStmt += wxT(" TO ");
1e92909e 2038 sqlStmt += userList;
108106cf 2039
1fc5dd6f 2040#ifdef DBDEBUG_CONSOLE
f6bcfd97 2041 cout << endl << sqlStmt.c_str() << endl;
108106cf
JS
2042#endif
2043
4fdae997 2044 WriteSqlLog(sqlStmt);
1fc5dd6f 2045
4fdae997 2046 return(ExecSql(sqlStmt));
108106cf 2047
f6bcfd97 2048} // wxDb::Grant()
108106cf 2049
67e9aaa3 2050
f6bcfd97 2051/********** wxDb::CreateView() **********/
4fdae997
GT
2052bool wxDb::CreateView(const wxString &viewName, const wxString &colList,
2053 const wxString &pSqlStmt, bool attemptDrop)
108106cf 2054{
1e92909e
GT
2055 wxString sqlStmt;
2056
2057 // Drop the view first
2058 if (attemptDrop && !DropView(viewName))
68379eaf 2059 return false;
1e92909e
GT
2060
2061 // Build the create view statement
4fdae997 2062 sqlStmt = wxT("CREATE VIEW ");
1e92909e 2063 sqlStmt += viewName;
23f681ec 2064
4fdae997 2065 if (colList.Length())
1e92909e 2066 {
4fdae997 2067 sqlStmt += wxT(" (");
1e92909e 2068 sqlStmt += colList;
4fdae997 2069 sqlStmt += wxT(")");
1e92909e 2070 }
108106cf 2071
4fdae997 2072 sqlStmt += wxT(" AS ");
1e92909e 2073 sqlStmt += pSqlStmt;
108106cf 2074
4fdae997 2075 WriteSqlLog(sqlStmt);
1fc5dd6f
JS
2076
2077#ifdef DBDEBUG_CONSOLE
f6bcfd97 2078 cout << sqlStmt.c_str() << endl;
108106cf
JS
2079#endif
2080
4fdae997 2081 return(ExecSql(sqlStmt));
108106cf 2082
f6bcfd97 2083} // wxDb::CreateView()
108106cf 2084
67e9aaa3 2085
f6bcfd97 2086/********** wxDb::DropView() **********/
4fdae997 2087bool wxDb::DropView(const wxString &viewName)
a2115c88 2088{
67e9aaa3 2089/*
68379eaf 2090 * NOTE: This function returns true if the View does not exist, but
67e9aaa3 2091 * only for identified databases. Code will need to be added
1e92909e 2092 * below for any other databases when those databases are defined
67e9aaa3
GT
2093 * to handle this situation consistently
2094 */
1e92909e 2095 wxString sqlStmt;
a2115c88 2096
942e67c3 2097 sqlStmt.Printf(wxT("DROP VIEW %s"), viewName.c_str());
a2115c88 2098
4fdae997 2099 WriteSqlLog(sqlStmt);
a2115c88
GT
2100
2101#ifdef DBDEBUG_CONSOLE
f6bcfd97 2102 cout << endl << sqlStmt.c_str() << endl;
a2115c88
GT
2103#endif
2104
8a39593e 2105 if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
1e92909e
GT
2106 {
2107 // Check for "Base table not found" error and ignore
2108 GetNextError(henv, hdbc, hstmt);
f6bcfd97 2109 if (wxStrcmp(sqlState,wxT("S0002"))) // "Base table not found"
1e92909e
GT
2110 {
2111 // Check for product specific error codes
f6bcfd97 2112 if (!((Dbms() == dbmsSYBASE_ASA && !wxStrcmp(sqlState,wxT("42000"))))) // 5.x (and lower?)
1e92909e
GT
2113 {
2114 DispNextError();
2115 DispAllErrors(henv, hdbc, hstmt);
2116 RollbackTrans();
68379eaf 2117 return false;
1e92909e
GT
2118 }
2119 }
2120 }
2121
2122 // Commit the transaction
2c257434 2123 if (!CommitTrans())
68379eaf 2124 return false;
1e92909e 2125
68379eaf 2126 return true;
a2115c88 2127
f6bcfd97 2128} // wxDb::DropView()
a2115c88
GT
2129
2130
f6bcfd97 2131/********** wxDb::ExecSql() **********/
4fdae997 2132bool wxDb::ExecSql(const wxString &pSqlStmt)
108106cf 2133{
2beca662
GT
2134 RETCODE retcode;
2135
1e92909e 2136 SQLFreeStmt(hstmt, SQL_CLOSE);
2beca662 2137
8a39593e 2138 retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
5600884a 2139 if (retcode == SQL_SUCCESS ||
2beca662
GT
2140 (Dbms() == dbmsDB2 && (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_NO_DATA_FOUND)))
2141 {
68379eaf 2142 return true;
2beca662 2143 }
1e92909e
GT
2144 else
2145 {
2146 DispAllErrors(henv, hdbc, hstmt);
68379eaf 2147 return false;
1e92909e 2148 }
108106cf 2149
f6bcfd97 2150} // wxDb::ExecSql()
108106cf 2151
67e9aaa3 2152
f6bcfd97
BP
2153/********** wxDb::GetNext() **********/
2154bool wxDb::GetNext(void)
a2115c88 2155{
1e92909e 2156 if (SQLFetch(hstmt) == SQL_SUCCESS)
68379eaf 2157 return true;
1e92909e
GT
2158 else
2159 {
2160 DispAllErrors(henv, hdbc, hstmt);
68379eaf 2161 return false;
1e92909e 2162 }
a2115c88 2163
f6bcfd97 2164} // wxDb::GetNext()
a2115c88 2165
67e9aaa3 2166
f6bcfd97
BP
2167/********** wxDb::GetData() **********/
2168bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SDWORD FAR *cbReturned)
a2115c88 2169{
4fdae997
GT
2170 wxASSERT(pData);
2171 wxASSERT(cbReturned);
a2115c88 2172
1e92909e 2173 if (SQLGetData(hstmt, colNo, cType, pData, maxLen, cbReturned) == SQL_SUCCESS)
68379eaf 2174 return true;
1e92909e
GT
2175 else
2176 {
2177 DispAllErrors(henv, hdbc, hstmt);
68379eaf 2178 return false;
1e92909e 2179 }
a2115c88 2180
f6bcfd97 2181} // wxDb::GetData()
a2115c88 2182
67e9aaa3 2183
f6bcfd97 2184/********** wxDb::GetKeyFields() **********/
02cf6fdd 2185int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCols)
67e9aaa3 2186{
4fdae997
GT
2187 wxChar szPkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Primary key table name */
2188 wxChar szFkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Foreign key table name */
564c92d9 2189 SWORD iKeySeq;
67e9aaa3 2190// SQLSMALLINT iKeySeq;
4fdae997
GT
2191 wxChar szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */
2192 wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */
67e9aaa3
GT
2193 SQLRETURN retcode;
2194 SDWORD cb;
02cf6fdd 2195 SWORD i;
4fdae997 2196 wxString tempStr;
67e9aaa3 2197 /*
4fdae997
GT
2198 * -----------------------------------------------------------------------
2199 * -- 19991224 : mj10777 : Create ------
2200 * -- : Three things are done and stored here : ------
2201 * -- : 1) which Column(s) is/are Primary Key(s) ------
2202 * -- : 2) which tables use this Key as a Foreign Key ------
2203 * -- : 3) which columns are Foreign Key and the name ------
2204 * -- : of the Table where the Key is the Primary Key -----
2205 * -- : Called from GetColumns(const wxString &tableName, ------
2206 * -- int *numCols,const wxChar *userID ) ------
2207 * -----------------------------------------------------------------------
67e9aaa3
GT
2208 */
2209
2210 /*---------------------------------------------------------------------*/
2211 /* Get the names of the columns in the primary key. */
2212 /*---------------------------------------------------------------------*/
2213 retcode = SQLPrimaryKeys(hstmt,
4fdae997
GT
2214 NULL, 0, /* Catalog name */
2215 NULL, 0, /* Schema name */
8a39593e 2216 (SQLTCHAR FAR *) tableName.c_str(), SQL_NTS); /* Table name */
67e9aaa3
GT
2217
2218 /*---------------------------------------------------------------------*/
2219 /* Fetch and display the result set. This will be a list of the */
2220 /* columns in the primary key of the tableName table. */
2221 /*---------------------------------------------------------------------*/
2222 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
2223 {
2224 retcode = SQLFetch(hstmt);
2225 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
2226 {
2227 GetData( 4, SQL_C_CHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2228 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
2229 //-------
2230 for (i=0;i<noCols;i++) // Find the Column name
2231 if (!wxStrcmp(colInf[i].colName,szPkCol)) // We have found the Column
2232 colInf[i].PkCol = iKeySeq; // Which Primary Key is this (first, second usw.) ?
3ca6a5f0
BP
2233 } // if
2234 } // while
67e9aaa3
GT
2235 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
2236
2237 /*---------------------------------------------------------------------*/
2238 /* Get all the foreign keys that refer to tableName primary key. */
2239 /*---------------------------------------------------------------------*/
2240 retcode = SQLForeignKeys(hstmt,
4fdae997
GT
2241 NULL, 0, /* Primary catalog */
2242 NULL, 0, /* Primary schema */
8a39593e 2243 (SQLTCHAR FAR *)tableName.c_str(), SQL_NTS,/* Primary table */
4fdae997
GT
2244 NULL, 0, /* Foreign catalog */
2245 NULL, 0, /* Foreign schema */
2246 NULL, 0); /* Foreign table */
67e9aaa3
GT
2247
2248 /*---------------------------------------------------------------------*/
2249 /* Fetch and display the result set. This will be all of the foreign */
2250 /* keys in other tables that refer to the tableName primary key. */
2251 /*---------------------------------------------------------------------*/
4fdae997 2252 tempStr.Empty();
67e9aaa3
GT
2253 szPkCol[0] = 0;
2254 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
2255 {
2256 retcode = SQLFetch(hstmt);
2257 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
2258 {
2259 GetData( 3, SQL_C_CHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
2260 GetData( 4, SQL_C_CHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2261 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
2262 GetData( 7, SQL_C_CHAR, szFkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
2263 GetData( 8, SQL_C_CHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
4fdae997 2264 tempStr.Printf(wxT("%s[%s] "),tempStr.c_str(),szFkTable); // [ ] in case there is a blank in the Table name
3ca6a5f0
BP
2265 } // if
2266 } // while
4fdae997
GT
2267
2268 tempStr.Trim(); // Get rid of any unneeded blanks
2269 if (!tempStr.IsEmpty())
67e9aaa3 2270 {
4fdae997 2271 for (i=0; i<noCols; i++)
3ca6a5f0 2272 { // Find the Column name
4fdae997
GT
2273 if (!wxStrcmp(colInf[i].colName, szPkCol)) // We have found the Column, store the Information
2274 wxStrcpy(colInf[i].PkTableName, tempStr.c_str()); // Name of the Tables where this Primary Key is used as a Foreign Key
3ca6a5f0
BP
2275 }
2276 } // if
4fdae997 2277
67e9aaa3
GT
2278 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
2279
2280 /*---------------------------------------------------------------------*/
2281 /* Get all the foreign keys in the tablename table. */
2282 /*---------------------------------------------------------------------*/
2283 retcode = SQLForeignKeys(hstmt,
4fdae997
GT
2284 NULL, 0, /* Primary catalog */
2285 NULL, 0, /* Primary schema */
2286 NULL, 0, /* Primary table */
2287 NULL, 0, /* Foreign catalog */
2288 NULL, 0, /* Foreign schema */
8a39593e 2289 (SQLTCHAR *)tableName.c_str(), SQL_NTS);/* Foreign table */
67e9aaa3
GT
2290
2291 /*---------------------------------------------------------------------*/
2292 /* Fetch and display the result set. This will be all of the */
2293 /* primary keys in other tables that are referred to by foreign */
2294 /* keys in the tableName table. */
2295 /*---------------------------------------------------------------------*/
67e9aaa3
GT
2296 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
2297 {
2298 retcode = SQLFetch(hstmt);
2299 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
2300 {
2301 GetData( 3, SQL_C_CHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
2302 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
2303 GetData( 8, SQL_C_CHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2304 //-------
4fdae997 2305 for (i=0; i<noCols; i++) // Find the Column name
67e9aaa3
GT
2306 {
2307 if (!wxStrcmp(colInf[i].colName,szFkCol)) // We have found the (Foreign Key) Column
2308 {
2309 colInf[i].FkCol = iKeySeq; // Which Foreign Key is this (first, second usw.) ?
3ca6a5f0
BP
2310 wxStrcpy(colInf[i].FkTableName,szPkTable); // Name of the Table where this Foriegn is the Primary Key
2311 } // if
2312 } // for
2313 } // if
2314 } // while
67e9aaa3
GT
2315 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
2316
a144affe 2317 return TRUE;
3ca6a5f0 2318
f6bcfd97 2319} // wxDb::GetKeyFields()
67e9aaa3
GT
2320
2321
f6bcfd97
BP
2322#if OLD_GETCOLUMNS
2323/********** wxDb::GetColumns() **********/
4fdae997 2324wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
108106cf 2325/*
1e92909e
GT
2326 * 1) The last array element of the tableName[] argument must be zero (null).
2327 * This is how the end of the array is detected.
f6bcfd97 2328 * 2) This function returns an array of wxDbColInf structures. If no columns
1e92909e
GT
2329 * were found, or an error occured, this pointer will be zero (null). THE
2330 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
2331 * IS FINISHED WITH IT. i.e.
108106cf 2332 *
f6bcfd97 2333 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
1e92909e
GT
2334 * if (colInf)
2335 * {
2336 * // Use the column inf
2337 * .......
2338 * // Destroy the memory
2339 * delete [] colInf;
2340 * }
67e9aaa3
GT
2341 *
2342 * userID is evaluated in the following manner:
1e92909e
GT
2343 * userID == NULL ... UserID is ignored
2344 * userID == "" ... UserID set equal to 'this->uid'
2345 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 2346 *
f6bcfd97
BP
2347 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2348 * by this function. This function should use its own wxDb instance
ea5d599d 2349 * to avoid undesired unbinding of columns.
108106cf 2350 */
108106cf 2351{
081eb1b1 2352 UWORD noCols = 0;
2c257434 2353 UWORD colNo = 0;
f6bcfd97 2354 wxDbColInf *colInf = 0;
1e92909e
GT
2355
2356 RETCODE retcode;
2357 SDWORD cb;
2358
1e92909e
GT
2359 wxString TableName;
2360
4fdae997
GT
2361 wxString UserID;
2362 convertUserID(userID,UserID);
1e92909e
GT
2363
2364 // Pass 1 - Determine how many columns there are.
f6bcfd97 2365 // Pass 2 - Allocate the wxDbColInf array and fill in
1e92909e
GT
2366 // the array with the column information.
2367 int pass;
2368 for (pass = 1; pass <= 2; pass++)
2369 {
2370 if (pass == 2)
2371 {
2372 if (noCols == 0) // Probably a bogus table name(s)
2373 break;
f6bcfd97
BP
2374 // Allocate n wxDbColInf objects to hold the column information
2375 colInf = new wxDbColInf[noCols+1];
1e92909e
GT
2376 if (!colInf)
2377 break;
2378 // Mark the end of the array
da99271d
GT
2379 wxStrcpy(colInf[noCols].tableName,wxEmptyString);
2380 wxStrcpy(colInf[noCols].colName,wxEmptyString);
1e92909e
GT
2381 colInf[noCols].sqlDataType = 0;
2382 }
2383 // Loop through each table name
2384 int tbl;
2385 for (tbl = 0; tableName[tbl]; tbl++)
2386 {
2387 TableName = tableName[tbl];
d8a0a1c9 2388 // Oracle and Interbase table names are uppercase only, so force
1e92909e 2389 // the name to uppercase just in case programmer forgot to do this
eedb1543 2390 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 2391 (Dbms() == dbmsINTERBASE))
1e92909e
GT
2392 TableName = TableName.Upper();
2393
2394 SQLFreeStmt(hstmt, SQL_CLOSE);
2395
a8aa2258 2396 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
1e92909e 2397 // use the call below that leaves out the user name
4fdae997
GT
2398 if (!UserID.IsEmpty() &&
2399 Dbms() != dbmsMY_SQL &&
2400 Dbms() != dbmsACCESS &&
2401 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
2402 {
2403 retcode = SQLColumns(hstmt,
2404 NULL, 0, // All qualifiers
8a39593e
JS
2405 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner
2406 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2407 NULL, 0); // All columns
2408 }
2409 else
2410 {
2411 retcode = SQLColumns(hstmt,
2412 NULL, 0, // All qualifiers
2413 NULL, 0, // Owner
8a39593e 2414 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2415 NULL, 0); // All columns
2416 }
2417 if (retcode != SQL_SUCCESS)
2418 { // Error occured, abort
2419 DispAllErrors(henv, hdbc, hstmt);
2420 if (colInf)
2421 delete [] colInf;
2422 SQLFreeStmt(hstmt, SQL_CLOSE);
2423 return(0);
2424 }
2425
2426 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2427 {
2428 if (pass == 1) // First pass, just add up the number of columns
2429 noCols++;
2430 else // Pass 2; Fill in the array of structures
2431 {
2432 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2433 {
2434 // NOTE: Only the ODBC 1.x fields are retrieved
2435 GetData( 1, SQL_C_CHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2436 GetData( 2, SQL_C_CHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2437 GetData( 3, SQL_C_CHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2438 GetData( 4, SQL_C_CHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2439 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
2440 GetData( 6, SQL_C_CHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
2441 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnSize, 0, &cb);
2442 GetData( 8, SQL_C_SLONG, (UCHAR*) &colInf[colNo].bufferLength, 0, &cb);
2443 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2444 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2445 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
52a17fe5 2446 GetData(12, SQL_C_CHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
eedb1543 2447
f6bcfd97 2448 // Determine the wxDb data type that is used to represent the native data type of this data source
1e92909e
GT
2449 colInf[colNo].dbDataType = 0;
2450 if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
52a17fe5 2451 {
eedb1543 2452#ifdef _IODBC_
a8aa2258
GT
2453 // IODBC does not return a correct columnSize, so we set
2454 // columnSize = bufferLength if no column size was returned
2455 // IODBC returns the columnSize in bufferLength.. (bug)
52a17fe5
GT
2456 if (colInf[colNo].columnSize < 1)
2457 {
52a17fe5
GT
2458 colInf[colNo].columnSize = colInf[colNo].bufferLength;
2459 }
a8aa2258 2460#endif
1e92909e 2461 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
52a17fe5 2462 }
bf5423ea 2463 else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName))
1e92909e 2464 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
bf5423ea 2465 else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName))
1e92909e 2466 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
bf5423ea 2467 else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName))
1e92909e 2468 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
bf5423ea
GT
2469 else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName))
2470 colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
1e92909e
GT
2471 colNo++;
2472 }
2473 }
2474 }
2475 if (retcode != SQL_NO_DATA_FOUND)
2476 { // Error occured, abort
2477 DispAllErrors(henv, hdbc, hstmt);
2478 if (colInf)
2479 delete [] colInf;
2480 SQLFreeStmt(hstmt, SQL_CLOSE);
2481 return(0);
2482 }
2483 }
2484 }
2485
2486 SQLFreeStmt(hstmt, SQL_CLOSE);
2487 return colInf;
108106cf 2488
f6bcfd97 2489} // wxDb::GetColumns()
108106cf
JS
2490
2491
f6bcfd97
BP
2492/********** wxDb::GetColumns() **********/
2493
02cf6fdd 2494wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wxChar *userID)
f6bcfd97
BP
2495//
2496// Same as the above GetColumns() function except this one gets columns
2497// only for a single table, and if 'numCols' is not NULL, the number of
2498// columns stored in the returned wxDbColInf is set in '*numCols'
2499//
2500// userID is evaluated in the following manner:
2501// userID == NULL ... UserID is ignored
2502// userID == "" ... UserID set equal to 'this->uid'
2503// userID != "" ... UserID set equal to 'userID'
2504//
2505// NOTE: ALL column bindings associated with this wxDb instance are unbound
2506// by this function. This function should use its own wxDb instance
2507// to avoid undesired unbinding of columns.
2508
67e9aaa3 2509{
02cf6fdd 2510 UWORD noCols = 0;
e938ff5e 2511 UWORD colNo = 0;
f6bcfd97 2512 wxDbColInf *colInf = 0;
1e92909e
GT
2513
2514 RETCODE retcode;
2515 SDWORD cb;
2516
1e92909e
GT
2517 wxString TableName;
2518
4fdae997
GT
2519 wxString UserID;
2520 convertUserID(userID,UserID);
1e92909e
GT
2521
2522 // Pass 1 - Determine how many columns there are.
f6bcfd97 2523 // Pass 2 - Allocate the wxDbColInf array and fill in
1e92909e
GT
2524 // the array with the column information.
2525 int pass;
2526 for (pass = 1; pass <= 2; pass++)
2527 {
2528 if (pass == 2)
2529 {
2530 if (noCols == 0) // Probably a bogus table name(s)
2531 break;
f6bcfd97
BP
2532 // Allocate n wxDbColInf objects to hold the column information
2533 colInf = new wxDbColInf[noCols+1];
1e92909e
GT
2534 if (!colInf)
2535 break;
2536 // Mark the end of the array
da99271d
GT
2537 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
2538 wxStrcpy(colInf[noCols].colName, wxEmptyString);
4fdae997 2539 colInf[noCols].sqlDataType = 0;
1e92909e
GT
2540 }
2541
2542 TableName = tableName;
d8a0a1c9 2543 // Oracle and Interbase table names are uppercase only, so force
1e92909e 2544 // the name to uppercase just in case programmer forgot to do this
eedb1543 2545 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 2546 (Dbms() == dbmsINTERBASE))
1e92909e
GT
2547 TableName = TableName.Upper();
2548
2549 SQLFreeStmt(hstmt, SQL_CLOSE);
2550
a8aa2258 2551 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
1e92909e 2552 // use the call below that leaves out the user name
4fdae997
GT
2553 if (!UserID.IsEmpty() &&
2554 Dbms() != dbmsMY_SQL &&
2555 Dbms() != dbmsACCESS &&
2556 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
2557 {
2558 retcode = SQLColumns(hstmt,
2559 NULL, 0, // All qualifiers
8a39593e
JS
2560 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner
2561 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2562 NULL, 0); // All columns
2563 }
2564 else
2565 {
2566 retcode = SQLColumns(hstmt,
2567 NULL, 0, // All qualifiers
2568 NULL, 0, // Owner
8a39593e 2569 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2570 NULL, 0); // All columns
2571 }
2572 if (retcode != SQL_SUCCESS)
2573 { // Error occured, abort
2574 DispAllErrors(henv, hdbc, hstmt);
2575 if (colInf)
2576 delete [] colInf;
2577 SQLFreeStmt(hstmt, SQL_CLOSE);
2578 if (numCols)
2579 *numCols = 0;
2580 return(0);
2581 }
2582
2583 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2584 {
2585 if (pass == 1) // First pass, just add up the number of columns
2586 noCols++;
2587 else // Pass 2; Fill in the array of structures
2588 {
2589 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2590 {
2591 // NOTE: Only the ODBC 1.x fields are retrieved
2592 GetData( 1, SQL_C_CHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2593 GetData( 2, SQL_C_CHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2594 GetData( 3, SQL_C_CHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2595 GetData( 4, SQL_C_CHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2596 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
2597 GetData( 6, SQL_C_CHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
2598 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnSize, 0, &cb);
67e9aaa3 2599 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
23f681ec 2600 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferLength, 0, &cb);
1e92909e
GT
2601 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2602 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2603 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
2604 GetData(12, SQL_C_CHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
67e9aaa3
GT
2605 // Start Values for Primary/Foriegn Key (=No)
2606 colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2607 colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2608 colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2609 colInf[colNo].FkTableName[0] = 0; // Foreign key table name
2610
3ca6a5f0
BP
2611 // BJO 20000428 : Virtuoso returns type names with upper cases!
2612 if (Dbms() == dbmsVIRTUOSO)
2613 {
4fdae997 2614 wxString s = colInf[colNo].typeName;
3ca6a5f0 2615 s = s.MakeLower();
eedb1543 2616 wxStrcmp(colInf[colNo].typeName, s.c_str());
3ca6a5f0 2617 }
eedb1543 2618
3ca6a5f0
BP
2619 // Determine the wxDb data type that is used to represent the native data type of this data source
2620 colInf[colNo].dbDataType = 0;
bf5423ea 2621 if (!wxStricmp(typeInfVarchar.TypeName, colInf[colNo].typeName))
3ca6a5f0 2622 {
eedb1543 2623#ifdef _IODBC_
a8aa2258
GT
2624 // IODBC does not return a correct columnSize, so we set
2625 // columnSize = bufferLength if no column size was returned
2626 // IODBC returns the columnSize in bufferLength.. (bug)
3ca6a5f0
BP
2627 if (colInf[colNo].columnSize < 1)
2628 {
a8aa2258 2629 colInf[colNo].columnSize = colInf[colNo].bufferLength;
3ca6a5f0 2630 }
a8aa2258
GT
2631#endif
2632
3ca6a5f0
BP
2633 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
2634 }
bf5423ea 2635 else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName))
3ca6a5f0 2636 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
bf5423ea 2637 else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName))
3ca6a5f0 2638 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
bf5423ea 2639 else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName))
eedb1543 2640 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
bf5423ea
GT
2641 else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName))
2642 colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
eedb1543 2643
1e92909e
GT
2644 colNo++;
2645 }
2646 }
2647 }
2648 if (retcode != SQL_NO_DATA_FOUND)
3ca6a5f0 2649 { // Error occured, abort
1e92909e
GT
2650 DispAllErrors(henv, hdbc, hstmt);
2651 if (colInf)
3ca6a5f0 2652 delete [] colInf;
1e92909e
GT
2653 SQLFreeStmt(hstmt, SQL_CLOSE);
2654 if (numCols)
3ca6a5f0 2655 *numCols = 0;
1e92909e 2656 return(0);
3ca6a5f0 2657 }
1e92909e 2658 }
67e9aaa3
GT
2659
2660 SQLFreeStmt(hstmt, SQL_CLOSE);
2661
2662 // Store Primary and Foriegn Keys
2663 GetKeyFields(tableName,colInf,noCols);
2664
2665 if (numCols)
1e92909e
GT
2666 *numCols = noCols;
2667 return colInf;
67e9aaa3 2668
f6bcfd97
BP
2669} // wxDb::GetColumns()
2670
f6bcfd97 2671
3ca6a5f0 2672#else // New GetColumns
67e9aaa3
GT
2673
2674
f6bcfd97 2675/*
3ca6a5f0
BP
2676 BJO 20000503
2677 These are tentative new GetColumns members which should be more database
eedb1543 2678 independant and which always returns the columns in the order they were
3ca6a5f0
BP
2679 created.
2680
4fdae997
GT
2681 - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const
2682 wxChar* userID)) calls the second implementation for each separate table
eedb1543 2683 before merging the results. This makes the code easier to maintain as
3ca6a5f0 2684 only one member (the second) makes the real work
4fdae997
GT
2685 - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const
2686 wxChar *userID) is a little bit improved
eedb1543 2687 - It doesn't anymore rely on the type-name to find out which database-type
3ca6a5f0 2688 each column has
eedb1543 2689 - It ends by sorting the columns, so that they are returned in the same
3ca6a5f0 2690 order they were created
f6bcfd97
BP
2691*/
2692
2693typedef struct
2694{
02cf6fdd 2695 UWORD noCols;
3ca6a5f0 2696 wxDbColInf *colInf;
f6bcfd97
BP
2697} _TableColumns;
2698
3ca6a5f0 2699
4fdae997 2700wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
f6bcfd97 2701{
3ca6a5f0
BP
2702 int i, j;
2703 // The last array element of the tableName[] argument must be zero (null).
2704 // This is how the end of the array is detected.
2705
02cf6fdd 2706 UWORD noCols = 0;
3ca6a5f0
BP
2707
2708 // How many tables ?
2709 int tbl;
eedb1543
DW
2710 for (tbl = 0 ; tableName[tbl]; tbl++);
2711
3ca6a5f0
BP
2712 // Create a table to maintain the columns for each separate table
2713 _TableColumns *TableColumns = new _TableColumns[tbl];
eedb1543 2714
3ca6a5f0
BP
2715 // Fill the table
2716 for (i = 0 ; i < tbl ; i++)
eedb1543 2717
3ca6a5f0
BP
2718 {
2719 TableColumns[i].colInf = GetColumns(tableName[i], &TableColumns[i].noCols, userID);
eedb1543 2720 if (TableColumns[i].colInf == NULL)
3ca6a5f0
BP
2721 return NULL;
2722 noCols += TableColumns[i].noCols;
2723 }
eedb1543 2724
3ca6a5f0
BP
2725 // Now merge all the separate table infos
2726 wxDbColInf *colInf = new wxDbColInf[noCols+1];
eedb1543 2727
3ca6a5f0 2728 // Mark the end of the array
da99271d
GT
2729 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
2730 wxStrcpy(colInf[noCols].colName, wxEmptyString);
4fdae997 2731 colInf[noCols].sqlDataType = 0;
eedb1543 2732
3ca6a5f0
BP
2733 // Merge ...
2734 int offset = 0;
eedb1543 2735
3ca6a5f0
BP
2736 for (i = 0 ; i < tbl ; i++)
2737 {
2738 for (j = 0 ; j < TableColumns[i].noCols ; j++)
2739 {
eedb1543 2740 colInf[offset++] = TableColumns[i].colInf[j];
3ca6a5f0
BP
2741 }
2742 }
eedb1543 2743
3ca6a5f0 2744 delete [] TableColumns;
eedb1543 2745
3ca6a5f0
BP
2746 return colInf;
2747} // wxDb::GetColumns() -- NEW
f6bcfd97
BP
2748
2749
4fdae997 2750wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxChar *userID)
3ca6a5f0
BP
2751//
2752// Same as the above GetColumns() function except this one gets columns
2753// only for a single table, and if 'numCols' is not NULL, the number of
2754// columns stored in the returned wxDbColInf is set in '*numCols'
2755//
2756// userID is evaluated in the following manner:
2757// userID == NULL ... UserID is ignored
2758// userID == "" ... UserID set equal to 'this->uid'
2759// userID != "" ... UserID set equal to 'userID'
2760//
2761// NOTE: ALL column bindings associated with this wxDb instance are unbound
2762// by this function. This function should use its own wxDb instance
2763// to avoid undesired unbinding of columns.
f6bcfd97 2764{
02cf6fdd 2765 UWORD noCols = 0;
e938ff5e 2766 UWORD colNo = 0;
3ca6a5f0 2767 wxDbColInf *colInf = 0;
eedb1543 2768
3ca6a5f0
BP
2769 RETCODE retcode;
2770 SDWORD cb;
eedb1543 2771
3ca6a5f0 2772 wxString TableName;
eedb1543 2773
4fdae997
GT
2774 wxString UserID;
2775 convertUserID(userID,UserID);
eedb1543 2776
3ca6a5f0
BP
2777 // Pass 1 - Determine how many columns there are.
2778 // Pass 2 - Allocate the wxDbColInf array and fill in
2779 // the array with the column information.
2780 int pass;
2781 for (pass = 1; pass <= 2; pass++)
2782 {
2783 if (pass == 2)
f6bcfd97 2784 {
3ca6a5f0
BP
2785 if (noCols == 0) // Probably a bogus table name(s)
2786 break;
2787 // Allocate n wxDbColInf objects to hold the column information
2788 colInf = new wxDbColInf[noCols+1];
2789 if (!colInf)
2790 break;
2791 // Mark the end of the array
da99271d
GT
2792 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
2793 wxStrcpy(colInf[noCols].colName, wxEmptyString);
3ca6a5f0 2794 colInf[noCols].sqlDataType = 0;
f6bcfd97 2795 }
eedb1543 2796
3ca6a5f0 2797 TableName = tableName;
d8a0a1c9 2798 // Oracle and Interbase table names are uppercase only, so force
3ca6a5f0 2799 // the name to uppercase just in case programmer forgot to do this
eedb1543 2800 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 2801 (Dbms() == dbmsINTERBASE))
3ca6a5f0 2802 TableName = TableName.Upper();
eedb1543 2803
3ca6a5f0 2804 SQLFreeStmt(hstmt, SQL_CLOSE);
eedb1543 2805
a8aa2258 2806 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
3ca6a5f0 2807 // use the call below that leaves out the user name
4fdae997 2808 if (!UserID.IsEmpty() &&
3ca6a5f0 2809 Dbms() != dbmsMY_SQL &&
a8aa2258
GT
2810 Dbms() != dbmsACCESS &&
2811 Dbms() != dbmsMS_SQL_SERVER)
f6bcfd97 2812 {
3ca6a5f0
BP
2813 retcode = SQLColumns(hstmt,
2814 NULL, 0, // All qualifiers
2815 (UCHAR *) UserID.c_str(), SQL_NTS, // Owner
2816 (UCHAR *) TableName.c_str(), SQL_NTS,
2817 NULL, 0); // All columns
f6bcfd97 2818 }
3ca6a5f0 2819 else
f6bcfd97 2820 {
3ca6a5f0
BP
2821 retcode = SQLColumns(hstmt,
2822 NULL, 0, // All qualifiers
2823 NULL, 0, // Owner
2824 (UCHAR *) TableName.c_str(), SQL_NTS,
2825 NULL, 0); // All columns
f6bcfd97 2826 }
3ca6a5f0 2827 if (retcode != SQL_SUCCESS)
f6bcfd97 2828 { // Error occured, abort
3ca6a5f0
BP
2829 DispAllErrors(henv, hdbc, hstmt);
2830 if (colInf)
2831 delete [] colInf;
2832 SQLFreeStmt(hstmt, SQL_CLOSE);
2833 if (numCols)
2834 *numCols = 0;
2835 return(0);
f6bcfd97 2836 }
eedb1543 2837
f6bcfd97
BP
2838 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2839 {
2840 if (pass == 1) // First pass, just add up the number of columns
2841 noCols++;
2842 else // Pass 2; Fill in the array of structures
2843 {
2844 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2845 {
2846 // NOTE: Only the ODBC 1.x fields are retrieved
2847 GetData( 1, SQL_C_CHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2848 GetData( 2, SQL_C_CHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2849 GetData( 3, SQL_C_CHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2850 GetData( 4, SQL_C_CHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2851 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
2852 GetData( 6, SQL_C_CHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
eedb1543 2853 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnSize, 0, &cb);
f6bcfd97
BP
2854 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferLength, 0, &cb);
2855 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2856 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2857 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
2858 GetData(12, SQL_C_CHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
2859 // Start Values for Primary/Foriegn Key (=No)
2860 colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2861 colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2862 colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2863 colInf[colNo].FkTableName[0] = 0; // Foreign key table name
eedb1543
DW
2864
2865#ifdef _IODBC_
a8aa2258
GT
2866 // IODBC does not return a correct columnSize, so we set
2867 // columnSize = bufferLength if no column size was returned
3ca6a5f0 2868 // IODBC returns the columnSize in bufferLength.. (bug)
a8aa2258
GT
2869 if (colInf[colNo].columnSize < 1)
2870 {
2871 colInf[colNo].columnSize = colInf[colNo].bufferLength;
2872 }
f6bcfd97 2873#endif
eedb1543 2874
3ca6a5f0
BP
2875 // Determine the wxDb data type that is used to represent the native data type of this data source
2876 colInf[colNo].dbDataType = 0;
2877 // Get the intern datatype
2878 switch (colInf[colNo].sqlDataType)
2879 {
2880 case SQL_VARCHAR:
2881 case SQL_CHAR:
eedb1543 2882 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
3ca6a5f0 2883 break;
eedb1543 2884
3ca6a5f0
BP
2885 case SQL_TINYINT:
2886 case SQL_SMALLINT:
2887 case SQL_INTEGER:
eedb1543 2888 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
3ca6a5f0
BP
2889 break;
2890 case SQL_DOUBLE:
2891 case SQL_DECIMAL:
2892 case SQL_NUMERIC:
2893 case SQL_FLOAT:
2894 case SQL_REAL:
eedb1543 2895 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
3ca6a5f0
BP
2896 break;
2897 case SQL_DATE:
eedb1543 2898 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
3ca6a5f0 2899 break;
bf5423ea
GT
2900 case SQL_BINARY:
2901 colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
2902 break;
f6bcfd97 2903#ifdef __WXDEBUG__
3ca6a5f0
BP
2904 default:
2905 wxString errMsg;
77ffb593 2906 errMsg.Printf(wxT("SQL Data type %d currently not supported by wxWidgets"), colInf[colNo].sqlDataType);
3ca6a5f0 2907 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
eedb1543 2908#endif
3ca6a5f0 2909 }
f6bcfd97
BP
2910 colNo++;
2911 }
2912 }
2913 }
2914 if (retcode != SQL_NO_DATA_FOUND)
3ca6a5f0 2915 { // Error occured, abort
f6bcfd97
BP
2916 DispAllErrors(henv, hdbc, hstmt);
2917 if (colInf)
3ca6a5f0 2918 delete [] colInf;
f6bcfd97
BP
2919 SQLFreeStmt(hstmt, SQL_CLOSE);
2920 if (numCols)
3ca6a5f0 2921 *numCols = 0;
f6bcfd97 2922 return(0);
3ca6a5f0
BP
2923 }
2924 }
eedb1543 2925
3ca6a5f0 2926 SQLFreeStmt(hstmt, SQL_CLOSE);
eedb1543 2927
3ca6a5f0
BP
2928 // Store Primary and Foreign Keys
2929 GetKeyFields(tableName,colInf,noCols);
2930
2931 ///////////////////////////////////////////////////////////////////////////
2932 // Now sort the the columns in order to make them appear in the right order
2933 ///////////////////////////////////////////////////////////////////////////
eedb1543 2934
3ca6a5f0
BP
2935 // Build a generic SELECT statement which returns 0 rows
2936 wxString Stmt;
eedb1543 2937
243d4b36 2938 Stmt.Printf(wxT("select * from \"%s\" where 0=1"), tableName);
eedb1543
DW
2939
2940 // Execute query
3ca6a5f0
BP
2941 if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS)
2942 {
2943 DispAllErrors(henv, hdbc, hstmt);
2944 return NULL;
eedb1543
DW
2945 }
2946
3ca6a5f0
BP
2947 // Get the number of result columns
2948 if (SQLNumResultCols (hstmt, &noCols) != SQL_SUCCESS)
2949 {
2950 DispAllErrors(henv, hdbc, hstmt);
2951 return NULL;
2952 }
eedb1543 2953
3ca6a5f0
BP
2954 if (noCols == 0) // Probably a bogus table name
2955 return NULL;
eedb1543
DW
2956
2957 // Get the name
3ca6a5f0
BP
2958 int i;
2959 short colNum;
2960 UCHAR name[100];
2961 SWORD Sword;
2962 SDWORD Sdword;
2963 for (colNum = 0; colNum < noCols; colNum++)
eedb1543
DW
2964 {
2965 if (SQLColAttributes(hstmt,colNum+1, SQL_COLUMN_NAME,
2966 name, sizeof(name),
3ca6a5f0
BP
2967 &Sword, &Sdword) != SQL_SUCCESS)
2968 {
2969 DispAllErrors(henv, hdbc, hstmt);
2970 return NULL;
eedb1543
DW
2971 }
2972
3ca6a5f0
BP
2973 wxString Name1 = name;
2974 Name1 = Name1.Upper();
eedb1543 2975
3ca6a5f0
BP
2976 // Where is this name in the array ?
2977 for (i = colNum ; i < noCols ; i++)
2978 {
2979 wxString Name2 = colInf[i].colName;
2980 Name2 = Name2.Upper();
2981 if (Name2 == Name1)
2982 {
2983 if (colNum != i) // swap to sort
2984 {
2985 wxDbColInf tmpColInf = colInf[colNum];
2986 colInf[colNum] = colInf[i];
2987 colInf[i] = tmpColInf;
2988 }
2989 break;
eedb1543
DW
2990 }
2991 }
2992 }
3ca6a5f0 2993 SQLFreeStmt(hstmt, SQL_CLOSE);
f6bcfd97 2994
3ca6a5f0
BP
2995 ///////////////////////////////////////////////////////////////////////////
2996 // End sorting
2997 ///////////////////////////////////////////////////////////////////////////
f6bcfd97 2998
3ca6a5f0
BP
2999 if (numCols)
3000 *numCols = noCols;
3001 return colInf;
eedb1543 3002
f6bcfd97
BP
3003} // wxDb::GetColumns()
3004
3005
3ca6a5f0 3006#endif // #else OLD_GETCOLUMNS
f6bcfd97
BP
3007
3008
3009/********** wxDb::GetColumnCount() **********/
dba2120c 3010int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID)
67e9aaa3
GT
3011/*
3012 * Returns a count of how many columns are in a table.
3013 * If an error occurs in computing the number of columns
3014 * this function will return a -1 for the count
3015 *
3016 * userID is evaluated in the following manner:
1e92909e
GT
3017 * userID == NULL ... UserID is ignored
3018 * userID == "" ... UserID set equal to 'this->uid'
3019 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3020 *
f6bcfd97
BP
3021 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3022 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
3023 * to avoid undesired unbinding of columns.
3024 */
3025{
02cf6fdd 3026 UWORD noCols = 0;
1e92909e
GT
3027
3028 RETCODE retcode;
3029
1e92909e
GT
3030 wxString TableName;
3031
4fdae997
GT
3032 wxString UserID;
3033 convertUserID(userID,UserID);
1e92909e 3034
4fdae997
GT
3035 TableName = tableName;
3036 // Oracle and Interbase table names are uppercase only, so force
3037 // the name to uppercase just in case programmer forgot to do this
3038 if ((Dbms() == dbmsORACLE) ||
3039 (Dbms() == dbmsINTERBASE))
3040 TableName = TableName.Upper();
1e92909e 3041
4fdae997 3042 SQLFreeStmt(hstmt, SQL_CLOSE);
1e92909e 3043
4fdae997
GT
3044 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
3045 // use the call below that leaves out the user name
3046 if (!UserID.IsEmpty() &&
3047 Dbms() != dbmsMY_SQL &&
3048 Dbms() != dbmsACCESS &&
3049 Dbms() != dbmsMS_SQL_SERVER)
1e92909e 3050 {
4fdae997
GT
3051 retcode = SQLColumns(hstmt,
3052 NULL, 0, // All qualifiers
8a39593e
JS
3053 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner
3054 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
4fdae997
GT
3055 NULL, 0); // All columns
3056 }
3057 else
3058 {
3059 retcode = SQLColumns(hstmt,
3060 NULL, 0, // All qualifiers
3061 NULL, 0, // Owner
8a39593e 3062 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
4fdae997
GT
3063 NULL, 0); // All columns
3064 }
3065 if (retcode != SQL_SUCCESS)
3066 { // Error occured, abort
3067 DispAllErrors(henv, hdbc, hstmt);
3068 SQLFreeStmt(hstmt, SQL_CLOSE);
3069 return(-1);
3070 }
1e92909e 3071
4fdae997
GT
3072 // Count the columns
3073 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
3074 noCols++;
1e92909e 3075
4fdae997
GT
3076 if (retcode != SQL_NO_DATA_FOUND)
3077 { // Error occured, abort
3078 DispAllErrors(henv, hdbc, hstmt);
3079 SQLFreeStmt(hstmt, SQL_CLOSE);
3080 return(-1);
1e92909e
GT
3081 }
3082
3083 SQLFreeStmt(hstmt, SQL_CLOSE);
3084 return noCols;
67e9aaa3 3085
f6bcfd97 3086} // wxDb::GetColumnCount()
67e9aaa3
GT
3087
3088
f6bcfd97 3089/********** wxDb::GetCatalog() *******/
4fdae997 3090wxDbInf *wxDb::GetCatalog(const wxChar *userID)
67e9aaa3
GT
3091/*
3092 * ---------------------------------------------------------------------
0cd121f9 3093 * -- 19991203 : mj10777 : Create ------
67e9aaa3
GT
3094 * -- : Creates a wxDbInf with Tables / Cols Array ------
3095 * -- : uses SQLTables and fills pTableInf; ------
3096 * -- : pColInf is set to NULL and numCols to 0; ------
3097 * -- : returns pDbInf (wxDbInf) ------
3098 * -- - if unsuccesfull (pDbInf == NULL) ------
3099 * -- : pColInf can be filled with GetColumns(..); ------
3100 * -- : numCols can be filled with GetColumnCount(..); ------
3101 * ---------------------------------------------------------------------
3102 *
3103 * userID is evaluated in the following manner:
1e92909e
GT
3104 * userID == NULL ... UserID is ignored
3105 * userID == "" ... UserID set equal to 'this->uid'
3106 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3107 *
f6bcfd97
BP
3108 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3109 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
3110 * to avoid undesired unbinding of columns.
3111 */
3112{
1e92909e
GT
3113 int noTab = 0; // Counter while filling table entries
3114 int pass;
3115 RETCODE retcode;
3116 SDWORD cb;
1e92909e
GT
3117 wxString tblNameSave;
3118
3119 wxString UserID;
4fdae997 3120 convertUserID(userID,UserID);
1e92909e
GT
3121
3122 //-------------------------------------------------------------
caf412d6
DS
3123 // Create the Database Array of catalog entries
3124
3125 wxDbInf *pDbInf = new wxDbInf;
3126
1e92909e
GT
3127 //-------------------------------------------------------------
3128 // Table Information
3129 // Pass 1 - Determine how many Tables there are.
3130 // Pass 2 - Create the Table array and fill it
3131 // - Create the Cols array = NULL
3132 //-------------------------------------------------------------
f6bcfd97 3133
1e92909e
GT
3134 for (pass = 1; pass <= 2; pass++)
3135 {
3136 SQLFreeStmt(hstmt, SQL_CLOSE); // Close if Open
4fdae997 3137 tblNameSave.Empty();
1e92909e 3138
4fdae997 3139 if (!UserID.IsEmpty() &&
3ca6a5f0 3140 Dbms() != dbmsMY_SQL &&
4fdae997
GT
3141 Dbms() != dbmsACCESS &&
3142 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
3143 {
3144 retcode = SQLTables(hstmt,
3145 NULL, 0, // All qualifiers
8a39593e 3146 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified
1e92909e
GT
3147 NULL, 0, // All tables
3148 NULL, 0); // All columns
3149 }
3150 else
3151 {
3152 retcode = SQLTables(hstmt,
3153 NULL, 0, // All qualifiers
3154 NULL, 0, // User specified
3155 NULL, 0, // All tables
3156 NULL, 0); // All columns
3157 }
f6bcfd97 3158
1e92909e
GT
3159 if (retcode != SQL_SUCCESS)
3160 {
3161 DispAllErrors(henv, hdbc, hstmt);
3162 pDbInf = NULL;
3163 SQLFreeStmt(hstmt, SQL_CLOSE);
3164 return pDbInf;
3165 }
eedb1543 3166
1e92909e
GT
3167 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) // Table Information
3168 {
3169 if (pass == 1) // First pass, just count the Tables
3170 {
3171 if (pDbInf->numTables == 0)
3172 {
3173 GetData( 1, SQL_C_CHAR, (UCHAR*) pDbInf->catalog, 128+1, &cb);
3174 GetData( 2, SQL_C_CHAR, (UCHAR*) pDbInf->schema, 128+1, &cb);
3175 }
3176 pDbInf->numTables++; // Counter for Tables
3177 } // if (pass == 1)
3178 if (pass == 2) // Create and fill the Table entries
3179 {
3180 if (pDbInf->pTableInf == NULL) // Has the Table Array been created
3181 { // no, then create the Array
f6bcfd97 3182 pDbInf->pTableInf = new wxDbTableInf[pDbInf->numTables];
1e92909e 3183 noTab = 0;
eedb1543 3184 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
f6bcfd97 3185
1e92909e
GT
3186 GetData( 3, SQL_C_CHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
3187 GetData( 4, SQL_C_CHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableType, 30+1, &cb);
3188 GetData( 5, SQL_C_CHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableRemarks, 254+1, &cb);
3ca6a5f0 3189
1e92909e 3190 noTab++;
3ca6a5f0
BP
3191 } // if
3192 } // while
3193 } // for
1e92909e
GT
3194 SQLFreeStmt(hstmt, SQL_CLOSE);
3195
3196 // Query how many columns are in each table
3197 for (noTab=0;noTab<pDbInf->numTables;noTab++)
3198 {
564c92d9 3199 (pDbInf->pTableInf+noTab)->numCols = (UWORD)GetColumnCount((pDbInf->pTableInf+noTab)->tableName,UserID);
1e92909e 3200 }
3ca6a5f0 3201
1e92909e 3202 return pDbInf;
3ca6a5f0 3203
f6bcfd97 3204} // wxDb::GetCatalog()
67e9aaa3
GT
3205
3206
f6bcfd97 3207/********** wxDb::Catalog() **********/
4fdae997 3208bool wxDb::Catalog(const wxChar *userID, const wxString &fileName)
67e9aaa3
GT
3209/*
3210 * Creates the text file specified in 'filename' which will contain
3211 * a minimal data dictionary of all tables accessible by the user specified
3212 * in 'userID'
3213 *
3214 * userID is evaluated in the following manner:
1e92909e
GT
3215 * userID == NULL ... UserID is ignored
3216 * userID == "" ... UserID set equal to 'this->uid'
3217 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3218 *
f6bcfd97
BP
3219 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3220 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
3221 * to avoid undesired unbinding of columns.
3222 */
1fc5dd6f 3223{
4fdae997 3224 wxASSERT(fileName.Length());
1e92909e
GT
3225
3226 RETCODE retcode;
3227 SDWORD cb;
4fdae997 3228 wxChar tblName[DB_MAX_TABLE_NAME_LEN+1];
1e92909e 3229 wxString tblNameSave;
4fdae997 3230 wxChar colName[DB_MAX_COLUMN_NAME_LEN+1];
1e92909e 3231 SWORD sqlDataType;
4fdae997 3232 wxChar typeName[30+1];
e262868d 3233 SDWORD precision, length;
1e92909e 3234
8a39593e 3235 FILE *fp = wxFopen(fileName.c_str(),wxT("wt"));
1e92909e 3236 if (fp == NULL)
68379eaf 3237 return false;
1e92909e
GT
3238
3239 SQLFreeStmt(hstmt, SQL_CLOSE);
3240
4fdae997
GT
3241 wxString UserID;
3242 convertUserID(userID,UserID);
1e92909e 3243
4fdae997
GT
3244 if (!UserID.IsEmpty() &&
3245 Dbms() != dbmsMY_SQL &&
3246 Dbms() != dbmsACCESS &&
081eb1b1 3247 Dbms() != dbmsINTERBASE &&
4fdae997 3248 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
3249 {
3250 retcode = SQLColumns(hstmt,
3251 NULL, 0, // All qualifiers
8a39593e 3252 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified
1e92909e
GT
3253 NULL, 0, // All tables
3254 NULL, 0); // All columns
3255 }
3256 else
3257 {
3258 retcode = SQLColumns(hstmt,
3259 NULL, 0, // All qualifiers
3260 NULL, 0, // User specified
3261 NULL, 0, // All tables
3262 NULL, 0); // All columns
3263 }
3264 if (retcode != SQL_SUCCESS)
3265 {
3266 DispAllErrors(henv, hdbc, hstmt);
3267 fclose(fp);
68379eaf 3268 return false;
1e92909e
GT
3269 }
3270
3271 wxString outStr;
4fdae997 3272 tblNameSave.Empty();
1e92909e
GT
3273 int cnt = 0;
3274
68379eaf 3275 while (true)
1e92909e 3276 {
e262868d
GT
3277 retcode = SQLFetch(hstmt);
3278 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
3279 break;
3280
b26e2b55
GT
3281 GetData(3,SQL_C_CHAR, (UCHAR *) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
3282 GetData(4,SQL_C_CHAR, (UCHAR *) colName, DB_MAX_COLUMN_NAME_LEN+1,&cb);
3283 GetData(5,SQL_C_SSHORT,(UCHAR *)&sqlDataType, 0, &cb);
3284 GetData(6,SQL_C_CHAR, (UCHAR *) typeName, sizeof(typeName), &cb);
3285 GetData(7,SQL_C_SLONG, (UCHAR *)&precision, 0, &cb);
3286 GetData(8,SQL_C_SLONG, (UCHAR *)&length, 0, &cb);
3287
4fdae997 3288 if (wxStrcmp(tblName, tblNameSave.c_str()))
1e92909e
GT
3289 {
3290 if (cnt)
8a39593e
JS
3291 wxFputs(wxT("\n"), fp);
3292 wxFputs(wxT("================================ "), fp);
3293 wxFputs(wxT("================================ "), fp);
3294 wxFputs(wxT("===================== "), fp);
3295 wxFputs(wxT("========= "), fp);
3296 wxFputs(wxT("=========\n"), fp);
4fdae997 3297 outStr.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
f6bcfd97 3298 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
8a39593e
JS
3299 wxFputs(outStr.c_str(), fp);
3300 wxFputs(wxT("================================ "), fp);
3301 wxFputs(wxT("================================ "), fp);
3302 wxFputs(wxT("===================== "), fp);
3303 wxFputs(wxT("========= "), fp);
3304 wxFputs(wxT("=========\n"), fp);
1e92909e
GT
3305 tblNameSave = tblName;
3306 }
67e9aaa3 3307
7fd4e7e1 3308 outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9ld %9ld\n"),
1e92909e 3309 tblName, colName, sqlDataType, typeName, precision, length);
8a39593e 3310 if (wxFputs(outStr.c_str(), fp) == EOF)
1e92909e
GT
3311 {
3312 SQLFreeStmt(hstmt, SQL_CLOSE);
3313 fclose(fp);
68379eaf 3314 return false;
1e92909e
GT
3315 }
3316 cnt++;
3317 }
1fc5dd6f 3318
1e92909e
GT
3319 if (retcode != SQL_NO_DATA_FOUND)
3320 DispAllErrors(henv, hdbc, hstmt);
1fc5dd6f 3321
1e92909e 3322 SQLFreeStmt(hstmt, SQL_CLOSE);
a2115c88 3323
1e92909e
GT
3324 fclose(fp);
3325 return(retcode == SQL_NO_DATA_FOUND);
1fc5dd6f 3326
f6bcfd97 3327} // wxDb::Catalog()
1fc5dd6f
JS
3328
3329
4fdae997 3330bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wxString &tablePath)
67e9aaa3 3331/*
68379eaf 3332 * Table name can refer to a table, view, alias or synonym. Returns true
67e9aaa3
GT
3333 * if the object exists in the database. This function does not indicate
3334 * whether or not the user has privleges to query or perform other functions
3335 * on the table.
3336 *
3337 * userID is evaluated in the following manner:
1e92909e
GT
3338 * userID == NULL ... UserID is ignored
3339 * userID == "" ... UserID set equal to 'this->uid'
3340 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3341 */
108106cf 3342{
4fdae997 3343 wxASSERT(tableName.Length());
eedb1543 3344
4fdae997 3345 wxString TableName;
eedb1543
DW
3346
3347 if (Dbms() == dbmsDBASE)
1e92909e 3348 {
3ca6a5f0 3349 wxString dbName;
4fdae997 3350 if (tablePath.Length())
942e67c3 3351 dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
3ca6a5f0 3352 else
942e67c3 3353 dbName.Printf(wxT("%s.dbf"), tableName.c_str());
eedb1543 3354
3ca6a5f0 3355 bool exists;
4fdae997 3356 exists = wxFileExists(dbName);
3ca6a5f0 3357 return exists;
1e92909e 3358 }
eedb1543 3359
4fdae997
GT
3360 wxString UserID;
3361 convertUserID(userID,UserID);
eedb1543 3362
1e92909e 3363 TableName = tableName;
d8a0a1c9 3364 // Oracle and Interbase table names are uppercase only, so force
1e92909e 3365 // the name to uppercase just in case programmer forgot to do this
eedb1543 3366 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 3367 (Dbms() == dbmsINTERBASE))
1e92909e 3368 TableName = TableName.Upper();
eedb1543 3369
1e92909e
GT
3370 SQLFreeStmt(hstmt, SQL_CLOSE);
3371 RETCODE retcode;
eedb1543 3372
a8aa2258
GT
3373 // Some databases cannot accept a user name when looking up table names,
3374 // so we use the call below that leaves out the user name
4fdae997 3375 if (!UserID.IsEmpty() &&
3ca6a5f0 3376 Dbms() != dbmsMY_SQL &&
a8aa2258 3377 Dbms() != dbmsACCESS &&
2beca662
GT
3378 Dbms() != dbmsMS_SQL_SERVER &&
3379 Dbms() != dbmsDB2 &&
081eb1b1 3380 Dbms() != dbmsINTERBASE &&
2beca662 3381 Dbms() != dbmsPERVASIVE_SQL)
1e92909e
GT
3382 {
3383 retcode = SQLTables(hstmt,
3ca6a5f0 3384 NULL, 0, // All qualifiers
8a39593e
JS
3385 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Only tables owned by this user
3386 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3387 NULL, 0); // All table types
1e92909e
GT
3388 }
3389 else
3390 {
3391 retcode = SQLTables(hstmt,
3ca6a5f0
BP
3392 NULL, 0, // All qualifiers
3393 NULL, 0, // All owners
8a39593e 3394 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3395 NULL, 0); // All table types
1e92909e
GT
3396 }
3397 if (retcode != SQL_SUCCESS)
3398 return(DispAllErrors(henv, hdbc, hstmt));
eedb1543 3399
1e92909e 3400 retcode = SQLFetch(hstmt);
a8aa2258 3401 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
1e92909e
GT
3402 {
3403 SQLFreeStmt(hstmt, SQL_CLOSE);
3404 return(DispAllErrors(henv, hdbc, hstmt));
3405 }
eedb1543 3406
1e92909e 3407 SQLFreeStmt(hstmt, SQL_CLOSE);
108106cf 3408
68379eaf 3409 return true;
eedb1543 3410
f6bcfd97 3411} // wxDb::TableExists()
108106cf
JS
3412
3413
a8aa2258 3414/********** wxDb::TablePrivileges() **********/
4fdae997 3415bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
8a39593e 3416 const wxChar *schema, const wxString &WXUNUSED(tablePath))
3ca6a5f0 3417{
4fdae997
GT
3418 wxASSERT(tableName.Length());
3419
3ca6a5f0
BP
3420 wxDbTablePrivilegeInfo result;
3421 SDWORD cbRetVal;
3422 RETCODE retcode;
eedb1543 3423
4fdae997
GT
3424 // We probably need to be able to dynamically set this based on
3425 // the driver type, and state.
3426 wxChar curRole[]=wxT("public");
eedb1543 3427
3ca6a5f0 3428 wxString TableName;
eedb1543 3429
02cf6fdd 3430 wxString UserID,Schema;
4fdae997 3431 convertUserID(userID,UserID);
02cf6fdd 3432 convertUserID(schema,Schema);
eedb1543 3433
3ca6a5f0 3434 TableName = tableName;
d8a0a1c9 3435 // Oracle and Interbase table names are uppercase only, so force
3ca6a5f0 3436 // the name to uppercase just in case programmer forgot to do this
eedb1543 3437 if ((Dbms() == dbmsORACLE) ||
d8a0a1c9 3438 (Dbms() == dbmsINTERBASE))
3ca6a5f0 3439 TableName = TableName.Upper();
eedb1543 3440
3ca6a5f0 3441 SQLFreeStmt(hstmt, SQL_CLOSE);
d8a0a1c9 3442
02cf6fdd
GT
3443 // Some databases cannot accept a user name when looking up table names,
3444 // so we use the call below that leaves out the user name
3445 if (!Schema.IsEmpty() &&
3446 Dbms() != dbmsMY_SQL &&
3447 Dbms() != dbmsACCESS &&
3448 Dbms() != dbmsMS_SQL_SERVER)
d8a0a1c9
GT
3449 {
3450 retcode = SQLTablePrivileges(hstmt,
3451 NULL, 0, // Catalog
8a39593e
JS
3452 (SQLTCHAR FAR *)Schema.c_str(), SQL_NTS, // Schema
3453 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
d8a0a1c9
GT
3454 }
3455 else
3456 {
3457 retcode = SQLTablePrivileges(hstmt,
3458 NULL, 0, // Catalog
02cf6fdd 3459 NULL, 0, // Schema
8a39593e 3460 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
d8a0a1c9 3461 }
a8aa2258 3462
eedb1543 3463#ifdef DBDEBUG_CONSOLE
8a39593e 3464 wxFprintf(stderr ,wxT("SQLTablePrivileges() returned %i \n"),retcode);
3ca6a5f0 3465#endif
eedb1543 3466
a8aa2258
GT
3467 if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
3468 return(DispAllErrors(henv, hdbc, hstmt));
3469
68379eaf 3470 bool failed = false;
d8a0a1c9 3471 retcode = SQLFetch(hstmt);
eedb1543 3472 while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
d8a0a1c9
GT
3473 {
3474 if (SQLGetData(hstmt, 1, SQL_C_CHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS)
68379eaf 3475 failed = true;
eedb1543 3476
5a226de0 3477 if (!failed && SQLGetData(hstmt, 2, SQL_C_CHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS)
68379eaf 3478 failed = true;
eedb1543 3479
5a226de0 3480 if (!failed && SQLGetData(hstmt, 3, SQL_C_CHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS)
68379eaf 3481 failed = true;
eedb1543 3482
5a226de0 3483 if (!failed && SQLGetData(hstmt, 4, SQL_C_CHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS)
68379eaf 3484 failed = true;
eedb1543 3485
5a226de0 3486 if (!failed && SQLGetData(hstmt, 5, SQL_C_CHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS)
68379eaf 3487 failed = true;
eedb1543 3488
5a226de0 3489 if (!failed && SQLGetData(hstmt, 6, SQL_C_CHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS)
68379eaf 3490 failed = true;
eedb1543 3491
5a226de0 3492 if (!failed && SQLGetData(hstmt, 7, SQL_C_CHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS)
68379eaf 3493 failed = true;
d8a0a1c9 3494
5a226de0
GT
3495 if (failed)
3496 {
3497 return(DispAllErrors(henv, hdbc, hstmt));
3498 }
3ca6a5f0 3499#ifdef DBDEBUG_CONSOLE
8a39593e 3500 wxFprintf(stderr,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
a8aa2258 3501 result.privilege,result.tableOwner,result.tableName,
3ca6a5f0 3502 result.grantor, result.grantee);
eedb1543 3503#endif
d8a0a1c9 3504
68379eaf 3505 if (UserID.IsSameAs(result.tableOwner,false))
a8aa2258
GT
3506 {
3507 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3508 return true;
a8aa2258 3509 }
eedb1543 3510
68379eaf 3511 if (UserID.IsSameAs(result.grantee,false) &&
a8aa2258
GT
3512 !wxStrcmp(result.privilege,priv))
3513 {
3514 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3515 return true;
a8aa2258 3516 }
eedb1543 3517
a8aa2258
GT
3518 if (!wxStrcmp(result.grantee,curRole) &&
3519 !wxStrcmp(result.privilege,priv))
3520 {
3521 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3522 return true;
a8aa2258 3523 }
eedb1543 3524
3ca6a5f0 3525 retcode = SQLFetch(hstmt);
eedb1543
DW
3526 }
3527
a8aa2258 3528 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3529 return false;
3ca6a5f0 3530
a8aa2258 3531} // wxDb::TablePrivileges
3ca6a5f0
BP
3532
3533
5bdad317 3534const wxString wxDb::SQLTableName(const wxChar *tableName)
243d4b36
GT
3535{
3536 wxString TableName;
3537
3538 if (Dbms() == dbmsACCESS)
8a39593e 3539 TableName = _T("\"");
243d4b36
GT
3540 TableName += tableName;
3541 if (Dbms() == dbmsACCESS)
8a39593e 3542 TableName += _T("\"");
243d4b36
GT
3543
3544 return TableName;
3545} // wxDb::SQLTableName()
3546
3547
5bdad317 3548const wxString wxDb::SQLColumnName(const wxChar *colName)
243d4b36
GT
3549{
3550 wxString ColName;
3551
3552 if (Dbms() == dbmsACCESS)
8a39593e 3553 ColName = _T("\"");
243d4b36
GT
3554 ColName += colName;
3555 if (Dbms() == dbmsACCESS)
8a39593e 3556 ColName += _T("\"");
243d4b36
GT
3557
3558 return ColName;
3559} // wxDb::SQLColumnName()
3560
3561
f6bcfd97 3562/********** wxDb::SetSqlLogging() **********/
4fdae997 3563bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
1fc5dd6f 3564{
4fdae997
GT
3565 wxASSERT(state == sqlLogON || state == sqlLogOFF);
3566 wxASSERT(state == sqlLogOFF || filename.Length());
1e92909e 3567
ea5d599d
GT
3568 if (state == sqlLogON)
3569 {
3570 if (fpSqlLog == 0)
3571 {
8a39593e 3572 fpSqlLog = wxFopen(filename, (append ? wxT("at") : wxT("wt")));
ea5d599d 3573 if (fpSqlLog == NULL)
68379eaf 3574 return false;
ea5d599d
GT
3575 }
3576 }
3577 else // sqlLogOFF
3578 {
3579 if (fpSqlLog)
3580 {
3581 if (fclose(fpSqlLog))
68379eaf 3582 return false;
ea5d599d
GT
3583 fpSqlLog = 0;
3584 }
3585 }
1e92909e 3586
ea5d599d 3587 sqlLogState = state;
68379eaf 3588 return true;
1fc5dd6f 3589
f6bcfd97 3590} // wxDb::SetSqlLogging()
1fc5dd6f
JS
3591
3592
f6bcfd97 3593/********** wxDb::WriteSqlLog() **********/
4fdae997 3594bool wxDb::WriteSqlLog(const wxString &logMsg)
1fc5dd6f 3595{
4fdae997 3596 wxASSERT(logMsg.Length());
1fc5dd6f 3597
1e92909e 3598 if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
68379eaf 3599 return false;
1fc5dd6f 3600
8a39593e 3601 if (wxFputs(wxT("\n"), fpSqlLog) == EOF)
68379eaf 3602 return false;
8a39593e 3603 if (wxFputs(logMsg, fpSqlLog) == EOF)
68379eaf 3604 return false;
8a39593e 3605 if (wxFputs(wxT("\n"), fpSqlLog) == EOF)
68379eaf 3606 return false;
1fc5dd6f 3607
68379eaf 3608 return true;
1fc5dd6f 3609
f6bcfd97 3610} // wxDb::WriteSqlLog()
1fc5dd6f
JS
3611
3612
f6bcfd97
BP
3613/********** wxDb::Dbms() **********/
3614wxDBMS wxDb::Dbms(void)
a2115c88
GT
3615/*
3616 * Be aware that not all database engines use the exact same syntax, and not
3617 * every ODBC compliant database is compliant to the same level of compliancy.
3618 * Some manufacturers support the minimum Level 1 compliancy, and others up
3619 * through Level 3. Others support subsets of features for levels above 1.
3620 *
f6bcfd97 3621 * If you find an inconsistency between the wxDb class and a specific database
a2115c88
GT
3622 * engine, and an identifier to this section, and special handle the database in
3623 * the area where behavior is non-conforming with the other databases.
3624 *
3625 *
3626 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3627 * ---------------------------------------------------
3628 *
3629 * ORACLE
1e92909e 3630 * - Currently the only database supported by the class to support VIEWS
a2115c88
GT
3631 *
3632 * DBASE
1e92909e
GT
3633 * - Does not support the SQL_TIMESTAMP structure
3634 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
fdc03678 3635 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
68379eaf 3636 * is true. The user must create ALL indexes from their program.
1e92909e
GT
3637 * - Table names can only be 8 characters long
3638 * - Column names can only be 10 characters long
a2115c88
GT
3639 *
3640 * SYBASE (all)
1e92909e
GT
3641 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3642 * after every table name involved in the query/join if that tables matching record(s)
3643 * are to be locked
3644 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
a2115c88
GT
3645 *
3646 * SYBASE (Enterprise)
1e92909e 3647 * - If a column is part of the Primary Key, the column cannot be NULL
3ca6a5f0 3648 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
a2115c88
GT
3649 *
3650 * MY_SQL
1e92909e 3651 * - If a column is part of the Primary Key, the column cannot be NULL
a144affe 3652 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3ca6a5f0
BP
3653 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3654 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3655 * column definition if it is not defined correctly, but it is experimental
3656 * - Does not support sub-queries in SQL statements
a2115c88
GT
3657 *
3658 * POSTGRES
23f681ec 3659 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3ca6a5f0 3660 * - Does not support sub-queries in SQL statements
a2115c88 3661 *
a8aa2258
GT
3662 * DB2
3663 * - Primary keys must be declared as NOT NULL
2beca662
GT
3664 * - Table and index names must not be longer than 13 characters in length (technically
3665 * table names can be up to 18 characters, but the primary index is created using the
3666 * base table name plus "_PIDX", so the limit if the table has a primary index is 13.
3667 *
3668 * PERVASIVE SQL
a8aa2258 3669 *
081eb1b1
GT
3670 * INTERBASE
3671 * - Columns that are part of primary keys must be defined as being NOT NULL
3672 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3673 * column definition if it is not defined correctly, but it is experimental
a2115c88 3674 */
a2115c88 3675{
a8aa2258 3676 // Should only need to do this once for each new database connection
eedb1543 3677 // so return the value we already determined it to be to save time
a8aa2258
GT
3678 // and lots of string comparisons
3679 if (dbmsType != dbmsUNIDENTIFIED)
3680 return(dbmsType);
3681
1e92909e 3682 wxChar baseName[25+1];
1e92909e 3683 wxStrncpy(baseName,dbInf.dbmsName,25);
3ca6a5f0 3684 baseName[25] = 0;
f6bcfd97 3685
d8a0a1c9
GT
3686 // RGG 20001025 : add support for Interbase
3687 // GT : Integrated to base classes on 20001121
4fdae997 3688 if (!wxStricmp(dbInf.dbmsName,wxT("Interbase")))
d8a0a1c9
GT
3689 return((wxDBMS)(dbmsType = dbmsINTERBASE));
3690
f6bcfd97 3691 // BJO 20000428 : add support for Virtuoso
4fdae997 3692 if (!wxStricmp(dbInf.dbmsName,wxT("OpenLink Virtuoso VDBMS")))
a8aa2258 3693 return((wxDBMS)(dbmsType = dbmsVIRTUOSO));
f6bcfd97 3694
4fdae997 3695 if (!wxStricmp(dbInf.dbmsName,wxT("Adaptive Server Anywhere")))
a8aa2258
GT
3696 return((wxDBMS)(dbmsType = dbmsSYBASE_ASA));
3697
f6bcfd97
BP
3698 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3699 // connected through an OpenLink driver.
eedb1543
DW
3700 // Is it also returned by Sybase Adapatitve server?
3701 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
4fdae997 3702 if (!wxStricmp(dbInf.dbmsName,wxT("SQL Server")))
3ca6a5f0 3703 {
4fdae997
GT
3704 if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) ||
3705 !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4))
081eb1b1
GT
3706 return ((wxDBMS)(dbmsMS_SQL_SERVER));
3707 else
3708 return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
3ca6a5f0 3709 }
f6bcfd97 3710
4fdae997 3711 if (!wxStricmp(dbInf.dbmsName,wxT("Microsoft SQL Server")))
a8aa2258 3712 return((wxDBMS)(dbmsType = dbmsMS_SQL_SERVER));
9af163d7
GT
3713
3714 baseName[10] = 0;
3715 if (!wxStricmp(baseName,wxT("PostgreSQL"))) // v6.5.0
a8aa2258 3716 return((wxDBMS)(dbmsType = dbmsPOSTGRES));
1e92909e 3717
2beca662 3718 baseName[9] = 0;
9af163d7 3719 if (!wxStricmp(baseName,wxT("Pervasive")))
081eb1b1 3720 return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL));
2beca662 3721
1e92909e 3722 baseName[8] = 0;
4fdae997 3723 if (!wxStricmp(baseName,wxT("Informix")))
a8aa2258 3724 return((wxDBMS)(dbmsType = dbmsINFORMIX));
1e92909e
GT
3725
3726 baseName[6] = 0;
4fdae997 3727 if (!wxStricmp(baseName,wxT("Oracle")))
a8aa2258 3728 return((wxDBMS)(dbmsType = dbmsORACLE));
9af163d7 3729 if (!wxStricmp(baseName,wxT("ACCESS")))
a8aa2258 3730 return((wxDBMS)(dbmsType = dbmsACCESS));
4fdae997 3731 if (!wxStricmp(baseName,wxT("Sybase")))
a8aa2258 3732 return((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
1e92909e
GT
3733
3734 baseName[5] = 0;
4fdae997 3735 if (!wxStricmp(baseName,wxT("DBASE")))
a8aa2258 3736 return((wxDBMS)(dbmsType = dbmsDBASE));
9f4de2dc
JS
3737 if (!wxStricmp(baseName,wxT("xBase")))
3738 return((wxDBMS)(dbmsType = dbmsXBASE_SEQUITER));
e25cdb86
GT
3739 if (!wxStricmp(baseName,wxT("MySQL")))
3740 return((wxDBMS)(dbmsType = dbmsMY_SQL));
3741
a8aa2258 3742 baseName[3] = 0;
4fdae997 3743 if (!wxStricmp(baseName,wxT("DB2")))
a8aa2258
GT
3744 return((wxDBMS)(dbmsType = dbmsDBASE));
3745
3746 return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
3ca6a5f0 3747
f6bcfd97 3748} // wxDb::Dbms()
a2115c88
GT
3749
3750
4fdae997
GT
3751bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
3752 int dataType, ULONG columnLength,
3753 const wxString &optionalParam)
3754{
3755 wxASSERT(tableName.Length());
3756 wxASSERT(columnName.Length());
3757 wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
3758 dataType != DB_DATA_TYPE_VARCHAR);
3759
3760 // Must specify a columnLength if modifying a VARCHAR type column
3761 if (dataType == DB_DATA_TYPE_VARCHAR && !columnLength)
68379eaf 3762 return false;
5600884a 3763
4fdae997 3764 wxString dataTypeName;
081eb1b1 3765 wxString sqlStmt;
4fdae997
GT
3766 wxString alterSlashModify;
3767
081eb1b1
GT
3768 switch(dataType)
3769 {
3770 case DB_DATA_TYPE_VARCHAR :
3771 dataTypeName = typeInfVarchar.TypeName;
3772 break;
3773 case DB_DATA_TYPE_INTEGER :
3774 dataTypeName = typeInfInteger.TypeName;
3775 break;
3776 case DB_DATA_TYPE_FLOAT :
3777 dataTypeName = typeInfFloat.TypeName;
3778 break;
3779 case DB_DATA_TYPE_DATE :
3780 dataTypeName = typeInfDate.TypeName;
3781 break;
3782 case DB_DATA_TYPE_BLOB :
3783 dataTypeName = typeInfBlob.TypeName;
3784 break;
3785 default:
68379eaf 3786 return false;
081eb1b1
GT
3787 }
3788
3789 // Set the modify or alter syntax depending on the type of database connected to
3790 switch (Dbms())
3791 {
3792 case dbmsORACLE :
8a39593e 3793 alterSlashModify = _T("MODIFY");
081eb1b1
GT
3794 break;
3795 case dbmsMS_SQL_SERVER :
8a39593e 3796 alterSlashModify = _T("ALTER COLUMN");
081eb1b1
GT
3797 break;
3798 case dbmsUNIDENTIFIED :
68379eaf 3799 return false;
081eb1b1
GT
3800 case dbmsSYBASE_ASA :
3801 case dbmsSYBASE_ASE :
3802 case dbmsMY_SQL :
3803 case dbmsPOSTGRES :
3804 case dbmsACCESS :
3805 case dbmsDBASE :
9f4de2dc 3806 case dbmsXBASE_SEQUITER :
081eb1b1 3807 default :
8a39593e 3808 alterSlashModify = _T("MODIFY");
081eb1b1
GT
3809 break;
3810 }
3811
3812 // create the SQL statement
9c136858
JS
3813 if ( Dbms() == dbmsMY_SQL )
3814 {
3815 sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(),
3816 columnName.c_str(), dataTypeName.c_str());
3817 }
3818 else
3819 {
3820 sqlStmt.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName.c_str(), alterSlashModify.c_str(),
081eb1b1 3821 columnName.c_str(), dataTypeName.c_str());
9c136858 3822 }
4fdae997
GT
3823
3824 // For varchars only, append the size of the column
e25cdb86 3825 if (dataType == DB_DATA_TYPE_VARCHAR &&
8a39593e 3826 (Dbms() != dbmsMY_SQL || dataTypeName != _T("text")))
4fdae997
GT
3827 {
3828 wxString s;
7fd4e7e1 3829 s.Printf(wxT("(%lu)"), columnLength);
4fdae997
GT
3830 sqlStmt += s;
3831 }
3832
3833 // for passing things like "NOT NULL"
3834 if (optionalParam.Length())
3835 {
3836 sqlStmt += wxT(" ");
3837 sqlStmt += optionalParam;
3838 }
3839
081eb1b1 3840 return ExecSql(sqlStmt);
4fdae997
GT
3841
3842} // wxDb::ModifyColumn()
3843
3844
fdc03678 3845/********** wxDbGetConnection() **********/
bb41dcbe 3846wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors)
108106cf 3847{
fdc03678 3848 wxDbList *pList;
1e92909e 3849
a8aa2258
GT
3850 // Used to keep a pointer to a DB connection that matches the requested
3851 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
3852 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
3853 // rather than having to re-query the datasource to get all the values
3854 // using the wxDb::Open(Dsn,Uid,AuthStr) function
3855 wxDb *matchingDbConnection = NULL;
3856
1e92909e
GT
3857 // Scan the linked list searching for an available database connection
3858 // that's already been opened but is currently not in use.
3859 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3860 {
3861 // The database connection must be for the same datasource
3862 // name and must currently not be in use.
3ca6a5f0 3863 if (pList->Free &&
0907ea9c 3864 (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors))
1e92909e 3865 {
0907ea9c
GT
3866 if (pDbConfig->UseConnectionStr())
3867 {
68379eaf 3868 if (pList->PtrDb->OpenedWithConnectionString() &&
0907ea9c
GT
3869 (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr)))
3870 {
3871 // Found a free connection
68379eaf 3872 pList->Free = false;
0907ea9c
GT
3873 return(pList->PtrDb);
3874 }
3875 }
3876 else
3877 {
3878 if (!pList->PtrDb->OpenedWithConnectionString() &&
3879 (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn)))
3880 {
3881 // Found a free connection
68379eaf 3882 pList->Free = false;
0907ea9c
GT
3883 return(pList->PtrDb);
3884 }
3885 }
1e92909e 3886 }
a8aa2258 3887
0907ea9c
GT
3888 if (pDbConfig->UseConnectionStr())
3889 {
3890 if (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr))
3891 matchingDbConnection = pList->PtrDb;
3892 }
3893 else
3894 {
3895 if (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn) &&
3896 !wxStrcmp(pDbConfig->GetUserID(), pList->Uid) &&
3897 !wxStrcmp(pDbConfig->GetPassword(), pList->AuthStr))
3898 matchingDbConnection = pList->PtrDb;
3899 }
1e92909e
GT
3900 }
3901
3902 // No available connections. A new connection must be made and
3903 // appended to the end of the linked list.
3904 if (PtrBegDbList)
3905 {
3906 // Find the end of the list
3907 for (pList = PtrBegDbList; pList->PtrNext; pList = pList->PtrNext);
3908 // Append a new list item
fdc03678 3909 pList->PtrNext = new wxDbList;
1e92909e
GT
3910 pList->PtrNext->PtrPrev = pList;
3911 pList = pList->PtrNext;
3912 }
3ca6a5f0 3913 else // Empty list
1e92909e
GT
3914 {
3915 // Create the first node on the list
fdc03678 3916 pList = PtrBegDbList = new wxDbList;
1e92909e
GT
3917 pList->PtrPrev = 0;
3918 }
3919
3920 // Initialize new node in the linked list
0907ea9c 3921 pList->PtrNext = 0;
68379eaf 3922 pList->Free = false;
0907ea9c
GT
3923 pList->Dsn = pDbConfig->GetDsn();
3924 pList->Uid = pDbConfig->GetUserID();
3925 pList->AuthStr = pDbConfig->GetPassword();
3926 pList->ConnectionStr = pDbConfig->GetConnectionStr();
a8aa2258 3927
9556da13 3928 pList->PtrDb = new wxDb(pDbConfig->GetHenv(), FwdOnlyCursors);
1e92909e 3929
caf412d6 3930 bool opened;
a8aa2258
GT
3931
3932 if (!matchingDbConnection)
0907ea9c
GT
3933 {
3934 if (pDbConfig->UseConnectionStr())
3935 {
3936 opened = pList->PtrDb->Open(pDbConfig->GetConnectionStr());
3937 }
3938 else
3939 {
3940 opened = pList->PtrDb->Open(pDbConfig->GetDsn(), pDbConfig->GetUserID(), pDbConfig->GetPassword());
3941 }
3942 }
a8aa2258
GT
3943 else
3944 opened = pList->PtrDb->Open(matchingDbConnection);
3945
1e92909e 3946 // Connect to the datasource
a8aa2258 3947 if (opened)
1e92909e 3948 {
68379eaf
WS
3949 pList->PtrDb->setCached(true); // Prevent a user from deleting a cached connection
3950 pList->PtrDb->SetSqlLogging(SQLLOGstate, SQLLOGfn, true);
1e92909e
GT
3951 return(pList->PtrDb);
3952 }
3953 else // Unable to connect, destroy list item
3954 {
3955 if (pList->PtrPrev)
3956 pList->PtrPrev->PtrNext = 0;
3957 else
0907ea9c
GT
3958 PtrBegDbList = 0; // Empty list again
3959
3960 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
3961 pList->PtrDb->Close(); // Close the wxDb object
3962 delete pList->PtrDb; // Deletes the wxDb object
3963 delete pList; // Deletes the linked list object
1e92909e
GT
3964 return(0);
3965 }
108106cf 3966
fdc03678 3967} // wxDbGetConnection()
108106cf 3968
67e9aaa3 3969
fdc03678 3970/********** wxDbFreeConnection() **********/
bb41dcbe 3971bool WXDLLIMPEXP_ODBC wxDbFreeConnection(wxDb *pDb)
108106cf 3972{
fdc03678 3973 wxDbList *pList;
108106cf 3974
1e92909e
GT
3975 // Scan the linked list searching for the database connection
3976 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
3977 {
3ca6a5f0 3978 if (pList->PtrDb == pDb) // Found it, now free it!!!
68379eaf 3979 return (pList->Free = true);
1e92909e 3980 }
108106cf 3981
1e92909e 3982 // Never found the database object, return failure
68379eaf 3983 return false;
108106cf 3984
fdc03678 3985} // wxDbFreeConnection()
108106cf 3986
67e9aaa3 3987
fdc03678 3988/********** wxDbCloseConnections() **********/
bb41dcbe 3989void WXDLLIMPEXP_ODBC wxDbCloseConnections(void)
108106cf 3990{
fdc03678 3991 wxDbList *pList, *pNext;
23f681ec 3992
1e92909e
GT
3993 // Traverse the linked list closing database connections and freeing memory as I go.
3994 for (pList = PtrBegDbList; pList; pList = pNext)
3995 {
3996 pNext = pList->PtrNext; // Save the pointer to next
f6bcfd97
BP
3997 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
3998 pList->PtrDb->Close(); // Close the wxDb object
68379eaf 3999 pList->PtrDb->setCached(false); // Allows deletion of the wxDb instance
f6bcfd97 4000 delete pList->PtrDb; // Deletes the wxDb object
1e92909e
GT
4001 delete pList; // Deletes the linked list object
4002 }
4003
4004 // Mark the list as empty
4005 PtrBegDbList = 0;
108106cf 4006
fdc03678 4007} // wxDbCloseConnections()
108106cf 4008
67e9aaa3 4009
eb3b9dda 4010/********** wxDbConnectionsInUse() **********/
bb41dcbe 4011int WXDLLIMPEXP_ODBC wxDbConnectionsInUse(void)
108106cf 4012{
fdc03678 4013 wxDbList *pList;
1e92909e 4014 int cnt = 0;
108106cf 4015
1e92909e
GT
4016 // Scan the linked list counting db connections that are currently in use
4017 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
4018 {
68379eaf 4019 if (pList->Free == false)
1e92909e
GT
4020 cnt++;
4021 }
108106cf 4022
1e92909e 4023 return(cnt);
108106cf 4024
fdc03678 4025} // wxDbConnectionsInUse()
108106cf 4026
67e9aaa3 4027
2c257434
GT
4028
4029/********** wxDbLogExtendedErrorMsg() **********/
4030// DEBUG ONLY function
f9ebf98b 4031const wxChar WXDLLIMPEXP_ODBC *wxDbLogExtendedErrorMsg(const wxChar *userText,
90350682
VZ
4032 wxDb *pDb,
4033 const wxChar *ErrFile,
4034 int ErrLine)
2c257434
GT
4035{
4036 static wxString msg;
4037 msg = userText;
4038
4039 wxString tStr;
4040
4041 if (ErrFile || ErrLine)
4042 {
4043 msg += wxT("File: ");
4044 msg += ErrFile;
4045 msg += wxT(" Line: ");
4046 tStr.Printf(wxT("%d"),ErrLine);
4047 msg += tStr.c_str();
4048 msg += wxT("\n");
4049 }
4050
4051 msg.Append (wxT("\nODBC errors:\n"));
4052 msg += wxT("\n");
2e57a9ef 4053
2c257434
GT
4054 // Display errors for this connection
4055 int i;
4056 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
4057 {
4058 if (pDb->errorList[i])
4059 {
4060 msg.Append(pDb->errorList[i]);
4061 if (wxStrcmp(pDb->errorList[i],wxT("")) != 0)
4062 msg.Append(wxT("\n"));
4063 // Clear the errmsg buffer so the next error will not
4064 // end up showing the previous error that have occurred
4065 wxStrcpy(pDb->errorList[i],wxT(""));
4066 }
4067 }
4068 msg += wxT("\n");
4069
4070 wxLogDebug(msg.c_str());
4071
4072 return msg.c_str();
4073} // wxDbLogExtendedErrorMsg()
4074
4075
fdc03678 4076/********** wxDbSqlLog() **********/
f6bcfd97 4077bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename)
a2115c88 4078{
68379eaf 4079 bool append = false;
fdc03678 4080 wxDbList *pList;
a2115c88 4081
1e92909e
GT
4082 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
4083 {
f6bcfd97 4084 if (!pList->PtrDb->SetSqlLogging(state,filename,append))
68379eaf
WS
4085 return false;
4086 append = true;
1e92909e 4087 }
a2115c88 4088
1e92909e 4089 SQLLOGstate = state;
3ca6a5f0 4090 SQLLOGfn = filename;
a2115c88 4091
68379eaf 4092 return true;
a2115c88 4093
fdc03678 4094} // wxDbSqlLog()
a2115c88 4095
67e9aaa3 4096
a8aa2258 4097#if 0
fdc03678 4098/********** wxDbCreateDataSource() **********/
4fdae997
GT
4099int wxDbCreateDataSource(const wxString &driverName, const wxString &dsn, const wxString &description,
4100 bool sysDSN, const wxString &defDir, wxWindow *parent)
fdc03678
GT
4101/*
4102 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
eedb1543 4103 * Very rudimentary creation of an ODBC data source.
a8aa2258
GT
4104 *
4105 * ODBC driver must be ODBC 3.0 compliant to use this function
fdc03678
GT
4106 */
4107{
a144affe 4108 int result = FALSE;
fdc03678 4109
a8aa2258
GT
4110//!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
4111#ifdef __VISUALC__
fdc03678
GT
4112 int dsnLocation;
4113 wxString setupStr;
4114
4115 if (sysDSN)
4116 dsnLocation = ODBC_ADD_SYS_DSN;
4117 else
4118 dsnLocation = ODBC_ADD_DSN;
4119
4120 // NOTE: The decimal 2 is an invalid character in all keyword pairs
eedb1543 4121 // so that is why I used it, as wxString does not deal well with
fdc03678 4122 // embedded nulls in strings
4fdae997 4123 setupStr.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn,2,description,2,defDir,2);
fdc03678
GT
4124
4125 // Replace the separator from above with the '\0' seperator needed
4126 // by the SQLConfigDataSource() function
4127 int k;
4128 do
4129 {
68379eaf 4130 k = setupStr.Find((wxChar)2,true);
fdc03678 4131 if (k != wxNOT_FOUND)
4fdae997 4132 setupStr[(UINT)k] = wxT('\0');
fdc03678
GT
4133 }
4134 while (k != wxNOT_FOUND);
4135
4136 result = SQLConfigDataSource((HWND)parent->GetHWND(), dsnLocation,
f6bcfd97 4137 driverName, setupStr.c_str());
fdc03678 4138
a8aa2258 4139 if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
fdc03678
GT
4140 {
4141 // check for errors caused by ConfigDSN based functions
4142 DWORD retcode = 0;
4143 WORD cb;
a8aa2258 4144 wxChar errMsg[SQL_MAX_MESSAGE_LENGTH];
4fdae997 4145 errMsg[0] = wxT('\0');
fdc03678 4146
a8aa2258
GT
4147 // This function is only supported in ODBC drivers v3.0 compliant and above
4148 SQLInstallerError(1,&retcode,errMsg,SQL_MAX_MESSAGE_LENGTH-1,&cb);
fdc03678
GT
4149 if (retcode)
4150 {
fdc03678 4151#ifdef DBDEBUG_CONSOLE
f6bcfd97
BP
4152 // When run in console mode, use standard out to display errors.
4153 cout << errMsg << endl;
a8aa2258 4154 cout << wxT("Press any key to continue...") << endl;
f6bcfd97 4155 getchar();
fdc03678 4156#endif // DBDEBUG_CONSOLE
fdc03678
GT
4157
4158#ifdef __WXDEBUG__
f6bcfd97 4159 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
fdc03678
GT
4160#endif // __WXDEBUG__
4161 }
4162 }
4163 else
a144affe 4164 result = TRUE;
a8aa2258
GT
4165#else
4166 // Using iODBC/unixODBC or some other compiler which does not support the APIs
4167 // necessary to use this function, so this function is not supported
fdc03678 4168#ifdef __WXDEBUG__
4fdae997 4169 wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
fdc03678 4170#endif
a144affe 4171 result = FALSE;
a8aa2258 4172#endif // __VISUALC__
fdc03678
GT
4173
4174 return result;
4175
4176} // wxDbCreateDataSource()
4177#endif
4178
4179
4180/********** wxDbGetDataSource() **********/
4fdae997 4181bool wxDbGetDataSource(HENV henv, wxChar *Dsn, SWORD DsnMax, wxChar *DsDesc,
dba2120c 4182 SWORD DsDescMax, UWORD direction)
67e9aaa3
GT
4183/*
4184 * Dsn and DsDesc will contain the data source name and data source
4185 * description upon return
4186 */
108106cf 4187{
1e92909e 4188 SWORD cb1,cb2;
108106cf 4189
8a39593e
JS
4190 if (SQLDataSources(henv, direction, (SQLTCHAR FAR *) Dsn, DsnMax, &cb1,
4191 (SQLTCHAR FAR *) DsDesc, DsDescMax, &cb2) == SQL_SUCCESS)
68379eaf 4192 return true;
1e92909e 4193 else
68379eaf 4194 return false;
108106cf 4195
fdc03678
GT
4196} // wxDbGetDataSource()
4197
4198
4199// Change this to 0 to remove use of all deprecated functions
f6bcfd97 4200#if wxODBC_BACKWARD_COMPATABILITY
fdc03678
GT
4201/********************************************************************
4202 ********************************************************************
4203 *
4204 * The following functions are all DEPRECATED and are included for
4205 * backward compatability reasons only
4206 *
4207 ********************************************************************
4208 ********************************************************************/
f6bcfd97 4209bool SqlLog(sqlLog state, const wxChar *filename)
fdc03678 4210{
f6bcfd97 4211 return wxDbSqlLog((enum wxDbSqlLogState)state, filename);
fdc03678
GT
4212}
4213/***** DEPRECATED: use wxGetDataSource() *****/
4214bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
4215 UWORD direction)
4216{
4217 return wxDbGetDataSource(henv, Dsn, DsnMax, DsDesc, DsDescMax, direction);
4218}
4219/***** DEPRECATED: use wxDbGetConnection() *****/
bb41dcbe 4220wxDb WXDLLIMPEXP_ODBC *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors)
fdc03678
GT
4221{
4222 return wxDbGetConnection((wxDbConnectInf *)pDbStuff, FwdOnlyCursors);
4223}
4224/***** DEPRECATED: use wxDbFreeConnection() *****/
bb41dcbe 4225bool WXDLLIMPEXP_ODBC FreeDbConnection(wxDb *pDb)
fdc03678
GT
4226{
4227 return wxDbFreeConnection(pDb);
4228}
4229/***** DEPRECATED: use wxDbCloseConnections() *****/
bb41dcbe 4230void WXDLLIMPEXP_ODBC CloseDbConnections(void)
fdc03678
GT
4231{
4232 wxDbCloseConnections();
4233}
4234/***** DEPRECATED: use wxDbConnectionsInUse() *****/
bb41dcbe 4235int WXDLLIMPEXP_ODBC NumberDbConnectionsInUse(void)
fdc03678
GT
4236{
4237 return wxDbConnectionsInUse();
4238}
4239#endif
4240
4241
108106cf 4242#endif
1fc5dd6f 4243 // wxUSE_ODBC