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
173static char const rcsid[]= "$RCSfile: SQLDrivers.c,v $ $Revision: 1.13 $";
174
175#define BUFFERSIZE 1024
176
177SQLRETURN 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
197SQLRETURN 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
314try_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