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