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: SQLGetInfoW.c,v 1.14 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLGetInfoW.c,v $
33 * Revision 1.14 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.13 2008/08/29 08:01:39 lurcher
37 * Alter the way W functions are passed to the driver
38 *
39 * Revision 1.12 2007/02/28 15:37:48 lurcher
40 * deal with drivers that call internal W functions and end up in the driver manager. controlled by the --enable-handlemap configure arg
41 *
42 * Revision 1.11 2005/10/06 08:50:58 lurcher
43 * Fix problem with SQLDrivers not returning first entry
44 *
45 * Revision 1.10 2004/11/22 17:02:49 lurcher
46 * Fix unicode/ansi conversion in the SQLGet functions
47 *
48 * Revision 1.9 2004/11/20 13:21:38 lurcher
49 * Fix unicode bug in SQLGetInfoW
50 *
51 * Revision 1.8 2003/10/30 18:20:46 lurcher
52 *
53 * Fix broken thread protection
54 * Remove SQLNumResultCols after execute, lease S4/S% to driver
55 * Fix string overrun in SQLDriverConnect
56 * Add initial support for Interix
57 *
58 * Revision 1.7 2003/03/05 09:48:44 lurcher
59 *
60 * Add some 64 bit fixes
61 *
62 * Revision 1.6 2002/12/05 17:44:31 lurcher
63 *
64 * Display unknown return values in return logging
65 *
66 * Revision 1.5 2002/08/23 09:42:37 lurcher
67 *
68 * Fix some build warnings with casts, and a AIX linker mod, to include
69 * deplib's on the link line, but not the libtool generated ones
70 *
71 * Revision 1.4 2002/07/24 08:49:52 lurcher
72 *
73 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
74 *
75 * Revision 1.3 2002/05/21 14:19:44 lurcher
76 *
77 * * Update libtool to escape from AIX build problem
78 * * Add fix to avoid file handle limitations
79 * * Add more UNICODE changes, it looks like it is native 16 representation
80 * the old way can be reproduced by defining UCS16BE
81 * * Add iusql, its just the same as isql but uses the wide functions
82 *
83 * Revision 1.2 2001/12/13 13:00:32 lurcher
84 *
85 * Remove most if not all warnings on 64 bit platforms
86 * Add support for new MS 3.52 64 bit changes
87 * Add override to disable the stopping of tracing
88 * Add MAX_ROWS support in postgres driver
89 *
90 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
91 *
92 * First upload to SourceForge
93 *
94 * Revision 1.3 2001/07/03 09:30:41 nick
95 *
96 * Add ability to alter size of displayed message in the log
97 *
98 * Revision 1.2 2001/04/12 17:43:36 nick
99 *
100 * Change logging and added autotest to odbctest
101 *
102 * Revision 1.1 2000/12/31 20:30:54 nick
103 *
104 * Add UNICODE support
105 *
106 *
107 **********************************************************************/
108
109#include <config.h>
110#include "drivermanager.h"
111
112static char const rcsid[]= "$RCSfile: SQLGetInfoW.c,v $";
113
114SQLRETURN SQLGetInfoW( SQLHDBC connection_handle,
115 SQLUSMALLINT info_type,
116 SQLPOINTER info_value,
117 SQLSMALLINT buffer_length,
118 SQLSMALLINT *string_length )
119{
120 DMHDBC connection = (DMHDBC)connection_handle;
121 SQLRETURN ret = SQL_SUCCESS;
122 int type;
123 char txt[ 30 ], *cptr;
124 SQLPOINTER *ptr;
125 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
126 SQLUSMALLINT sval;
127
128 /*
129 * check connection
130 */
131
132 if ( !__validate_dbc( connection ))
133 {
134 dm_log_write( __FILE__,
135 __LINE__,
136 LOG_INFO,
137 LOG_INFO,
138 "Error: SQL_INVALID_HANDLE" );
139
140#ifdef WITH_HANDLE_REDIRECT
141 {
142 DMHDBC parent_connection;
143
144 parent_connection = find_parent_handle( connection, SQL_HANDLE_DBC );
145
146 if ( parent_connection ) {
147 dm_log_write( __FILE__,
148 __LINE__,
149 LOG_INFO,
150 LOG_INFO,
151 "Info: found parent handle" );
152
153 if ( CHECK_SQLGETINFOW( parent_connection ))
154 {
155 dm_log_write( __FILE__,
156 __LINE__,
157 LOG_INFO,
158 LOG_INFO,
159 "Info: calling redirected driver function" );
160
161 return SQLGETINFOW( parent_connection,
162 connection_handle,
163 info_type,
164 info_value,
165 buffer_length,
166 string_length );
167 }
168 }
169 }
170#endif
171 return SQL_INVALID_HANDLE;
172 }
173
174 function_entry( connection );
175
176 if ( log_info.log_flag )
177 {
178 sprintf( connection -> msg, "\n\t\tEntry:\
179\n\t\t\tConnection = %p\
180\n\t\t\tInfo Type = %s\
181\n\t\t\tInfo Value = %p\
182\n\t\t\tBuffer Length = %d\
183\n\t\t\tStrLen = %p",
184 connection,
185 __info_as_string( s1, info_type ),
186 info_value,
187 (int)buffer_length,
188 (void*)string_length );
189
190 dm_log_write( __FILE__,
191 __LINE__,
192 LOG_INFO,
193 LOG_INFO,
194 connection -> msg );
195 }
196
197 thread_protect( SQL_HANDLE_DBC, connection );
198
199 if ( info_type != SQL_ODBC_VER &&
200 info_type != SQL_DM_VER &&
201 connection -> state == STATE_C2 )
202 {
203 dm_log_write( __FILE__,
204 __LINE__,
205 LOG_INFO,
206 LOG_INFO,
207 "Error: 08003" );
208
209 __post_internal_error( &connection -> error,
210 ERROR_08003, NULL,
211 connection -> environment -> requested_version );
212
213 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
214 }
215 else if ( connection -> state == STATE_C3 )
216 {
217 dm_log_write( __FILE__,
218 __LINE__,
219 LOG_INFO,
220 LOG_INFO,
221 "Error: 08003" );
222
223 __post_internal_error( &connection -> error,
224 ERROR_08003, NULL,
225 connection -> environment -> requested_version );
226
227 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
228 }
229
230 if ( buffer_length < 0 )
231 {
232 dm_log_write( __FILE__,
233 __LINE__,
234 LOG_INFO,
235 LOG_INFO,
236 "Error: HY090" );
237
238 __post_internal_error( &connection -> error,
239 ERROR_HY090, NULL,
240 connection -> environment -> requested_version );
241
242 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
243 }
244
245 switch ( info_type )
246 {
247 case SQL_DATA_SOURCE_NAME:
248 type = 1;
249 cptr = connection -> dsn;
250 break;
251
252 case SQL_DM_VER:
253 type = 1;
254 sprintf( txt, "%02d.%02d.%04d.%04d",
255 SQL_SPEC_MAJOR, SQL_SPEC_MINOR,
256 atoi( VERSION ), atoi( VERSION + 2 ));
257 cptr = txt;
258 break;
259
260 case SQL_ODBC_VER:
261 type = 1;
262 sprintf( txt, "%02d.%02d",
263 SQL_SPEC_MAJOR, SQL_SPEC_MINOR );
264 cptr = txt;
265 break;
266
267 case SQL_DRIVER_HDBC:
268 type = 2;
269 ptr = (SQLPOINTER) connection -> driver_dbc;
270 break;
271
272 case SQL_DRIVER_HENV:
273 type = 2;
274 ptr = (SQLPOINTER) connection -> driver_env;
275 break;
276
277 case SQL_DRIVER_HDESC:
278 {
279 DMHDESC hdesc;
280 if ( info_value && __validate_desc ( hdesc = *(DMHDESC*) info_value ) )
281 {
282 type = 2;
283
284 ptr = (SQLPOINTER) hdesc -> driver_desc;
285 }
286 else
287 {
288 dm_log_write( __FILE__,
289 __LINE__,
290 LOG_INFO,
291 LOG_INFO,
292 "Error: HY024" );
293
294 __post_internal_error( &connection -> error,
295 ERROR_HY024, NULL,
296 connection -> environment -> requested_version );
297
298 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
299 }
300 }
301 break;
302
303 case SQL_DRIVER_HLIB:
304 type = 2;
305 ptr = connection -> dl_handle;
306 break;
307
308 case SQL_DRIVER_HSTMT:
309 {
310 DMHSTMT hstmt;
311 if ( info_value && __validate_stmt( hstmt = *(DMHSTMT*)info_value ) )
312 {
313 type = 2;
314
315 ptr = (SQLPOINTER) hstmt -> driver_stmt;
316 }
317 else
318 {
319 dm_log_write( __FILE__,
320 __LINE__,
321 LOG_INFO,
322 LOG_INFO,
323 "Error: HY024" );
324
325 __post_internal_error( &connection -> error,
326 ERROR_HY024, NULL,
327 connection -> environment -> requested_version );
328
329 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
330 }
331 }
332 break;
333
334 case SQL_XOPEN_CLI_YEAR:
335 type = 1;
336 cptr = "1994";
337 break;
338
339 case SQL_ATTR_DRIVER_THREADING:
340 type = 3;
341 sval = connection -> threading_level;
342 break;
343
344 default:
345 /*
346 * pass all the others on
347 */
348 if ( connection -> unicode_driver ||
349 CHECK_SQLGETINFOW( connection ))
350 {
351 if ( !CHECK_SQLGETINFOW( connection ))
352 {
353 dm_log_write( __FILE__,
354 __LINE__,
355 LOG_INFO,
356 LOG_INFO,
357 "Error: IM001" );
358
359 __post_internal_error( &connection -> error,
360 ERROR_IM001, NULL,
361 connection -> environment -> requested_version );
362
363 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
364 }
365
366 ret = SQLGETINFOW( connection,
367 connection -> driver_dbc,
368 info_type,
369 info_value,
370 buffer_length,
371 string_length );
372
373 if ( log_info.log_flag )
374 {
375 sprintf( connection -> msg,
376 "\n\t\tExit:[%s]",
377 __get_return_status( ret, s1 ));
378
379 dm_log_write( __FILE__,
380 __LINE__,
381 LOG_INFO,
382 LOG_INFO,
383 connection -> msg );
384 }
385 }
386 else
387 {
388 SQLCHAR *as1 = NULL;
389
390 if ( !CHECK_SQLGETINFO( connection ))
391 {
392 dm_log_write( __FILE__,
393 __LINE__,
394 LOG_INFO,
395 LOG_INFO,
396 "Error: IM001" );
397
398 __post_internal_error( &connection -> error,
399 ERROR_IM001, NULL,
400 connection -> environment -> requested_version );
401
402 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
403 }
404
405 switch( info_type )
406 {
407 case SQL_ACCESSIBLE_PROCEDURES:
408 case SQL_ACCESSIBLE_TABLES:
409 case SQL_CATALOG_NAME:
410 case SQL_CATALOG_NAME_SEPARATOR:
411 case SQL_CATALOG_TERM:
412 case SQL_COLLATION_SEQ:
413 case SQL_COLUMN_ALIAS:
414 case SQL_DATA_SOURCE_NAME:
415 case SQL_DATA_SOURCE_READ_ONLY:
416 case SQL_DATABASE_NAME:
417 case SQL_DBMS_NAME:
418 case SQL_DBMS_VER:
419 case SQL_DESCRIBE_PARAMETER:
420 case SQL_DRIVER_NAME:
421 case SQL_DRIVER_ODBC_VER:
422 case SQL_DRIVER_VER:
423 case SQL_ODBC_VER:
424 case SQL_EXPRESSIONS_IN_ORDERBY:
425 case SQL_IDENTIFIER_QUOTE_CHAR:
426 case SQL_INTEGRITY:
427 case SQL_KEYWORDS:
428 case SQL_LIKE_ESCAPE_CLAUSE:
429 case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
430 case SQL_MULT_RESULT_SETS:
431 case SQL_MULTIPLE_ACTIVE_TXN:
432 case SQL_NEED_LONG_DATA_LEN:
433 case SQL_ORDER_BY_COLUMNS_IN_SELECT:
434 case SQL_PROCEDURE_TERM:
435 case SQL_PROCEDURES:
436 case SQL_ROW_UPDATES:
437 case SQL_SCHEMA_TERM:
438 case SQL_SEARCH_PATTERN_ESCAPE:
439 case SQL_SERVER_NAME:
440 case SQL_SPECIAL_CHARACTERS:
441 case SQL_TABLE_TERM:
442 case SQL_USER_NAME:
443 case SQL_XOPEN_CLI_YEAR:
444 case SQL_OUTER_JOINS:
445 if ( SQL_SUCCEEDED( ret ) && info_value && buffer_length > 0 )
446 {
447 as1 = malloc( buffer_length + 1 );
448 }
449 break;
450 }
451
452 ret = SQLGETINFO( connection,
453 connection -> driver_dbc,
454 info_type,
455 as1 ? as1 : info_value,
456 buffer_length,
457 string_length );
458
459 switch( info_type )
460 {
461 case SQL_ACCESSIBLE_PROCEDURES:
462 case SQL_ACCESSIBLE_TABLES:
463 case SQL_CATALOG_NAME:
464 case SQL_CATALOG_NAME_SEPARATOR:
465 case SQL_CATALOG_TERM:
466 case SQL_COLLATION_SEQ:
467 case SQL_COLUMN_ALIAS:
468 case SQL_DATA_SOURCE_NAME:
469 case SQL_DATA_SOURCE_READ_ONLY:
470 case SQL_DATABASE_NAME:
471 case SQL_DBMS_NAME:
472 case SQL_DBMS_VER:
473 case SQL_DESCRIBE_PARAMETER:
474 case SQL_DRIVER_NAME:
475 case SQL_DRIVER_ODBC_VER:
476 case SQL_DRIVER_VER:
477 case SQL_ODBC_VER:
478 case SQL_EXPRESSIONS_IN_ORDERBY:
479 case SQL_IDENTIFIER_QUOTE_CHAR:
480 case SQL_INTEGRITY:
481 case SQL_KEYWORDS:
482 case SQL_LIKE_ESCAPE_CLAUSE:
483 case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
484 case SQL_MULT_RESULT_SETS:
485 case SQL_MULTIPLE_ACTIVE_TXN:
486 case SQL_NEED_LONG_DATA_LEN:
487 case SQL_ORDER_BY_COLUMNS_IN_SELECT:
488 case SQL_PROCEDURE_TERM:
489 case SQL_PROCEDURES:
490 case SQL_ROW_UPDATES:
491 case SQL_SCHEMA_TERM:
492 case SQL_SEARCH_PATTERN_ESCAPE:
493 case SQL_SERVER_NAME:
494 case SQL_SPECIAL_CHARACTERS:
495 case SQL_TABLE_TERM:
496 case SQL_USER_NAME:
497 case SQL_XOPEN_CLI_YEAR:
498 case SQL_OUTER_JOINS:
499 if ( SQL_SUCCEEDED( ret ) && info_value && as1 )
500 {
501 ansi_to_unicode_copy( info_value, (char*) as1, SQL_NTS, connection, NULL );
502 }
503 if ( SQL_SUCCEEDED( ret ) && string_length )
504 {
505 *string_length *= sizeof( SQLWCHAR );
506 }
507 break;
508 }
509
510 if ( as1 ) free( as1 );
511
512 if ( log_info.log_flag )
513 {
514 sprintf( connection -> msg,
515 "\n\t\tExit:[%s]",
516 __get_return_status( ret, s1 ));
517
518 dm_log_write( __FILE__,
519 __LINE__,
520 LOG_INFO,
521 LOG_INFO,
522 connection -> msg );
523 }
524 }
525
526 return function_return( SQL_HANDLE_DBC, connection, ret );
527 }
528
529 if ( type == 1 )
530 {
531 SQLWCHAR *s1;
532 int len;
533
534 s1 = ansi_to_unicode_alloc((SQLCHAR*) cptr, SQL_NTS, connection, NULL );
535
536 len = strlen( cptr ) * sizeof( SQLWCHAR );
537
538 if ( string_length )
539 *string_length = len;
540
541 if ( info_value )
542 {
543 if ( buffer_length > len + 1 )
544 {
545 wide_strcpy( info_value, s1 );
546 }
547 else
548 {
549 memcpy( info_value, s1, ( buffer_length - 1 * sizeof( SQLWCHAR )));
550 ((SQLWCHAR*)info_value)[ buffer_length - 1 ] = '\0';
551 ret = SQL_SUCCESS_WITH_INFO;
552 }
553 }
554
555 if ( s1 )
556 free( s1 );
557 }
558 else if ( type == 2 )
559 {
560 if ( info_value )
561 *((void **)info_value) = ptr;
562
563 if ( string_length )
564 *string_length = sizeof( SQLPOINTER );
565 }
566 else if ( type == 3 )
567 {
568 if ( info_value )
569 *((SQLUSMALLINT *)info_value) = sval;
570
571 if ( string_length )
572 *string_length = sizeof( SQLUSMALLINT );
573 }
574
575 if ( log_info.log_flag )
576 {
577 sprintf( connection -> msg,
578 "\n\t\tExit:[%s]",
579 __get_return_status( ret, s1 ));
580
581 dm_log_write( __FILE__,
582 __LINE__,
583 LOG_INFO,
584 LOG_INFO,
585 connection -> msg );
586 }
587
588 return function_return_nodrv( SQL_HANDLE_DBC, connection, ret );
589}
590