1 | /********************************************************************* |
2 | * |
3 | * This is based on code created by Peter Harvey, |
4 | * (pharvey@codebydesign.com). |
5 | * |
6 | * Modified and extended by Nick Gorham |
7 | * (nick@lurcher.org). |
8 | * |
9 | * Any bugs or problems should be considered the fault of Nick and not |
10 | * Peter. |
11 | * |
12 | * copyright (c) 1999 Nick Gorham |
13 | * |
14 | * This library is free software; you can redistribute it and/or |
15 | * modify it under the terms of the GNU Lesser General Public |
16 | * License as published by the Free Software Foundation; either |
17 | * version 2 of the License, or (at your option) any later version. |
18 | * |
19 | * This library is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
22 | * Lesser General Public License for more details. |
23 | * |
24 | * You should have received a copy of the GNU Lesser General Public |
25 | * License along with this library; if not, write to the Free Software |
26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
27 | * |
28 | ********************************************************************** |
29 | * |
30 | * $Id: SQLDrivers.c,v 1.13 2009/02/18 17:59:08 lurcher Exp $ |
31 | * |
32 | * $Log: SQLDrivers.c,v $ |
33 | * Revision 1.13 2009/02/18 17:59:08 lurcher |
34 | * Shift to using config.h, the compile lines were making it hard to spot warnings |
35 | * |
36 | * Revision 1.12 2009/02/17 09:47:44 lurcher |
37 | * Clear up a number of bugs |
38 | * |
39 | * Revision 1.11 2008/09/29 14:02:45 lurcher |
40 | * Fix missing dlfcn group option |
41 | * |
42 | * Revision 1.10 2005/10/06 08:58:19 lurcher |
43 | * Fix problem with SQLDrivers not returning first entry |
44 | * |
45 | * Revision 1.9 2005/07/17 09:11:23 lurcher |
46 | * Fix bug in SQLDrivers that was stopping the return of the attribute length |
47 | * |
48 | * Revision 1.8 2004/07/25 00:42:02 peteralexharvey |
49 | * for OS2 port |
50 | * |
51 | * Revision 1.7 2003/11/13 15:12:53 lurcher |
52 | * |
53 | * small change to ODBCConfig to have the password field in the driver |
54 | * properties hide the password |
55 | * Make both # and ; comments in ini files |
56 | * |
57 | * Revision 1.6 2003/10/30 18:20:45 lurcher |
58 | * |
59 | * Fix broken thread protection |
60 | * Remove SQLNumResultCols after execute, lease S4/S% to driver |
61 | * Fix string overrun in SQLDriverConnect |
62 | * Add initial support for Interix |
63 | * |
64 | * Revision 1.5 2003/02/27 12:19:39 lurcher |
65 | * |
66 | * Add the A functions as well as the W |
67 | * |
68 | * Revision 1.4 2002/12/05 17:44:30 lurcher |
69 | * |
70 | * Display unknown return values in return logging |
71 | * |
72 | * Revision 1.3 2002/05/21 14:19:44 lurcher |
73 | * |
74 | * * Update libtool to escape from AIX build problem |
75 | * * Add fix to avoid file handle limitations |
76 | * * Add more UNICODE changes, it looks like it is native 16 representation |
77 | * the old way can be reproduced by defining UCS16BE |
78 | * * Add iusql, its just the same as isql but uses the wide functions |
79 | * |
80 | * Revision 1.2 2001/12/13 13:00:32 lurcher |
81 | * |
82 | * Remove most if not all warnings on 64 bit platforms |
83 | * Add support for new MS 3.52 64 bit changes |
84 | * Add override to disable the stopping of tracing |
85 | * Add MAX_ROWS support in postgres driver |
86 | * |
87 | * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher |
88 | * |
89 | * First upload to SourceForge |
90 | * |
91 | * Revision 1.3 2001/05/15 10:57:44 nick |
92 | * |
93 | * Add initial support for VMS |
94 | * |
95 | * Revision 1.2 2001/04/12 17:43:36 nick |
96 | * |
97 | * Change logging and added autotest to odbctest |
98 | * |
99 | * Revision 1.1.1.1 2000/09/04 16:42:52 nick |
100 | * Imported Sources |
101 | * |
102 | * Revision 1.12 2000/08/16 13:06:21 ngorham |
103 | * |
104 | * Fix invalid return code |
105 | * |
106 | * Revision 1.11 2000/07/13 13:27:24 ngorham |
107 | * |
108 | * remove _ from odbcinst_system_file_path() |
109 | * |
110 | * Revision 1.10 2001/04/04 23:10:34 ngorham |
111 | * |
112 | * Fix a SQLDrivers problem |
113 | * |
114 | * Revision 1.9 2000/02/20 10:18:47 ngorham |
115 | * |
116 | * Add support for ODBCINI environment override for Applix. |
117 | * |
118 | * Revision 1.8 1999/11/13 23:40:59 ngorham |
119 | * |
120 | * Alter the way DM logging works |
121 | * Upgrade the Postgres driver to 6.4.6 |
122 | * |
123 | * Revision 1.7 1999/10/24 23:54:17 ngorham |
124 | * |
125 | * First part of the changes to the error reporting |
126 | * |
127 | * Revision 1.6 1999/09/21 22:34:24 ngorham |
128 | * |
129 | * Improve performance by removing unneeded logging calls when logging is |
130 | * disabled |
131 | * |
132 | * Revision 1.5 1999/09/19 22:24:33 ngorham |
133 | * |
134 | * Added support for the cursor library |
135 | * |
136 | * Revision 1.4 1999/07/10 21:10:16 ngorham |
137 | * |
138 | * Adjust error sqlstate from driver manager, depending on requested |
139 | * version (ODBC2/3) |
140 | * |
141 | * Revision 1.3 1999/07/04 21:05:07 ngorham |
142 | * |
143 | * Add LGPL Headers to code |
144 | * |
145 | * Revision 1.2 1999/06/30 23:56:54 ngorham |
146 | * |
147 | * Add initial thread safety code |
148 | * |
149 | * Revision 1.1.1.1 1999/05/29 13:41:06 sShandyb |
150 | * first go at it |
151 | * |
152 | * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey |
153 | * Imported sources |
154 | * |
155 | * Revision 1.4 1999/05/09 23:27:11 nick |
156 | * All the API done now |
157 | * |
158 | * Revision 1.3 1999/04/30 16:22:47 nick |
159 | * Another checkpoint |
160 | * |
161 | * Revision 1.2 1999/04/29 20:47:37 nick |
162 | * Another checkpoint |
163 | * |
164 | * Revision 1.1 1999/04/25 23:06:11 nick |
165 | * Initial revision |
166 | * |
167 | * |
168 | **********************************************************************/ |
169 | |
170 | #include <config.h> |
171 | #include "drivermanager.h" |
172 | |
173 | static char const rcsid[]= "$RCSfile: SQLDrivers.c,v $ $Revision: 1.13 $" ; |
174 | |
175 | #define BUFFERSIZE 1024 |
176 | |
177 | SQLRETURN SQLDriversA( |
178 | SQLHENV henv, |
179 | SQLUSMALLINT fdirection, |
180 | SQLCHAR *sz_driver_desc, |
181 | SQLSMALLINT cb_driver_desc_max, |
182 | SQLSMALLINT *pcb_driver_desc, |
183 | SQLCHAR *sz_driver_attributes, |
184 | SQLSMALLINT cb_drvr_attr_max, |
185 | SQLSMALLINT *pcb_drvr_attr ) |
186 | { |
187 | return SQLDrivers( henv, |
188 | fdirection, |
189 | sz_driver_desc, |
190 | cb_driver_desc_max, |
191 | pcb_driver_desc, |
192 | sz_driver_attributes, |
193 | cb_drvr_attr_max, |
194 | pcb_drvr_attr ); |
195 | } |
196 | |
197 | SQLRETURN SQLDrivers( |
198 | SQLHENV henv, |
199 | SQLUSMALLINT fdirection, |
200 | SQLCHAR *sz_driver_desc, |
201 | SQLSMALLINT cb_driver_desc_max, |
202 | SQLSMALLINT *pcb_driver_desc, |
203 | SQLCHAR *sz_driver_attributes, |
204 | SQLSMALLINT cb_drvr_attr_max, |
205 | SQLSMALLINT *pcb_drvr_attr ) |
206 | { |
207 | DMHENV environment = (DMHENV) henv; |
208 | char buffer[ BUFFERSIZE + 1 ]; |
209 | char object[ INI_MAX_OBJECT_NAME + 1 ]; |
210 | SQLRETURN ret = SQL_SUCCESS; |
211 | SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ]; |
212 | |
213 | if ( !__validate_env( environment )) |
214 | { |
215 | dm_log_write( __FILE__, |
216 | __LINE__, |
217 | LOG_INFO, |
218 | LOG_INFO, |
219 | "Error: SQL_INVALID_HANDLE" ); |
220 | |
221 | return SQL_INVALID_HANDLE; |
222 | } |
223 | |
224 | function_entry( environment ); |
225 | |
226 | if ( log_info.log_flag ) |
227 | { |
228 | sprintf( environment -> msg, "\n\t\tEntry:\ |
229 | \n\t\t\tEnvironment = %p\ |
230 | \n\t\t\tDirection = %d" , |
231 | environment, |
232 | (int)fdirection ); |
233 | |
234 | dm_log_write( __FILE__, |
235 | __LINE__, |
236 | LOG_INFO, |
237 | LOG_INFO, |
238 | environment -> msg ); |
239 | } |
240 | |
241 | thread_protect( SQL_HANDLE_ENV, environment ); |
242 | |
243 | /* |
244 | * check that a version has been requested |
245 | */ |
246 | |
247 | if ( ! environment -> version_set ) |
248 | { |
249 | dm_log_write( __FILE__, |
250 | __LINE__, |
251 | LOG_INFO, |
252 | LOG_INFO, |
253 | "Error: HY010" ); |
254 | |
255 | __post_internal_error( &environment -> error, |
256 | ERROR_HY010, NULL, |
257 | SQL_OV_ODBC3 ); |
258 | |
259 | return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR ); |
260 | } |
261 | |
262 | if ( cb_driver_desc_max < 0 ) |
263 | { |
264 | dm_log_write( __FILE__, |
265 | __LINE__, |
266 | LOG_INFO, |
267 | LOG_INFO, |
268 | "Error: HY090" ); |
269 | |
270 | __post_internal_error( &environment -> error, |
271 | ERROR_HY090, NULL, |
272 | environment -> requested_version ); |
273 | |
274 | return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR ); |
275 | } |
276 | |
277 | if ( cb_drvr_attr_max < 0 |
278 | || cb_drvr_attr_max == 1 ) |
279 | { |
280 | dm_log_write( __FILE__, |
281 | __LINE__, |
282 | LOG_INFO, |
283 | LOG_INFO, |
284 | "Error: HY090" ); |
285 | |
286 | __post_internal_error( &environment -> error, |
287 | ERROR_HY090, NULL, |
288 | environment -> requested_version ); |
289 | |
290 | return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR ); |
291 | } |
292 | |
293 | if ( fdirection != SQL_FETCH_FIRST && |
294 | fdirection != SQL_FETCH_NEXT ) |
295 | { |
296 | dm_log_write( __FILE__, |
297 | __LINE__, |
298 | LOG_INFO, |
299 | LOG_INFO, |
300 | "Error: HY103" ); |
301 | |
302 | __post_internal_error( &environment -> error, |
303 | ERROR_HY103, NULL, |
304 | environment -> requested_version ); |
305 | |
306 | return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR ); |
307 | } |
308 | |
309 | if ( fdirection == SQL_FETCH_FIRST ) |
310 | environment -> sql_driver_count = 0; |
311 | else |
312 | environment -> sql_driver_count ++; |
313 | |
314 | try_again: |
315 | |
316 | memset( buffer, '\0', sizeof( buffer )); |
317 | memset( object, '\0', sizeof( object )); |
318 | SQLGetPrivateProfileString( NULL, NULL, |
319 | NULL, buffer, sizeof( buffer ), "ODBCINST.INI" ); |
320 | |
321 | if ( iniElement( buffer, '\0', '\0', |
322 | environment -> sql_driver_count, |
323 | object, sizeof( object )) != INI_SUCCESS ) |
324 | { |
325 | /* |
326 | * Set up for the next time |
327 | */ |
328 | environment -> sql_driver_count = -1; |
329 | ret = SQL_NO_DATA; |
330 | } |
331 | else |
332 | { |
333 | ret = SQL_SUCCESS; |
334 | |
335 | /* |
336 | * this section is used for internal info |
337 | */ |
338 | |
339 | if ( strcmp( object, "ODBC" ) == 0 ) |
340 | { |
341 | environment -> sql_driver_count ++; |
342 | goto try_again; |
343 | } |
344 | |
345 | if ( pcb_driver_desc ) |
346 | *pcb_driver_desc = strlen( object ); |
347 | |
348 | if ( sz_driver_desc ) |
349 | { |
350 | if ( strlen( object ) >= cb_driver_desc_max ) |
351 | { |
352 | memcpy( sz_driver_desc, object, cb_driver_desc_max - 1 ); |
353 | sz_driver_desc[ cb_driver_desc_max - 1 ] = '\0'; |
354 | ret = SQL_SUCCESS_WITH_INFO; |
355 | } |
356 | else |
357 | { |
358 | strcpy((char*) sz_driver_desc, object ); |
359 | } |
360 | } |
361 | else |
362 | { |
363 | ret = SQL_SUCCESS; |
364 | } |
365 | |
366 | if ( sz_driver_attributes || |
367 | pcb_drvr_attr ) |
368 | { |
369 | HINI hIni; |
370 | char szPropertyName[INI_MAX_PROPERTY_NAME+1]; |
371 | char szValue[INI_MAX_PROPERTY_NAME+1]; |
372 | char szIniName[ INI_MAX_OBJECT_NAME + 1 ]; |
373 | char buffer[ 1024 ]; |
374 | int total_len = 0; |
375 | char b1[ 256 ], b2[ 256 ]; |
376 | int found = 0; |
377 | |
378 | /* |
379 | * enumerate the driver attributes, first in system odbcinst.ini and if not found in user odbcinst.ini |
380 | */ |
381 | |
382 | sprintf( szIniName, "%s/%s" , odbcinst_system_file_path( b1 ), odbcinst_system_file_name( b2 )); |
383 | |
384 | memset( buffer, '\0', sizeof( buffer )); |
385 | #ifdef __OS2__ |
386 | if ( iniOpen( &hIni, szIniName, "#;" , '[', ']', '=', FALSE, 1L ) == |
387 | INI_SUCCESS ) |
388 | #else |
389 | if ( iniOpen( &hIni, szIniName, "#;" , '[', ']', '=', FALSE ) == |
390 | INI_SUCCESS ) |
391 | #endif |
392 | { |
393 | iniObjectSeek( hIni, (char *)object ); |
394 | iniPropertyFirst( hIni ); |
395 | while ( iniPropertyEOL( hIni ) != TRUE ) |
396 | { |
397 | iniProperty( hIni, szPropertyName ); |
398 | iniValue( hIni, szValue ); |
399 | sprintf( buffer, "%s=%s" , szPropertyName, |
400 | szValue ); |
401 | |
402 | found = 1; |
403 | |
404 | if ( sz_driver_attributes ) { |
405 | |
406 | if ( total_len + strlen( buffer ) + 1 > cb_drvr_attr_max ) |
407 | { |
408 | ret = SQL_SUCCESS_WITH_INFO; |
409 | } |
410 | else |
411 | { |
412 | strcpy((char*) sz_driver_attributes, buffer ); |
413 | sz_driver_attributes += strlen( buffer ) + 1; |
414 | } |
415 | } |
416 | total_len += strlen( buffer ) + 1; |
417 | |
418 | iniPropertyNext( hIni ); |
419 | } |
420 | /* |
421 | * add extra null |
422 | */ |
423 | if ( sz_driver_attributes ) |
424 | *sz_driver_attributes = '\0'; |
425 | |
426 | if ( pcb_drvr_attr ) |
427 | { |
428 | *pcb_drvr_attr = total_len; |
429 | } |
430 | |
431 | iniClose( hIni ); |
432 | } |
433 | |
434 | if ( !found ) |
435 | { |
436 | |
437 | sprintf( szIniName, "%s/%s" , odbcinst_user_file_path( b1 ), odbcinst_user_file_name( b2 )); |
438 | |
439 | memset( buffer, '\0', sizeof( buffer )); |
440 | #ifdef __OS2__ |
441 | if ( iniOpen( &hIni, szIniName, "#;" , '[', ']', '=', FALSE, 1L ) == |
442 | INI_SUCCESS ) |
443 | #else |
444 | if ( iniOpen( &hIni, szIniName, "#;" , '[', ']', '=', FALSE ) == |
445 | INI_SUCCESS ) |
446 | #endif |
447 | { |
448 | iniObjectSeek( hIni, (char *)object ); |
449 | iniPropertyFirst( hIni ); |
450 | while ( iniPropertyEOL( hIni ) != TRUE ) |
451 | { |
452 | iniProperty( hIni, szPropertyName ); |
453 | iniValue( hIni, szValue ); |
454 | sprintf( buffer, "%s=%s" , szPropertyName, |
455 | szValue ); |
456 | |
457 | if ( sz_driver_attributes ) { |
458 | |
459 | if ( total_len + strlen( buffer ) + 1 > cb_drvr_attr_max ) |
460 | { |
461 | ret = SQL_SUCCESS_WITH_INFO; |
462 | } |
463 | else |
464 | { |
465 | strcpy((char*) sz_driver_attributes, buffer ); |
466 | sz_driver_attributes += strlen( buffer ) + 1; |
467 | } |
468 | } |
469 | total_len += strlen( buffer ) + 1; |
470 | |
471 | iniPropertyNext( hIni ); |
472 | } |
473 | /* |
474 | * add extra null |
475 | */ |
476 | if ( sz_driver_attributes ) |
477 | *sz_driver_attributes = '\0'; |
478 | |
479 | if ( pcb_drvr_attr ) |
480 | { |
481 | *pcb_drvr_attr = total_len; |
482 | } |
483 | |
484 | iniClose( hIni ); |
485 | } |
486 | } |
487 | } |
488 | } |
489 | |
490 | if ( ret == SQL_SUCCESS_WITH_INFO ) |
491 | { |
492 | dm_log_write( __FILE__, |
493 | __LINE__, |
494 | LOG_INFO, |
495 | LOG_INFO, |
496 | "Error: 01004" ); |
497 | |
498 | __post_internal_error( &environment -> error, |
499 | ERROR_01004, NULL, |
500 | environment -> requested_version ); |
501 | } |
502 | |
503 | if ( log_info.log_flag ) |
504 | { |
505 | sprintf( environment -> msg, |
506 | "\n\t\tExit:[%s]" , |
507 | __get_return_status( ret, s1 )); |
508 | |
509 | dm_log_write( __FILE__, |
510 | __LINE__, |
511 | LOG_INFO, |
512 | LOG_INFO, |
513 | environment -> msg ); |
514 | } |
515 | |
516 | return function_return_nodrv( SQL_HANDLE_ENV, environment, ret ); |
517 | } |
518 | |