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