]> git.saurik.com Git - wxWidgets.git/blob - src/common/db.cpp
Updated the Remstar ODBC files, got the db sample compiling; added Freq and SubString
[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:
8 // Mods: Dec, 1998: Added support for SQL statement logging and database
9 // cataloging
10 // Created: 9.96
11 // RCS-ID: $Id$
12 // Copyright: (c) 1996 Remstar International, Inc.
13 // Licence: wxWindows licence, plus:
14 // Notice: This class library and its intellectual design are free of charge for use,
15 // modification, enhancement, debugging under the following conditions:
16 // 1) These classes may only be used as part of the implementation of a
17 // wxWindows-based application
18 // 2) All enhancements and bug fixes are to be submitted back to the wxWindows
19 // user groups free of all charges for use with the wxWindows library.
20 // 3) These classes may not be distributed as part of any other class library,
21 // DLL, text (written or electronic), other than a complete distribution of
22 // the wxWindows GUI development toolkit.
23 ///////////////////////////////////////////////////////////////////////////////
24
25 #ifdef __GNUG__
26 #pragma implementation "db.h"
27 #endif
28
29 /*
30 // SYNOPSIS START
31 // SYNOPSIS STOP
32 */
33
34 /*
35 #ifdef DBDEBUG_CONSOLE
36 #include <iostream.h>
37 #endif
38 */
39
40 #include "wx/wxprec.h"
41
42 #ifdef __BORLANDC__
43 #pragma hdrstop
44 #endif //__BORLANDC__
45
46 #ifndef WX_PRECOMP
47 #include <wx/wx.h>
48 #endif //WX_PRECOMP
49
50 #if wxUSE_ODBC
51
52 #include <stdio.h>
53 #include <string.h>
54 #include <assert.h>
55 #include "wx/db.h"
56
57 DbList *PtrBegDbList = 0;
58
59 /********** wxDB Constructor **********/
60 wxDB::wxDB(HENV &aHenv)
61 {
62 int i;
63
64 fpSqlLog = 0; // Sql Log file pointer
65 sqlLogState = sqlLogOFF; // By default, logging is turned off
66
67 strcpy(sqlState,"");
68 strcpy(errorMsg,"");
69 nativeError = cbErrorMsg = 0;
70 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
71 strcpy(errorList[i], "");
72
73 // Init typeInf structures
74 strcpy(typeInfVarchar.TypeName,"");
75 typeInfVarchar.FsqlType = 0;
76 typeInfVarchar.Precision = 0;
77 typeInfVarchar.CaseSensitive = 0;
78 typeInfVarchar.MaximumScale = 0;
79
80 strcpy(typeInfInteger.TypeName,"");
81 typeInfInteger.FsqlType = 0;
82 typeInfInteger.Precision = 0;
83 typeInfInteger.CaseSensitive = 0;
84 typeInfInteger.MaximumScale = 0;
85
86 strcpy(typeInfFloat.TypeName,"");
87 typeInfFloat.FsqlType = 0;
88 typeInfFloat.Precision = 0;
89 typeInfFloat.CaseSensitive = 0;
90 typeInfFloat.MaximumScale = 0;
91
92 strcpy(typeInfDate.TypeName,"");
93 typeInfDate.FsqlType = 0;
94 typeInfDate.Precision = 0;
95 typeInfDate.CaseSensitive = 0;
96 typeInfDate.MaximumScale = 0;
97
98 // Error reporting is turned OFF by default
99 silent = TRUE;
100
101 // Copy the HENV into the db class
102 henv = aHenv;
103
104 // Allocate a data source connection handle
105 if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS)
106 DispAllErrors(henv);
107
108 // Initialize the db status flag
109 DB_STATUS = 0;
110
111 // Mark database as not open as of yet
112 dbIsOpen = FALSE;
113
114 } // wxDB::wxDB()
115
116 /********** wxDB::Open() **********/
117 bool wxDB::Open(char *Dsn, char *Uid, char *AuthStr)
118 {
119 assert(Dsn && strlen(Dsn));
120 dsn = Dsn;
121 uid = Uid;
122 authStr = AuthStr;
123
124 #ifndef FWD_ONLY_CURSORS
125
126 RETCODE retcode;
127
128 // Specify that the ODBC cursor library be used, if needed. This must be
129 // specified before the connection is made.
130 retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED);
131
132 #ifdef DBDEBUG_CONSOLE
133 if (retcode == SQL_SUCCESS)
134 cout << "SQLSetConnectOption(CURSOR_LIB) successful" << endl;
135 else
136 cout << "SQLSetConnectOption(CURSOR_LIB) failed" << endl;
137 #endif
138
139 #endif
140
141 // Connect to the data source
142 if (SQLConnect(hdbc, (UCHAR FAR *) Dsn, SQL_NTS,
143 (UCHAR FAR *) Uid, SQL_NTS,
144 (UCHAR FAR *) AuthStr, SQL_NTS) != SQL_SUCCESS)
145 return(DispAllErrors(henv, hdbc));
146
147 // Mark database as open
148 dbIsOpen = TRUE;
149
150 // Allocate a statement handle for the database connection
151 if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS)
152 return(DispAllErrors(henv, hdbc));
153
154 // Set Connection Options
155 if (! setConnectionOptions())
156 return(FALSE);
157
158 // Query the data source for inf. about itself
159 if (! getDbInfo())
160 return(FALSE);
161
162 // Query the data source regarding data type information
163
164 //
165 // The way I determined which SQL data types to use was by calling SQLGetInfo
166 // for all of the possible SQL data types to see which ones were supported. If
167 // a type is not supported, the SQLFetch() that's called from getDataTypeInfo()
168 // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data
169 // types I've selected below will not alway's be what we want. These are just
170 // what happened to work against an Oracle 7/Intersolv combination. The following is
171 // a complete list of the results I got back against the Oracle 7 database:
172 //
173 // SQL_BIGINT SQL_NO_DATA_FOUND
174 // SQL_BINARY SQL_NO_DATA_FOUND
175 // SQL_BIT SQL_NO_DATA_FOUND
176 // SQL_CHAR type name = 'CHAR', Precision = 255
177 // SQL_DATE SQL_NO_DATA_FOUND
178 // SQL_DECIMAL type name = 'NUMBER', Precision = 38
179 // SQL_DOUBLE type name = 'NUMBER', Precision = 15
180 // SQL_FLOAT SQL_NO_DATA_FOUND
181 // SQL_INTEGER SQL_NO_DATA_FOUND
182 // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion
183 // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion
184 // SQL_NUMERIC SQL_NO_DATA_FOUND
185 // SQL_REAL SQL_NO_DATA_FOUND
186 // SQL_SMALLINT SQL_NO_DATA_FOUND
187 // SQL_TIME SQL_NO_DATA_FOUND
188 // SQL_TIMESTAMP type name = 'DATE', Precision = 19
189 // SQL_VARBINARY type name = 'RAW', Precision = 255
190 // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000
191 // =====================================================================
192 // Results from a Microsoft Access 7.0 db, using a driver from Microsoft
193 //
194 // SQL_VARCHAR type name = 'TEXT', Precision = 255
195 // SQL_TIMESTAMP type name = 'DATETIME'
196 // SQL_DECIMAL SQL_NO_DATA_FOUND
197 // SQL_NUMERIC type name = 'CURRENCY', Precision = 19
198 // SQL_FLOAT SQL_NO_DATA_FOUND
199 // SQL_REAL type name = 'SINGLE', Precision = 7
200 // SQL_DOUBLE type name = 'DOUBLE', Precision = 15
201 // SQL_INTEGER type name = 'LONG', Precision = 10
202
203 // VARCHAR = Variable length character string
204 if (! getDataTypeInfo(SQL_VARCHAR, typeInfVarchar))
205 if (! getDataTypeInfo(SQL_CHAR, typeInfVarchar))
206 return(FALSE);
207 else
208 typeInfVarchar.FsqlType = SQL_CHAR;
209 else
210 typeInfVarchar.FsqlType = SQL_VARCHAR;
211
212 // Float
213 if (! getDataTypeInfo(SQL_DOUBLE, typeInfFloat))
214 if (! getDataTypeInfo(SQL_REAL, typeInfFloat))
215 if (! getDataTypeInfo(SQL_FLOAT, typeInfFloat))
216 if (! getDataTypeInfo(SQL_DECIMAL, typeInfFloat))
217 if (! getDataTypeInfo(SQL_NUMERIC, typeInfFloat))
218 return(FALSE);
219 else
220 typeInfFloat.FsqlType = SQL_NUMERIC;
221 else
222 typeInfFloat.FsqlType = SQL_DECIMAL;
223 else
224 typeInfFloat.FsqlType = SQL_FLOAT;
225 else
226 typeInfFloat.FsqlType = SQL_REAL;
227 else
228 typeInfFloat.FsqlType = SQL_DOUBLE;
229
230 // Integer
231 if (! getDataTypeInfo(SQL_INTEGER, typeInfInteger))
232 // If SQL_INTEGER is not supported, use the floating point
233 // data type to store integers as well as floats
234 if (! getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger))
235 return(FALSE);
236 else
237 typeInfInteger.FsqlType = typeInfFloat.FsqlType;
238 else
239 typeInfInteger.FsqlType = SQL_INTEGER;
240
241 // Date/Time
242 if (! getDataTypeInfo(SQL_TIMESTAMP, typeInfDate))
243 return(FALSE);
244 else
245 typeInfDate.FsqlType = SQL_TIMESTAMP;
246
247 #ifdef DBDEBUG_CONSOLE
248 cout << "VARCHAR DATA TYPE: " << typeInfVarchar.TypeName << endl;
249 cout << "INTEGER DATA TYPE: " << typeInfInteger.TypeName << endl;
250 cout << "FLOAT DATA TYPE: " << typeInfFloat.TypeName << endl;
251 cout << "DATE DATA TYPE: " << typeInfDate.TypeName << endl;
252 cout << endl;
253 #endif
254
255 // Completed Successfully
256 return(TRUE);
257
258 } // wxDB::Open()
259
260 // The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout.
261
262 /********** wxDB::setConnectionOptions() **********/
263 bool wxDB::setConnectionOptions(void)
264 {
265 SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
266 SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF);
267
268 // Display the connection options to verify them
269 #ifdef DBDEBUG_CONSOLE
270 long l;
271 cout << ">>>>> CONNECTION OPTIONS <<<<<<" << endl;
272
273 if (SQLGetConnectOption(hdbc, SQL_AUTOCOMMIT, &l) != SQL_SUCCESS)
274 return(DispAllErrors(henv, hdbc));
275 cout << "AUTOCOMMIT: " << (l == SQL_AUTOCOMMIT_OFF ? "OFF" : "ON") << endl;
276
277 if (SQLGetConnectOption(hdbc, SQL_ODBC_CURSORS, &l) != SQL_SUCCESS)
278 return(DispAllErrors(henv, hdbc));
279 cout << "ODBC CURSORS: ";
280 switch(l)
281 {
282 case(SQL_CUR_USE_IF_NEEDED):
283 cout << "SQL_CUR_USE_IF_NEEDED";
284 break;
285 case(SQL_CUR_USE_ODBC):
286 cout << "SQL_CUR_USE_ODBC";
287 break;
288 case(SQL_CUR_USE_DRIVER):
289 cout << "SQL_CUR_USE_DRIVER";
290 break;
291 }
292 cout << endl;
293
294 if (SQLGetConnectOption(hdbc, SQL_OPT_TRACE, &l) != SQL_SUCCESS)
295 return(DispAllErrors(henv, hdbc));
296 cout << "TRACING: " << (l == SQL_OPT_TRACE_OFF ? "OFF" : "ON") << endl;
297
298 cout << endl;
299 #endif
300
301 // Completed Successfully
302 return(TRUE);
303
304 } // wxDB::setConnectionOptions()
305
306 /********** wxDB::getDbInfo() **********/
307 bool wxDB::getDbInfo(void)
308 {
309 SWORD cb;
310
311 if (SQLGetInfo(hdbc, SQL_SERVER_NAME, dbInf.serverName, 40, &cb) != SQL_SUCCESS)
312 return(DispAllErrors(henv, hdbc));
313
314 if (SQLGetInfo(hdbc, SQL_DATABASE_NAME, dbInf.databaseName, 128, &cb) != SQL_SUCCESS)
315 return(DispAllErrors(henv, hdbc));
316
317 if (SQLGetInfo(hdbc, SQL_DBMS_NAME, dbInf.dbmsName, 40, &cb) != SQL_SUCCESS)
318 return(DispAllErrors(henv, hdbc));
319
320 if (SQLGetInfo(hdbc, SQL_DBMS_VER, dbInf.dbmsVer, 20, &cb) != SQL_SUCCESS)
321 return(DispAllErrors(henv, hdbc));
322
323 if (SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, &dbInf.maxConnections, sizeof(dbInf.maxConnections), &cb) != SQL_SUCCESS)
324 return(DispAllErrors(henv, hdbc));
325
326 if (SQLGetInfo(hdbc, SQL_ACTIVE_STATEMENTS, &dbInf.maxStmts, sizeof(dbInf.maxStmts), &cb) != SQL_SUCCESS)
327 return(DispAllErrors(henv, hdbc));
328
329 if (SQLGetInfo(hdbc, SQL_DRIVER_NAME, dbInf.driverName, 40, &cb) != SQL_SUCCESS)
330 return(DispAllErrors(henv, hdbc));
331
332 if (SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, dbInf.odbcVer, 20, &cb) != SQL_SUCCESS)
333 return(DispAllErrors(henv, hdbc));
334
335 if (SQLGetInfo(hdbc, SQL_ODBC_VER, dbInf.drvMgrOdbcVer, 20, &cb) != SQL_SUCCESS)
336 return(DispAllErrors(henv, hdbc));
337
338 if (SQLGetInfo(hdbc, SQL_DRIVER_VER, dbInf.driverVer, 40, &cb) != SQL_SUCCESS)
339 return(DispAllErrors(henv, hdbc));
340
341 if (SQLGetInfo(hdbc, SQL_ODBC_API_CONFORMANCE, &dbInf.apiConfLvl, sizeof(dbInf.apiConfLvl), &cb) != SQL_SUCCESS)
342 return(DispAllErrors(henv, hdbc));
343
344 if (SQLGetInfo(hdbc, SQL_ODBC_SAG_CLI_CONFORMANCE, &dbInf.cliConfLvl, sizeof(dbInf.cliConfLvl), &cb) != SQL_SUCCESS)
345 return(DispAllErrors(henv, hdbc));
346
347 if (SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, &dbInf.sqlConfLvl, sizeof(dbInf.sqlConfLvl), &cb) != SQL_SUCCESS)
348 return(DispAllErrors(henv, hdbc));
349
350 if (SQLGetInfo(hdbc, SQL_OUTER_JOINS, dbInf.outerJoins, 2, &cb) != SQL_SUCCESS)
351 return(DispAllErrors(henv, hdbc));
352
353 if (SQLGetInfo(hdbc, SQL_PROCEDURES, dbInf.procedureSupport, 2, &cb) != SQL_SUCCESS)
354 return(DispAllErrors(henv, hdbc));
355
356 if (SQLGetInfo(hdbc, SQL_CURSOR_COMMIT_BEHAVIOR, &dbInf.cursorCommitBehavior, sizeof(dbInf.cursorCommitBehavior), &cb) != SQL_SUCCESS)
357 return(DispAllErrors(henv, hdbc));
358
359 if (SQLGetInfo(hdbc, SQL_CURSOR_ROLLBACK_BEHAVIOR, &dbInf.cursorRollbackBehavior, sizeof(dbInf.cursorRollbackBehavior), &cb) != SQL_SUCCESS)
360 return(DispAllErrors(henv, hdbc));
361
362 if (SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, &dbInf.supportNotNullClause, sizeof(dbInf.supportNotNullClause), &cb) != SQL_SUCCESS)
363 return(DispAllErrors(henv, hdbc));
364
365 if (SQLGetInfo(hdbc, SQL_ODBC_SQL_OPT_IEF, dbInf.supportIEF, 2, &cb) != SQL_SUCCESS)
366 return(DispAllErrors(henv, hdbc));
367
368 if (SQLGetInfo(hdbc, SQL_DEFAULT_TXN_ISOLATION, &dbInf.txnIsolation, sizeof(dbInf.txnIsolation), &cb) != SQL_SUCCESS)
369 return(DispAllErrors(henv, hdbc));
370
371 if (SQLGetInfo(hdbc, SQL_TXN_ISOLATION_OPTION, &dbInf.txnIsolationOptions, sizeof(dbInf.txnIsolationOptions), &cb) != SQL_SUCCESS)
372 return(DispAllErrors(henv, hdbc));
373
374 if (SQLGetInfo(hdbc, SQL_FETCH_DIRECTION, &dbInf.fetchDirections, sizeof(dbInf.fetchDirections), &cb) != SQL_SUCCESS)
375 return(DispAllErrors(henv, hdbc));
376
377 if (SQLGetInfo(hdbc, SQL_LOCK_TYPES, &dbInf.lockTypes, sizeof(dbInf.lockTypes), &cb) != SQL_SUCCESS)
378 return(DispAllErrors(henv, hdbc));
379
380 if (SQLGetInfo(hdbc, SQL_POS_OPERATIONS, &dbInf.posOperations, sizeof(dbInf.posOperations), &cb) != SQL_SUCCESS)
381 return(DispAllErrors(henv, hdbc));
382
383 if (SQLGetInfo(hdbc, SQL_POSITIONED_STATEMENTS, &dbInf.posStmts, sizeof(dbInf.posStmts), &cb) != SQL_SUCCESS)
384 return(DispAllErrors(henv, hdbc));
385
386 if (SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, &dbInf.scrollConcurrency, sizeof(dbInf.scrollConcurrency), &cb) != SQL_SUCCESS)
387 return(DispAllErrors(henv, hdbc));
388
389 if (SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, &dbInf.scrollOptions, sizeof(dbInf.scrollOptions), &cb) != SQL_SUCCESS)
390 return(DispAllErrors(henv, hdbc));
391
392 if (SQLGetInfo(hdbc, SQL_STATIC_SENSITIVITY, &dbInf.staticSensitivity, sizeof(dbInf.staticSensitivity), &cb) != SQL_SUCCESS)
393 return(DispAllErrors(henv, hdbc));
394
395 if (SQLGetInfo(hdbc, SQL_TXN_CAPABLE, &dbInf.txnCapable, sizeof(dbInf.txnCapable), &cb) != SQL_SUCCESS)
396 return(DispAllErrors(henv, hdbc));
397
398 if (SQLGetInfo(hdbc, SQL_LOGIN_TIMEOUT, &dbInf.loginTimeout, sizeof(dbInf.loginTimeout), &cb) != SQL_SUCCESS)
399 return(DispAllErrors(henv, hdbc));
400
401 #ifdef DBDEBUG_CONSOLE
402 cout << ">>>>> DATA SOURCE INFORMATION <<<<<" << endl;
403 cout << "SERVER Name: " << dbInf.serverName << endl;
404 cout << "DBMS Name: " << dbInf.dbmsName << "; DBMS Version: " << dbInf.dbmsVer << endl;
405 cout << "ODBC Version: " << dbInf.odbcVer << "; Driver Version: " << dbInf.driverVer << endl;
406
407 cout << "API Conf. Level: ";
408 switch(dbInf.apiConfLvl)
409 {
410 case SQL_OAC_NONE: cout << "None"; break;
411 case SQL_OAC_LEVEL1: cout << "Level 1"; break;
412 case SQL_OAC_LEVEL2: cout << "Level 2"; break;
413 }
414 cout << endl;
415
416 cout << "SAG CLI Conf. Level: ";
417 switch(dbInf.cliConfLvl)
418 {
419 case SQL_OSCC_NOT_COMPLIANT: cout << "Not Compliant"; break;
420 case SQL_OSCC_COMPLIANT: cout << "Compliant"; break;
421 }
422 cout << endl;
423
424 cout << "SQL Conf. Level: ";
425 switch(dbInf.sqlConfLvl)
426 {
427 case SQL_OSC_MINIMUM: cout << "Minimum Grammer"; break;
428 case SQL_OSC_CORE: cout << "Core Grammer"; break;
429 case SQL_OSC_EXTENDED: cout << "Extended Grammer"; break;
430 }
431 cout << endl;
432
433 cout << "Max. Connections: " << dbInf.maxConnections << endl;
434 cout << "Outer Joins: " << dbInf.outerJoins << endl;
435 cout << "Support for Procedures: " << dbInf.procedureSupport << endl;
436
437 cout << "Cursor COMMIT Behavior: ";
438 switch(dbInf.cursorCommitBehavior)
439 {
440 case SQL_CB_DELETE: cout << "Delete cursors"; break;
441 case SQL_CB_CLOSE: cout << "Close cursors"; break;
442 case SQL_CB_PRESERVE: cout << "Preserve cursors"; break;
443 }
444 cout << endl;
445
446 cout << "Cursor ROLLBACK Behavior: ";
447 switch(dbInf.cursorRollbackBehavior)
448 {
449 case SQL_CB_DELETE: cout << "Delete cursors"; break;
450 case SQL_CB_CLOSE: cout << "Close cursors"; break;
451 case SQL_CB_PRESERVE: cout << "Preserve cursors"; break;
452 }
453 cout << endl;
454
455 cout << "Support NOT NULL clause: ";
456 switch(dbInf.supportNotNullClause)
457 {
458 case SQL_NNC_NULL: cout << "No"; break;
459 case SQL_NNC_NON_NULL: cout << "Yes"; break;
460 }
461 cout << endl;
462
463 cout << "Support IEF (Ref. Integrity): " << dbInf.supportIEF << endl;
464 cout << "Login Timeout: " << dbInf.loginTimeout << endl;
465
466 cout << endl << endl << "more ..." << endl;
467 getchar();
468
469 cout << "Default Transaction Isolation: ";
470 switch(dbInf.txnIsolation)
471 {
472 case SQL_TXN_READ_UNCOMMITTED: cout << "Read Uncommitted"; break;
473 case SQL_TXN_READ_COMMITTED: cout << "Read Committed"; break;
474 case SQL_TXN_REPEATABLE_READ: cout << "Repeatable Read"; break;
475 case SQL_TXN_SERIALIZABLE: cout << "Serializable"; break;
476 #ifdef ODBC_V20
477 case SQL_TXN_VERSIONING: cout << "Versioning"; break;
478 #endif
479 }
480 cout << endl;
481
482 cout << "Transaction Isolation Options: ";
483 if (dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED)
484 cout << "Read Uncommitted, ";
485 if (dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED)
486 cout << "Read Committed, ";
487 if (dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ)
488 cout << "Repeatable Read, ";
489 if (dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE)
490 cout << "Serializable, ";
491 #ifdef ODBC_V20
492 if (dbInf.txnIsolationOptions & SQL_TXN_VERSIONING)
493 cout << "Versioning";
494 #endif
495 cout << endl;
496
497 cout << "Fetch Directions Supported:" << endl << " ";
498 if (dbInf.fetchDirections & SQL_FD_FETCH_NEXT)
499 cout << "Next, ";
500 if (dbInf.fetchDirections & SQL_FD_FETCH_PRIOR)
501 cout << "Prev, ";
502 if (dbInf.fetchDirections & SQL_FD_FETCH_FIRST)
503 cout << "First, ";
504 if (dbInf.fetchDirections & SQL_FD_FETCH_LAST)
505 cout << "Last, ";
506 if (dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE)
507 cout << "Absolute, ";
508 if (dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE)
509 cout << "Relative, ";
510 #ifdef ODBC_V20
511 if (dbInf.fetchDirections & SQL_FD_FETCH_RESUME)
512 cout << "Resume, ";
513 #endif
514 if (dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK)
515 cout << "Bookmark";
516 cout << endl;
517
518 cout << "Lock Types Supported (SQLSetPos): ";
519 if (dbInf.lockTypes & SQL_LCK_NO_CHANGE)
520 cout << "No Change, ";
521 if (dbInf.lockTypes & SQL_LCK_EXCLUSIVE)
522 cout << "Exclusive, ";
523 if (dbInf.lockTypes & SQL_LCK_UNLOCK)
524 cout << "UnLock";
525 cout << endl;
526
527 cout << "Position Operations Supported (SQLSetPos): ";
528 if (dbInf.posOperations & SQL_POS_POSITION)
529 cout << "Position, ";
530 if (dbInf.posOperations & SQL_POS_REFRESH)
531 cout << "Refresh, ";
532 if (dbInf.posOperations & SQL_POS_UPDATE)
533 cout << "Upd, ";
534 if (dbInf.posOperations & SQL_POS_DELETE)
535 cout << "Del, ";
536 if (dbInf.posOperations & SQL_POS_ADD)
537 cout << "Add";
538 cout << endl;
539
540 cout << "Positioned Statements Supported: ";
541 if (dbInf.posStmts & SQL_PS_POSITIONED_DELETE)
542 cout << "Pos delete, ";
543 if (dbInf.posStmts & SQL_PS_POSITIONED_UPDATE)
544 cout << "Pos update, ";
545 if (dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)
546 cout << "Select for update";
547 cout << endl;
548
549 cout << "Scroll Concurrency: ";
550 if (dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY)
551 cout << "Read Only, ";
552 if (dbInf.scrollConcurrency & SQL_SCCO_LOCK)
553 cout << "Lock, ";
554 if (dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER)
555 cout << "Opt. Rowver, ";
556 if (dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES)
557 cout << "Opt. Values";
558 cout << endl;
559
560 cout << "Scroll Options: ";
561 if (dbInf.scrollOptions & SQL_SO_FORWARD_ONLY)
562 cout << "Fwd Only, ";
563 if (dbInf.scrollOptions & SQL_SO_STATIC)
564 cout << "Static, ";
565 if (dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN)
566 cout << "Keyset Driven, ";
567 if (dbInf.scrollOptions & SQL_SO_DYNAMIC)
568 cout << "Dynamic, ";
569 if (dbInf.scrollOptions & SQL_SO_MIXED)
570 cout << "Mixed";
571 cout << endl;
572
573 cout << "Static Sensitivity: ";
574 if (dbInf.staticSensitivity & SQL_SS_ADDITIONS)
575 cout << "Additions, ";
576 if (dbInf.staticSensitivity & SQL_SS_DELETIONS)
577 cout << "Deletions, ";
578 if (dbInf.staticSensitivity & SQL_SS_UPDATES)
579 cout << "Updates";
580 cout << endl;
581
582 cout << "Transaction Capable?: ";
583 switch(dbInf.txnCapable)
584 {
585 case SQL_TC_NONE: cout << "No"; break;
586 case SQL_TC_DML: cout << "DML Only"; break;
587 case SQL_TC_DDL_COMMIT: cout << "DDL Commit"; break;
588 case SQL_TC_DDL_IGNORE: cout << "DDL Ignore"; break;
589 case SQL_TC_ALL: cout << "DDL & DML"; break;
590 }
591 cout << endl;
592
593 cout << endl;
594
595 #endif
596
597 // Completed Successfully
598 return(TRUE);
599
600 } // wxDB::getDbInfo()
601
602 /********** wxDB::getDataTypeInfo() **********/
603 bool wxDB::getDataTypeInfo(SWORD fSqlType, SqlTypeInfo &structSQLTypeInfo)
604 {
605 // fSqlType will be something like SQL_VARCHAR. This parameter determines
606 // the data type inf. is gathered for.
607 //
608 // SqlTypeInfo is a structure that is filled in with data type information,
609
610 RETCODE retcode;
611 SDWORD cbRet;
612
613 // Get information about the data type specified
614 if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS)
615 return(DispAllErrors(henv, hdbc, hstmt));
616 // Fetch the record
617 if ((retcode = SQLFetch(hstmt)) != SQL_SUCCESS)
618 {
619 #ifdef DBDEBUG_CONSOLE
620 if (retcode == SQL_NO_DATA_FOUND)
621 cout << "SQL_NO_DATA_FOUND fetching inf. about data type." << endl;
622 #endif
623 DispAllErrors(henv, hdbc, hstmt);
624 SQLFreeStmt(hstmt, SQL_CLOSE);
625 return(FALSE);
626 }
627 // Obtain columns from the record
628 if (SQLGetData(hstmt, 1, SQL_C_CHAR, structSQLTypeInfo.TypeName, DB_TYPE_NAME_LEN, &cbRet) != SQL_SUCCESS)
629 return(DispAllErrors(henv, hdbc, hstmt));
630 if (SQLGetData(hstmt, 3, SQL_C_LONG, &structSQLTypeInfo.Precision, 0, &cbRet) != SQL_SUCCESS)
631 return(DispAllErrors(henv, hdbc, hstmt));
632 if (SQLGetData(hstmt, 8, SQL_C_SHORT, &structSQLTypeInfo.CaseSensitive, 0, &cbRet) != SQL_SUCCESS)
633 return(DispAllErrors(henv, hdbc, hstmt));
634 // if (SQLGetData(hstmt, 14, SQL_C_SHORT, &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS)
635 // return(DispAllErrors(henv, hdbc, hstmt));
636 if (SQLGetData(hstmt, 15, SQL_C_SHORT, &structSQLTypeInfo.MaximumScale, 0, &cbRet) != SQL_SUCCESS)
637 return(DispAllErrors(henv, hdbc, hstmt));
638
639 if (structSQLTypeInfo.MaximumScale < 0)
640 structSQLTypeInfo.MaximumScale = 0;
641
642 // Close the statement handle which closes open cursors
643 if (SQLFreeStmt(hstmt, SQL_CLOSE) != SQL_SUCCESS)
644 return(DispAllErrors(henv, hdbc, hstmt));
645
646 // Completed Successfully
647 return(TRUE);
648
649 } // wxDB::getDataTypeInfo()
650
651 /********** wxDB::Close() **********/
652 void wxDB::Close(void)
653 {
654 // Close the Sql Log file
655 if (fpSqlLog)
656 {
657 fclose(fpSqlLog);
658 fpSqlLog = 0; //glt
659 }
660
661 // Free statement handle
662 if (dbIsOpen)
663 {
664 if (SQLFreeStmt(hstmt, SQL_DROP) != SQL_SUCCESS)
665 DispAllErrors(henv, hdbc);
666 }
667
668 // Disconnect from the datasource
669 if (SQLDisconnect(hdbc) != SQL_SUCCESS)
670 DispAllErrors(henv, hdbc);
671
672 // Free the connection to the datasource
673 if (SQLFreeConnect(hdbc) != SQL_SUCCESS)
674 DispAllErrors(henv, hdbc);
675
676 } // wxDB::Close()
677
678 /********** wxDB::CommitTrans() **********/
679 bool wxDB::CommitTrans(void)
680 {
681 // Commit the transaction
682 if (SQLTransact(henv, hdbc, SQL_COMMIT) != SQL_SUCCESS)
683 return(DispAllErrors(henv, hdbc));
684
685 // Completed successfully
686 return(TRUE);
687
688 } // wxDB::CommitTrans()
689
690 /********** wxDB::RollbackTrans() **********/
691 bool wxDB::RollbackTrans(void)
692 {
693 // Rollback the transaction
694 if (SQLTransact(henv, hdbc, SQL_ROLLBACK) != SQL_SUCCESS)
695 return(DispAllErrors(henv, hdbc));
696
697 // Completed successfully
698 return(TRUE);
699
700 } // wxDB::RollbackTrans()
701
702 /********** wxDB::DispAllErrors() **********/
703 bool wxDB::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
704 {
705 char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
706
707 while (SQLError(aHenv, aHdbc, aHstmt, (UCHAR FAR *) sqlState, &nativeError, (UCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
708 {
709 sprintf(odbcErrMsg, "SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState, nativeError, errorMsg);
710 logError(odbcErrMsg, sqlState);
711 if (!silent)
712 {
713 #ifdef DBDEBUG_CONSOLE
714 // When run in console mode, use standard out to display errors.
715 cout << odbcErrMsg << endl;
716 cout << "Press any key to continue..." << endl;
717 getchar();
718 #endif
719 }
720 }
721
722 return(FALSE); // This function alway's returns false.
723
724 } // wxDB::DispAllErrors()
725
726 /********** wxDB::GetNextError() **********/
727 bool wxDB::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt)
728 {
729 if (SQLError(aHenv, aHdbc, aHstmt, (UCHAR FAR *) sqlState, &nativeError, (UCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS)
730 return(TRUE);
731 else
732 return(FALSE);
733
734 } // wxDB::GetNextError()
735
736 /********** wxDB::DispNextError() **********/
737 void wxDB::DispNextError(void)
738 {
739 char odbcErrMsg[DB_MAX_ERROR_MSG_LEN];
740
741 sprintf(odbcErrMsg, "SQL State = %s\nNative Error Code = %li\nError Message = %s\n", sqlState, nativeError, errorMsg);
742 logError(odbcErrMsg, sqlState);
743
744 if (silent)
745 return;
746
747 #ifdef DBDEBUG_CONSOLE
748 // When run in console mode, use standard out to display errors.
749 cout << odbcErrMsg << endl;
750 cout << "Press any key to continue..." << endl;
751 getchar();
752 #endif
753
754 } // wxDB::DispNextError()
755
756 /********** wxDB::logError() **********/
757 void wxDB::logError(char *errMsg, char *SQLState)
758 {
759 assert(errMsg && strlen(errMsg));
760
761 static int pLast = -1;
762 int dbStatus;
763
764 if (++pLast == DB_MAX_ERROR_HISTORY)
765 {
766 for (int i = 0; i < DB_MAX_ERROR_HISTORY; i++)
767 strcpy(errorList[i], errorList[i+1]);
768 pLast--;
769 }
770
771 strcpy(errorList[pLast], errMsg);
772
773 if (SQLState && strlen(SQLState))
774 if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR)
775 DB_STATUS = dbStatus;
776
777 } // wxDB::logError()
778
779 /**********wxDB::TranslateSqlState() **********/
780 int wxDB::TranslateSqlState(char *SQLState)
781 {
782 if (!strcmp(SQLState, "01000"))
783 return(DB_ERR_GENERAL_WARNING);
784 if (!strcmp(SQLState, "01002"))
785 return(DB_ERR_DISCONNECT_ERROR);
786 if (!strcmp(SQLState, "01004"))
787 return(DB_ERR_DATA_TRUNCATED);
788 if (!strcmp(SQLState, "01006"))
789 return(DB_ERR_PRIV_NOT_REVOKED);
790 if (!strcmp(SQLState, "01S00"))
791 return(DB_ERR_INVALID_CONN_STR_ATTR);
792 if (!strcmp(SQLState, "01S01"))
793 return(DB_ERR_ERROR_IN_ROW);
794 if (!strcmp(SQLState, "01S02"))
795 return(DB_ERR_OPTION_VALUE_CHANGED);
796 if (!strcmp(SQLState, "01S03"))
797 return(DB_ERR_NO_ROWS_UPD_OR_DEL);
798 if (!strcmp(SQLState, "01S04"))
799 return(DB_ERR_MULTI_ROWS_UPD_OR_DEL);
800 if (!strcmp(SQLState, "07001"))
801 return(DB_ERR_WRONG_NO_OF_PARAMS);
802 if (!strcmp(SQLState, "07006"))
803 return(DB_ERR_DATA_TYPE_ATTR_VIOL);
804 if (!strcmp(SQLState, "08001"))
805 return(DB_ERR_UNABLE_TO_CONNECT);
806 if (!strcmp(SQLState, "08002"))
807 return(DB_ERR_CONNECTION_IN_USE);
808 if (!strcmp(SQLState, "08003"))
809 return(DB_ERR_CONNECTION_NOT_OPEN);
810 if (!strcmp(SQLState, "08004"))
811 return(DB_ERR_REJECTED_CONNECTION);
812 if (!strcmp(SQLState, "08007"))
813 return(DB_ERR_CONN_FAIL_IN_TRANS);
814 if (!strcmp(SQLState, "08S01"))
815 return(DB_ERR_COMM_LINK_FAILURE);
816 if (!strcmp(SQLState, "21S01"))
817 return(DB_ERR_INSERT_VALUE_LIST_MISMATCH);
818 if (!strcmp(SQLState, "21S02"))
819 return(DB_ERR_DERIVED_TABLE_MISMATCH);
820 if (!strcmp(SQLState, "22001"))
821 return(DB_ERR_STRING_RIGHT_TRUNC);
822 if (!strcmp(SQLState, "22003"))
823 return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG);
824 if (!strcmp(SQLState, "22005"))
825 return(DB_ERR_ERROR_IN_ASSIGNMENT);
826 if (!strcmp(SQLState, "22008"))
827 return(DB_ERR_DATETIME_FLD_OVERFLOW);
828 if (!strcmp(SQLState, "22012"))
829 return(DB_ERR_DIVIDE_BY_ZERO);
830 if (!strcmp(SQLState, "22026"))
831 return(DB_ERR_STR_DATA_LENGTH_MISMATCH);
832 if (!strcmp(SQLState, "23000"))
833 return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL);
834 if (!strcmp(SQLState, "24000"))
835 return(DB_ERR_INVALID_CURSOR_STATE);
836 if (!strcmp(SQLState, "25000"))
837 return(DB_ERR_INVALID_TRANS_STATE);
838 if (!strcmp(SQLState, "28000"))
839 return(DB_ERR_INVALID_AUTH_SPEC);
840 if (!strcmp(SQLState, "34000"))
841 return(DB_ERR_INVALID_CURSOR_NAME);
842 if (!strcmp(SQLState, "37000"))
843 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL);
844 if (!strcmp(SQLState, "3C000"))
845 return(DB_ERR_DUPLICATE_CURSOR_NAME);
846 if (!strcmp(SQLState, "40001"))
847 return(DB_ERR_SERIALIZATION_FAILURE);
848 if (!strcmp(SQLState, "42000"))
849 return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2);
850 if (!strcmp(SQLState, "70100"))
851 return(DB_ERR_OPERATION_ABORTED);
852 if (!strcmp(SQLState, "IM001"))
853 return(DB_ERR_UNSUPPORTED_FUNCTION);
854 if (!strcmp(SQLState, "IM002"))
855 return(DB_ERR_NO_DATA_SOURCE);
856 if (!strcmp(SQLState, "IM003"))
857 return(DB_ERR_DRIVER_LOAD_ERROR);
858 if (!strcmp(SQLState, "IM004"))
859 return(DB_ERR_SQLALLOCENV_FAILED);
860 if (!strcmp(SQLState, "IM005"))
861 return(DB_ERR_SQLALLOCCONNECT_FAILED);
862 if (!strcmp(SQLState, "IM006"))
863 return(DB_ERR_SQLSETCONNECTOPTION_FAILED);
864 if (!strcmp(SQLState, "IM007"))
865 return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB);
866 if (!strcmp(SQLState, "IM008"))
867 return(DB_ERR_DIALOG_FAILED);
868 if (!strcmp(SQLState, "IM009"))
869 return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL);
870 if (!strcmp(SQLState, "IM010"))
871 return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG);
872 if (!strcmp(SQLState, "IM011"))
873 return(DB_ERR_DRIVER_NAME_TOO_LONG);
874 if (!strcmp(SQLState, "IM012"))
875 return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR);
876 if (!strcmp(SQLState, "IM013"))
877 return(DB_ERR_TRACE_FILE_ERROR);
878 if (!strcmp(SQLState, "S0001"))
879 return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS);
880 if (!strcmp(SQLState, "S0002"))
881 return(DB_ERR_TABLE_NOT_FOUND);
882 if (!strcmp(SQLState, "S0011"))
883 return(DB_ERR_INDEX_ALREADY_EXISTS);
884 if (!strcmp(SQLState, "S0012"))
885 return(DB_ERR_INDEX_NOT_FOUND);
886 if (!strcmp(SQLState, "S0021"))
887 return(DB_ERR_COLUMN_ALREADY_EXISTS);
888 if (!strcmp(SQLState, "S0022"))
889 return(DB_ERR_COLUMN_NOT_FOUND);
890 if (!strcmp(SQLState, "S0023"))
891 return(DB_ERR_NO_DEFAULT_FOR_COLUMN);
892 if (!strcmp(SQLState, "S1000"))
893 return(DB_ERR_GENERAL_ERROR);
894 if (!strcmp(SQLState, "S1001"))
895 return(DB_ERR_MEMORY_ALLOCATION_FAILURE);
896 if (!strcmp(SQLState, "S1002"))
897 return(DB_ERR_INVALID_COLUMN_NUMBER);
898 if (!strcmp(SQLState, "S1003"))
899 return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE);
900 if (!strcmp(SQLState, "S1004"))
901 return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE);
902 if (!strcmp(SQLState, "S1008"))
903 return(DB_ERR_OPERATION_CANCELLED);
904 if (!strcmp(SQLState, "S1009"))
905 return(DB_ERR_INVALID_ARGUMENT_VALUE);
906 if (!strcmp(SQLState, "S1010"))
907 return(DB_ERR_FUNCTION_SEQUENCE_ERROR);
908 if (!strcmp(SQLState, "S1011"))
909 return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME);
910 if (!strcmp(SQLState, "S1012"))
911 return(DB_ERR_INVALID_TRANS_OPERATION_CODE);
912 if (!strcmp(SQLState, "S1015"))
913 return(DB_ERR_NO_CURSOR_NAME_AVAIL);
914 if (!strcmp(SQLState, "S1090"))
915 return(DB_ERR_INVALID_STR_OR_BUF_LEN);
916 if (!strcmp(SQLState, "S1091"))
917 return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE);
918 if (!strcmp(SQLState, "S1092"))
919 return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE);
920 if (!strcmp(SQLState, "S1093"))
921 return(DB_ERR_INVALID_PARAM_NO);
922 if (!strcmp(SQLState, "S1094"))
923 return(DB_ERR_INVALID_SCALE_VALUE);
924 if (!strcmp(SQLState, "S1095"))
925 return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE);
926 if (!strcmp(SQLState, "S1096"))
927 return(DB_ERR_INF_TYPE_OUT_OF_RANGE);
928 if (!strcmp(SQLState, "S1097"))
929 return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE);
930 if (!strcmp(SQLState, "S1098"))
931 return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE);
932 if (!strcmp(SQLState, "S1099"))
933 return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE);
934 if (!strcmp(SQLState, "S1100"))
935 return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE);
936 if (!strcmp(SQLState, "S1101"))
937 return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE);
938 if (!strcmp(SQLState, "S1103"))
939 return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE);
940 if (!strcmp(SQLState, "S1104"))
941 return(DB_ERR_INVALID_PRECISION_VALUE);
942 if (!strcmp(SQLState, "S1105"))
943 return(DB_ERR_INVALID_PARAM_TYPE);
944 if (!strcmp(SQLState, "S1106"))
945 return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE);
946 if (!strcmp(SQLState, "S1107"))
947 return(DB_ERR_ROW_VALUE_OUT_OF_RANGE);
948 if (!strcmp(SQLState, "S1108"))
949 return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE);
950 if (!strcmp(SQLState, "S1109"))
951 return(DB_ERR_INVALID_CURSOR_POSITION);
952 if (!strcmp(SQLState, "S1110"))
953 return(DB_ERR_INVALID_DRIVER_COMPLETION);
954 if (!strcmp(SQLState, "S1111"))
955 return(DB_ERR_INVALID_BOOKMARK_VALUE);
956 if (!strcmp(SQLState, "S1C00"))
957 return(DB_ERR_DRIVER_NOT_CAPABLE);
958 if (!strcmp(SQLState, "S1T00"))
959 return(DB_ERR_TIMEOUT_EXPIRED);
960
961 // No match
962 return(0);
963
964 } // wxDB::TranslateSqlState()
965
966 /********** wxDB::Grant() **********/
967 bool wxDB::Grant(int privileges, char *tableName, char *userList)
968 {
969 char sqlStmt[DB_MAX_STATEMENT_LEN];
970
971 // Build the grant statement
972 strcpy(sqlStmt, "GRANT ");
973 if (privileges == DB_GRANT_ALL)
974 strcat(sqlStmt, "ALL");
975 else
976 {
977 int c = 0;
978 if (privileges & DB_GRANT_SELECT)
979 {
980 strcat(sqlStmt, "SELECT");
981 c++;
982 }
983 if (privileges & DB_GRANT_INSERT)
984 {
985 if (c++)
986 strcat(sqlStmt, ", ");
987 strcat(sqlStmt, "INSERT");
988 }
989 if (privileges & DB_GRANT_UPDATE)
990 {
991 if (c++)
992 strcat(sqlStmt, ", ");
993 strcat(sqlStmt, "UPDATE");
994 }
995 if (privileges & DB_GRANT_DELETE)
996 {
997 if (c++)
998 strcat(sqlStmt, ", ");
999 strcat(sqlStmt, "DELETE");
1000 }
1001 }
1002
1003 strcat(sqlStmt, " ON ");
1004 strcat(sqlStmt, tableName);
1005 strcat(sqlStmt, " TO ");
1006 strcat(sqlStmt, userList);
1007
1008 #ifdef DBDEBUG_CONSOLE
1009 cout << endl << sqlStmt << endl;
1010 #endif
1011
1012 WriteSqlLog(sqlStmt);
1013
1014 return(ExecSql(sqlStmt));
1015
1016 } // wxDB::Grant()
1017
1018 /********** wxDB::CreateView() **********/
1019 bool wxDB::CreateView(char *viewName, char *colList, char *pSqlStmt)
1020 {
1021 char sqlStmt[DB_MAX_STATEMENT_LEN];
1022
1023 // Drop the view first
1024 sprintf(sqlStmt, "DROP VIEW %s", viewName);
1025 if (SQLExecDirect(hstmt, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS)
1026 {
1027 // Check for sqlState = S0002, "Table or view not found".
1028 // Ignore this error, bomb out on any other error.
1029 // SQL Sybase Anwhere v5.5 returns an access violation error here
1030 // (sqlstate = 42000) rather than an S0002.
1031 GetNextError(henv, hdbc, hstmt);
1032 if (strcmp(sqlState, "S0002") && strcmp(sqlState, "42000"))
1033 {
1034 DispNextError();
1035 DispAllErrors(henv, hdbc, hstmt);
1036 RollbackTrans();
1037 return(FALSE);
1038 }
1039 }
1040
1041 WriteSqlLog(sqlStmt);
1042
1043 #ifdef DBDEBUG_CONSOLE
1044 cout << endl << sqlStmt << endl;
1045 #endif
1046
1047 // Build the create view statement
1048 strcpy(sqlStmt, "CREATE VIEW ");
1049 strcat(sqlStmt, viewName);
1050
1051 if (strlen(colList))
1052 {
1053 strcat(sqlStmt, " (");
1054 strcat(sqlStmt, colList);
1055 strcat(sqlStmt, ")");
1056 }
1057
1058 strcat(sqlStmt, " AS ");
1059 strcat(sqlStmt, pSqlStmt);
1060
1061 WriteSqlLog(sqlStmt);
1062
1063 #ifdef DBDEBUG_CONSOLE
1064 cout << sqlStmt << endl;
1065 #endif
1066
1067 return(ExecSql(sqlStmt));
1068
1069 } // wxDB::CreateView()
1070
1071 /********** wxDB::ExecSql() **********/
1072 bool wxDB::ExecSql(char *pSqlStmt)
1073 {
1074 if (SQLExecDirect(hstmt, (UCHAR FAR *) pSqlStmt, SQL_NTS) == SQL_SUCCESS)
1075 return(TRUE);
1076 else
1077 {
1078 DispAllErrors(henv, hdbc, hstmt);
1079 return(FALSE);
1080 }
1081
1082 } // wxDB::ExecSql()
1083
1084 /********** wxDB::GetColumns() **********/
1085 /*
1086 * 1) The last array element of the tableName[] argument must be zero (null).
1087 * This is how the end of the array is detected.
1088 * 2) This function returns an array of CcolInf structures. If no columns
1089 * were found, or an error occured, this pointer will be zero (null). THE
1090 * CALLING FUNCTION IS RESPONSIBLE FOR DELETING THE MEMORY RETURNED WHEN IT
1091 * IS FINISHED WITH IT. i.e.
1092 *
1093 * CcolInf *colInf = pDb->GetColumns(tableList);
1094 * if (colInf)
1095 * {
1096 * // Use the column inf
1097 * .......
1098 * // Destroy the memory
1099 * delete [] colInf;
1100 * }
1101 */
1102 CcolInf *wxDB::GetColumns(char *tableName[])
1103 {
1104 UINT noCols = 0;
1105 UINT colNo = 0;
1106 CcolInf *colInf = 0;
1107 RETCODE retcode;
1108 SDWORD cb;
1109 char tblName[DB_MAX_TABLE_NAME_LEN+1];
1110 char colName[DB_MAX_COLUMN_NAME_LEN+1];
1111 SWORD sqlDataType;
1112
1113 // Pass 1 - Determine how many columns there are.
1114 // Pass 2 - Allocate the CcolInf array and fill in
1115 // the array with the column information.
1116 for (int pass = 1; pass <= 2; pass++)
1117 {
1118 if (pass == 2)
1119 {
1120 if (noCols == 0) // Probably a bogus table name(s)
1121 break;
1122 // Allocate n CcolInf objects to hold the column information
1123 colInf = new CcolInf[noCols+1];
1124 if (!colInf)
1125 break;
1126 // Mark the end of the array
1127 strcpy(colInf[noCols].tableName, "");
1128 strcpy(colInf[noCols].colName, "");
1129 colInf[noCols].sqlDataType = 0;
1130 }
1131 // Loop through each table name
1132 for (int tbl = 0; tableName[tbl]; tbl++)
1133 {
1134 SQLFreeStmt(hstmt, SQL_CLOSE);
1135 retcode = SQLColumns(hstmt,
1136 NULL, 0, // All qualifiers
1137 NULL, 0, // All owners
1138 (UCHAR *) tableName[tbl], SQL_NTS,
1139 NULL, 0); // All columns
1140 if (retcode != SQL_SUCCESS)
1141 { // Error occured, abort
1142 DispAllErrors(henv, hdbc, hstmt);
1143 if (colInf)
1144 delete [] colInf;
1145 return(0);
1146 }
1147 SQLBindCol(hstmt, 3, SQL_C_CHAR, tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
1148 SQLBindCol(hstmt, 4, SQL_C_CHAR, colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1149 SQLBindCol(hstmt, 5, SQL_C_SSHORT, &sqlDataType, 0, &cb);
1150 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
1151 {
1152 if (pass == 1) // First pass, just add up the number of columns
1153 noCols++;
1154 else // Pass 2; Fill in the array of structures
1155 {
1156 if (colNo < noCols) // Some extra error checking to prevent memory overwrites
1157 {
1158 strcpy(colInf[colNo].tableName, tblName);
1159 strcpy(colInf[colNo].colName, colName);
1160 colInf[colNo].sqlDataType = sqlDataType;
1161 colNo++;
1162 }
1163 }
1164 }
1165 if (retcode != SQL_NO_DATA_FOUND)
1166 { // Error occured, abort
1167 DispAllErrors(henv, hdbc, hstmt);
1168 if (colInf)
1169 delete [] colInf;
1170 return(0);
1171 }
1172 }
1173 }
1174
1175 SQLFreeStmt(hstmt, SQL_CLOSE);
1176 return colInf;
1177
1178 } // wxDB::GetColumns()
1179
1180
1181 /********** wxDB::Catalog() **********/
1182 bool wxDB::Catalog(char *userID, char *fileName)
1183 {
1184 assert(userID && strlen(userID));
1185 assert(fileName && strlen(fileName));
1186
1187 RETCODE retcode;
1188 SDWORD cb;
1189 char tblName[DB_MAX_TABLE_NAME_LEN+1];
1190 char tblNameSave[DB_MAX_TABLE_NAME_LEN+1];
1191 char colName[DB_MAX_COLUMN_NAME_LEN+1];
1192 SWORD sqlDataType;
1193 char typeName[16];
1194 SWORD precision, length;
1195
1196 FILE *fp = fopen(fileName,"wt");
1197 if (fp == NULL)
1198 return(FALSE);
1199
1200 SQLFreeStmt(hstmt, SQL_CLOSE);
1201
1202 int i = 0;
1203 char userIdUC[81];
1204 for (char *p = userID; *p; p++)
1205 userIdUC[i++] = toupper(*p);
1206 userIdUC[i] = 0;
1207
1208 retcode = SQLColumns(hstmt,
1209 NULL, 0, // All qualifiers
1210 (UCHAR *) userIdUC, SQL_NTS, // User specified
1211 NULL, 0, // All tables
1212 NULL, 0); // All columns
1213 if (retcode != SQL_SUCCESS)
1214 {
1215 DispAllErrors(henv, hdbc, hstmt);
1216 fclose(fp);
1217 return(FALSE);
1218 }
1219
1220 SQLBindCol(hstmt, 3, SQL_C_CHAR, tblName, DB_MAX_TABLE_NAME_LEN+1, &cb);
1221 SQLBindCol(hstmt, 4, SQL_C_CHAR, colName, DB_MAX_COLUMN_NAME_LEN+1, &cb);
1222 SQLBindCol(hstmt, 5, SQL_C_SSHORT, &sqlDataType, 0, &cb);
1223 SQLBindCol(hstmt, 6, SQL_C_CHAR, typeName, 16, &cb);
1224 SQLBindCol(hstmt, 7, SQL_C_SSHORT, &precision, 0, &cb);
1225 SQLBindCol(hstmt, 8, SQL_C_SSHORT, &length, 0, &cb);
1226
1227 char outStr[256];
1228 strcpy(tblNameSave,"");
1229 int cnt = 0;
1230
1231 while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
1232 {
1233 if (strcmp(tblName,tblNameSave))
1234 {
1235 if (cnt)
1236 fputs("\n", fp);
1237 fputs("================================ ", fp);
1238 fputs("================================ ", fp);
1239 fputs("===================== ", fp);
1240 fputs("========= ", fp);
1241 fputs("=========\n", fp);
1242 sprintf(outStr, "%-32s %-32s %-21s %9s %9s\n",
1243 "TABLE NAME", "COLUMN NAME", "DATA TYPE", "PRECISION", "LENGTH");
1244 fputs(outStr, fp);
1245 fputs("================================ ", fp);
1246 fputs("================================ ", fp);
1247 fputs("===================== ", fp);
1248 fputs("========= ", fp);
1249 fputs("=========\n", fp);
1250 strcpy(tblNameSave,tblName);
1251 }
1252 sprintf(outStr, "%-32s %-32s (%04d)%-15s %9d %9d\n",
1253 tblName, colName, sqlDataType, typeName, precision, length);
1254 if (fputs(outStr, fp) == EOF)
1255 {
1256 fclose(fp);
1257 return(FALSE);
1258 }
1259 cnt++;
1260 }
1261
1262 if (retcode != SQL_NO_DATA_FOUND)
1263 {
1264 DispAllErrors(henv, hdbc, hstmt);
1265 fclose(fp);
1266 return(FALSE);
1267 }
1268
1269 SQLFreeStmt(hstmt, SQL_CLOSE);
1270 fclose(fp);
1271 return(TRUE);
1272
1273 } // wxDB::Catalog()
1274
1275
1276 // Table name can refer to a table, view, alias or synonym. Returns true
1277 // if the object exists in the database. This function does not indicate
1278 // whether or not the user has privleges to query or perform other functions
1279 // on the table.
1280 bool wxDB::TableExists(char *tableName)
1281 {
1282 assert(tableName && strlen(tableName));
1283
1284 SQLFreeStmt(hstmt, SQL_CLOSE);
1285 RETCODE retcode = SQLTables(hstmt,
1286 NULL, 0, // All qualifiers
1287 NULL, 0, // All owners
1288 (UCHAR FAR *)tableName, SQL_NTS,
1289 NULL, 0); // All table types
1290 if (retcode != SQL_SUCCESS)
1291 return(DispAllErrors(henv, hdbc, hstmt));
1292
1293 if (SQLFetch(hstmt) != SQL_SUCCESS)
1294 {
1295 SQLFreeStmt(hstmt, SQL_CLOSE);
1296 return(DispAllErrors(henv, hdbc, hstmt));
1297 }
1298
1299 SQLFreeStmt(hstmt, SQL_CLOSE);
1300 return(TRUE);
1301
1302 } // wxDB::TableExists()
1303
1304
1305 /********** wxDB::SqlLog() **********/
1306 bool wxDB::SqlLog(enum sqlLog state, char *filename, bool append)
1307 {
1308 assert(state == sqlLogON || state == sqlLogOFF);
1309 assert(state == sqlLogOFF || filename);
1310
1311 if (state == sqlLogON)
1312 {
1313 if (fpSqlLog == 0)
1314 {
1315 fpSqlLog = fopen(filename, (append ? "at" : "wt"));
1316 if (fpSqlLog == NULL)
1317 return(FALSE);
1318 }
1319 }
1320 else // sqlLogOFF
1321 {
1322 if (fpSqlLog)
1323 {
1324 if (fclose(fpSqlLog))
1325 return(FALSE);
1326 fpSqlLog = 0;
1327 }
1328 }
1329
1330 sqlLogState = state;
1331 return(TRUE);
1332
1333 } // wxDB::SqlLog()
1334
1335
1336 /********** wxDB::WriteSqlLog() **********/
1337 bool wxDB::WriteSqlLog(char *logMsg)
1338 {
1339 assert(logMsg);
1340
1341 if (fpSqlLog == 0 || sqlLogState == sqlLogOFF)
1342 return(FALSE);
1343
1344 if (fputs("\n", fpSqlLog) == EOF) return(FALSE);
1345 if (fputs(logMsg, fpSqlLog) == EOF) return(FALSE);
1346 if (fputs("\n", fpSqlLog) == EOF) return(FALSE);
1347
1348 return(TRUE);
1349
1350 } // wxDB::WriteSqlLog()
1351
1352
1353 /********** GetDbConnection() **********/
1354 wxDB *GetDbConnection(DbStuff *pDbStuff)
1355 {
1356 DbList *pList;
1357
1358 // Scan the linked list searching for an available database connection
1359 // that's already been opened but is currently not in use.
1360 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
1361 {
1362 // The database connection must be for the same datasource
1363 // name and must currently not be in use.
1364 if (pList->Free && (! strcmp(pDbStuff->Dsn, pList->Dsn))) // Found a free connection
1365 {
1366 pList->Free = FALSE;
1367 return(pList->PtrDb);
1368 }
1369 }
1370
1371 // No available connections. A new connection must be made and
1372 // appended to the end of the linked list.
1373 if (PtrBegDbList)
1374 {
1375 // Find the end of the list
1376 for (pList = PtrBegDbList; pList->PtrNext; pList = pList->PtrNext);
1377 // Append a new list item
1378 pList->PtrNext = new DbList;
1379 pList->PtrNext->PtrPrev = pList;
1380 pList = pList->PtrNext;
1381 }
1382 else // Empty list
1383 {
1384 // Create the first node on the list
1385 pList = PtrBegDbList = new DbList;
1386 pList->PtrPrev = 0;
1387 }
1388
1389 // Initialize new node in the linked list
1390 pList->PtrNext = 0;
1391 pList->Free = FALSE;
1392 strcpy(pList->Dsn, pDbStuff->Dsn);
1393 pList->PtrDb = new wxDB(pDbStuff->Henv);
1394
1395 // Connect to the datasource
1396 if (pList->PtrDb->Open(pDbStuff->Dsn, pDbStuff->Uid, pDbStuff->AuthStr))
1397 return(pList->PtrDb);
1398 else // Unable to connect, destroy list item
1399 {
1400 if (pList->PtrPrev)
1401 pList->PtrPrev->PtrNext = 0;
1402 else
1403 PtrBegDbList = 0; // Empty list again
1404 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDB object
1405 pList->PtrDb->Close(); // Close the wxDB object
1406 delete pList->PtrDb; // Deletes the wxDB object
1407 delete pList; // Deletes the linked list object
1408 return(0);
1409 }
1410
1411 } // GetDbConnection()
1412
1413 /********** FreeDbConnection() **********/
1414 bool FreeDbConnection(wxDB *pDb)
1415 {
1416 DbList *pList;
1417
1418 // Scan the linked list searching for the database connection
1419 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
1420 {
1421 if (pList->PtrDb == pDb) // Found it!!!
1422 return(pList->Free = TRUE);
1423 }
1424
1425 // Never found the database object, return failure
1426 return(FALSE);
1427
1428 } // FreeDbConnection()
1429
1430 /********** CloseDbConnections() **********/
1431 void CloseDbConnections(void)
1432 {
1433 DbList *pList, *pNext;
1434
1435 // Traverse the linked list closing database connections and freeing memory as I go.
1436 for (pList = PtrBegDbList; pList; pList = pNext)
1437 {
1438 pNext = pList->PtrNext; // Save the pointer to next
1439 pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDB object
1440 pList->PtrDb->Close(); // Close the wxDB object
1441 delete pList->PtrDb; // Deletes the wxDB object
1442 delete pList; // Deletes the linked list object
1443 }
1444
1445 // Mark the list as empty
1446 PtrBegDbList = 0;
1447
1448 } // CloseDbConnections()
1449
1450 /********** NumberDbConnectionsInUse() **********/
1451 int NumberDbConnectionsInUse(void)
1452 {
1453 DbList *pList;
1454 int cnt = 0;
1455
1456 // Scan the linked list counting db connections that are currently in use
1457 for (pList = PtrBegDbList; pList; pList = pList->PtrNext)
1458 {
1459 if (pList->Free == FALSE)
1460 cnt++;
1461 }
1462
1463 return(cnt);
1464
1465 } // NumberDbConnectionsInUse()
1466
1467 /********** GetDataSource() **********/
1468 bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax,
1469 UWORD direction)
1470 {
1471 SWORD cb;
1472
1473 if (SQLDataSources(henv, direction, (UCHAR FAR *) Dsn, DsnMax, &cb,
1474 (UCHAR FAR *) DsDesc, DsDescMax, &cb) == SQL_SUCCESS)
1475 return(TRUE);
1476 else
1477 return(FALSE);
1478
1479 } // GetDataSource()
1480
1481 #endif
1482 // wxUSE_ODBC
1483