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