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