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