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