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: SQLDriversW.c,v 1.12 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLDriversW.c,v $
33 * Revision 1.12 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.11 2009/02/17 09:47:44 lurcher
37 * Clear up a number of bugs
38 *
39 * Revision 1.10 2008/09/29 14:02:45 lurcher
40 * Fix missing dlfcn group option
41 *
42 * Revision 1.9 2005/07/17 09:11:23 lurcher
43 * Fix bug in SQLDrivers that was stopping the return of the attribute length
44 *
45 * Revision 1.8 2004/07/25 00:42:02 peteralexharvey
46 * for OS2 port
47 *
48 * Revision 1.7 2003/11/13 15:12:53 lurcher
49 *
50 * small change to ODBCConfig to have the password field in the driver
51 * properties hide the password
52 * Make both # and ; comments in ini files
53 *
54 * Revision 1.6 2003/10/30 18:20:45 lurcher
55 *
56 * Fix broken thread protection
57 * Remove SQLNumResultCols after execute, lease S4/S% to driver
58 * Fix string overrun in SQLDriverConnect
59 * Add initial support for Interix
60 *
61 * Revision 1.5 2002/12/05 17:44:30 lurcher
62 *
63 * Display unknown return values in return logging
64 *
65 * Revision 1.4 2002/07/24 08:49:51 lurcher
66 *
67 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
68 *
69 * Revision 1.3 2002/05/21 14:19:44 lurcher
70 *
71 * * Update libtool to escape from AIX build problem
72 * * Add fix to avoid file handle limitations
73 * * Add more UNICODE changes, it looks like it is native 16 representation
74 * the old way can be reproduced by defining UCS16BE
75 * * Add iusql, its just the same as isql but uses the wide functions
76 *
77 * Revision 1.2 2001/12/13 13:00:32 lurcher
78 *
79 * Remove most if not all warnings on 64 bit platforms
80 * Add support for new MS 3.52 64 bit changes
81 * Add override to disable the stopping of tracing
82 * Add MAX_ROWS support in postgres driver
83 *
84 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
85 *
86 * First upload to SourceForge
87 *
88 * Revision 1.4 2001/05/15 10:57:44 nick
89 *
90 * Add initial support for VMS
91 *
92 * Revision 1.3 2001/04/12 17:43:36 nick
93 *
94 * Change logging and added autotest to odbctest
95 *
96 * Revision 1.2 2001/01/02 09:55:04 nick
97 *
98 * More unicode bits
99 *
100 * Revision 1.1 2000/12/31 20:30:54 nick
101 *
102 * Add UNICODE support
103 *
104 *
105 **********************************************************************/
106
107#include <config.h>
108#include "drivermanager.h"
109
110static char const rcsid[]= "$RCSfile: SQLDriversW.c,v $";
111
112#define BUFFERSIZE 1024
113
114SQLRETURN SQLDriversW(
115 SQLHENV henv,
116 SQLUSMALLINT fdirection,
117 SQLWCHAR *sz_driver_desc,
118 SQLSMALLINT cb_driver_desc_max,
119 SQLSMALLINT *pcb_driver_desc,
120 SQLWCHAR *sz_driver_attributes,
121 SQLSMALLINT cb_drvr_attr_max,
122 SQLSMALLINT *pcb_drvr_attr )
123{
124 DMHENV environment = (DMHENV) henv;
125 char buffer[ BUFFERSIZE + 1 ];
126 char object[ INI_MAX_OBJECT_NAME + 1 ];
127 SQLRETURN ret = SQL_SUCCESS;
128 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
129
130 if ( !__validate_env( environment ))
131 {
132 dm_log_write( __FILE__,
133 __LINE__,
134 LOG_INFO,
135 LOG_INFO,
136 "Error: SQL_INVALID_HANDLE" );
137
138 return SQL_INVALID_HANDLE;
139 }
140
141 function_entry( environment );
142
143 if ( log_info.log_flag )
144 {
145 sprintf( environment -> msg, "\n\t\tEntry:\
146\n\t\t\tEnvironment = %p\
147\n\t\t\tDirection = %d",
148 environment,
149 (int)fdirection );
150
151 dm_log_write( __FILE__,
152 __LINE__,
153 LOG_INFO,
154 LOG_INFO,
155 environment -> msg );
156 }
157
158 thread_protect( SQL_HANDLE_ENV, environment );
159
160 /*
161 * check that a version has been requested
162 */
163
164 if ( ! environment -> version_set )
165 {
166 dm_log_write( __FILE__,
167 __LINE__,
168 LOG_INFO,
169 LOG_INFO,
170 "Error: HY010" );
171
172 __post_internal_error( &environment -> error,
173 ERROR_HY010, NULL,
174 SQL_OV_ODBC3 );
175
176 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
177 }
178
179 if ( cb_driver_desc_max < 0 )
180 {
181 dm_log_write( __FILE__,
182 __LINE__,
183 LOG_INFO,
184 LOG_INFO,
185 "Error: HY090" );
186
187 __post_internal_error( &environment -> error,
188 ERROR_HY090, NULL,
189 environment -> requested_version );
190
191 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
192 }
193
194 if ( cb_drvr_attr_max < 0
195 || cb_drvr_attr_max == 1 )
196 {
197 dm_log_write( __FILE__,
198 __LINE__,
199 LOG_INFO,
200 LOG_INFO,
201 "Error: HY090" );
202
203 __post_internal_error( &environment -> error,
204 ERROR_HY090, NULL,
205 environment -> requested_version );
206
207 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
208 }
209
210 if ( fdirection != SQL_FETCH_FIRST &&
211 fdirection != SQL_FETCH_NEXT )
212 {
213 dm_log_write( __FILE__,
214 __LINE__,
215 LOG_INFO,
216 LOG_INFO,
217 "Error: HY103" );
218
219 __post_internal_error( &environment -> error,
220 ERROR_HY103, NULL,
221 environment -> requested_version );
222
223 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
224 }
225
226 if ( fdirection == SQL_FETCH_FIRST )
227 environment -> sql_driver_count = 0;
228 else
229 environment -> sql_driver_count ++;
230
231try_again:
232
233 memset( buffer, '\0', sizeof( buffer ));
234 memset( object, '\0', sizeof( object ));
235 SQLGetPrivateProfileString( NULL, NULL,
236 NULL, buffer, sizeof( buffer ), "ODBCINST.INI" );
237
238 if ( iniElement( buffer, '\0', '\0',
239 environment -> sql_driver_count,
240 object, sizeof( object )) != INI_SUCCESS )
241 {
242 /*
243 * Set up for the next time
244 */
245 environment -> sql_driver_count = -1;
246 ret = SQL_NO_DATA;
247 }
248 else
249 {
250 ret = SQL_SUCCESS;
251
252 /*
253 * this section is used for internal info
254 */
255
256 if ( strcmp( object, "ODBC" ) == 0 )
257 {
258 environment -> sql_driver_count ++;
259 goto try_again;
260 }
261
262 if ( pcb_driver_desc )
263 *pcb_driver_desc = strlen( object );
264
265 if ( sz_driver_desc )
266 {
267 if ( strlen( object ) >= cb_driver_desc_max )
268 {
269 memcpy( sz_driver_desc, object, cb_driver_desc_max - 1 );
270 sz_driver_desc[ cb_driver_desc_max - 1 ] = '\0';
271 ret = SQL_SUCCESS_WITH_INFO;
272 }
273 else
274 {
275 SQLWCHAR *s1;
276
277 s1 = ansi_to_unicode_alloc((SQLCHAR*) object, SQL_NTS, NULL, NULL );
278 if ( s1 )
279 {
280 wide_strcpy( sz_driver_desc, s1 );
281 free( s1 );
282 }
283 }
284 }
285 else
286 {
287 ret = SQL_SUCCESS;
288 }
289
290 if ( sz_driver_attributes ||
291 pcb_drvr_attr )
292 {
293 HINI hIni;
294 char szPropertyName[INI_MAX_PROPERTY_NAME+1];
295 char szValue[INI_MAX_PROPERTY_NAME+1];
296 char szIniName[ INI_MAX_OBJECT_NAME + 1 ];
297 char buffer[ 1024 ];
298 int total_len = 0;
299 char b1[ 512 ], b2[ 512 ];
300 int found = 0;
301
302 /*
303 * enumerate the driver attributes, first in system odbcinst.ini and if not found in user odbcinst.ini
304 */
305
306 sprintf( szIniName, "%s/%s", odbcinst_system_file_path( b1 ), odbcinst_system_file_name( b2 ));
307
308 memset( buffer, '\0', sizeof( buffer ));
309#ifdef __OS2__
310 if ( iniOpen( &hIni, szIniName, "#;", '[', ']', '=', FALSE, 1L ) ==
311 INI_SUCCESS )
312#else
313 if ( iniOpen( &hIni, szIniName, "#;", '[', ']', '=', FALSE ) ==
314 INI_SUCCESS )
315#endif
316 {
317 iniObjectSeek( hIni, (char *)object );
318 iniPropertyFirst( hIni );
319 while ( iniPropertyEOL( hIni ) != TRUE )
320 {
321 iniProperty( hIni, szPropertyName );
322 iniValue( hIni, szValue );
323 sprintf( buffer, "%s=%s", szPropertyName,
324 szValue );
325
326 found = 1;
327
328 if ( sz_driver_attributes ) {
329
330 if ( total_len + strlen( buffer ) + 1 > cb_drvr_attr_max )
331 {
332 ret = SQL_SUCCESS_WITH_INFO;
333 }
334 else
335 {
336 SQLWCHAR *s1;
337
338 s1 = ansi_to_unicode_alloc((SQLCHAR*) buffer, SQL_NTS, NULL, NULL );
339
340 if ( s1 )
341 {
342 wide_strcpy( sz_driver_attributes, s1 );
343 free( s1 );
344 }
345 sz_driver_attributes += strlen( buffer ) + 1;
346 }
347 }
348
349 total_len += strlen( buffer ) + 1;
350
351 iniPropertyNext( hIni );
352 }
353 /*
354 * add extra null
355 */
356 if ( sz_driver_attributes )
357 *sz_driver_attributes = '\0';
358
359 if ( pcb_drvr_attr )
360 {
361 *pcb_drvr_attr = total_len;
362 }
363
364 iniClose( hIni );
365 }
366
367 if ( !found )
368 {
369 sprintf( szIniName, "%s/%s", odbcinst_system_file_path( b1 ), odbcinst_system_file_name( b2 ));
370
371 memset( buffer, '\0', sizeof( buffer ));
372 #ifdef __OS2__
373 if ( iniOpen( &hIni, szIniName, "#;", '[', ']', '=', FALSE, 1L ) ==
374 INI_SUCCESS )
375 #else
376 if ( iniOpen( &hIni, szIniName, "#;", '[', ']', '=', FALSE ) ==
377 INI_SUCCESS )
378 #endif
379 {
380 iniObjectSeek( hIni, (char *)object );
381 iniPropertyFirst( hIni );
382 while ( iniPropertyEOL( hIni ) != TRUE )
383 {
384 iniProperty( hIni, szPropertyName );
385 iniValue( hIni, szValue );
386 sprintf( buffer, "%s=%s", szPropertyName,
387 szValue );
388
389 if ( sz_driver_attributes ) {
390
391 if ( total_len + strlen( buffer ) + 1 > cb_drvr_attr_max )
392 {
393 ret = SQL_SUCCESS_WITH_INFO;
394 }
395 else
396 {
397 SQLWCHAR *s1;
398
399 s1 = ansi_to_unicode_alloc((SQLCHAR*) buffer, SQL_NTS, NULL, NULL );
400
401 if ( s1 )
402 {
403 wide_strcpy( sz_driver_attributes, s1 );
404 free( s1 );
405 }
406 sz_driver_attributes += strlen( buffer ) + 1;
407 }
408 }
409
410 total_len += strlen( buffer ) + 1;
411
412 iniPropertyNext( hIni );
413 }
414 /*
415 * add extra null
416 */
417 if ( sz_driver_attributes )
418 *sz_driver_attributes = '\0';
419
420 if ( pcb_drvr_attr )
421 {
422 *pcb_drvr_attr = total_len;
423 }
424
425 iniClose( hIni );
426 }
427 }
428 }
429 }
430
431 if ( ret == SQL_SUCCESS_WITH_INFO )
432 {
433 dm_log_write( __FILE__,
434 __LINE__,
435 LOG_INFO,
436 LOG_INFO,
437 "Error: 01004" );
438
439 __post_internal_error( &environment -> error,
440 ERROR_01004, NULL,
441 environment -> requested_version );
442 }
443
444 if ( log_info.log_flag )
445 {
446 sprintf( environment -> msg,
447 "\n\t\tExit:[%s]",
448 __get_return_status( ret, s1 ));
449
450 dm_log_write( __FILE__,
451 __LINE__,
452 LOG_INFO,
453 LOG_INFO,
454 environment -> msg );
455 }
456
457 return function_return_nodrv( SQL_HANDLE_ENV, environment, ret );
458}
459