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