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