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: SQLGetConnectAttr.c,v 1.15 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLGetConnectAttr.c,v $
33 * Revision 1.15 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.14 2009/02/17 09:47:44 lurcher
37 * Clear up a number of bugs
38 *
39 * Revision 1.13 2008/09/29 14:02:45 lurcher
40 * Fix missing dlfcn group option
41 *
42 * Revision 1.12 2006/03/08 09:18:41 lurcher
43 * fix silly typo that was using sizeof( SQL_WCHAR ) instead of SQLWCHAR
44 *
45 * Revision 1.11 2004/11/22 17:02:48 lurcher
46 * Fix unicode/ansi conversion in the SQLGet functions
47 *
48 * Revision 1.10 2003/10/30 18:20:45 lurcher
49 *
50 * Fix broken thread protection
51 * Remove SQLNumResultCols after execute, lease S4/S% to driver
52 * Fix string overrun in SQLDriverConnect
53 * Add initial support for Interix
54 *
55 * Revision 1.9 2003/02/27 12:19:39 lurcher
56 *
57 * Add the A functions as well as the W
58 *
59 * Revision 1.8 2002/12/05 17:44:30 lurcher
60 *
61 * Display unknown return values in return logging
62 *
63 * Revision 1.7 2002/11/11 17:10:09 lurcher
64 *
65 * VMS changes
66 *
67 * Revision 1.6 2002/07/24 08:49:52 lurcher
68 *
69 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
70 *
71 * Revision 1.5 2002/07/16 13:08:18 lurcher
72 *
73 * Filter attribute values from SQLSetStmtAttr to SQLSetStmtOption to fit
74 * within ODBC 2
75 * Make DSN's double clickable in ODBCConfig
76 *
77 * Revision 1.4 2002/01/30 12:20:02 lurcher
78 *
79 * Add MyODBC 3 driver source
80 *
81 * Revision 1.3 2001/12/13 13:00:32 lurcher
82 *
83 * Remove most if not all warnings on 64 bit platforms
84 * Add support for new MS 3.52 64 bit changes
85 * Add override to disable the stopping of tracing
86 * Add MAX_ROWS support in postgres driver
87 *
88 * Revision 1.2 2001/12/04 16:46:19 lurcher
89 *
90 * Allow the Unix Domain Socket to be set from the ini file (DSN)
91 * Make the DataManager browser work with drivers that don't support
92 * SQLRowCount
93 * Make the directory selection from odbctest work simplier
94 *
95 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
96 *
97 * First upload to SourceForge
98 *
99 * Revision 1.5 2001/08/03 15:19:00 nick
100 *
101 * Add changes to set values before connect
102 *
103 * Revision 1.4 2001/07/03 09:30:41 nick
104 *
105 * Add ability to alter size of displayed message in the log
106 *
107 * Revision 1.3 2001/04/12 17:43:36 nick
108 *
109 * Change logging and added autotest to odbctest
110 *
111 * Revision 1.2 2000/12/31 20:30:54 nick
112 *
113 * Add UNICODE support
114 *
115 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
116 * Imported Sources
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:18 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:55 ngorham
146 *
147 * Add initial thread safety code
148 *
149 * Revision 1.1.1.1 1999/05/29 13:41:07 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.2 1999/04/30 16:22:47 nick
156 * Another checkpoint
157 *
158 * Revision 1.1 1999/04/25 23:06:11 nick
159 * Initial revision
160 *
161 *
162 **********************************************************************/
163
164#include <config.h>
165#include "drivermanager.h"
166
167static char const rcsid[]= "$RCSfile: SQLGetConnectAttr.c,v $ $Revision: 1.15 $";
168
169SQLRETURN SQLGetConnectAttrA( SQLHDBC connection_handle,
170 SQLINTEGER attribute,
171 SQLPOINTER value,
172 SQLINTEGER buffer_length,
173 SQLINTEGER *string_length )
174{
175 return SQLGetConnectAttr( connection_handle,
176 attribute,
177 value,
178 buffer_length,
179 string_length );
180}
181
182SQLRETURN SQLGetConnectAttr( SQLHDBC connection_handle,
183 SQLINTEGER attribute,
184 SQLPOINTER value,
185 SQLINTEGER buffer_length,
186 SQLINTEGER *string_length )
187{
188 DMHDBC connection = (DMHDBC)connection_handle;
189 int type = 0;
190 char *ptr;
191 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
192
193 /*
194 * doesn't require a handle
195 */
196
197 if ( attribute == SQL_ATTR_TRACE )
198 {
199 if ( value )
200 {
201 if ( log_info.log_flag )
202 {
203 *((SQLINTEGER*)value) = SQL_OPT_TRACE_ON;
204 }
205 else
206 {
207 *((SQLINTEGER*)value) = SQL_OPT_TRACE_OFF;
208 }
209 }
210
211 return SQL_SUCCESS;
212 }
213 else if ( attribute == SQL_ATTR_TRACEFILE )
214 {
215 SQLRETURN ret = SQL_SUCCESS;
216
217 ptr = log_info.log_file_name;
218
219 if ( log_info.log_file_name )
220 {
221 if ( string_length )
222 {
223 *string_length = strlen( ptr );
224 }
225 if ( value )
226 {
227 if ( buffer_length > strlen( log_info.log_file_name ) + 1 )
228 {
229 strcpy( value, ptr );
230 }
231 else
232 {
233 memcpy( value, log_info.log_file_name, buffer_length - 1 );
234 ((char*)value)[ buffer_length - 1 ] = '\0';
235 ret = SQL_SUCCESS_WITH_INFO;
236 }
237 }
238 }
239 else
240 {
241 if ( string_length )
242 {
243 *string_length = 0;
244 }
245 if ( value )
246 {
247 if ( buffer_length >= 1 )
248 {
249 strcpy( value, "" );
250 }
251 else
252 {
253 ret = SQL_SUCCESS_WITH_INFO;
254 }
255 }
256 }
257 return ret;
258 }
259
260 /*
261 * check connection
262 */
263
264 if ( !__validate_dbc( connection ))
265 {
266 dm_log_write( __FILE__,
267 __LINE__,
268 LOG_INFO,
269 LOG_INFO,
270 "Error: SQL_INVALID_HANDLE" );
271
272 return SQL_INVALID_HANDLE;
273 }
274
275 function_entry( connection );
276
277 if ( log_info.log_flag )
278 {
279 sprintf( connection -> msg, "\n\t\tEntry:\
280\n\t\t\tConnection = %p\
281\n\t\t\tAttribute = %s\
282\n\t\t\tValue = %p\
283\n\t\t\tBuffer Length = %d\
284\n\t\t\tStrLen = %p",
285 connection,
286 __con_attr_as_string( s1, attribute ),
287 value,
288 (int)buffer_length,
289 (void*)string_length );
290
291 dm_log_write( __FILE__,
292 __LINE__,
293 LOG_INFO,
294 LOG_INFO,
295 connection -> msg );
296 }
297
298 thread_protect( SQL_HANDLE_DBC, connection );
299
300 if ( connection -> state == STATE_C3 )
301 {
302 dm_log_write( __FILE__,
303 __LINE__,
304 LOG_INFO,
305 LOG_INFO,
306 "Error: HY010" );
307
308 __post_internal_error( &connection -> error,
309 ERROR_HY010, NULL,
310 connection -> environment -> requested_version );
311
312 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
313 }
314
315 if ( connection -> state == STATE_C2 )
316 {
317 switch ( attribute )
318 {
319 case SQL_ATTR_ACCESS_MODE:
320 case SQL_ATTR_AUTOCOMMIT:
321 case SQL_ATTR_LOGIN_TIMEOUT:
322 case SQL_ATTR_ODBC_CURSORS:
323 case SQL_ATTR_TRACE:
324 case SQL_ATTR_TRACEFILE:
325 case SQL_ATTR_ASYNC_ENABLE:
326 break;
327
328 case SQL_ATTR_PACKET_SIZE:
329 if ( connection -> packet_size_set )
330 break;
331 case SQL_ATTR_QUIET_MODE:
332 if ( connection -> quite_mode_set )
333 break;
334
335 default:
336 {
337 struct save_attr *sa = connection -> save_attr;
338 while (sa)
339 {
340 if (sa -> attr_type == attribute)
341 {
342 SQLRETURN rc = SQL_SUCCESS;
343 if (sa -> str_len == SQL_NTS || sa -> str_len > 0)
344 {
345 SQLLEN realLen = sa->str_attr ? strlen(sa->str_attr) : 0;
346 if(value && sa->str_attr)
347 {
348 strncpy(value, sa->str_attr, buffer_length - 1);
349 ((SQLCHAR*)value)[buffer_length - 1] = 0;
350 }
351 if(string_length)
352 {
353 *string_length = realLen;
354 }
355 if(realLen > buffer_length - 1)
356 {
357 __post_internal_error( &connection -> error,
358 ERROR_01004, NULL,
359 connection -> environment -> requested_version );
360 rc = SQL_SUCCESS_WITH_INFO;
361 }
362 }
363 else if(buffer_length >= sizeof(SQLLEN))
364 {
365 *(SQLLEN*)value = sa -> int_attr;
366 if(string_length)
367 {
368 *string_length = sizeof(SQLLEN);
369 }
370 }
371 else
372 {
373 memcpy(value, &sa->int_attr, buffer_length);
374 }
375 return function_return_nodrv( SQL_HANDLE_DBC, connection, rc );
376 }
377 sa = sa -> next;
378 }
379 }
380 dm_log_write( __FILE__,
381 __LINE__,
382 LOG_INFO,
383 LOG_INFO,
384 "Error: 08003" );
385
386 __post_internal_error( &connection -> error,
387 ERROR_08003, NULL,
388 connection -> environment -> requested_version );
389
390 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
391 }
392 }
393
394 switch ( attribute )
395 {
396 case SQL_ATTR_ACCESS_MODE:
397 /*
398 * if connected, call the driver
399 */
400 if ( connection -> state != STATE_C2 )
401 {
402 type = 0;
403 }
404 else
405 {
406 *((SQLINTEGER*)value) = connection -> access_mode;
407 type = 1;
408 }
409 break;
410
411 case SQL_ATTR_AUTOCOMMIT:
412 /*
413 * if connected, call the driver
414 */
415 if ( connection -> state != STATE_C2 )
416 {
417 type = 0;
418 }
419 else
420 {
421 *((SQLINTEGER*)value) = connection -> auto_commit;
422 type = 1;
423 }
424 break;
425
426 case SQL_ATTR_LOGIN_TIMEOUT:
427 /*
428 * if connected, call the driver
429 */
430 if ( connection -> state != STATE_C2 )
431 {
432 type = 0;
433 }
434 else
435 {
436 *((SQLINTEGER*)value) = connection -> login_timeout;
437 type = 1;
438 }
439 break;
440
441 case SQL_ATTR_ODBC_CURSORS:
442 *((SQLULEN*)value) = connection -> cursors;
443 type = 1;
444 break;
445
446 case SQL_ATTR_TRACE:
447 *((SQLINTEGER*)value) = connection -> trace;
448 type = 1;
449 break;
450
451 case SQL_ATTR_TRACEFILE:
452 ptr = connection -> tracefile;
453 type = 2;
454 break;
455
456 case SQL_ATTR_ASYNC_ENABLE:
457 /*
458 * if connected, call the driver
459 */
460 if ( connection -> state != STATE_C2 )
461 {
462 type = 0;
463 }
464 else
465 {
466 *((SQLULEN*)value) = connection -> async_enable;
467 type = 1;
468 }
469 break;
470
471 case SQL_ATTR_AUTO_IPD:
472 /*
473 * if connected, call the driver
474 */
475 if ( connection -> state != STATE_C2 )
476 {
477 type = 0;
478 }
479 else
480 {
481 *((SQLINTEGER*)value) = connection -> auto_ipd;
482 type = 1;
483 }
484 break;
485
486 case SQL_ATTR_CONNECTION_TIMEOUT:
487 /*
488 * if connected, call the driver
489 */
490 if ( connection -> state != STATE_C2 )
491 {
492 type = 0;
493 }
494 else
495 {
496 *((SQLINTEGER*)value) = connection -> connection_timeout;
497 type = 1;
498 }
499 break;
500
501 case SQL_ATTR_METADATA_ID:
502 /*
503 * if connected, call the driver
504 */
505 if ( connection -> state != STATE_C2 )
506 {
507 type = 0;
508 }
509 else
510 {
511 *((SQLINTEGER*)value) = connection -> metadata_id;
512 type = 1;
513 }
514 break;
515
516 case SQL_ATTR_PACKET_SIZE:
517 /*
518 * if connected, call the driver
519 */
520 if ( connection -> state != STATE_C2 )
521 {
522 type = 0;
523 }
524 else
525 {
526 *((SQLINTEGER*)value) = connection -> packet_size;
527 type = 1;
528 }
529 break;
530
531 case SQL_ATTR_QUIET_MODE:
532 /*
533 * if connected, call the driver
534 */
535 if ( connection -> state != STATE_C2 )
536 {
537 type = 0;
538 }
539 else
540 {
541 *((SQLLEN*)value) = connection -> quite_mode;
542 type = 1;
543 }
544 break;
545
546 case SQL_ATTR_TXN_ISOLATION:
547 /*
548 * if connected, call the driver
549 */
550 if ( connection -> state != STATE_C2 )
551 {
552 type = 0;
553 }
554 else
555 {
556 *((SQLINTEGER*)value) = connection -> txn_isolation;
557 type = 1;
558 }
559 break;
560
561 default:
562 break;
563 }
564
565 /*
566 * if type has been set we have already set the value,
567 * so just return
568 */
569 if ( type )
570 {
571 SQLRETURN ret = SQL_SUCCESS;
572 if ( type == 1 )
573 {
574 if ( string_length )
575 {
576 *string_length = sizeof( SQLUINTEGER );
577 }
578 }
579 else
580 {
581 if ( string_length )
582 {
583 *string_length = strlen( ptr );
584 }
585 if ( value )
586 {
587 if ( buffer_length > strlen( ptr ) + 1 )
588 {
589 strcpy( value, ptr );
590 }
591 else
592 {
593 memcpy( value, ptr, buffer_length - 1 );
594 ((char*)value)[ buffer_length - 1 ] = '\0';
595 ret = SQL_SUCCESS_WITH_INFO;
596 }
597 }
598 }
599
600 sprintf( connection -> msg,
601 "\n\t\tExit:[%s]",
602 __get_return_status( ret, s1 ));
603
604 dm_log_write( __FILE__,
605 __LINE__,
606 LOG_INFO,
607 LOG_INFO,
608 connection -> msg );
609
610 return function_return_nodrv( SQL_HANDLE_DBC, connection, ret );
611 }
612 else
613 {
614 SQLRETURN ret = 0;
615
616 /*
617 * call the driver
618 */
619 if ( connection -> unicode_driver )
620 {
621 if ( !CHECK_SQLGETCONNECTATTRW( connection ))
622 {
623 if (( ret = CHECK_SQLGETCONNECTOPTIONW( connection )))
624 {
625 SQLWCHAR *s1 = NULL;
626
627 /*
628 * Is it in the legal range of values
629 */
630
631 if ( attribute < SQL_CONN_DRIVER_MIN &&
632 ( attribute > SQL_PACKET_SIZE || attribute < SQL_ACCESS_MODE ))
633 {
634 dm_log_write( __FILE__,
635 __LINE__,
636 LOG_INFO,
637 LOG_INFO,
638 "Error: HY092" );
639
640 __post_internal_error( &connection -> error,
641 ERROR_HY092, NULL,
642 connection -> environment -> requested_version );
643
644 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
645 }
646
647 switch( attribute )
648 {
649 case SQL_ATTR_CURRENT_CATALOG:
650 case SQL_ATTR_TRACEFILE:
651 case SQL_ATTR_TRANSLATE_LIB:
652 if ( SQL_SUCCEEDED( ret ) && value )
653 {
654 s1 = malloc( sizeof( SQLWCHAR ) * ( 1024 ));
655 }
656 break;
657 }
658
659 ret = SQLGETCONNECTOPTIONW( connection,
660 connection -> driver_dbc,
661 attribute,
662 s1 ? s1 : value );
663
664 switch( attribute )
665 {
666 case SQL_ATTR_CURRENT_CATALOG:
667 case SQL_ATTR_TRACEFILE:
668 case SQL_ATTR_TRANSLATE_LIB:
669 if ( SQL_SUCCEEDED( ret ) && value && s1 )
670 {
671 unicode_to_ansi_copy( value, buffer_length, s1, SQL_NTS, connection, NULL );
672 }
673 if ( SQL_SUCCEEDED( ret ) && string_length )
674 {
675 *string_length /= sizeof( SQLWCHAR );
676 }
677 break;
678 }
679
680 if ( s1 )
681 {
682 free( s1 );
683 }
684 }
685 else
686 {
687 dm_log_write( __FILE__,
688 __LINE__,
689 LOG_INFO,
690 LOG_INFO,
691 "Error: IM001" );
692
693 __post_internal_error( &connection -> error,
694 ERROR_IM001, NULL,
695 connection -> environment -> requested_version );
696
697 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
698 }
699 }
700 else
701 {
702 SQLWCHAR *s1 = NULL;
703
704 switch( attribute )
705 {
706 case SQL_ATTR_CURRENT_CATALOG:
707 case SQL_ATTR_TRACEFILE:
708 case SQL_ATTR_TRANSLATE_LIB:
709 if ( SQL_SUCCEEDED( ret ) && value && buffer_length > 0 )
710 {
711 s1 = malloc( sizeof( SQLWCHAR ) * ( buffer_length + 1 ));
712 }
713 break;
714 }
715
716 ret = SQLGETCONNECTATTRW( connection,
717 connection -> driver_dbc,
718 attribute,
719 s1 ? s1 : value,
720 s1 ? sizeof( SQLWCHAR ) * buffer_length : buffer_length,
721 string_length );
722
723 switch( attribute )
724 {
725 case SQL_ATTR_CURRENT_CATALOG:
726 case SQL_ATTR_TRACEFILE:
727 case SQL_ATTR_TRANSLATE_LIB:
728 if ( SQL_SUCCEEDED( ret ) && value && s1 )
729 {
730 unicode_to_ansi_copy( value, buffer_length, s1, SQL_NTS, connection, NULL );
731 }
732 if ( SQL_SUCCEEDED( ret ) && string_length )
733 {
734 *string_length /= sizeof( SQLWCHAR );
735 }
736 break;
737 }
738
739 if ( s1 )
740 {
741 free( s1 );
742 }
743 }
744 }
745 else
746 {
747 if ( !CHECK_SQLGETCONNECTATTR( connection ))
748 {
749 if ( CHECK_SQLGETCONNECTOPTION( connection ))
750 {
751 /*
752 * Is it in the legal range of values
753 */
754
755 if ( attribute < SQL_CONN_DRIVER_MIN &&
756 ( attribute > SQL_PACKET_SIZE || attribute < SQL_ACCESS_MODE ))
757 {
758 dm_log_write( __FILE__,
759 __LINE__,
760 LOG_INFO,
761 LOG_INFO,
762 "Error: HY092" );
763
764 __post_internal_error( &connection -> error,
765 ERROR_HY092, NULL,
766 connection -> environment -> requested_version );
767
768 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
769 }
770
771 ret = SQLGETCONNECTOPTION( connection,
772 connection -> driver_dbc,
773 attribute,
774 value );
775 }
776 else
777 {
778 dm_log_write( __FILE__,
779 __LINE__,
780 LOG_INFO,
781 LOG_INFO,
782 "Error: IM001" );
783
784 __post_internal_error( &connection -> error,
785 ERROR_IM001, NULL,
786 connection -> environment -> requested_version );
787
788 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
789 }
790 }
791 else
792 {
793 ret = SQLGETCONNECTATTR( connection,
794 connection -> driver_dbc,
795 attribute,
796 value,
797 buffer_length,
798 string_length );
799 }
800 }
801
802 if ( log_info.log_flag )
803 {
804 sprintf( connection -> msg,
805 "\n\t\tExit:[%s]",
806 __get_return_status( ret, s1 ));
807
808 dm_log_write( __FILE__,
809 __LINE__,
810 LOG_INFO,
811 LOG_INFO,
812 connection -> msg );
813 }
814
815
816 return function_return( SQL_HANDLE_DBC, connection, ret );
817 }
818}
819