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