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