]> git.saurik.com Git - wxWidgets.git/blame - src/common/db.cpp
Added Set/GetQuickBestSize
[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,
0907ea9c
GT
861 sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE );
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())
923 return Open(GetConnectionInStr(), failOnDataTypeUnsupported);
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,
0907ea9c
GT
966 sizeof(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE);
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 {
4fdae997 1758 s.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), tiu->tableName,tiu->tableID,tiu->pDb);
d2129c82
GT
1759 s2.Printf(wxT("Orphaned table found using pDb:[%p]"),this);
1760 wxLogDebug(s.c_str(),s2.c_str());
1e92909e 1761 }
c27be5db 1762 pNode = pNode->GetNext();
1e92909e 1763 }
a2115c88
GT
1764#endif
1765
1e92909e
GT
1766 // Copy the error messages to a global variable
1767 int i;
1768 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
942e67c3 1769 wxStrcpy(DBerrorList[i], errorList[i]);
a2115c88 1770
2c257434 1771 dbmsType = dbmsUNIDENTIFIED;
68379eaf 1772 dbIsOpen = false;
a8aa2258 1773
f6bcfd97 1774} // wxDb::Close()
108106cf 1775
67e9aaa3 1776
f6bcfd97
BP
1777/********** wxDb::CommitTrans() **********/
1778bool wxDb::CommitTrans(void)
108106cf 1779{
1e92909e
GT
1780 if (this)
1781 {
1782 // Commit the transaction
1783 if (SQLTransact(henv, hdbc, SQL_COMMIT) != SQL_SUCCESS)
1784 return(DispAllErrors(henv, hdbc));
1785 }
108106cf 1786
1e92909e 1787 // Completed successfully
68379eaf 1788 return true;
108106cf 1789
f6bcfd97 1790} // wxDb::CommitTrans()
108106cf 1791
67e9aaa3 1792
f6bcfd97
BP
1793/********** wxDb::RollbackTrans() **********/
1794bool wxDb::RollbackTrans(void)
108106cf 1795{
1e92909e
GT
1796 // Rollback the transaction
1797 if (SQLTransact(henv, hdbc, SQL_ROLLBACK) != SQL_SUCCESS)
1798 return(DispAllErrors(henv, hdbc));
108106cf 1799
1e92909e 1800 // Completed successfully
68379eaf 1801 return true;
108106cf 1802
f6bcfd97 1803} // wxDb::RollbackTrans()
108106cf 1804
67e9aaa3 1805
f6bcfd97
BP
1806/********** wxDb::DispAllErrors() **********/
1807bool wxDb::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
a8aa2258
GT
1808/*
1809 * This function is called internally whenever an error condition prevents the user's
1810 * request from being executed. This function will query the datasource as to the
3103e8a9 1811 * actual error(s) that just occurred on the previous request of the datasource.
a8aa2258 1812 *
eedb1543 1813 * The function will retrieve each error condition from the datasource and
4fdae997 1814 * Printf the codes/text values into a string which it then logs via logError().
a8aa2258
GT
1815 * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console
1816 * window and program execution will be paused until the user presses a key.
1817 *
3103e8a9 1818 * This function always returns false, so that functions which call this function
a8aa2258 1819 * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure
3103e8a9 1820 * of the user's request, so that the calling code can then process the error message log.
a8aa2258 1821 */
108106cf 1822{
1e92909e
GT
1823 wxString odbcErrMsg;
1824
c497d0b2 1825 while (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
fa06876d 1826 {
4fdae997
GT
1827 odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState, nativeError, errorMsg);
1828 logError(odbcErrMsg, sqlState);
1e92909e
GT
1829 if (!silent)
1830 {
1fc5dd6f 1831#ifdef DBDEBUG_CONSOLE
1e92909e 1832 // When run in console mode, use standard out to display errors.
f6bcfd97 1833 cout << odbcErrMsg.c_str() << endl;
4fdae997 1834 cout << wxT("Press any key to continue...") << endl;
1e92909e 1835 getchar();
108106cf 1836#endif
a2115c88
GT
1837
1838#ifdef __WXDEBUG__
4fdae997 1839 wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE from DispAllErrors()"));
a2115c88 1840#endif
f6bcfd97 1841 }
1e92909e 1842 }
108106cf 1843
68379eaf 1844 return false; // This function always returns false.
108106cf 1845
f6bcfd97 1846} // wxDb::DispAllErrors()
108106cf 1847
67e9aaa3 1848
f6bcfd97
BP
1849/********** wxDb::GetNextError() **********/
1850bool wxDb::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
108106cf 1851{
c497d0b2 1852 if (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
fa06876d 1853 return true;
1e92909e 1854 else
68379eaf 1855 return false;
108106cf 1856
f6bcfd97 1857} // wxDb::GetNextError()
108106cf 1858
67e9aaa3 1859
f6bcfd97
BP
1860/********** wxDb::DispNextError() **********/
1861void wxDb::DispNextError(void)
108106cf 1862{
1e92909e 1863 wxString odbcErrMsg;
108106cf 1864
4fdae997
GT
1865 odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), sqlState, nativeError, errorMsg);
1866 logError(odbcErrMsg, sqlState);
108106cf 1867
1e92909e
GT
1868 if (silent)
1869 return;
108106cf 1870
1fc5dd6f 1871#ifdef DBDEBUG_CONSOLE
1e92909e 1872 // When run in console mode, use standard out to display errors.
f6bcfd97 1873 cout << odbcErrMsg.c_str() << endl;
4fdae997 1874 cout << wxT("Press any key to continue...") << endl;
1e92909e 1875 getchar();
108106cf
JS
1876#endif
1877
f6bcfd97
BP
1878#ifdef __WXDEBUG__
1879 wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE"));
1880#endif // __WXDEBUG__
108106cf 1881
f6bcfd97
BP
1882} // wxDb::DispNextError()
1883
1884
1885/********** wxDb::logError() **********/
4fdae997 1886void wxDb::logError(const wxString &errMsg, const wxString &SQLState)
108106cf 1887{
8e3f3880 1888 wxASSERT(errMsg.length());
108106cf 1889
1e92909e
GT
1890 static int pLast = -1;
1891 int dbStatus;
108106cf 1892
1e92909e
GT
1893 if (++pLast == DB_MAX_ERROR_HISTORY)
1894 {
1895 int i;
3387ea29 1896 for (i = 0; i < DB_MAX_ERROR_HISTORY-1; i++)
1e92909e
GT
1897 wxStrcpy(errorList[i], errorList[i+1]);
1898 pLast--;
1899 }
108106cf 1900
7086c32a
GT
1901 wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN);
1902 errorList[pLast][DB_MAX_ERROR_MSG_LEN] = 0;
108106cf 1903
8e3f3880 1904 if (SQLState.length())
1e92909e
GT
1905 if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
1906 DB_STATUS = dbStatus;
108106cf 1907
1e92909e
GT
1908 // Add the errmsg to the sql log
1909 WriteSqlLog(errMsg);
a2115c88 1910
f6bcfd97 1911} // wxDb::logError()
108106cf 1912
67e9aaa3 1913
f6bcfd97 1914/**********wxDb::TranslateSqlState() **********/
4fdae997 1915int wxDb::TranslateSqlState(const wxString &SQLState)
108106cf 1916{
f6bcfd97 1917 if (!wxStrcmp(SQLState, wxT("01000")))
1e92909e 1918 return(DB_ERR_GENERAL_WARNING);
f6bcfd97 1919 if (!wxStrcmp(SQLState, wxT("01002")))
1e92909e 1920 return(DB_ERR_DISCONNECT_ERROR);
f6bcfd97 1921 if (!wxStrcmp(SQLState, wxT("01004")))
1e92909e 1922 return(DB_ERR_DATA_TRUNCATED);
f6bcfd97 1923 if (!wxStrcmp(SQLState, wxT("01006")))
1e92909e 1924 return(DB_ERR_PRIV_NOT_REVOKED);
f6bcfd97 1925 if (!wxStrcmp(SQLState, wxT("01S00")))
1e92909e 1926 return(DB_ERR_INVALID_CONN_STR_ATTR);
f6bcfd97 1927 if (!wxStrcmp(SQLState, wxT("01S01")))
1e92909e 1928 return(DB_ERR_ERROR_IN_ROW);
f6bcfd97 1929 if (!wxStrcmp(SQLState, wxT("01S02")))
1e92909e 1930 return(DB_ERR_OPTION_VALUE_CHANGED);
f6bcfd97 1931 if (!wxStrcmp(SQLState, wxT("01S03")))
1e92909e 1932 return(DB_ERR_NO_ROWS_UPD_OR_DEL);
f6bcfd97 1933 if (!wxStrcmp(SQLState, wxT("01S04")))
1e92909e 1934 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL);
f6bcfd97 1935 if (!wxStrcmp(SQLState, wxT("07001")))
1e92909e 1936 return(DB_ERR_WRONG_NO_OF_PARAMS);
f6bcfd97 1937 if (!wxStrcmp(SQLState, wxT("07006")))
1e92909e 1938 return(DB_ERR_DATA_TYPE_ATTR_VIOL);
f6bcfd97 1939 if (!wxStrcmp(SQLState, wxT("08001")))
1e92909e 1940 return(DB_ERR_UNABLE_TO_CONNECT);
f6bcfd97 1941 if (!wxStrcmp(SQLState, wxT("08002")))
1e92909e 1942 return(DB_ERR_CONNECTION_IN_USE);
f6bcfd97 1943 if (!wxStrcmp(SQLState, wxT("08003")))
1e92909e 1944 return(DB_ERR_CONNECTION_NOT_OPEN);
f6bcfd97 1945 if (!wxStrcmp(SQLState, wxT("08004")))
1e92909e 1946 return(DB_ERR_REJECTED_CONNECTION);
f6bcfd97 1947 if (!wxStrcmp(SQLState, wxT("08007")))
1e92909e 1948 return(DB_ERR_CONN_FAIL_IN_TRANS);
f6bcfd97 1949 if (!wxStrcmp(SQLState, wxT("08S01")))
1e92909e 1950 return(DB_ERR_COMM_LINK_FAILURE);
f6bcfd97 1951 if (!wxStrcmp(SQLState, wxT("21S01")))
1e92909e 1952 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH);
f6bcfd97 1953 if (!wxStrcmp(SQLState, wxT("21S02")))
1e92909e 1954 return(DB_ERR_DERIVED_TABLE_MISMATCH);
f6bcfd97 1955 if (!wxStrcmp(SQLState, wxT("22001")))
1e92909e 1956 return(DB_ERR_STRING_RIGHT_TRUNC);
f6bcfd97 1957 if (!wxStrcmp(SQLState, wxT("22003")))
1e92909e 1958 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG);
f6bcfd97 1959 if (!wxStrcmp(SQLState, wxT("22005")))
1e92909e 1960 return(DB_ERR_ERROR_IN_ASSIGNMENT);
f6bcfd97 1961 if (!wxStrcmp(SQLState, wxT("22008")))
1e92909e 1962 return(DB_ERR_DATETIME_FLD_OVERFLOW);
f6bcfd97 1963 if (!wxStrcmp(SQLState, wxT("22012")))
1e92909e 1964 return(DB_ERR_DIVIDE_BY_ZERO);
f6bcfd97 1965 if (!wxStrcmp(SQLState, wxT("22026")))
1e92909e 1966 return(DB_ERR_STR_DATA_LENGTH_MISMATCH);
f6bcfd97 1967 if (!wxStrcmp(SQLState, wxT("23000")))
1e92909e 1968 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL);
f6bcfd97 1969 if (!wxStrcmp(SQLState, wxT("24000")))
1e92909e 1970 return(DB_ERR_INVALID_CURSOR_STATE);
f6bcfd97 1971 if (!wxStrcmp(SQLState, wxT("25000")))
1e92909e 1972 return(DB_ERR_INVALID_TRANS_STATE);
f6bcfd97 1973 if (!wxStrcmp(SQLState, wxT("28000")))
1e92909e 1974 return(DB_ERR_INVALID_AUTH_SPEC);
f6bcfd97 1975 if (!wxStrcmp(SQLState, wxT("34000")))
1e92909e 1976 return(DB_ERR_INVALID_CURSOR_NAME);
f6bcfd97 1977 if (!wxStrcmp(SQLState, wxT("37000")))
1e92909e 1978 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL);
f6bcfd97 1979 if (!wxStrcmp(SQLState, wxT("3C000")))
1e92909e 1980 return(DB_ERR_DUPLICATE_CURSOR_NAME);
f6bcfd97 1981 if (!wxStrcmp(SQLState, wxT("40001")))
1e92909e 1982 return(DB_ERR_SERIALIZATION_FAILURE);
f6bcfd97 1983 if (!wxStrcmp(SQLState, wxT("42000")))
1e92909e 1984 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2);
f6bcfd97 1985 if (!wxStrcmp(SQLState, wxT("70100")))
1e92909e 1986 return(DB_ERR_OPERATION_ABORTED);
f6bcfd97 1987 if (!wxStrcmp(SQLState, wxT("IM001")))
1e92909e 1988 return(DB_ERR_UNSUPPORTED_FUNCTION);
f6bcfd97 1989 if (!wxStrcmp(SQLState, wxT("IM002")))
1e92909e 1990 return(DB_ERR_NO_DATA_SOURCE);
f6bcfd97 1991 if (!wxStrcmp(SQLState, wxT("IM003")))
1e92909e 1992 return(DB_ERR_DRIVER_LOAD_ERROR);
f6bcfd97 1993 if (!wxStrcmp(SQLState, wxT("IM004")))
1e92909e 1994 return(DB_ERR_SQLALLOCENV_FAILED);
f6bcfd97 1995 if (!wxStrcmp(SQLState, wxT("IM005")))
1e92909e 1996 return(DB_ERR_SQLALLOCCONNECT_FAILED);
f6bcfd97 1997 if (!wxStrcmp(SQLState, wxT("IM006")))
1e92909e 1998 return(DB_ERR_SQLSETCONNECTOPTION_FAILED);
f6bcfd97 1999 if (!wxStrcmp(SQLState, wxT("IM007")))
1e92909e 2000 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB);
f6bcfd97 2001 if (!wxStrcmp(SQLState, wxT("IM008")))
1e92909e 2002 return(DB_ERR_DIALOG_FAILED);
f6bcfd97 2003 if (!wxStrcmp(SQLState, wxT("IM009")))
1e92909e 2004 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL);
f6bcfd97 2005 if (!wxStrcmp(SQLState, wxT("IM010")))
1e92909e 2006 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG);
f6bcfd97 2007 if (!wxStrcmp(SQLState, wxT("IM011")))
1e92909e 2008 return(DB_ERR_DRIVER_NAME_TOO_LONG);
f6bcfd97 2009 if (!wxStrcmp(SQLState, wxT("IM012")))
1e92909e 2010 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR);
f6bcfd97 2011 if (!wxStrcmp(SQLState, wxT("IM013")))
1e92909e 2012 return(DB_ERR_TRACE_FILE_ERROR);
f6bcfd97 2013 if (!wxStrcmp(SQLState, wxT("S0001")))
1e92909e 2014 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS);
f6bcfd97 2015 if (!wxStrcmp(SQLState, wxT("S0002")))
1e92909e 2016 return(DB_ERR_TABLE_NOT_FOUND);
f6bcfd97 2017 if (!wxStrcmp(SQLState, wxT("S0011")))
1e92909e 2018 return(DB_ERR_INDEX_ALREADY_EXISTS);
f6bcfd97 2019 if (!wxStrcmp(SQLState, wxT("S0012")))
1e92909e 2020 return(DB_ERR_INDEX_NOT_FOUND);
f6bcfd97 2021 if (!wxStrcmp(SQLState, wxT("S0021")))
1e92909e 2022 return(DB_ERR_COLUMN_ALREADY_EXISTS);
f6bcfd97 2023 if (!wxStrcmp(SQLState, wxT("S0022")))
1e92909e 2024 return(DB_ERR_COLUMN_NOT_FOUND);
f6bcfd97 2025 if (!wxStrcmp(SQLState, wxT("S0023")))
1e92909e 2026 return(DB_ERR_NO_DEFAULT_FOR_COLUMN);
f6bcfd97 2027 if (!wxStrcmp(SQLState, wxT("S1000")))
1e92909e 2028 return(DB_ERR_GENERAL_ERROR);
f6bcfd97 2029 if (!wxStrcmp(SQLState, wxT("S1001")))
1e92909e 2030 return(DB_ERR_MEMORY_ALLOCATION_FAILURE);
f6bcfd97 2031 if (!wxStrcmp(SQLState, wxT("S1002")))
1e92909e 2032 return(DB_ERR_INVALID_COLUMN_NUMBER);
f6bcfd97 2033 if (!wxStrcmp(SQLState, wxT("S1003")))
1e92909e 2034 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE);
f6bcfd97 2035 if (!wxStrcmp(SQLState, wxT("S1004")))
1e92909e 2036 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE);
f6bcfd97 2037 if (!wxStrcmp(SQLState, wxT("S1008")))
1e92909e 2038 return(DB_ERR_OPERATION_CANCELLED);
f6bcfd97 2039 if (!wxStrcmp(SQLState, wxT("S1009")))
1e92909e 2040 return(DB_ERR_INVALID_ARGUMENT_VALUE);
f6bcfd97 2041 if (!wxStrcmp(SQLState, wxT("S1010")))
1e92909e 2042 return(DB_ERR_FUNCTION_SEQUENCE_ERROR);
f6bcfd97 2043 if (!wxStrcmp(SQLState, wxT("S1011")))
1e92909e 2044 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME);
f6bcfd97 2045 if (!wxStrcmp(SQLState, wxT("S1012")))
1e92909e 2046 return(DB_ERR_INVALID_TRANS_OPERATION_CODE);
f6bcfd97 2047 if (!wxStrcmp(SQLState, wxT("S1015")))
1e92909e 2048 return(DB_ERR_NO_CURSOR_NAME_AVAIL);
f6bcfd97 2049 if (!wxStrcmp(SQLState, wxT("S1090")))
1e92909e 2050 return(DB_ERR_INVALID_STR_OR_BUF_LEN);
f6bcfd97 2051 if (!wxStrcmp(SQLState, wxT("S1091")))
1e92909e 2052 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE);
f6bcfd97 2053 if (!wxStrcmp(SQLState, wxT("S1092")))
1e92909e 2054 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE);
f6bcfd97 2055 if (!wxStrcmp(SQLState, wxT("S1093")))
1e92909e 2056 return(DB_ERR_INVALID_PARAM_NO);
f6bcfd97 2057 if (!wxStrcmp(SQLState, wxT("S1094")))
1e92909e 2058 return(DB_ERR_INVALID_SCALE_VALUE);
f6bcfd97 2059 if (!wxStrcmp(SQLState, wxT("S1095")))
1e92909e 2060 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE);
f6bcfd97 2061 if (!wxStrcmp(SQLState, wxT("S1096")))
1e92909e 2062 return(DB_ERR_INF_TYPE_OUT_OF_RANGE);
f6bcfd97 2063 if (!wxStrcmp(SQLState, wxT("S1097")))
1e92909e 2064 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE);
f6bcfd97 2065 if (!wxStrcmp(SQLState, wxT("S1098")))
1e92909e 2066 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE);
f6bcfd97 2067 if (!wxStrcmp(SQLState, wxT("S1099")))
1e92909e 2068 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE);
f6bcfd97 2069 if (!wxStrcmp(SQLState, wxT("S1100")))
1e92909e 2070 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE);
f6bcfd97 2071 if (!wxStrcmp(SQLState, wxT("S1101")))
1e92909e 2072 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE);
f6bcfd97 2073 if (!wxStrcmp(SQLState, wxT("S1103")))
1e92909e 2074 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE);
f6bcfd97 2075 if (!wxStrcmp(SQLState, wxT("S1104")))
1e92909e 2076 return(DB_ERR_INVALID_PRECISION_VALUE);
f6bcfd97 2077 if (!wxStrcmp(SQLState, wxT("S1105")))
1e92909e 2078 return(DB_ERR_INVALID_PARAM_TYPE);
f6bcfd97 2079 if (!wxStrcmp(SQLState, wxT("S1106")))
1e92909e 2080 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE);
f6bcfd97 2081 if (!wxStrcmp(SQLState, wxT("S1107")))
1e92909e 2082 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE);
f6bcfd97 2083 if (!wxStrcmp(SQLState, wxT("S1108")))
1e92909e 2084 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE);
f6bcfd97 2085 if (!wxStrcmp(SQLState, wxT("S1109")))
1e92909e 2086 return(DB_ERR_INVALID_CURSOR_POSITION);
f6bcfd97 2087 if (!wxStrcmp(SQLState, wxT("S1110")))
1e92909e 2088 return(DB_ERR_INVALID_DRIVER_COMPLETION);
f6bcfd97 2089 if (!wxStrcmp(SQLState, wxT("S1111")))
1e92909e 2090 return(DB_ERR_INVALID_BOOKMARK_VALUE);
f6bcfd97 2091 if (!wxStrcmp(SQLState, wxT("S1C00")))
1e92909e 2092 return(DB_ERR_DRIVER_NOT_CAPABLE);
f6bcfd97 2093 if (!wxStrcmp(SQLState, wxT("S1T00")))
1e92909e
GT
2094 return(DB_ERR_TIMEOUT_EXPIRED);
2095
2096 // No match
2097 return(0);
108106cf 2098
f6bcfd97 2099} // wxDb::TranslateSqlState()
67e9aaa3 2100
23f681ec 2101
f6bcfd97 2102/********** wxDb::Grant() **********/
4fdae997 2103bool wxDb::Grant(int privileges, const wxString &tableName, const wxString &userList)
108106cf 2104{
1e92909e
GT
2105 wxString sqlStmt;
2106
2107 // Build the grant statement
4fdae997 2108 sqlStmt = wxT("GRANT ");
1e92909e 2109 if (privileges == DB_GRANT_ALL)
4fdae997 2110 sqlStmt += wxT("ALL");
1e92909e
GT
2111 else
2112 {
2113 int c = 0;
2114 if (privileges & DB_GRANT_SELECT)
2115 {
4fdae997 2116 sqlStmt += wxT("SELECT");
1e92909e
GT
2117 c++;
2118 }
2119 if (privileges & DB_GRANT_INSERT)
2120 {
2121 if (c++)
4fdae997
GT
2122 sqlStmt += wxT(", ");
2123 sqlStmt += wxT("INSERT");
1e92909e
GT
2124 }
2125 if (privileges & DB_GRANT_UPDATE)
2126 {
2127 if (c++)
4fdae997
GT
2128 sqlStmt += wxT(", ");
2129 sqlStmt += wxT("UPDATE");
1e92909e
GT
2130 }
2131 if (privileges & DB_GRANT_DELETE)
2132 {
2133 if (c++)
4fdae997
GT
2134 sqlStmt += wxT(", ");
2135 sqlStmt += wxT("DELETE");
1e92909e
GT
2136 }
2137 }
2138
4fdae997 2139 sqlStmt += wxT(" ON ");
243d4b36 2140 sqlStmt += SQLTableName(tableName);
4fdae997 2141 sqlStmt += wxT(" TO ");
1e92909e 2142 sqlStmt += userList;
108106cf 2143
1fc5dd6f 2144#ifdef DBDEBUG_CONSOLE
f6bcfd97 2145 cout << endl << sqlStmt.c_str() << endl;
108106cf
JS
2146#endif
2147
4fdae997 2148 WriteSqlLog(sqlStmt);
1fc5dd6f 2149
4fdae997 2150 return(ExecSql(sqlStmt));
108106cf 2151
f6bcfd97 2152} // wxDb::Grant()
108106cf 2153
67e9aaa3 2154
f6bcfd97 2155/********** wxDb::CreateView() **********/
4fdae997
GT
2156bool wxDb::CreateView(const wxString &viewName, const wxString &colList,
2157 const wxString &pSqlStmt, bool attemptDrop)
108106cf 2158{
1e92909e
GT
2159 wxString sqlStmt;
2160
2161 // Drop the view first
2162 if (attemptDrop && !DropView(viewName))
68379eaf 2163 return false;
1e92909e
GT
2164
2165 // Build the create view statement
4fdae997 2166 sqlStmt = wxT("CREATE VIEW ");
1e92909e 2167 sqlStmt += viewName;
23f681ec 2168
8e3f3880 2169 if (colList.length())
1e92909e 2170 {
4fdae997 2171 sqlStmt += wxT(" (");
1e92909e 2172 sqlStmt += colList;
4fdae997 2173 sqlStmt += wxT(")");
1e92909e 2174 }
108106cf 2175
4fdae997 2176 sqlStmt += wxT(" AS ");
1e92909e 2177 sqlStmt += pSqlStmt;
108106cf 2178
4fdae997 2179 WriteSqlLog(sqlStmt);
1fc5dd6f
JS
2180
2181#ifdef DBDEBUG_CONSOLE
f6bcfd97 2182 cout << sqlStmt.c_str() << endl;
108106cf
JS
2183#endif
2184
4fdae997 2185 return(ExecSql(sqlStmt));
108106cf 2186
f6bcfd97 2187} // wxDb::CreateView()
108106cf 2188
67e9aaa3 2189
f6bcfd97 2190/********** wxDb::DropView() **********/
4fdae997 2191bool wxDb::DropView(const wxString &viewName)
a2115c88 2192{
67e9aaa3 2193/*
68379eaf 2194 * NOTE: This function returns true if the View does not exist, but
67e9aaa3 2195 * only for identified databases. Code will need to be added
1e92909e 2196 * below for any other databases when those databases are defined
67e9aaa3
GT
2197 * to handle this situation consistently
2198 */
1e92909e 2199 wxString sqlStmt;
a2115c88 2200
942e67c3 2201 sqlStmt.Printf(wxT("DROP VIEW %s"), viewName.c_str());
a2115c88 2202
4fdae997 2203 WriteSqlLog(sqlStmt);
a2115c88
GT
2204
2205#ifdef DBDEBUG_CONSOLE
f6bcfd97 2206 cout << endl << sqlStmt.c_str() << endl;
a2115c88
GT
2207#endif
2208
8a39593e 2209 if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS)
1e92909e
GT
2210 {
2211 // Check for "Base table not found" error and ignore
2212 GetNextError(henv, hdbc, hstmt);
f6bcfd97 2213 if (wxStrcmp(sqlState,wxT("S0002"))) // "Base table not found"
1e92909e
GT
2214 {
2215 // Check for product specific error codes
f6bcfd97 2216 if (!((Dbms() == dbmsSYBASE_ASA && !wxStrcmp(sqlState,wxT("42000"))))) // 5.x (and lower?)
1e92909e
GT
2217 {
2218 DispNextError();
2219 DispAllErrors(henv, hdbc, hstmt);
2220 RollbackTrans();
68379eaf 2221 return false;
1e92909e
GT
2222 }
2223 }
2224 }
2225
2226 // Commit the transaction
2c257434 2227 if (!CommitTrans())
68379eaf 2228 return false;
1e92909e 2229
68379eaf 2230 return true;
a2115c88 2231
f6bcfd97 2232} // wxDb::DropView()
a2115c88
GT
2233
2234
f6bcfd97 2235/********** wxDb::ExecSql() **********/
4fdae997 2236bool wxDb::ExecSql(const wxString &pSqlStmt)
108106cf 2237{
2beca662
GT
2238 RETCODE retcode;
2239
1e92909e 2240 SQLFreeStmt(hstmt, SQL_CLOSE);
2beca662 2241
8a39593e 2242 retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS);
5600884a 2243 if (retcode == SQL_SUCCESS ||
2beca662
GT
2244 (Dbms() == dbmsDB2 && (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_NO_DATA_FOUND)))
2245 {
68379eaf 2246 return true;
2beca662 2247 }
1e92909e
GT
2248 else
2249 {
2250 DispAllErrors(henv, hdbc, hstmt);
68379eaf 2251 return false;
1e92909e 2252 }
108106cf 2253
f6bcfd97 2254} // wxDb::ExecSql()
108106cf 2255
67e9aaa3 2256
a6f4dbbd 2257/********** wxDb::ExecSql() with column info **********/
08429a81 2258bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcols)
f110f395
RN
2259{
2260 //execute the statement first
c9065104
GT
2261 if (!ExecSql(pSqlStmt))
2262 return false;
f110f395
RN
2263
2264 SWORD noCols;
c9065104 2265 if (SQLNumResultCols(hstmt, &noCols) != SQL_SUCCESS)
f110f395
RN
2266 {
2267 DispAllErrors(henv, hdbc, hstmt);
2268 return false;
2269 }
a6f4dbbd 2270
c9065104
GT
2271 if (noCols == 0)
2272 return false;
a6f4dbbd 2273 else
c9065104 2274 numcols = noCols;
a6f4dbbd 2275
f110f395
RN
2276 // Get column information
2277 short colNum;
c9065104 2278 wxChar name[DB_MAX_COLUMN_NAME_LEN+1];
f110f395 2279 SWORD Sword;
e716b9be 2280 SQLLEN Sqllen;
f110f395 2281 wxDbColInf* pColInf = new wxDbColInf[noCols];
a6f4dbbd 2282
7086c32a 2283 // Fill in column information (name, datatype)
a6f4dbbd 2284 for (colNum = 0; colNum < noCols; colNum++)
f110f395 2285 {
bb8a8478 2286 if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_NAME,
f110f395 2287 name, sizeof(name),
e716b9be 2288 &Sword, &Sqllen) != SQL_SUCCESS)
f110f395
RN
2289 {
2290 DispAllErrors(henv, hdbc, hstmt);
2291 delete[] pColInf;
2292 return false;
2293 }
a6f4dbbd 2294
c9065104 2295 wxStrncpy(pColInf[colNum].colName, name, DB_MAX_COLUMN_NAME_LEN);
7086c32a 2296 pColInf[colNum].colName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun
a6f4dbbd 2297
bb8a8478 2298 if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_TYPE,
e716b9be 2299 NULL, 0, &Sword, &Sqllen) != SQL_SUCCESS)
f110f395
RN
2300 {
2301 DispAllErrors(henv, hdbc, hstmt);
2302 delete[] pColInf;
2303 return false;
2304 }
a6f4dbbd 2305
e716b9be 2306 switch (Sqllen)
f110f395 2307 {
69baadbb
GT
2308#if wxUSE_UNICODE
2309 #if defined(SQL_WCHAR)
362a97bf 2310 case SQL_WCHAR:
69baadbb
GT
2311 #endif
2312 #if defined(SQL_WVARCHAR)
362a97bf 2313 case SQL_WVARCHAR:
69baadbb
GT
2314 #endif
2315#endif
c9065104
GT
2316 case SQL_VARCHAR:
2317 case SQL_CHAR:
2318 pColInf[colNum].dbDataType = DB_DATA_TYPE_VARCHAR;
2319 break;
7eeba511
JS
2320 case SQL_LONGVARCHAR:
2321 pColInf[colNum].dbDataType = DB_DATA_TYPE_MEMO;
8e3f3880 2322 break;
c9065104
GT
2323 case SQL_TINYINT:
2324 case SQL_SMALLINT:
2325 case SQL_INTEGER:
2326 case SQL_BIT:
2327 pColInf[colNum].dbDataType = DB_DATA_TYPE_INTEGER;
2328 break;
2329 case SQL_DOUBLE:
2330 case SQL_DECIMAL:
2331 case SQL_NUMERIC:
2332 case SQL_FLOAT:
2333 case SQL_REAL:
2334 pColInf[colNum].dbDataType = DB_DATA_TYPE_FLOAT;
2335 break;
2336 case SQL_DATE:
2337 case SQL_TIMESTAMP:
2338 pColInf[colNum].dbDataType = DB_DATA_TYPE_DATE;
2339 break;
2340 case SQL_BINARY:
2341 pColInf[colNum].dbDataType = DB_DATA_TYPE_BLOB;
2342 break;
f110f395 2343#ifdef __WXDEBUG__
c9065104
GT
2344 default:
2345 wxString errMsg;
e716b9be 2346 errMsg.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sqllen);
c9065104 2347 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
f110f395
RN
2348#endif
2349 }
2350 }
a6f4dbbd 2351
f110f395
RN
2352 *columns = pColInf;
2353 return true;
c9065104 2354} // wxDb::ExecSql()
f110f395 2355
f6bcfd97
BP
2356/********** wxDb::GetNext() **********/
2357bool wxDb::GetNext(void)
a2115c88 2358{
1e92909e 2359 if (SQLFetch(hstmt) == SQL_SUCCESS)
68379eaf 2360 return true;
1e92909e
GT
2361 else
2362 {
2363 DispAllErrors(henv, hdbc, hstmt);
68379eaf 2364 return false;
1e92909e 2365 }
a2115c88 2366
f6bcfd97 2367} // wxDb::GetNext()
a2115c88 2368
67e9aaa3 2369
f6bcfd97 2370/********** wxDb::GetData() **********/
e716b9be 2371bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SQLLEN FAR *cbReturned)
a2115c88 2372{
4fdae997
GT
2373 wxASSERT(pData);
2374 wxASSERT(cbReturned);
a2115c88 2375
e4e45573
GT
2376 long bufferSize = maxLen;
2377
2378 if (cType == SQL_C_WXCHAR)
2379 bufferSize = maxLen * sizeof(wxChar);
2380
2381 if (SQLGetData(hstmt, colNo, cType, pData, bufferSize, cbReturned) == SQL_SUCCESS)
68379eaf 2382 return true;
1e92909e
GT
2383 else
2384 {
2385 DispAllErrors(henv, hdbc, hstmt);
68379eaf 2386 return false;
1e92909e 2387 }
a2115c88 2388
f6bcfd97 2389} // wxDb::GetData()
a2115c88 2390
67e9aaa3 2391
f6bcfd97 2392/********** wxDb::GetKeyFields() **********/
02cf6fdd 2393int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCols)
67e9aaa3 2394{
4fdae997
GT
2395 wxChar szPkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Primary key table name */
2396 wxChar szFkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Foreign key table name */
564c92d9 2397 SWORD iKeySeq;
4fdae997
GT
2398 wxChar szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */
2399 wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */
67e9aaa3 2400 SQLRETURN retcode;
e716b9be 2401 SQLLEN cb;
02cf6fdd 2402 SWORD i;
4fdae997 2403 wxString tempStr;
67e9aaa3 2404 /*
4fdae997
GT
2405 * -----------------------------------------------------------------------
2406 * -- 19991224 : mj10777 : Create ------
2407 * -- : Three things are done and stored here : ------
2408 * -- : 1) which Column(s) is/are Primary Key(s) ------
2409 * -- : 2) which tables use this Key as a Foreign Key ------
2410 * -- : 3) which columns are Foreign Key and the name ------
2411 * -- : of the Table where the Key is the Primary Key -----
2412 * -- : Called from GetColumns(const wxString &tableName, ------
2413 * -- int *numCols,const wxChar *userID ) ------
2414 * -----------------------------------------------------------------------
67e9aaa3
GT
2415 */
2416
2417 /*---------------------------------------------------------------------*/
2418 /* Get the names of the columns in the primary key. */
2419 /*---------------------------------------------------------------------*/
2420 retcode = SQLPrimaryKeys(hstmt,
4fdae997
GT
2421 NULL, 0, /* Catalog name */
2422 NULL, 0, /* Schema name */
8a39593e 2423 (SQLTCHAR FAR *) tableName.c_str(), SQL_NTS); /* Table name */
67e9aaa3
GT
2424
2425 /*---------------------------------------------------------------------*/
2426 /* Fetch and display the result set. This will be a list of the */
2427 /* columns in the primary key of the tableName table. */
2428 /*---------------------------------------------------------------------*/
2429 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
2430 {
2431 retcode = SQLFetch(hstmt);
2432 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
2433 {
e4e45573 2434 GetData( 4, SQL_C_WXCHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
67e9aaa3
GT
2435 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
2436 //-------
2437 for (i=0;i<noCols;i++) // Find the Column name
2438 if (!wxStrcmp(colInf[i].colName,szPkCol)) // We have found the Column
2439 colInf[i].PkCol = iKeySeq; // Which Primary Key is this (first, second usw.) ?
3ca6a5f0
BP
2440 } // if
2441 } // while
67e9aaa3
GT
2442 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
2443
2444 /*---------------------------------------------------------------------*/
2445 /* Get all the foreign keys that refer to tableName primary key. */
2446 /*---------------------------------------------------------------------*/
2447 retcode = SQLForeignKeys(hstmt,
4fdae997
GT
2448 NULL, 0, /* Primary catalog */
2449 NULL, 0, /* Primary schema */
8a39593e 2450 (SQLTCHAR FAR *)tableName.c_str(), SQL_NTS,/* Primary table */
4fdae997
GT
2451 NULL, 0, /* Foreign catalog */
2452 NULL, 0, /* Foreign schema */
2453 NULL, 0); /* Foreign table */
67e9aaa3
GT
2454
2455 /*---------------------------------------------------------------------*/
2456 /* Fetch and display the result set. This will be all of the foreign */
2457 /* keys in other tables that refer to the tableName primary key. */
2458 /*---------------------------------------------------------------------*/
4fdae997 2459 tempStr.Empty();
67e9aaa3
GT
2460 szPkCol[0] = 0;
2461 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
2462 {
2463 retcode = SQLFetch(hstmt);
2464 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
2465 {
e4e45573
GT
2466 GetData( 3, SQL_C_WXCHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
2467 GetData( 4, SQL_C_WXCHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2468 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
2469 GetData( 7, SQL_C_WXCHAR, szFkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
2470 GetData( 8, SQL_C_WXCHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
f8be01b1 2471 tempStr << _T('[') << szFkTable << _T(']'); // [ ] in case there is a blank in the Table name
3ca6a5f0
BP
2472 } // if
2473 } // while
4fdae997
GT
2474
2475 tempStr.Trim(); // Get rid of any unneeded blanks
bb8a8478 2476 if (!tempStr.empty())
67e9aaa3 2477 {
4fdae997 2478 for (i=0; i<noCols; i++)
3ca6a5f0 2479 { // Find the Column name
4fdae997 2480 if (!wxStrcmp(colInf[i].colName, szPkCol)) // We have found the Column, store the Information
7086c32a
GT
2481 {
2482 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
2483 colInf[i].PkTableName[DB_MAX_TABLE_NAME_LEN] = 0; // Prevent buffer overrun
2484 }
3ca6a5f0
BP
2485 }
2486 } // if
4fdae997 2487
67e9aaa3
GT
2488 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
2489
2490 /*---------------------------------------------------------------------*/
2491 /* Get all the foreign keys in the tablename table. */
2492 /*---------------------------------------------------------------------*/
2493 retcode = SQLForeignKeys(hstmt,
4fdae997
GT
2494 NULL, 0, /* Primary catalog */
2495 NULL, 0, /* Primary schema */
2496 NULL, 0, /* Primary table */
2497 NULL, 0, /* Foreign catalog */
2498 NULL, 0, /* Foreign schema */
8a39593e 2499 (SQLTCHAR *)tableName.c_str(), SQL_NTS);/* Foreign table */
67e9aaa3
GT
2500
2501 /*---------------------------------------------------------------------*/
2502 /* Fetch and display the result set. This will be all of the */
2503 /* primary keys in other tables that are referred to by foreign */
2504 /* keys in the tableName table. */
2505 /*---------------------------------------------------------------------*/
67e9aaa3
GT
2506 while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
2507 {
2508 retcode = SQLFetch(hstmt);
2509 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
2510 {
e4e45573
GT
2511 GetData( 3, SQL_C_WXCHAR, szPkTable, DB_MAX_TABLE_NAME_LEN+1, &cb);
2512 GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb);
2513 GetData( 8, SQL_C_WXCHAR, szFkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb);
67e9aaa3 2514 //-------
4fdae997 2515 for (i=0; i<noCols; i++) // Find the Column name
67e9aaa3
GT
2516 {
2517 if (!wxStrcmp(colInf[i].colName,szFkCol)) // We have found the (Foreign Key) Column
2518 {
2519 colInf[i].FkCol = iKeySeq; // Which Foreign Key is this (first, second usw.) ?
7086c32a
GT
2520 wxStrncpy(colInf[i].FkTableName, szFkTable, DB_MAX_TABLE_NAME_LEN); // Name of the Table where this Foriegn is the Primary Key
2521 colInf[i].FkTableName[DB_MAX_TABLE_NAME_LEN] = 0; // Prevent buffer overrun
3ca6a5f0
BP
2522 } // if
2523 } // for
2524 } // if
2525 } // while
67e9aaa3
GT
2526 SQLFreeStmt(hstmt, SQL_CLOSE); /* Close the cursor (the hstmt is still allocated). */
2527
a144affe 2528 return TRUE;
3ca6a5f0 2529
f6bcfd97 2530} // wxDb::GetKeyFields()
67e9aaa3
GT
2531
2532
f6bcfd97
BP
2533#if OLD_GETCOLUMNS
2534/********** wxDb::GetColumns() **********/
4fdae997 2535wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
108106cf 2536/*
1e92909e
GT
2537 * 1) The last array element of the tableName[] argument must be zero (null).
2538 * This is how the end of the array is detected.
f6bcfd97 2539 * 2) This function returns an array of wxDbColInf structures. If no columns
3103e8a9 2540 * were found, or an error occurred, this pointer will be zero (null). THE
1e92909e
GT
2541 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
2542 * IS FINISHED WITH IT. i.e.
108106cf 2543 *
f6bcfd97 2544 * wxDbColInf *colInf = pDb->GetColumns(tableList, userID);
1e92909e
GT
2545 * if (colInf)
2546 * {
2547 * // Use the column inf
2548 * .......
2549 * // Destroy the memory
2550 * delete [] colInf;
2551 * }
67e9aaa3
GT
2552 *
2553 * userID is evaluated in the following manner:
1e92909e
GT
2554 * userID == NULL ... UserID is ignored
2555 * userID == "" ... UserID set equal to 'this->uid'
2556 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 2557 *
f6bcfd97
BP
2558 * NOTE: ALL column bindings associated with this wxDb instance are unbound
2559 * by this function. This function should use its own wxDb instance
ea5d599d 2560 * to avoid undesired unbinding of columns.
108106cf 2561 */
108106cf 2562{
081eb1b1 2563 UWORD noCols = 0;
2c257434 2564 UWORD colNo = 0;
f6bcfd97 2565 wxDbColInf *colInf = 0;
1e92909e
GT
2566
2567 RETCODE retcode;
e716b9be 2568 SQLLEN cb;
1e92909e 2569
1e92909e
GT
2570 wxString TableName;
2571
4fdae997
GT
2572 wxString UserID;
2573 convertUserID(userID,UserID);
1e92909e
GT
2574
2575 // Pass 1 - Determine how many columns there are.
f6bcfd97 2576 // Pass 2 - Allocate the wxDbColInf array and fill in
1e92909e
GT
2577 // the array with the column information.
2578 int pass;
2579 for (pass = 1; pass <= 2; pass++)
2580 {
2581 if (pass == 2)
2582 {
2583 if (noCols == 0) // Probably a bogus table name(s)
2584 break;
f6bcfd97
BP
2585 // Allocate n wxDbColInf objects to hold the column information
2586 colInf = new wxDbColInf[noCols+1];
1e92909e
GT
2587 if (!colInf)
2588 break;
2589 // Mark the end of the array
7086c32a
GT
2590 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
2591 wxStrcpy(colInf[noCols].colName, wxEmptyString);
1e92909e
GT
2592 colInf[noCols].sqlDataType = 0;
2593 }
2594 // Loop through each table name
2595 int tbl;
2596 for (tbl = 0; tableName[tbl]; tbl++)
2597 {
2598 TableName = tableName[tbl];
d8a0a1c9 2599 // Oracle and Interbase table names are uppercase only, so force
1e92909e 2600 // the name to uppercase just in case programmer forgot to do this
eedb1543 2601 if ((Dbms() == dbmsORACLE) ||
215a0070 2602 (Dbms() == dbmsFIREBIRD) ||
d8a0a1c9 2603 (Dbms() == dbmsINTERBASE))
1e92909e
GT
2604 TableName = TableName.Upper();
2605
2606 SQLFreeStmt(hstmt, SQL_CLOSE);
2607
a8aa2258 2608 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
1e92909e 2609 // use the call below that leaves out the user name
bb8a8478 2610 if (!UserID.empty() &&
4fdae997
GT
2611 Dbms() != dbmsMY_SQL &&
2612 Dbms() != dbmsACCESS &&
2613 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
2614 {
2615 retcode = SQLColumns(hstmt,
2616 NULL, 0, // All qualifiers
8a39593e
JS
2617 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner
2618 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2619 NULL, 0); // All columns
2620 }
2621 else
2622 {
2623 retcode = SQLColumns(hstmt,
2624 NULL, 0, // All qualifiers
2625 NULL, 0, // Owner
8a39593e 2626 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2627 NULL, 0); // All columns
2628 }
2629 if (retcode != SQL_SUCCESS)
3103e8a9 2630 { // Error occurred, abort
1e92909e
GT
2631 DispAllErrors(henv, hdbc, hstmt);
2632 if (colInf)
2633 delete [] colInf;
2634 SQLFreeStmt(hstmt, SQL_CLOSE);
2635 return(0);
2636 }
2637
2638 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2639 {
2640 if (pass == 1) // First pass, just add up the number of columns
2641 noCols++;
2642 else // Pass 2; Fill in the array of structures
2643 {
2644 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2645 {
2646 // NOTE: Only the ODBC 1.x fields are retrieved
e4e45573
GT
2647 GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2648 GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2649 GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2650 GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1e92909e 2651 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
e4e45573
GT
2652 GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
2653 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb);
2654 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb);
1e92909e
GT
2655 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2656 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2657 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
e4e45573 2658 GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
eedb1543 2659
f6bcfd97 2660 // Determine the wxDb data type that is used to represent the native data type of this data source
1e92909e
GT
2661 colInf[colNo].dbDataType = 0;
2662 if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName))
52a17fe5 2663 {
eedb1543 2664#ifdef _IODBC_
e4e45573
GT
2665 // IODBC does not return a correct columnLength, so we set
2666 // columnLength = bufferSize if no column length was returned
2667 // IODBC returns the columnLength in bufferSize. (bug)
2668 if (colInf[colNo].columnLength < 1)
52a17fe5 2669 {
e4e45573 2670 colInf[colNo].columnLength = colInf[colNo].bufferSize;
52a17fe5 2671 }
a8aa2258 2672#endif
1e92909e 2673 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
52a17fe5 2674 }
bf5423ea 2675 else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName))
1e92909e 2676 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
bf5423ea 2677 else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName))
1e92909e 2678 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
bf5423ea 2679 else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName))
1e92909e 2680 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
bf5423ea
GT
2681 else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName))
2682 colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
1e92909e
GT
2683 colNo++;
2684 }
2685 }
2686 }
2687 if (retcode != SQL_NO_DATA_FOUND)
3103e8a9 2688 { // Error occurred, abort
1e92909e
GT
2689 DispAllErrors(henv, hdbc, hstmt);
2690 if (colInf)
2691 delete [] colInf;
2692 SQLFreeStmt(hstmt, SQL_CLOSE);
2693 return(0);
2694 }
2695 }
2696 }
2697
2698 SQLFreeStmt(hstmt, SQL_CLOSE);
2699 return colInf;
108106cf 2700
f6bcfd97 2701} // wxDb::GetColumns()
108106cf
JS
2702
2703
f6bcfd97
BP
2704/********** wxDb::GetColumns() **********/
2705
02cf6fdd 2706wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wxChar *userID)
f6bcfd97
BP
2707//
2708// Same as the above GetColumns() function except this one gets columns
2709// only for a single table, and if 'numCols' is not NULL, the number of
2710// columns stored in the returned wxDbColInf is set in '*numCols'
2711//
2712// userID is evaluated in the following manner:
2713// userID == NULL ... UserID is ignored
2714// userID == "" ... UserID set equal to 'this->uid'
2715// userID != "" ... UserID set equal to 'userID'
2716//
2717// NOTE: ALL column bindings associated with this wxDb instance are unbound
2718// by this function. This function should use its own wxDb instance
2719// to avoid undesired unbinding of columns.
2720
67e9aaa3 2721{
02cf6fdd 2722 UWORD noCols = 0;
e938ff5e 2723 UWORD colNo = 0;
f6bcfd97 2724 wxDbColInf *colInf = 0;
1e92909e
GT
2725
2726 RETCODE retcode;
e716b9be 2727 SQLLEN cb;
1e92909e 2728
1e92909e
GT
2729 wxString TableName;
2730
4fdae997
GT
2731 wxString UserID;
2732 convertUserID(userID,UserID);
1e92909e
GT
2733
2734 // Pass 1 - Determine how many columns there are.
f6bcfd97 2735 // Pass 2 - Allocate the wxDbColInf array and fill in
1e92909e
GT
2736 // the array with the column information.
2737 int pass;
2738 for (pass = 1; pass <= 2; pass++)
2739 {
2740 if (pass == 2)
2741 {
2742 if (noCols == 0) // Probably a bogus table name(s)
2743 break;
f6bcfd97
BP
2744 // Allocate n wxDbColInf objects to hold the column information
2745 colInf = new wxDbColInf[noCols+1];
1e92909e
GT
2746 if (!colInf)
2747 break;
2748 // Mark the end of the array
da99271d
GT
2749 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
2750 wxStrcpy(colInf[noCols].colName, wxEmptyString);
7086c32a 2751 colInf[noCols].sqlDataType = 0;
1e92909e
GT
2752 }
2753
2754 TableName = tableName;
d8a0a1c9 2755 // Oracle and Interbase table names are uppercase only, so force
1e92909e 2756 // the name to uppercase just in case programmer forgot to do this
eedb1543 2757 if ((Dbms() == dbmsORACLE) ||
215a0070 2758 (Dbms() == dbmsFIREBIRD) ||
d8a0a1c9 2759 (Dbms() == dbmsINTERBASE))
1e92909e
GT
2760 TableName = TableName.Upper();
2761
2762 SQLFreeStmt(hstmt, SQL_CLOSE);
2763
a8aa2258 2764 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
1e92909e 2765 // use the call below that leaves out the user name
bb8a8478 2766 if (!UserID.empty() &&
4fdae997
GT
2767 Dbms() != dbmsMY_SQL &&
2768 Dbms() != dbmsACCESS &&
2769 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
2770 {
2771 retcode = SQLColumns(hstmt,
2772 NULL, 0, // All qualifiers
8a39593e
JS
2773 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner
2774 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2775 NULL, 0); // All columns
2776 }
2777 else
2778 {
2779 retcode = SQLColumns(hstmt,
2780 NULL, 0, // All qualifiers
2781 NULL, 0, // Owner
8a39593e 2782 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
1e92909e
GT
2783 NULL, 0); // All columns
2784 }
2785 if (retcode != SQL_SUCCESS)
3103e8a9 2786 { // Error occurred, abort
1e92909e
GT
2787 DispAllErrors(henv, hdbc, hstmt);
2788 if (colInf)
2789 delete [] colInf;
2790 SQLFreeStmt(hstmt, SQL_CLOSE);
2791 if (numCols)
2792 *numCols = 0;
2793 return(0);
2794 }
2795
2796 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
2797 {
2798 if (pass == 1) // First pass, just add up the number of columns
2799 noCols++;
2800 else // Pass 2; Fill in the array of structures
2801 {
2802 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
2803 {
2804 // NOTE: Only the ODBC 1.x fields are retrieved
e4e45573
GT
2805 GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
2806 GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
2807 GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
2808 GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
2809 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
2810 GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
2811 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb);
67e9aaa3 2812 // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures)
e4e45573
GT
2813 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb);
2814 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
2815 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
2816 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
2817 GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
67e9aaa3
GT
2818 // Start Values for Primary/Foriegn Key (=No)
2819 colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
2820 colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
2821 colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
2822 colInf[colNo].FkTableName[0] = 0; // Foreign key table name
2823
3ca6a5f0
BP
2824 // BJO 20000428 : Virtuoso returns type names with upper cases!
2825 if (Dbms() == dbmsVIRTUOSO)
2826 {
4fdae997 2827 wxString s = colInf[colNo].typeName;
3ca6a5f0 2828 s = s.MakeLower();
eedb1543 2829 wxStrcmp(colInf[colNo].typeName, s.c_str());
3ca6a5f0 2830 }
eedb1543 2831
3ca6a5f0
BP
2832 // Determine the wxDb data type that is used to represent the native data type of this data source
2833 colInf[colNo].dbDataType = 0;
bf5423ea 2834 if (!wxStricmp(typeInfVarchar.TypeName, colInf[colNo].typeName))
3ca6a5f0 2835 {
eedb1543 2836#ifdef _IODBC_
e4e45573
GT
2837 // IODBC does not return a correct columnLength, so we set
2838 // columnLength = bufferSize if no column length was returned
2839 // IODBC returns the columnLength in bufferSize. (bug)
2840 if (colInf[colNo].columnLength < 1)
3ca6a5f0 2841 {
e4e45573 2842 colInf[colNo].columnLength = colInf[colNo].bufferSize;
3ca6a5f0 2843 }
a8aa2258
GT
2844#endif
2845
3ca6a5f0
BP
2846 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
2847 }
bf5423ea 2848 else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName))
3ca6a5f0 2849 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
bf5423ea 2850 else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName))
3ca6a5f0 2851 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
bf5423ea 2852 else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName))
eedb1543 2853 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
bf5423ea
GT
2854 else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName))
2855 colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
eedb1543 2856
1e92909e
GT
2857 colNo++;
2858 }
2859 }
2860 }
2861 if (retcode != SQL_NO_DATA_FOUND)
3103e8a9 2862 { // Error occurred, abort
1e92909e
GT
2863 DispAllErrors(henv, hdbc, hstmt);
2864 if (colInf)
3ca6a5f0 2865 delete [] colInf;
1e92909e
GT
2866 SQLFreeStmt(hstmt, SQL_CLOSE);
2867 if (numCols)
3ca6a5f0 2868 *numCols = 0;
1e92909e 2869 return(0);
3ca6a5f0 2870 }
1e92909e 2871 }
67e9aaa3
GT
2872
2873 SQLFreeStmt(hstmt, SQL_CLOSE);
2874
2875 // Store Primary and Foriegn Keys
2876 GetKeyFields(tableName,colInf,noCols);
2877
2878 if (numCols)
1e92909e
GT
2879 *numCols = noCols;
2880 return colInf;
67e9aaa3 2881
f6bcfd97
BP
2882} // wxDb::GetColumns()
2883
f6bcfd97 2884
3ca6a5f0 2885#else // New GetColumns
67e9aaa3
GT
2886
2887
f6bcfd97 2888/*
3ca6a5f0
BP
2889 BJO 20000503
2890 These are tentative new GetColumns members which should be more database
43e8916f 2891 independent and which always returns the columns in the order they were
3ca6a5f0
BP
2892 created.
2893
4fdae997
GT
2894 - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const
2895 wxChar* userID)) calls the second implementation for each separate table
eedb1543 2896 before merging the results. This makes the code easier to maintain as
3ca6a5f0 2897 only one member (the second) makes the real work
4fdae997
GT
2898 - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const
2899 wxChar *userID) is a little bit improved
eedb1543 2900 - It doesn't anymore rely on the type-name to find out which database-type
3ca6a5f0 2901 each column has
eedb1543 2902 - It ends by sorting the columns, so that they are returned in the same
3ca6a5f0 2903 order they were created
f6bcfd97
BP
2904*/
2905
2906typedef struct
2907{
02cf6fdd 2908 UWORD noCols;
3ca6a5f0 2909 wxDbColInf *colInf;
f6bcfd97
BP
2910} _TableColumns;
2911
3ca6a5f0 2912
4fdae997 2913wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID)
f6bcfd97 2914{
3ca6a5f0
BP
2915 int i, j;
2916 // The last array element of the tableName[] argument must be zero (null).
2917 // This is how the end of the array is detected.
2918
02cf6fdd 2919 UWORD noCols = 0;
3ca6a5f0
BP
2920
2921 // How many tables ?
2922 int tbl;
eedb1543
DW
2923 for (tbl = 0 ; tableName[tbl]; tbl++);
2924
3ca6a5f0
BP
2925 // Create a table to maintain the columns for each separate table
2926 _TableColumns *TableColumns = new _TableColumns[tbl];
eedb1543 2927
3ca6a5f0
BP
2928 // Fill the table
2929 for (i = 0 ; i < tbl ; i++)
eedb1543 2930
3ca6a5f0
BP
2931 {
2932 TableColumns[i].colInf = GetColumns(tableName[i], &TableColumns[i].noCols, userID);
eedb1543 2933 if (TableColumns[i].colInf == NULL)
3ca6a5f0
BP
2934 return NULL;
2935 noCols += TableColumns[i].noCols;
2936 }
eedb1543 2937
3ca6a5f0
BP
2938 // Now merge all the separate table infos
2939 wxDbColInf *colInf = new wxDbColInf[noCols+1];
eedb1543 2940
3ca6a5f0 2941 // Mark the end of the array
da99271d
GT
2942 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
2943 wxStrcpy(colInf[noCols].colName, wxEmptyString);
7086c32a 2944 colInf[noCols].sqlDataType = 0;
eedb1543 2945
3ca6a5f0
BP
2946 // Merge ...
2947 int offset = 0;
eedb1543 2948
3ca6a5f0
BP
2949 for (i = 0 ; i < tbl ; i++)
2950 {
2951 for (j = 0 ; j < TableColumns[i].noCols ; j++)
2952 {
eedb1543 2953 colInf[offset++] = TableColumns[i].colInf[j];
3ca6a5f0
BP
2954 }
2955 }
eedb1543 2956
3ca6a5f0 2957 delete [] TableColumns;
eedb1543 2958
3ca6a5f0
BP
2959 return colInf;
2960} // wxDb::GetColumns() -- NEW
f6bcfd97
BP
2961
2962
4fdae997 2963wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxChar *userID)
3ca6a5f0
BP
2964//
2965// Same as the above GetColumns() function except this one gets columns
2966// only for a single table, and if 'numCols' is not NULL, the number of
2967// columns stored in the returned wxDbColInf is set in '*numCols'
2968//
2969// userID is evaluated in the following manner:
2970// userID == NULL ... UserID is ignored
2971// userID == "" ... UserID set equal to 'this->uid'
2972// userID != "" ... UserID set equal to 'userID'
2973//
2974// NOTE: ALL column bindings associated with this wxDb instance are unbound
2975// by this function. This function should use its own wxDb instance
2976// to avoid undesired unbinding of columns.
f6bcfd97 2977{
02cf6fdd 2978 UWORD noCols = 0;
e938ff5e 2979 UWORD colNo = 0;
3ca6a5f0 2980 wxDbColInf *colInf = 0;
eedb1543 2981
3ca6a5f0
BP
2982 RETCODE retcode;
2983 SDWORD cb;
eedb1543 2984
3ca6a5f0 2985 wxString TableName;
eedb1543 2986
4fdae997
GT
2987 wxString UserID;
2988 convertUserID(userID,UserID);
eedb1543 2989
3ca6a5f0
BP
2990 // Pass 1 - Determine how many columns there are.
2991 // Pass 2 - Allocate the wxDbColInf array and fill in
2992 // the array with the column information.
2993 int pass;
2994 for (pass = 1; pass <= 2; pass++)
2995 {
2996 if (pass == 2)
f6bcfd97 2997 {
3ca6a5f0
BP
2998 if (noCols == 0) // Probably a bogus table name(s)
2999 break;
3000 // Allocate n wxDbColInf objects to hold the column information
3001 colInf = new wxDbColInf[noCols+1];
3002 if (!colInf)
3003 break;
3004 // Mark the end of the array
da99271d
GT
3005 wxStrcpy(colInf[noCols].tableName, wxEmptyString);
3006 wxStrcpy(colInf[noCols].colName, wxEmptyString);
3ca6a5f0 3007 colInf[noCols].sqlDataType = 0;
f6bcfd97 3008 }
eedb1543 3009
3ca6a5f0 3010 TableName = tableName;
d8a0a1c9 3011 // Oracle and Interbase table names are uppercase only, so force
3ca6a5f0 3012 // the name to uppercase just in case programmer forgot to do this
eedb1543 3013 if ((Dbms() == dbmsORACLE) ||
215a0070 3014 (Dbms() == dbmsFIREBIRD) ||
d8a0a1c9 3015 (Dbms() == dbmsINTERBASE))
3ca6a5f0 3016 TableName = TableName.Upper();
eedb1543 3017
3ca6a5f0 3018 SQLFreeStmt(hstmt, SQL_CLOSE);
eedb1543 3019
a8aa2258 3020 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
3ca6a5f0 3021 // use the call below that leaves out the user name
bb8a8478 3022 if (!UserID.empty() &&
3ca6a5f0 3023 Dbms() != dbmsMY_SQL &&
a8aa2258
GT
3024 Dbms() != dbmsACCESS &&
3025 Dbms() != dbmsMS_SQL_SERVER)
f6bcfd97 3026 {
3ca6a5f0
BP
3027 retcode = SQLColumns(hstmt,
3028 NULL, 0, // All qualifiers
3029 (UCHAR *) UserID.c_str(), SQL_NTS, // Owner
3030 (UCHAR *) TableName.c_str(), SQL_NTS,
3031 NULL, 0); // All columns
f6bcfd97 3032 }
3ca6a5f0 3033 else
f6bcfd97 3034 {
3ca6a5f0
BP
3035 retcode = SQLColumns(hstmt,
3036 NULL, 0, // All qualifiers
3037 NULL, 0, // Owner
3038 (UCHAR *) TableName.c_str(), SQL_NTS,
3039 NULL, 0); // All columns
f6bcfd97 3040 }
3ca6a5f0 3041 if (retcode != SQL_SUCCESS)
3103e8a9 3042 { // Error occurred, abort
3ca6a5f0
BP
3043 DispAllErrors(henv, hdbc, hstmt);
3044 if (colInf)
3045 delete [] colInf;
3046 SQLFreeStmt(hstmt, SQL_CLOSE);
3047 if (numCols)
3048 *numCols = 0;
3049 return(0);
f6bcfd97 3050 }
eedb1543 3051
f6bcfd97
BP
3052 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
3053 {
3054 if (pass == 1) // First pass, just add up the number of columns
3055 noCols++;
3056 else // Pass 2; Fill in the array of structures
3057 {
3058 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
3059 {
3060 // NOTE: Only the ODBC 1.x fields are retrieved
e4e45573
GT
3061 GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb);
3062 GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb);
3063 GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
3064 GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
3065 GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb);
3066 GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb);
3067 GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb);
3068 GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb);
3069 GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb);
3070 GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb);
3071 GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb);
3072 GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb);
f6bcfd97
BP
3073 // Start Values for Primary/Foriegn Key (=No)
3074 colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc.
3075 colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key
3076 colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc.
3077 colInf[colNo].FkTableName[0] = 0; // Foreign key table name
eedb1543
DW
3078
3079#ifdef _IODBC_
e4e45573
GT
3080 // IODBC does not return a correct columnLength, so we set
3081 // columnLength = bufferSize if no column length was returned
3082 // IODBC returns the columnLength in bufferSize. (bug)
3083 if (colInf[colNo].columnLength < 1)
a8aa2258 3084 {
e4e45573 3085 colInf[colNo].columnLength = colInf[colNo].bufferSize;
a8aa2258 3086 }
f6bcfd97 3087#endif
eedb1543 3088
3ca6a5f0
BP
3089 // Determine the wxDb data type that is used to represent the native data type of this data source
3090 colInf[colNo].dbDataType = 0;
3091 // Get the intern datatype
3092 switch (colInf[colNo].sqlDataType)
3093 {
69baadbb
GT
3094#if wxUSE_UNICODE
3095 #if defined(SQL_WCHAR)
362a97bf 3096 case SQL_WCHAR:
69baadbb
GT
3097 #endif
3098 #if defined(SQL_WVARCHAR)
362a97bf 3099 case SQL_WVARCHAR:
69baadbb
GT
3100 #endif
3101#endif
3ca6a5f0
BP
3102 case SQL_VARCHAR:
3103 case SQL_CHAR:
eedb1543 3104 colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR;
3ca6a5f0 3105 break;
8e3f3880 3106 case SQL_LONGVARCHAR:
7eeba511 3107 colInf[colNo].dbDataType = DB_DATA_TYPE_MEMO;
8e3f3880 3108 break;
3ca6a5f0
BP
3109 case SQL_TINYINT:
3110 case SQL_SMALLINT:
3111 case SQL_INTEGER:
c9065104 3112 case SQL_BIT:
eedb1543 3113 colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER;
3ca6a5f0
BP
3114 break;
3115 case SQL_DOUBLE:
3116 case SQL_DECIMAL:
3117 case SQL_NUMERIC:
3118 case SQL_FLOAT:
3119 case SQL_REAL:
eedb1543 3120 colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT;
3ca6a5f0
BP
3121 break;
3122 case SQL_DATE:
c9065104 3123 case SQL_TIMESTAMP:
eedb1543 3124 colInf[colNo].dbDataType = DB_DATA_TYPE_DATE;
3ca6a5f0 3125 break;
bf5423ea
GT
3126 case SQL_BINARY:
3127 colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB;
3128 break;
f6bcfd97 3129#ifdef __WXDEBUG__
3ca6a5f0
BP
3130 default:
3131 wxString errMsg;
77ffb593 3132 errMsg.Printf(wxT("SQL Data type %d currently not supported by wxWidgets"), colInf[colNo].sqlDataType);
3ca6a5f0 3133 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
eedb1543 3134#endif
3ca6a5f0 3135 }
f6bcfd97
BP
3136 colNo++;
3137 }
3138 }
3139 }
3140 if (retcode != SQL_NO_DATA_FOUND)
3103e8a9 3141 { // Error occurred, abort
f6bcfd97
BP
3142 DispAllErrors(henv, hdbc, hstmt);
3143 if (colInf)
3ca6a5f0 3144 delete [] colInf;
f6bcfd97
BP
3145 SQLFreeStmt(hstmt, SQL_CLOSE);
3146 if (numCols)
3ca6a5f0 3147 *numCols = 0;
f6bcfd97 3148 return(0);
3ca6a5f0
BP
3149 }
3150 }
eedb1543 3151
3ca6a5f0 3152 SQLFreeStmt(hstmt, SQL_CLOSE);
eedb1543 3153
3ca6a5f0
BP
3154 // Store Primary and Foreign Keys
3155 GetKeyFields(tableName,colInf,noCols);
3156
3157 ///////////////////////////////////////////////////////////////////////////
3158 // Now sort the the columns in order to make them appear in the right order
3159 ///////////////////////////////////////////////////////////////////////////
eedb1543 3160
3ca6a5f0
BP
3161 // Build a generic SELECT statement which returns 0 rows
3162 wxString Stmt;
eedb1543 3163
243d4b36 3164 Stmt.Printf(wxT("select * from \"%s\" where 0=1"), tableName);
eedb1543
DW
3165
3166 // Execute query
3ca6a5f0
BP
3167 if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS)
3168 {
3169 DispAllErrors(henv, hdbc, hstmt);
3170 return NULL;
eedb1543
DW
3171 }
3172
3ca6a5f0
BP
3173 // Get the number of result columns
3174 if (SQLNumResultCols (hstmt, &noCols) != SQL_SUCCESS)
3175 {
3176 DispAllErrors(henv, hdbc, hstmt);
3177 return NULL;
3178 }
eedb1543 3179
3ca6a5f0
BP
3180 if (noCols == 0) // Probably a bogus table name
3181 return NULL;
eedb1543
DW
3182
3183 // Get the name
3ca6a5f0
BP
3184 int i;
3185 short colNum;
3186 UCHAR name[100];
3187 SWORD Sword;
3188 SDWORD Sdword;
3189 for (colNum = 0; colNum < noCols; colNum++)
eedb1543
DW
3190 {
3191 if (SQLColAttributes(hstmt,colNum+1, SQL_COLUMN_NAME,
3192 name, sizeof(name),
3ca6a5f0
BP
3193 &Sword, &Sdword) != SQL_SUCCESS)
3194 {
3195 DispAllErrors(henv, hdbc, hstmt);
3196 return NULL;
eedb1543
DW
3197 }
3198
3ca6a5f0
BP
3199 wxString Name1 = name;
3200 Name1 = Name1.Upper();
eedb1543 3201
3ca6a5f0
BP
3202 // Where is this name in the array ?
3203 for (i = colNum ; i < noCols ; i++)
3204 {
3205 wxString Name2 = colInf[i].colName;
3206 Name2 = Name2.Upper();
3207 if (Name2 == Name1)
3208 {
3209 if (colNum != i) // swap to sort
3210 {
3211 wxDbColInf tmpColInf = colInf[colNum];
3212 colInf[colNum] = colInf[i];
3213 colInf[i] = tmpColInf;
3214 }
3215 break;
eedb1543
DW
3216 }
3217 }
3218 }
3ca6a5f0 3219 SQLFreeStmt(hstmt, SQL_CLOSE);
f6bcfd97 3220
3ca6a5f0
BP
3221 ///////////////////////////////////////////////////////////////////////////
3222 // End sorting
3223 ///////////////////////////////////////////////////////////////////////////
f6bcfd97 3224
3ca6a5f0
BP
3225 if (numCols)
3226 *numCols = noCols;
3227 return colInf;
eedb1543 3228
f6bcfd97
BP
3229} // wxDb::GetColumns()
3230
3231
3ca6a5f0 3232#endif // #else OLD_GETCOLUMNS
f6bcfd97
BP
3233
3234
3235/********** wxDb::GetColumnCount() **********/
dba2120c 3236int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID)
67e9aaa3
GT
3237/*
3238 * Returns a count of how many columns are in a table.
3239 * If an error occurs in computing the number of columns
3240 * this function will return a -1 for the count
3241 *
3242 * userID is evaluated in the following manner:
1e92909e
GT
3243 * userID == NULL ... UserID is ignored
3244 * userID == "" ... UserID set equal to 'this->uid'
3245 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3246 *
f6bcfd97
BP
3247 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3248 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
3249 * to avoid undesired unbinding of columns.
3250 */
3251{
02cf6fdd 3252 UWORD noCols = 0;
1e92909e
GT
3253
3254 RETCODE retcode;
3255
1e92909e
GT
3256 wxString TableName;
3257
4fdae997
GT
3258 wxString UserID;
3259 convertUserID(userID,UserID);
1e92909e 3260
4fdae997
GT
3261 TableName = tableName;
3262 // Oracle and Interbase table names are uppercase only, so force
3263 // the name to uppercase just in case programmer forgot to do this
3264 if ((Dbms() == dbmsORACLE) ||
215a0070 3265 (Dbms() == dbmsFIREBIRD) ||
4fdae997
GT
3266 (Dbms() == dbmsINTERBASE))
3267 TableName = TableName.Upper();
1e92909e 3268
4fdae997 3269 SQLFreeStmt(hstmt, SQL_CLOSE);
1e92909e 3270
4fdae997
GT
3271 // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we
3272 // use the call below that leaves out the user name
bb8a8478 3273 if (!UserID.empty() &&
4fdae997
GT
3274 Dbms() != dbmsMY_SQL &&
3275 Dbms() != dbmsACCESS &&
3276 Dbms() != dbmsMS_SQL_SERVER)
1e92909e 3277 {
4fdae997
GT
3278 retcode = SQLColumns(hstmt,
3279 NULL, 0, // All qualifiers
8a39593e
JS
3280 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner
3281 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
4fdae997
GT
3282 NULL, 0); // All columns
3283 }
3284 else
3285 {
3286 retcode = SQLColumns(hstmt,
3287 NULL, 0, // All qualifiers
3288 NULL, 0, // Owner
8a39593e 3289 (SQLTCHAR *) TableName.c_str(), SQL_NTS,
4fdae997
GT
3290 NULL, 0); // All columns
3291 }
3292 if (retcode != SQL_SUCCESS)
3103e8a9 3293 { // Error occurred, abort
4fdae997
GT
3294 DispAllErrors(henv, hdbc, hstmt);
3295 SQLFreeStmt(hstmt, SQL_CLOSE);
3296 return(-1);
3297 }
1e92909e 3298
4fdae997
GT
3299 // Count the columns
3300 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
3301 noCols++;
1e92909e 3302
4fdae997 3303 if (retcode != SQL_NO_DATA_FOUND)
3103e8a9 3304 { // Error occurred, abort
4fdae997
GT
3305 DispAllErrors(henv, hdbc, hstmt);
3306 SQLFreeStmt(hstmt, SQL_CLOSE);
3307 return(-1);
1e92909e
GT
3308 }
3309
3310 SQLFreeStmt(hstmt, SQL_CLOSE);
3311 return noCols;
67e9aaa3 3312
f6bcfd97 3313} // wxDb::GetColumnCount()
67e9aaa3
GT
3314
3315
f6bcfd97 3316/********** wxDb::GetCatalog() *******/
4fdae997 3317wxDbInf *wxDb::GetCatalog(const wxChar *userID)
67e9aaa3
GT
3318/*
3319 * ---------------------------------------------------------------------
0cd121f9 3320 * -- 19991203 : mj10777 : Create ------
67e9aaa3
GT
3321 * -- : Creates a wxDbInf with Tables / Cols Array ------
3322 * -- : uses SQLTables and fills pTableInf; ------
3323 * -- : pColInf is set to NULL and numCols to 0; ------
3324 * -- : returns pDbInf (wxDbInf) ------
3103e8a9 3325 * -- - if unsuccessful (pDbInf == NULL) ------
67e9aaa3
GT
3326 * -- : pColInf can be filled with GetColumns(..); ------
3327 * -- : numCols can be filled with GetColumnCount(..); ------
3328 * ---------------------------------------------------------------------
3329 *
3330 * userID is evaluated in the following manner:
1e92909e
GT
3331 * userID == NULL ... UserID is ignored
3332 * userID == "" ... UserID set equal to 'this->uid'
3333 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3334 *
f6bcfd97
BP
3335 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3336 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
3337 * to avoid undesired unbinding of columns.
3338 */
3339{
1e92909e
GT
3340 int noTab = 0; // Counter while filling table entries
3341 int pass;
3342 RETCODE retcode;
e716b9be 3343 SQLLEN cb;
1e92909e
GT
3344 wxString tblNameSave;
3345
3346 wxString UserID;
4fdae997 3347 convertUserID(userID,UserID);
1e92909e
GT
3348
3349 //-------------------------------------------------------------
caf412d6
DS
3350 // Create the Database Array of catalog entries
3351
3352 wxDbInf *pDbInf = new wxDbInf;
3353
1e92909e
GT
3354 //-------------------------------------------------------------
3355 // Table Information
3356 // Pass 1 - Determine how many Tables there are.
3357 // Pass 2 - Create the Table array and fill it
3358 // - Create the Cols array = NULL
3359 //-------------------------------------------------------------
f6bcfd97 3360
1e92909e
GT
3361 for (pass = 1; pass <= 2; pass++)
3362 {
3363 SQLFreeStmt(hstmt, SQL_CLOSE); // Close if Open
4fdae997 3364 tblNameSave.Empty();
1e92909e 3365
bb8a8478 3366 if (!UserID.empty() &&
3ca6a5f0 3367 Dbms() != dbmsMY_SQL &&
4fdae997
GT
3368 Dbms() != dbmsACCESS &&
3369 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
3370 {
3371 retcode = SQLTables(hstmt,
3372 NULL, 0, // All qualifiers
8a39593e 3373 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified
1e92909e
GT
3374 NULL, 0, // All tables
3375 NULL, 0); // All columns
3376 }
3377 else
3378 {
3379 retcode = SQLTables(hstmt,
3380 NULL, 0, // All qualifiers
3381 NULL, 0, // User specified
3382 NULL, 0, // All tables
3383 NULL, 0); // All columns
3384 }
f6bcfd97 3385
1e92909e
GT
3386 if (retcode != SQL_SUCCESS)
3387 {
3388 DispAllErrors(henv, hdbc, hstmt);
3389 pDbInf = NULL;
3390 SQLFreeStmt(hstmt, SQL_CLOSE);
3391 return pDbInf;
3392 }
eedb1543 3393
1e92909e
GT
3394 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) // Table Information
3395 {
3396 if (pass == 1) // First pass, just count the Tables
3397 {
3398 if (pDbInf->numTables == 0)
3399 {
e4e45573
GT
3400 GetData( 1, SQL_C_WXCHAR, (UCHAR*) pDbInf->catalog, 128+1, &cb);
3401 GetData( 2, SQL_C_WXCHAR, (UCHAR*) pDbInf->schema, 128+1, &cb);
1e92909e
GT
3402 }
3403 pDbInf->numTables++; // Counter for Tables
3404 } // if (pass == 1)
3405 if (pass == 2) // Create and fill the Table entries
3406 {
3407 if (pDbInf->pTableInf == NULL) // Has the Table Array been created
3408 { // no, then create the Array
f6bcfd97 3409 pDbInf->pTableInf = new wxDbTableInf[pDbInf->numTables];
1e92909e 3410 noTab = 0;
eedb1543 3411 } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created
f6bcfd97 3412
e4e45573
GT
3413 GetData( 3, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableName, DB_MAX_TABLE_NAME_LEN+1, &cb);
3414 GetData( 4, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableType, 30+1, &cb);
3415 GetData( 5, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableRemarks, 254+1, &cb);
3ca6a5f0 3416
1e92909e 3417 noTab++;
3ca6a5f0
BP
3418 } // if
3419 } // while
3420 } // for
1e92909e
GT
3421 SQLFreeStmt(hstmt, SQL_CLOSE);
3422
3423 // Query how many columns are in each table
3424 for (noTab=0;noTab<pDbInf->numTables;noTab++)
3425 {
564c92d9 3426 (pDbInf->pTableInf+noTab)->numCols = (UWORD)GetColumnCount((pDbInf->pTableInf+noTab)->tableName,UserID);
1e92909e 3427 }
3ca6a5f0 3428
1e92909e 3429 return pDbInf;
3ca6a5f0 3430
f6bcfd97 3431} // wxDb::GetCatalog()
67e9aaa3
GT
3432
3433
f6bcfd97 3434/********** wxDb::Catalog() **********/
4fdae997 3435bool wxDb::Catalog(const wxChar *userID, const wxString &fileName)
67e9aaa3
GT
3436/*
3437 * Creates the text file specified in 'filename' which will contain
3438 * a minimal data dictionary of all tables accessible by the user specified
3439 * in 'userID'
3440 *
3441 * userID is evaluated in the following manner:
1e92909e
GT
3442 * userID == NULL ... UserID is ignored
3443 * userID == "" ... UserID set equal to 'this->uid'
3444 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3445 *
f6bcfd97
BP
3446 * NOTE: ALL column bindings associated with this wxDb instance are unbound
3447 * by this function. This function should use its own wxDb instance
67e9aaa3
GT
3448 * to avoid undesired unbinding of columns.
3449 */
1fc5dd6f 3450{
8e3f3880 3451 wxASSERT(fileName.length());
1e92909e
GT
3452
3453 RETCODE retcode;
e716b9be 3454 SQLLEN cb;
4fdae997 3455 wxChar tblName[DB_MAX_TABLE_NAME_LEN+1];
1e92909e 3456 wxString tblNameSave;
4fdae997 3457 wxChar colName[DB_MAX_COLUMN_NAME_LEN+1];
1e92909e 3458 SWORD sqlDataType;
4fdae997 3459 wxChar typeName[30+1];
e262868d 3460 SDWORD precision, length;
1e92909e 3461
5054c936 3462 FILE *fp = wxFopen(fileName.c_str(),wxT("wt"));
1e92909e 3463 if (fp == NULL)
68379eaf 3464 return false;
1e92909e
GT
3465
3466 SQLFreeStmt(hstmt, SQL_CLOSE);
3467
4fdae997
GT
3468 wxString UserID;
3469 convertUserID(userID,UserID);
1e92909e 3470
bb8a8478 3471 if (!UserID.empty() &&
4fdae997
GT
3472 Dbms() != dbmsMY_SQL &&
3473 Dbms() != dbmsACCESS &&
215a0070 3474 Dbms() != dbmsFIREBIRD &&
081eb1b1 3475 Dbms() != dbmsINTERBASE &&
4fdae997 3476 Dbms() != dbmsMS_SQL_SERVER)
1e92909e
GT
3477 {
3478 retcode = SQLColumns(hstmt,
3479 NULL, 0, // All qualifiers
8a39593e 3480 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified
1e92909e
GT
3481 NULL, 0, // All tables
3482 NULL, 0); // All columns
3483 }
3484 else
3485 {
3486 retcode = SQLColumns(hstmt,
3487 NULL, 0, // All qualifiers
3488 NULL, 0, // User specified
3489 NULL, 0, // All tables
3490 NULL, 0); // All columns
3491 }
3492 if (retcode != SQL_SUCCESS)
3493 {
3494 DispAllErrors(henv, hdbc, hstmt);
3495 fclose(fp);
68379eaf 3496 return false;
1e92909e
GT
3497 }
3498
3499 wxString outStr;
4fdae997 3500 tblNameSave.Empty();
1e92909e
GT
3501 int cnt = 0;
3502
68379eaf 3503 while (true)
1e92909e 3504 {
e262868d
GT
3505 retcode = SQLFetch(hstmt);
3506 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
3507 break;
3508
e4e45573
GT
3509 GetData(3,SQL_C_WXCHAR, (UCHAR *) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
3510 GetData(4,SQL_C_WXCHAR, (UCHAR *) colName, DB_MAX_COLUMN_NAME_LEN+1,&cb);
3511 GetData(5,SQL_C_SSHORT, (UCHAR *)&sqlDataType, 0, &cb);
3512 GetData(6,SQL_C_WXCHAR, (UCHAR *) typeName, sizeof(typeName), &cb);
3513 GetData(7,SQL_C_SLONG, (UCHAR *)&precision, 0, &cb);
3514 GetData(8,SQL_C_SLONG, (UCHAR *)&length, 0, &cb);
b26e2b55 3515
4fdae997 3516 if (wxStrcmp(tblName, tblNameSave.c_str()))
1e92909e
GT
3517 {
3518 if (cnt)
8a39593e
JS
3519 wxFputs(wxT("\n"), fp);
3520 wxFputs(wxT("================================ "), fp);
3521 wxFputs(wxT("================================ "), fp);
3522 wxFputs(wxT("===================== "), fp);
3523 wxFputs(wxT("========= "), fp);
3524 wxFputs(wxT("=========\n"), fp);
4fdae997 3525 outStr.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"),
f6bcfd97 3526 wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH"));
8a39593e
JS
3527 wxFputs(outStr.c_str(), fp);
3528 wxFputs(wxT("================================ "), fp);
3529 wxFputs(wxT("================================ "), fp);
3530 wxFputs(wxT("===================== "), fp);
3531 wxFputs(wxT("========= "), fp);
3532 wxFputs(wxT("=========\n"), fp);
1e92909e
GT
3533 tblNameSave = tblName;
3534 }
67e9aaa3 3535
7fd4e7e1 3536 outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9ld %9ld\n"),
1e92909e 3537 tblName, colName, sqlDataType, typeName, precision, length);
8a39593e 3538 if (wxFputs(outStr.c_str(), fp) == EOF)
1e92909e
GT
3539 {
3540 SQLFreeStmt(hstmt, SQL_CLOSE);
3541 fclose(fp);
68379eaf 3542 return false;
1e92909e
GT
3543 }
3544 cnt++;
3545 }
1fc5dd6f 3546
1e92909e
GT
3547 if (retcode != SQL_NO_DATA_FOUND)
3548 DispAllErrors(henv, hdbc, hstmt);
1fc5dd6f 3549
1e92909e 3550 SQLFreeStmt(hstmt, SQL_CLOSE);
a2115c88 3551
1e92909e
GT
3552 fclose(fp);
3553 return(retcode == SQL_NO_DATA_FOUND);
1fc5dd6f 3554
f6bcfd97 3555} // wxDb::Catalog()
1fc5dd6f
JS
3556
3557
4fdae997 3558bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wxString &tablePath)
67e9aaa3 3559/*
68379eaf 3560 * Table name can refer to a table, view, alias or synonym. Returns true
67e9aaa3
GT
3561 * if the object exists in the database. This function does not indicate
3562 * whether or not the user has privleges to query or perform other functions
3563 * on the table.
3564 *
3565 * userID is evaluated in the following manner:
1e92909e
GT
3566 * userID == NULL ... UserID is ignored
3567 * userID == "" ... UserID set equal to 'this->uid'
3568 * userID != "" ... UserID set equal to 'userID'
67e9aaa3 3569 */
108106cf 3570{
8e3f3880 3571 wxASSERT(tableName.length());
eedb1543 3572
4fdae997 3573 wxString TableName;
eedb1543
DW
3574
3575 if (Dbms() == dbmsDBASE)
1e92909e 3576 {
3ca6a5f0 3577 wxString dbName;
8e3f3880 3578 if (tablePath.length())
942e67c3 3579 dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str());
3ca6a5f0 3580 else
942e67c3 3581 dbName.Printf(wxT("%s.dbf"), tableName.c_str());
eedb1543 3582
3ca6a5f0 3583 bool exists;
4fdae997 3584 exists = wxFileExists(dbName);
3ca6a5f0 3585 return exists;
1e92909e 3586 }
eedb1543 3587
4fdae997
GT
3588 wxString UserID;
3589 convertUserID(userID,UserID);
eedb1543 3590
1e92909e 3591 TableName = tableName;
d8a0a1c9 3592 // Oracle and Interbase table names are uppercase only, so force
1e92909e 3593 // the name to uppercase just in case programmer forgot to do this
eedb1543 3594 if ((Dbms() == dbmsORACLE) ||
215a0070 3595 (Dbms() == dbmsFIREBIRD) ||
d8a0a1c9 3596 (Dbms() == dbmsINTERBASE))
1e92909e 3597 TableName = TableName.Upper();
eedb1543 3598
1e92909e
GT
3599 SQLFreeStmt(hstmt, SQL_CLOSE);
3600 RETCODE retcode;
eedb1543 3601
a8aa2258
GT
3602 // Some databases cannot accept a user name when looking up table names,
3603 // so we use the call below that leaves out the user name
bb8a8478 3604 if (!UserID.empty() &&
3ca6a5f0 3605 Dbms() != dbmsMY_SQL &&
a8aa2258 3606 Dbms() != dbmsACCESS &&
2beca662
GT
3607 Dbms() != dbmsMS_SQL_SERVER &&
3608 Dbms() != dbmsDB2 &&
215a0070 3609 Dbms() != dbmsFIREBIRD &&
081eb1b1 3610 Dbms() != dbmsINTERBASE &&
2beca662 3611 Dbms() != dbmsPERVASIVE_SQL)
1e92909e
GT
3612 {
3613 retcode = SQLTables(hstmt,
3ca6a5f0 3614 NULL, 0, // All qualifiers
8a39593e
JS
3615 (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Only tables owned by this user
3616 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3617 NULL, 0); // All table types
1e92909e
GT
3618 }
3619 else
3620 {
3621 retcode = SQLTables(hstmt,
3ca6a5f0
BP
3622 NULL, 0, // All qualifiers
3623 NULL, 0, // All owners
8a39593e 3624 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS,
3ca6a5f0 3625 NULL, 0); // All table types
1e92909e
GT
3626 }
3627 if (retcode != SQL_SUCCESS)
3628 return(DispAllErrors(henv, hdbc, hstmt));
eedb1543 3629
1e92909e 3630 retcode = SQLFetch(hstmt);
a8aa2258 3631 if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
1e92909e
GT
3632 {
3633 SQLFreeStmt(hstmt, SQL_CLOSE);
3634 return(DispAllErrors(henv, hdbc, hstmt));
3635 }
eedb1543 3636
1e92909e 3637 SQLFreeStmt(hstmt, SQL_CLOSE);
108106cf 3638
68379eaf 3639 return true;
eedb1543 3640
f6bcfd97 3641} // wxDb::TableExists()
108106cf
JS
3642
3643
a8aa2258 3644/********** wxDb::TablePrivileges() **********/
4fdae997 3645bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID,
8a39593e 3646 const wxChar *schema, const wxString &WXUNUSED(tablePath))
3ca6a5f0 3647{
8e3f3880 3648 wxASSERT(tableName.length());
4fdae997 3649
3ca6a5f0 3650 wxDbTablePrivilegeInfo result;
e716b9be 3651 SQLLEN cbRetVal;
3ca6a5f0 3652 RETCODE retcode;
eedb1543 3653
4fdae997
GT
3654 // We probably need to be able to dynamically set this based on
3655 // the driver type, and state.
3656 wxChar curRole[]=wxT("public");
eedb1543 3657
3ca6a5f0 3658 wxString TableName;
eedb1543 3659
02cf6fdd 3660 wxString UserID,Schema;
4fdae997 3661 convertUserID(userID,UserID);
02cf6fdd 3662 convertUserID(schema,Schema);
eedb1543 3663
3ca6a5f0 3664 TableName = tableName;
d8a0a1c9 3665 // Oracle and Interbase table names are uppercase only, so force
3ca6a5f0 3666 // the name to uppercase just in case programmer forgot to do this
eedb1543 3667 if ((Dbms() == dbmsORACLE) ||
215a0070 3668 (Dbms() == dbmsFIREBIRD) ||
d8a0a1c9 3669 (Dbms() == dbmsINTERBASE))
3ca6a5f0 3670 TableName = TableName.Upper();
eedb1543 3671
3ca6a5f0 3672 SQLFreeStmt(hstmt, SQL_CLOSE);
d8a0a1c9 3673
02cf6fdd
GT
3674 // Some databases cannot accept a user name when looking up table names,
3675 // so we use the call below that leaves out the user name
bb8a8478 3676 if (!Schema.empty() &&
02cf6fdd
GT
3677 Dbms() != dbmsMY_SQL &&
3678 Dbms() != dbmsACCESS &&
3679 Dbms() != dbmsMS_SQL_SERVER)
d8a0a1c9
GT
3680 {
3681 retcode = SQLTablePrivileges(hstmt,
3682 NULL, 0, // Catalog
8a39593e
JS
3683 (SQLTCHAR FAR *)Schema.c_str(), SQL_NTS, // Schema
3684 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
d8a0a1c9
GT
3685 }
3686 else
3687 {
3688 retcode = SQLTablePrivileges(hstmt,
3689 NULL, 0, // Catalog
02cf6fdd 3690 NULL, 0, // Schema
8a39593e 3691 (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS);
d8a0a1c9 3692 }
a8aa2258 3693
eedb1543 3694#ifdef DBDEBUG_CONSOLE
8a39593e 3695 wxFprintf(stderr ,wxT("SQLTablePrivileges() returned %i \n"),retcode);
3ca6a5f0 3696#endif
eedb1543 3697
a8aa2258 3698 if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
e4e45573 3699 return (DispAllErrors(henv, hdbc, hstmt));
a8aa2258 3700
68379eaf 3701 bool failed = false;
d8a0a1c9 3702 retcode = SQLFetch(hstmt);
eedb1543 3703 while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
d8a0a1c9 3704 {
e4e45573 3705 if (SQLGetData(hstmt, 1, SQL_C_WXCHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS)
68379eaf 3706 failed = true;
eedb1543 3707
e4e45573 3708 if (!failed && SQLGetData(hstmt, 2, SQL_C_WXCHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS)
68379eaf 3709 failed = true;
eedb1543 3710
e4e45573 3711 if (!failed && SQLGetData(hstmt, 3, SQL_C_WXCHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS)
68379eaf 3712 failed = true;
eedb1543 3713
e4e45573 3714 if (!failed && SQLGetData(hstmt, 4, SQL_C_WXCHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS)
68379eaf 3715 failed = true;
eedb1543 3716
e4e45573 3717 if (!failed && SQLGetData(hstmt, 5, SQL_C_WXCHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS)
68379eaf 3718 failed = true;
eedb1543 3719
e4e45573 3720 if (!failed && SQLGetData(hstmt, 6, SQL_C_WXCHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS)
68379eaf 3721 failed = true;
eedb1543 3722
e4e45573 3723 if (!failed && SQLGetData(hstmt, 7, SQL_C_WXCHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS)
68379eaf 3724 failed = true;
d8a0a1c9 3725
5a226de0
GT
3726 if (failed)
3727 {
3728 return(DispAllErrors(henv, hdbc, hstmt));
3729 }
3ca6a5f0 3730#ifdef DBDEBUG_CONSOLE
8a39593e 3731 wxFprintf(stderr,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"),
a8aa2258 3732 result.privilege,result.tableOwner,result.tableName,
3ca6a5f0 3733 result.grantor, result.grantee);
eedb1543 3734#endif
d8a0a1c9 3735
68379eaf 3736 if (UserID.IsSameAs(result.tableOwner,false))
a8aa2258
GT
3737 {
3738 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3739 return true;
a8aa2258 3740 }
eedb1543 3741
68379eaf 3742 if (UserID.IsSameAs(result.grantee,false) &&
a8aa2258
GT
3743 !wxStrcmp(result.privilege,priv))
3744 {
3745 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3746 return true;
a8aa2258 3747 }
eedb1543 3748
a8aa2258
GT
3749 if (!wxStrcmp(result.grantee,curRole) &&
3750 !wxStrcmp(result.privilege,priv))
3751 {
3752 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3753 return true;
a8aa2258 3754 }
eedb1543 3755
3ca6a5f0 3756 retcode = SQLFetch(hstmt);
eedb1543
DW
3757 }
3758
a8aa2258 3759 SQLFreeStmt(hstmt, SQL_CLOSE);
68379eaf 3760 return false;
3ca6a5f0 3761
a8aa2258 3762} // wxDb::TablePrivileges
3ca6a5f0
BP
3763
3764
5bdad317 3765const wxString wxDb::SQLTableName(const wxChar *tableName)
243d4b36
GT
3766{
3767 wxString TableName;
3768
3769 if (Dbms() == dbmsACCESS)
8a39593e 3770 TableName = _T("\"");
243d4b36
GT
3771 TableName += tableName;
3772 if (Dbms() == dbmsACCESS)
8a39593e 3773 TableName += _T("\"");
243d4b36
GT
3774
3775 return TableName;
3776} // wxDb::SQLTableName()
3777
3778
5bdad317 3779const wxString wxDb::SQLColumnName(const wxChar *colName)
243d4b36
GT
3780{
3781 wxString ColName;
3782
3783 if (Dbms() == dbmsACCESS)
8a39593e 3784 ColName = _T("\"");
243d4b36
GT
3785 ColName += colName;
3786 if (Dbms() == dbmsACCESS)
8a39593e 3787 ColName += _T("\"");
243d4b36
GT
3788
3789 return ColName;
3790} // wxDb::SQLColumnName()
3791
3792
f6bcfd97 3793/********** wxDb::SetSqlLogging() **********/
4fdae997 3794bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append)
1fc5dd6f 3795{
4fdae997 3796 wxASSERT(state == sqlLogON || state == sqlLogOFF);
8e3f3880 3797 wxASSERT(state == sqlLogOFF || filename.length());
1e92909e 3798
ea5d599d
GT
3799 if (state == sqlLogON)
3800 {
3801 if (fpSqlLog == 0)
3802 {
e04507df 3803 fpSqlLog = wxFopen(filename.c_str(), (append ? wxT("at") : wxT("wt")));
ea5d599d 3804 if (fpSqlLog == NULL)
68379eaf 3805 return false;
ea5d599d
GT
3806 }
3807 }
3808 else // sqlLogOFF
3809 {
3810 if (fpSqlLog)
3811 {
3812 if (fclose(fpSqlLog))
68379eaf 3813 return false;
ea5d599d
GT
3814 fpSqlLog = 0;
3815 }
3816 }
1e92909e 3817
ea5d599d 3818 sqlLogState = state;
68379eaf 3819 return true;
1fc5dd6f 3820
f6bcfd97 3821} // wxDb::SetSqlLogging()
1fc5dd6f
JS
3822
3823
f6bcfd97 3824/********** wxDb::WriteSqlLog() **********/
4fdae997 3825bool wxDb::WriteSqlLog(const wxString &logMsg)
1fc5dd6f 3826{
8e3f3880 3827 wxASSERT(logMsg.length());
1fc5dd6f 3828
1e92909e 3829 if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
68379eaf 3830 return false;
1fc5dd6f 3831
8a39593e 3832 if (wxFputs(wxT("\n"), fpSqlLog) == EOF)
68379eaf 3833 return false;
8a39593e 3834 if (wxFputs(logMsg, fpSqlLog) == EOF)
68379eaf 3835 return false;
8a39593e 3836 if (wxFputs(wxT("\n"), fpSqlLog) == EOF)
68379eaf 3837 return false;
1fc5dd6f 3838
68379eaf 3839 return true;
1fc5dd6f 3840
f6bcfd97 3841} // wxDb::WriteSqlLog()
1fc5dd6f
JS
3842
3843
f6bcfd97
BP
3844/********** wxDb::Dbms() **********/
3845wxDBMS wxDb::Dbms(void)
a2115c88
GT
3846/*
3847 * Be aware that not all database engines use the exact same syntax, and not
3848 * every ODBC compliant database is compliant to the same level of compliancy.
3849 * Some manufacturers support the minimum Level 1 compliancy, and others up
3850 * through Level 3. Others support subsets of features for levels above 1.
3851 *
f6bcfd97 3852 * If you find an inconsistency between the wxDb class and a specific database
a2115c88
GT
3853 * engine, and an identifier to this section, and special handle the database in
3854 * the area where behavior is non-conforming with the other databases.
3855 *
3856 *
3857 * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE
3858 * ---------------------------------------------------
3859 *
3860 * ORACLE
1e92909e 3861 * - Currently the only database supported by the class to support VIEWS
a2115c88
GT
3862 *
3863 * DBASE
1e92909e
GT
3864 * - Does not support the SQL_TIMESTAMP structure
3865 * - Supports only one cursor and one connect (apparently? with Microsoft driver only?)
fdc03678 3866 * - Does not automatically create the primary index if the 'keyField' param of SetColDef
68379eaf 3867 * is true. The user must create ALL indexes from their program.
1e92909e
GT
3868 * - Table names can only be 8 characters long
3869 * - Column names can only be 10 characters long
a2115c88
GT
3870 *
3871 * SYBASE (all)
1e92909e
GT
3872 * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added
3873 * after every table name involved in the query/join if that tables matching record(s)
3874 * are to be locked
3875 * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above
a2115c88
GT
3876 *
3877 * SYBASE (Enterprise)
1e92909e 3878 * - If a column is part of the Primary Key, the column cannot be NULL
3ca6a5f0 3879 * - Maximum row size is somewhere in the neighborhood of 1920 bytes
a2115c88
GT
3880 *
3881 * MY_SQL
1e92909e 3882 * - If a column is part of the Primary Key, the column cannot be NULL
a144affe 3883 * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE
3ca6a5f0
BP
3884 * - Columns that are part of primary or secondary keys must be defined as being NOT NULL
3885 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3886 * column definition if it is not defined correctly, but it is experimental
3887 * - Does not support sub-queries in SQL statements
a2115c88
GT
3888 *
3889 * POSTGRES
23f681ec 3890 * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0
3ca6a5f0 3891 * - Does not support sub-queries in SQL statements
a2115c88 3892 *
a8aa2258
GT
3893 * DB2
3894 * - Primary keys must be declared as NOT NULL
2beca662
GT
3895 * - Table and index names must not be longer than 13 characters in length (technically
3896 * table names can be up to 18 characters, but the primary index is created using the
3897 * base table name plus "_PIDX", so the limit if the table has a primary index is 13.
3898 *
3899 * PERVASIVE SQL
a8aa2258 3900 *
081eb1b1
GT
3901 * INTERBASE
3902 * - Columns that are part of primary keys must be defined as being NOT NULL
3903 * when they are created. Some code is added in ::CreateIndex to try to adjust the
3904 * column definition if it is not defined correctly, but it is experimental
a2115c88 3905 */
a2115c88 3906{
a8aa2258 3907 // Should only need to do this once for each new database connection
eedb1543 3908 // so return the value we already determined it to be to save time
a8aa2258
GT
3909 // and lots of string comparisons
3910 if (dbmsType != dbmsUNIDENTIFIED)
3911 return(dbmsType);
3912
215a0070
GT
3913#ifdef DBDEBUG_CONSOLE
3914 // When run in console mode, use standard out to display errors.
3915 cout << "Database connecting to: " << dbInf.dbmsName << endl;
215a0070
GT
3916#endif // DBDEBUG_CONSOLE
3917
3918 wxLogDebug(wxT("Database connecting to: "));
3919 wxLogDebug(dbInf.dbmsName);
3920
1e92909e 3921 wxChar baseName[25+1];
215a0070 3922 wxStrncpy(baseName, dbInf.dbmsName, 25);
3ca6a5f0 3923 baseName[25] = 0;
f6bcfd97 3924
d8a0a1c9
GT
3925 // RGG 20001025 : add support for Interbase
3926 // GT : Integrated to base classes on 20001121
4fdae997 3927 if (!wxStricmp(dbInf.dbmsName,wxT("Interbase")))
d8a0a1c9
GT
3928 return((wxDBMS)(dbmsType = dbmsINTERBASE));
3929
f6bcfd97 3930 // BJO 20000428 : add support for Virtuoso
4fdae997 3931 if (!wxStricmp(dbInf.dbmsName,wxT("OpenLink Virtuoso VDBMS")))
a8aa2258 3932 return((wxDBMS)(dbmsType = dbmsVIRTUOSO));
f6bcfd97 3933
4fdae997 3934 if (!wxStricmp(dbInf.dbmsName,wxT("Adaptive Server Anywhere")))
a8aa2258
GT
3935 return((wxDBMS)(dbmsType = dbmsSYBASE_ASA));
3936
f6bcfd97
BP
3937 // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when
3938 // connected through an OpenLink driver.
eedb1543
DW
3939 // Is it also returned by Sybase Adapatitve server?
3940 // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix
4fdae997 3941 if (!wxStricmp(dbInf.dbmsName,wxT("SQL Server")))
3ca6a5f0 3942 {
4fdae997
GT
3943 if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) ||
3944 !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4))
081eb1b1
GT
3945 return ((wxDBMS)(dbmsMS_SQL_SERVER));
3946 else
3947 return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
3ca6a5f0 3948 }
f6bcfd97 3949
4fdae997 3950 if (!wxStricmp(dbInf.dbmsName,wxT("Microsoft SQL Server")))
a8aa2258 3951 return((wxDBMS)(dbmsType = dbmsMS_SQL_SERVER));
9af163d7
GT
3952
3953 baseName[10] = 0;
3954 if (!wxStricmp(baseName,wxT("PostgreSQL"))) // v6.5.0
a8aa2258 3955 return((wxDBMS)(dbmsType = dbmsPOSTGRES));
1e92909e 3956
2beca662 3957 baseName[9] = 0;
9af163d7 3958 if (!wxStricmp(baseName,wxT("Pervasive")))
081eb1b1 3959 return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL));
2beca662 3960
1e92909e 3961 baseName[8] = 0;
4fdae997 3962 if (!wxStricmp(baseName,wxT("Informix")))
a8aa2258 3963 return((wxDBMS)(dbmsType = dbmsINFORMIX));
1e92909e 3964
215a0070
GT
3965 if (!wxStricmp(baseName,wxT("Firebird")))
3966 return((wxDBMS)(dbmsType = dbmsFIREBIRD));
3967
1e92909e 3968 baseName[6] = 0;
4fdae997 3969 if (!wxStricmp(baseName,wxT("Oracle")))
a8aa2258 3970 return((wxDBMS)(dbmsType = dbmsORACLE));
9af163d7 3971 if (!wxStricmp(baseName,wxT("ACCESS")))
a8aa2258 3972 return((wxDBMS)(dbmsType = dbmsACCESS));
4fdae997 3973 if (!wxStricmp(baseName,wxT("Sybase")))
a8aa2258 3974 return((wxDBMS)(dbmsType = dbmsSYBASE_ASE));
1e92909e
GT
3975
3976 baseName[5] = 0;
4fdae997 3977 if (!wxStricmp(baseName,wxT("DBASE")))
a8aa2258 3978 return((wxDBMS)(dbmsType = dbmsDBASE));
9f4de2dc
JS
3979 if (!wxStricmp(baseName,wxT("xBase")))
3980 return((wxDBMS)(dbmsType = dbmsXBASE_SEQUITER));
e25cdb86
GT
3981 if (!wxStricmp(baseName,wxT("MySQL")))
3982 return((wxDBMS)(dbmsType = dbmsMY_SQL));
f6a9f9ad
GT
3983 if (!wxStricmp(baseName,wxT("MaxDB")))
3984 return((wxDBMS)(dbmsType = dbmsMAXDB));
e25cdb86 3985
a8aa2258 3986 baseName[3] = 0;
4fdae997 3987 if (!wxStricmp(baseName,wxT("DB2")))
ae2807c2 3988 return((wxDBMS)(dbmsType = dbmsDB2));
a8aa2258
GT
3989
3990 return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED));
3ca6a5f0 3991
f6bcfd97 3992} // wxDb::Dbms()
a2115c88
GT
3993
3994
4fdae997
GT
3995bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName,
3996 int dataType, ULONG columnLength,
3997 const wxString &optionalParam)
3998{
8e3f3880
WS
3999 wxASSERT(tableName.length());
4000 wxASSERT(columnName.length());
4fdae997
GT
4001 wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) ||
4002 dataType != DB_DATA_TYPE_VARCHAR);
4003
4004 // Must specify a columnLength if modifying a VARCHAR type column
4005 if (dataType == DB_DATA_TYPE_VARCHAR && !columnLength)
68379eaf 4006 return false;
5600884a 4007
4fdae997 4008 wxString dataTypeName;
081eb1b1 4009 wxString sqlStmt;
4fdae997
GT
4010 wxString alterSlashModify;
4011
081eb1b1
GT
4012 switch(dataType)
4013 {
4014 case DB_DATA_TYPE_VARCHAR :
4015 dataTypeName = typeInfVarchar.TypeName;
4016 break;
4017 case DB_DATA_TYPE_INTEGER :
4018 dataTypeName = typeInfInteger.TypeName;
4019 break;
4020 case DB_DATA_TYPE_FLOAT :
4021 dataTypeName = typeInfFloat.TypeName;
4022 break;
4023 case DB_DATA_TYPE_DATE :
4024 dataTypeName = typeInfDate.TypeName;
4025 break;
4026 case DB_DATA_TYPE_BLOB :
4027 dataTypeName = typeInfBlob.TypeName;
4028 break;
4029 default:
68379eaf 4030 return false;
081eb1b1
GT
4031 }
4032
4033 // Set the modify or alter syntax depending on the type of database connected to
4034 switch (Dbms())
4035 {
4036 case dbmsORACLE :
8a39593e 4037 alterSlashModify = _T("MODIFY");
081eb1b1
GT
4038 break;
4039 case dbmsMS_SQL_SERVER :
8a39593e 4040 alterSlashModify = _T("ALTER COLUMN");
081eb1b1
GT
4041 break;
4042 case dbmsUNIDENTIFIED :
68379eaf 4043 return false;
081eb1b1
GT
4044 case dbmsSYBASE_ASA :
4045 case dbmsSYBASE_ASE :
4046 case dbmsMY_SQL :
4047 case dbmsPOSTGRES :
4048 case dbmsACCESS :
4049 case dbmsDBASE :
9f4de2dc 4050 case dbmsXBASE_SEQUITER :
081eb1b1 4051 default :
8a39593e 4052 alterSlashModify = _T("MODIFY");
081eb1b1
GT
4053 break;
4054 }
4055
4056 // create the SQL statement
9c136858
JS
4057 if ( Dbms() == dbmsMY_SQL )
4058 {
4059 sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(),
4060 columnName.c_str(), dataTypeName.c_str());
4061 }
4062 else
4063 {
4064 sqlStmt.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName.c_str(), alterSlashModify.c_str(),
081eb1b1 4065 columnName.c_str(), dataTypeName.c_str());
9c136858 4066 }
4fdae997
GT
4067
4068 // For varchars only, append the size of the column
e25cdb86 4069 if (dataType == DB_DATA_TYPE_VARCHAR &&
8a39593e 4070 (Dbms() != dbmsMY_SQL || dataTypeName != _T("text")))
4fdae997
GT
4071 {
4072 wxString s;
7fd4e7e1 4073 s.Printf(wxT("(%lu)"), columnLength);
4fdae997
GT
4074 sqlStmt += s;
4075 }
4076
4077 // for passing things like "NOT NULL"
8e3f3880 4078 if (optionalParam.length())
4fdae997
GT
4079 {
4080 sqlStmt += wxT(" ");
4081 sqlStmt += optionalParam;
4082 }
4083
081eb1b1 4084 return ExecSql(sqlStmt);
4fdae997
GT
4085
4086} // wxDb::ModifyColumn()
4087
4088
fdc03678 4089/********** wxDbGetConnection() **********/
bb41dcbe 4090wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors)
108106cf 4091{
fdc03678 4092 wxDbList *pList;
1e92909e 4093
a8aa2258
GT
4094 // Used to keep a pointer to a DB connection that matches the requested
4095 // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the
4096 // data types can be copied from it (using the wxDb::Open(wxDb *) function)
4097 // rather than having to re-query the datasource to get all the values
4098 // using the wxDb::Open(Dsn,Uid,AuthStr) function
4099 wxDb *matchingDbConnection = NULL;
4100
1e92909e
GT
4101 // Scan the linked list searching for an available database connection
4102 // that's already been opened but is currently not in use.
4103 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
4104 {
4105 // The database connection must be for the same datasource
4106 // name and must currently not be in use.
3ca6a5f0 4107 if (pList->Free &&
0907ea9c 4108 (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors))
1e92909e 4109 {
0907ea9c
GT
4110 if (pDbConfig->UseConnectionStr())
4111 {
68379eaf 4112 if (pList->PtrDb->OpenedWithConnectionString() &&
0907ea9c
GT
4113 (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr)))
4114 {
4115 // Found a free connection
68379eaf 4116 pList->Free = false;
0907ea9c
GT
4117 return(pList->PtrDb);
4118 }
4119 }
4120 else
4121 {
4122 if (!pList->PtrDb->OpenedWithConnectionString() &&
4123 (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn)))
4124 {
4125 // Found a free connection
68379eaf 4126 pList->Free = false;
0907ea9c
GT
4127 return(pList->PtrDb);
4128 }
4129 }
1e92909e 4130 }
a8aa2258 4131
0907ea9c
GT
4132 if (pDbConfig->UseConnectionStr())
4133 {
4134 if (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr))
4135 matchingDbConnection = pList->PtrDb;
4136 }
4137 else
4138 {
4139 if (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn) &&
4140 !wxStrcmp(pDbConfig->GetUserID(), pList->Uid) &&
4141 !wxStrcmp(pDbConfig->GetPassword(), pList->AuthStr))
4142 matchingDbConnection = pList->PtrDb;
4143 }
1e92909e
GT
4144 }
4145
4146 // No available connections. A new connection must be made and
4147 // appended to the end of the linked list.
4148 if (PtrBegDbList)
4149 {
4150 // Find the end of the list
4151 for (pList = PtrBegDbList; pList->PtrNext; pList = pList->PtrNext);
4152 // Append a new list item
fdc03678 4153 pList->PtrNext = new wxDbList;
1e92909e
GT
4154 pList->PtrNext->PtrPrev = pList;
4155 pList = pList->PtrNext;
4156 }
3ca6a5f0 4157 else // Empty list
1e92909e
GT
4158 {
4159 // Create the first node on the list
fdc03678 4160 pList = PtrBegDbList = new wxDbList;
1e92909e
GT
4161 pList->PtrPrev = 0;
4162 }
4163
4164 // Initialize new node in the linked list
0907ea9c 4165 pList->PtrNext = 0;
68379eaf 4166 pList->Free = false;
0907ea9c
GT
4167 pList->Dsn = pDbConfig->GetDsn();
4168 pList->Uid = pDbConfig->GetUserID();
4169 pList->AuthStr = pDbConfig->GetPassword();
4170 pList->ConnectionStr = pDbConfig->GetConnectionStr();
a8aa2258 4171
9556da13 4172 pList->PtrDb = new wxDb(pDbConfig->GetHenv(), FwdOnlyCursors);
1e92909e 4173
caf412d6 4174 bool opened;
a8aa2258
GT
4175
4176 if (!matchingDbConnection)
0907ea9c
GT
4177 {
4178 if (pDbConfig->UseConnectionStr())
4179 {
4180 opened = pList->PtrDb->Open(pDbConfig->GetConnectionStr());
4181 }
4182 else
4183 {
4184 opened = pList->PtrDb->Open(pDbConfig->GetDsn(), pDbConfig->GetUserID(), pDbConfig->GetPassword());
4185 }
4186 }
a8aa2258
GT
4187 else
4188 opened = pList->PtrDb->Open(matchingDbConnection);
4189
1e92909e 4190 // Connect to the datasource
a8aa2258 4191 if (opened)
1e92909e 4192 {
68379eaf
WS
4193 pList->PtrDb->setCached(true); // Prevent a user from deleting a cached connection
4194 pList->PtrDb->SetSqlLogging(SQLLOGstate, SQLLOGfn, true);
1e92909e
GT
4195 return(pList->PtrDb);
4196 }
4197 else // Unable to connect, destroy list item
4198 {
4199 if (pList->PtrPrev)
4200 pList->PtrPrev->PtrNext = 0;
4201 else
0907ea9c
GT
4202 PtrBegDbList = 0; // Empty list again
4203
4204 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
4205 pList->PtrDb->Close(); // Close the wxDb object
4206 delete pList->PtrDb; // Deletes the wxDb object
4207 delete pList; // Deletes the linked list object
1e92909e
GT
4208 return(0);
4209 }
108106cf 4210
fdc03678 4211} // wxDbGetConnection()
108106cf 4212
67e9aaa3 4213
fdc03678 4214/********** wxDbFreeConnection() **********/
bb41dcbe 4215bool WXDLLIMPEXP_ODBC wxDbFreeConnection(wxDb *pDb)
108106cf 4216{
fdc03678 4217 wxDbList *pList;
108106cf 4218
1e92909e
GT
4219 // Scan the linked list searching for the database connection
4220 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
4221 {
3ca6a5f0 4222 if (pList->PtrDb == pDb) // Found it, now free it!!!
68379eaf 4223 return (pList->Free = true);
1e92909e 4224 }
108106cf 4225
1e92909e 4226 // Never found the database object, return failure
68379eaf 4227 return false;
108106cf 4228
fdc03678 4229} // wxDbFreeConnection()
108106cf 4230
67e9aaa3 4231
fdc03678 4232/********** wxDbCloseConnections() **********/
bb41dcbe 4233void WXDLLIMPEXP_ODBC wxDbCloseConnections(void)
108106cf 4234{
fdc03678 4235 wxDbList *pList, *pNext;
23f681ec 4236
1e92909e
GT
4237 // Traverse the linked list closing database connections and freeing memory as I go.
4238 for (pList = PtrBegDbList; pList; pList = pNext)
4239 {
4240 pNext = pList->PtrNext; // Save the pointer to next
f6bcfd97
BP
4241 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object
4242 pList->PtrDb->Close(); // Close the wxDb object
68379eaf 4243 pList->PtrDb->setCached(false); // Allows deletion of the wxDb instance
f6bcfd97 4244 delete pList->PtrDb; // Deletes the wxDb object
1e92909e
GT
4245 delete pList; // Deletes the linked list object
4246 }
4247
4248 // Mark the list as empty
4249 PtrBegDbList = 0;
108106cf 4250
fdc03678 4251} // wxDbCloseConnections()
108106cf 4252
67e9aaa3 4253
eb3b9dda 4254/********** wxDbConnectionsInUse() **********/
bb41dcbe 4255int WXDLLIMPEXP_ODBC wxDbConnectionsInUse(void)
108106cf 4256{
fdc03678 4257 wxDbList *pList;
1e92909e 4258 int cnt = 0;
108106cf 4259
1e92909e
GT
4260 // Scan the linked list counting db connections that are currently in use
4261 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
4262 {
68379eaf 4263 if (pList->Free == false)
1e92909e
GT
4264 cnt++;
4265 }
108106cf 4266
1e92909e 4267 return(cnt);
108106cf 4268
fdc03678 4269} // wxDbConnectionsInUse()
108106cf 4270
67e9aaa3 4271
2c257434
GT
4272
4273/********** wxDbLogExtendedErrorMsg() **********/
4274// DEBUG ONLY function
f9ebf98b 4275const wxChar WXDLLIMPEXP_ODBC *wxDbLogExtendedErrorMsg(const wxChar *userText,
90350682
VZ
4276 wxDb *pDb,
4277 const wxChar *ErrFile,
4278 int ErrLine)
2c257434
GT
4279{
4280 static wxString msg;
4281 msg = userText;
4282
4283 wxString tStr;
4284
4285 if (ErrFile || ErrLine)
4286 {
4287 msg += wxT("File: ");
4288 msg += ErrFile;
4289 msg += wxT(" Line: ");
4290 tStr.Printf(wxT("%d"),ErrLine);
4291 msg += tStr.c_str();
4292 msg += wxT("\n");
4293 }
4294
4295 msg.Append (wxT("\nODBC errors:\n"));
4296 msg += wxT("\n");
2e57a9ef 4297
2c257434
GT
4298 // Display errors for this connection
4299 int i;
4300 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
4301 {
4302 if (pDb->errorList[i])
4303 {
4304 msg.Append(pDb->errorList[i]);
b8126f93 4305 if (wxStrcmp(pDb->errorList[i], wxEmptyString) != 0)
2c257434
GT
4306 msg.Append(wxT("\n"));
4307 // Clear the errmsg buffer so the next error will not
4308 // end up showing the previous error that have occurred
7086c32a 4309 wxStrcpy(pDb->errorList[i], wxEmptyString);
2c257434
GT
4310 }
4311 }
4312 msg += wxT("\n");
4313
4314 wxLogDebug(msg.c_str());
4315
4316 return msg.c_str();
4317} // wxDbLogExtendedErrorMsg()
4318
4319
fdc03678 4320/********** wxDbSqlLog() **********/
f6bcfd97 4321bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename)
a2115c88 4322{
68379eaf 4323 bool append = false;
fdc03678 4324 wxDbList *pList;
a2115c88 4325
1e92909e
GT
4326 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
4327 {
f6bcfd97 4328 if (!pList->PtrDb->SetSqlLogging(state,filename,append))
68379eaf
WS
4329 return false;
4330 append = true;
1e92909e 4331 }
a2115c88 4332
1e92909e 4333 SQLLOGstate = state;
3ca6a5f0 4334 SQLLOGfn = filename;
a2115c88 4335
68379eaf 4336 return true;
a2115c88 4337
fdc03678 4338} // wxDbSqlLog()
a2115c88 4339
67e9aaa3 4340
a8aa2258 4341#if 0
fdc03678 4342/********** wxDbCreateDataSource() **********/
4fdae997
GT
4343int wxDbCreateDataSource(const wxString &driverName, const wxString &dsn, const wxString &description,
4344 bool sysDSN, const wxString &defDir, wxWindow *parent)
fdc03678
GT
4345/*
4346 * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
eedb1543 4347 * Very rudimentary creation of an ODBC data source.
a8aa2258
GT
4348 *
4349 * ODBC driver must be ODBC 3.0 compliant to use this function
fdc03678
GT
4350 */
4351{
a144affe 4352 int result = FALSE;
fdc03678 4353
a8aa2258
GT
4354//!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!!
4355#ifdef __VISUALC__
fdc03678
GT
4356 int dsnLocation;
4357 wxString setupStr;
4358
4359 if (sysDSN)
4360 dsnLocation = ODBC_ADD_SYS_DSN;
4361 else
4362 dsnLocation = ODBC_ADD_DSN;
4363
4364 // NOTE: The decimal 2 is an invalid character in all keyword pairs
eedb1543 4365 // so that is why I used it, as wxString does not deal well with
fdc03678 4366 // embedded nulls in strings
4fdae997 4367 setupStr.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn,2,description,2,defDir,2);
fdc03678 4368
3103e8a9 4369 // Replace the separator from above with the '\0' separator needed
fdc03678
GT
4370 // by the SQLConfigDataSource() function
4371 int k;
4372 do
4373 {
68379eaf 4374 k = setupStr.Find((wxChar)2,true);
fdc03678 4375 if (k != wxNOT_FOUND)
4fdae997 4376 setupStr[(UINT)k] = wxT('\0');
fdc03678
GT
4377 }
4378 while (k != wxNOT_FOUND);
4379
4380 result = SQLConfigDataSource((HWND)parent->GetHWND(), dsnLocation,
f6bcfd97 4381 driverName, setupStr.c_str());
fdc03678 4382
a8aa2258 4383 if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
fdc03678
GT
4384 {
4385 // check for errors caused by ConfigDSN based functions
4386 DWORD retcode = 0;
4387 WORD cb;
a8aa2258 4388 wxChar errMsg[SQL_MAX_MESSAGE_LENGTH];
4fdae997 4389 errMsg[0] = wxT('\0');
fdc03678 4390
a8aa2258
GT
4391 // This function is only supported in ODBC drivers v3.0 compliant and above
4392 SQLInstallerError(1,&retcode,errMsg,SQL_MAX_MESSAGE_LENGTH-1,&cb);
fdc03678
GT
4393 if (retcode)
4394 {
fdc03678 4395#ifdef DBDEBUG_CONSOLE
f6bcfd97
BP
4396 // When run in console mode, use standard out to display errors.
4397 cout << errMsg << endl;
a8aa2258 4398 cout << wxT("Press any key to continue...") << endl;
f6bcfd97 4399 getchar();
fdc03678 4400#endif // DBDEBUG_CONSOLE
fdc03678
GT
4401
4402#ifdef __WXDEBUG__
f6bcfd97 4403 wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE"));
fdc03678
GT
4404#endif // __WXDEBUG__
4405 }
4406 }
4407 else
a144affe 4408 result = TRUE;
a8aa2258
GT
4409#else
4410 // Using iODBC/unixODBC or some other compiler which does not support the APIs
4411 // necessary to use this function, so this function is not supported
fdc03678 4412#ifdef __WXDEBUG__
4fdae997 4413 wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE"));
fdc03678 4414#endif
a144affe 4415 result = FALSE;
a8aa2258 4416#endif // __VISUALC__
fdc03678
GT
4417
4418 return result;
4419
4420} // wxDbCreateDataSource()
4421#endif
4422
4423
4424/********** wxDbGetDataSource() **********/
e4e45573
GT
4425bool wxDbGetDataSource(HENV henv, wxChar *Dsn, SWORD DsnMaxLength, wxChar *DsDesc,
4426 SWORD DsDescMaxLength, UWORD direction)
67e9aaa3
GT
4427/*
4428 * Dsn and DsDesc will contain the data source name and data source
4429 * description upon return
4430 */
108106cf 4431{
1e92909e 4432 SWORD cb1,cb2;
bb8a8478
WS
4433 SWORD lengthDsn = (SWORD)(DsnMaxLength*sizeof(wxChar));
4434 SWORD lengthDsDesc = (SWORD)(DsDescMaxLength*sizeof(wxChar));
108106cf 4435
bb8a8478
WS
4436 if (SQLDataSources(henv, direction, (SQLTCHAR FAR *) Dsn, lengthDsn, &cb1,
4437 (SQLTCHAR FAR *) DsDesc, lengthDsDesc, &cb2) == SQL_SUCCESS)
68379eaf 4438 return true;
1e92909e 4439 else
68379eaf 4440 return false;
108106cf 4441
fdc03678
GT
4442} // wxDbGetDataSource()
4443
4444
4445// Change this to 0 to remove use of all deprecated functions
f6bcfd97 4446#if wxODBC_BACKWARD_COMPATABILITY
fdc03678
GT
4447/********************************************************************
4448 ********************************************************************
4449 *
4450 * The following functions are all DEPRECATED and are included for
3103e8a9 4451 * backward compatibility reasons only
fdc03678
GT
4452 *
4453 ********************************************************************
4454 ********************************************************************/
f6bcfd97 4455bool SqlLog(sqlLog state, const wxChar *filename)
fdc03678 4456{
f6bcfd97 4457 return wxDbSqlLog((enum wxDbSqlLogState)state, filename);
fdc03678
GT
4458}
4459/***** DEPRECATED: use wxGetDataSource() *****/
4460bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
4461 UWORD direction)
4462{
4463 return wxDbGetDataSource(henv, Dsn, DsnMax, DsDesc, DsDescMax, direction);
4464}
4465/***** DEPRECATED: use wxDbGetConnection() *****/
bb41dcbe 4466wxDb WXDLLIMPEXP_ODBC *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors)
fdc03678
GT
4467{
4468 return wxDbGetConnection((wxDbConnectInf *)pDbStuff, FwdOnlyCursors);
4469}
4470/***** DEPRECATED: use wxDbFreeConnection() *****/
bb41dcbe 4471bool WXDLLIMPEXP_ODBC FreeDbConnection(wxDb *pDb)
fdc03678
GT
4472{
4473 return wxDbFreeConnection(pDb);
4474}
4475/***** DEPRECATED: use wxDbCloseConnections() *****/
bb41dcbe 4476void WXDLLIMPEXP_ODBC CloseDbConnections(void)
fdc03678
GT
4477{
4478 wxDbCloseConnections();
4479}
4480/***** DEPRECATED: use wxDbConnectionsInUse() *****/
bb41dcbe 4481int WXDLLIMPEXP_ODBC NumberDbConnectionsInUse(void)
fdc03678
GT
4482{
4483 return wxDbConnectionsInUse();
4484}
4485#endif
4486
4487
108106cf 4488#endif
1fc5dd6f 4489 // wxUSE_ODBC