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