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: SQLSetConnectOption.c,v 1.12 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLSetConnectOption.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 2003/10/30 18:20:46 lurcher
37 *
38 * Fix broken thread protection
39 * Remove SQLNumResultCols after execute, lease S4/S% to driver
40 * Fix string overrun in SQLDriverConnect
41 * Add initial support for Interix
42 *
43 * Revision 1.10 2003/03/05 09:48:45 lurcher
44 *
45 * Add some 64 bit fixes
46 *
47 * Revision 1.9 2003/02/27 12:19:40 lurcher
48 *
49 * Add the A functions as well as the W
50 *
51 * Revision 1.8 2002/12/05 17:44:31 lurcher
52 *
53 * Display unknown return values in return logging
54 *
55 * Revision 1.7 2002/07/25 09:30:26 lurcher
56 *
57 * Additional unicode and iconv changes
58 *
59 * Revision 1.6 2002/07/24 08:49:52 lurcher
60 *
61 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
62 *
63 * Revision 1.5 2002/07/04 17:27:56 lurcher
64 *
65 * Small bug fixes
66 *
67 * Revision 1.3 2002/01/30 12:20:02 lurcher
68 *
69 * Add MyODBC 3 driver source
70 *
71 * Revision 1.2 2001/12/13 13:00:32 lurcher
72 *
73 * Remove most if not all warnings on 64 bit platforms
74 * Add support for new MS 3.52 64 bit changes
75 * Add override to disable the stopping of tracing
76 * Add MAX_ROWS support in postgres driver
77 *
78 * Revision 1.1.1.1 2001/10/17 16:40:07 lurcher
79 *
80 * First upload to SourceForge
81 *
82 * Revision 1.8 2001/09/27 17:05:48 nick
83 *
84 * Assorted fixes and tweeks
85 *
86 * Revision 1.7 2001/08/08 17:05:17 nick
87 *
88 * Add support for attribute setting in the ini files
89 *
90 * Revision 1.6 2001/07/03 09:30:41 nick
91 *
92 * Add ability to alter size of displayed message in the log
93 *
94 * Revision 1.5 2001/04/12 17:43:36 nick
95 *
96 * Change logging and added autotest to odbctest
97 *
98 * Revision 1.4 2001/02/07 11:20:23 nick
99 *
100 * Remove some compile warnings
101 *
102 * Revision 1.3 2001/02/06 18:46:55 nick
103 *
104 * More UNICODE ommissions
105 *
106 * Revision 1.2 2000/11/14 10:15:27 nick
107 *
108 * Add test for localtime_r
109 *
110 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
111 * Imported Sources
112 *
113 * Revision 1.11 2000/06/20 13:30:10 ngorham
114 *
115 * Fix problems when using bookmarks
116 *
117 * Revision 1.10 2000/05/21 21:49:19 ngorham
118 *
119 * Assorted fixes
120 *
121 * Revision 1.9 1999/11/13 23:41:00 ngorham
122 *
123 * Alter the way DM logging works
124 * Upgrade the Postgres driver to 6.4.6
125 *
126 * Revision 1.8 1999/11/10 03:51:34 ngorham
127 *
128 * Update the error reporting in the DM to enable ODBC 3 and 2 calls to
129 * work at the same time
130 *
131 * Revision 1.7 1999/10/24 23:54:18 ngorham
132 *
133 * First part of the changes to the error reporting
134 *
135 * Revision 1.6 1999/09/21 22:34:25 ngorham
136 *
137 * Improve performance by removing unneeded logging calls when logging is
138 * disabled
139 *
140 * Revision 1.5 1999/09/19 22:24:34 ngorham
141 *
142 * Added support for the cursor library
143 *
144 * Revision 1.4 1999/07/10 21:10:17 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:08 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:08 sShandyb
158 * first go at it
159 *
160 * Revision 1.4 1999/06/03 22:20:25 ngorham
161 *
162 * Finished off the ODBC3-2 mapping
163 *
164 * Revision 1.3 1999/06/02 20:12:10 ngorham
165 *
166 * Fixed botched log entry, and removed the dos \r from the sql header files.
167 *
168 * Revision 1.2 1999/06/02 19:57:21 ngorham
169 *
170 * Added code to check if a attempt is being made to compile with a C++
171 * Compiler, and issue a message.
172 * Start work on the ODBC2-3 conversions.
173 *
174 * Revision 1.1.1.1 1999/05/27 18:23:18 pharvey
175 * Imported sources
176 *
177 * Revision 1.2 1999/05/09 23:27:11 nick
178 * All the API done now
179 *
180 * Revision 1.1 1999/04/25 23:06:11 nick
181 * Initial revision
182 *
183 *
184 **********************************************************************/
185
186#include <config.h>
187#ifdef HAVE_STRING_H
188#include <string.h>
189#endif
190#ifdef HAVE_STRINGS_H
191#include <strings.h>
192#endif
193#ifdef HAVE_STDLIB_H
194#include <stdlib.h>
195#endif
196#include "drivermanager.h"
197
198static char const rcsid[]= "$RCSfile: SQLSetConnectOption.c,v $ $Revision: 1.12 $";
199
200SQLRETURN SQLSetConnectOptionA( SQLHDBC connection_handle,
201 SQLUSMALLINT option,
202 SQLULEN value )
203{
204 return SQLSetConnectOption( connection_handle,
205 option,
206 value );
207}
208
209SQLRETURN SQLSetConnectOption( SQLHDBC connection_handle,
210 SQLUSMALLINT option,
211 SQLULEN value )
212{
213 DMHDBC connection = (DMHDBC)connection_handle;
214 SQLRETURN ret;
215 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
216
217 /*
218 * doesn't require a handle
219 */
220
221 if ( option == SQL_ATTR_TRACE )
222 {
223 if ((SQLLEN) value != SQL_OPT_TRACE_OFF &&
224 (SQLLEN) value != SQL_OPT_TRACE_ON )
225 {
226 if ( __validate_dbc( connection ))
227 {
228 thread_protect( SQL_HANDLE_DBC, connection );
229 function_entry( connection );
230 dm_log_write( __FILE__,
231 __LINE__,
232 LOG_INFO,
233 LOG_INFO,
234 "Error: HY024" );
235
236 __post_internal_error( &connection -> error,
237 ERROR_HY024, NULL,
238 connection -> environment -> requested_version );
239
240 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
241 }
242 else
243 {
244 return SQL_INVALID_HANDLE;
245 }
246 }
247
248 if ( value == SQL_OPT_TRACE_OFF )
249 {
250 log_info.log_flag = 0;
251 }
252 else
253 {
254 log_info.log_flag = 1;
255 }
256
257 return SQL_SUCCESS;
258 }
259 else if ( option == SQL_ATTR_TRACEFILE )
260 {
261 if ( value )
262 {
263 if (((SQLCHAR*)value)[ 0 ] == '\0' )
264 {
265 if ( __validate_dbc( connection ))
266 {
267 thread_protect( SQL_HANDLE_DBC, connection );
268 function_entry( connection );
269 dm_log_write( __FILE__,
270 __LINE__,
271 LOG_INFO,
272 LOG_INFO,
273 "Error: HY024" );
274
275 __post_internal_error( &connection -> error,
276 ERROR_HY024, NULL,
277 connection -> environment -> requested_version );
278
279 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
280 }
281 else
282 {
283 return SQL_INVALID_HANDLE;
284 }
285 }
286 else
287 {
288 if ( log_info.log_file_name )
289 {
290 free( log_info.log_file_name );
291 }
292 log_info.log_file_name = strdup((char*) value );
293 }
294 }
295 else
296 {
297 if ( __validate_dbc( connection ))
298 {
299 thread_protect( SQL_HANDLE_DBC, connection );
300 function_entry( connection );
301 dm_log_write( __FILE__,
302 __LINE__,
303 LOG_INFO,
304 LOG_INFO,
305 "Error: HY024" );
306
307 __post_internal_error( &connection -> error,
308 ERROR_HY024, NULL,
309 connection -> environment -> requested_version );
310
311 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
312 }
313 else
314 {
315 return SQL_INVALID_HANDLE;
316 }
317 }
318 return SQL_SUCCESS;
319 }
320
321 /*
322 * check connection
323 */
324
325 if ( !__validate_dbc( connection ))
326 {
327 dm_log_write( __FILE__,
328 __LINE__,
329 LOG_INFO,
330 LOG_INFO,
331 "Error: SQL_INVALID_HANDLE" );
332
333 return SQL_INVALID_HANDLE;
334 }
335
336 function_entry( connection );
337
338 if ( log_info.log_flag )
339 {
340 sprintf( connection -> msg, "\n\t\tEntry:\
341\n\t\t\tConnection = %p\
342\n\t\t\tOption = %s\
343\n\t\t\tValue = %d",
344 connection,
345 __con_attr_as_string( s1, option ),
346 (int)value );
347
348 dm_log_write( __FILE__,
349 __LINE__,
350 LOG_INFO,
351 LOG_INFO,
352 connection -> msg );
353 }
354
355 thread_protect( SQL_HANDLE_DBC, connection );
356
357 if ( connection -> state == STATE_C2 )
358 {
359 if ( option == SQL_TRANSLATE_OPTION ||
360 option == SQL_TRANSLATE_DLL )
361 {
362 dm_log_write( __FILE__,
363 __LINE__,
364 LOG_INFO,
365 LOG_INFO,
366 "Error: 08003" );
367
368 __post_internal_error( &connection -> error,
369 ERROR_08003, NULL,
370 connection -> environment -> requested_version );
371
372 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
373 }
374 }
375 else if ( connection -> state == STATE_C3 )
376 {
377 dm_log_write( __FILE__,
378 __LINE__,
379 LOG_INFO,
380 LOG_INFO,
381 "Error: HY010" );
382
383 __post_internal_error( &connection -> error,
384 ERROR_HY010, NULL,
385 connection -> environment -> requested_version );
386
387 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
388 }
389 else if ( connection -> state == STATE_C4 ||
390 connection -> state == STATE_C5 )
391 {
392 if ( option == SQL_ODBC_CURSORS )
393 {
394 dm_log_write( __FILE__,
395 __LINE__,
396 LOG_INFO,
397 LOG_INFO,
398 "Error: 08002" );
399
400 __post_internal_error( &connection -> error,
401 ERROR_08002, NULL,
402 connection -> environment -> requested_version );
403
404 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
405 }
406 }
407 else if ( connection -> state == STATE_C6 )
408 {
409 if ( option == SQL_ODBC_CURSORS )
410 {
411 dm_log_write( __FILE__,
412 __LINE__,
413 LOG_INFO,
414 LOG_INFO,
415 "Error: 08002" );
416
417 __post_internal_error( &connection -> error,
418 ERROR_08002, NULL,
419 connection -> environment -> requested_version );
420
421 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
422 }
423 else if ( option == SQL_TXN_ISOLATION )
424 {
425 dm_log_write( __FILE__,
426 __LINE__,
427 LOG_INFO,
428 LOG_INFO,
429 "Error: S1011" );
430
431 __post_internal_error( &connection -> error,
432 ERROR_S1011, NULL,
433 connection -> environment -> requested_version );
434
435 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
436 }
437 }
438
439 /*
440 * is it a legitimate value
441 */
442 ret = dm_check_connection_attrs( connection, option, (SQLPOINTER)value );
443
444 if ( ret != SQL_SUCCESS )
445 {
446 dm_log_write( __FILE__,
447 __LINE__,
448 LOG_INFO,
449 LOG_INFO,
450 "Error: HY024" );
451
452 __post_internal_error( &connection -> error,
453 ERROR_HY024, NULL,
454 connection -> environment -> requested_version );
455
456 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
457 }
458
459 /*
460 * is it something overridden
461 */
462
463 value = (SQLULEN) __attr_override( connection, SQL_HANDLE_DBC, option, (void*) value, NULL );
464
465 /*
466 * we need to save this even if connected so we can use it for the next connect
467 */
468 if ( option == SQL_LOGIN_TIMEOUT )
469 {
470 connection -> login_timeout_set = 1;
471 connection -> login_timeout = value;
472 }
473 else if ( option == SQL_ATTR_ACCESS_MODE )
474 {
475 connection -> access_mode = ( SQLLEN ) value;
476 connection -> access_mode_set = 1;
477 }
478 else if ( option == SQL_AUTOCOMMIT )
479 {
480 connection -> auto_commit = ( SQLINTEGER ) value;
481 connection -> auto_commit_set = 1;
482 }
483
484 if ( option == SQL_ODBC_CURSORS )
485 {
486 connection -> cursors = value;
487 ret = SQL_SUCCESS;
488 }
489 else if ( connection -> state == STATE_C2 )
490 {
491 if ( option == SQL_AUTOCOMMIT )
492 {
493 connection -> auto_commit = ( SQLINTEGER ) value;
494 connection -> auto_commit_set = 1;
495 }
496 else if ( option == SQL_ATTR_QUIET_MODE )
497 {
498 connection -> quite_mode = ( SQLLEN ) value;
499 connection -> quite_mode_set = 1;
500 }
501 else if ( option == SQL_ATTR_ACCESS_MODE )
502 {
503 connection -> access_mode = ( SQLLEN ) value;
504 connection -> access_mode_set = 1;
505 }
506 else
507 {
508 /*
509 * save any unknown attributes untill connect
510 */
511
512 struct save_attr *sa = calloc( 1, sizeof( struct save_attr ));
513
514 sa -> attr_type = option;
515 sa -> int_attr = ( SQLINTEGER ) value;
516 sa -> next = connection -> save_attr;
517 connection -> save_attr = sa;
518 }
519
520 if ( log_info.log_flag )
521 {
522 sprintf( connection -> msg,
523 "\n\t\tExit:[%s]",
524 __get_return_status( SQL_SUCCESS, s1 ));
525
526 dm_log_write( __FILE__,
527 __LINE__,
528 LOG_INFO,
529 LOG_INFO,
530 connection -> msg );
531 }
532
533 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_SUCCESS );
534 }
535 else
536 {
537 /*
538 * call the driver
539 */
540 if ( connection -> unicode_driver )
541 {
542 if ( CHECK_SQLSETCONNECTOPTIONW( connection ))
543 {
544 ret = SQLSETCONNECTOPTIONW( connection,
545 connection -> driver_dbc,
546 option,
547 value );
548 }
549 else if ( CHECK_SQLSETCONNECTATTRW( connection ))
550 {
551 SQLINTEGER string_length;
552 void *ptr = (void *) value;
553
554 switch( option )
555 {
556 case SQL_ATTR_CURRENT_CATALOG:
557 case SQL_ATTR_TRACEFILE:
558 case SQL_ATTR_TRANSLATE_LIB:
559 string_length = SQL_NTS;
560 ptr = (void *) ansi_to_unicode_alloc(( SQLCHAR * ) value, SQL_NTS, connection, NULL );
561 break;
562
563 default:
564 string_length = 0;
565 break;
566 }
567 ret = SQLSETCONNECTATTRW( connection,
568 connection -> driver_dbc,
569 option,
570 ptr,
571 string_length );
572
573 if ( ptr != (void*) value )
574 {
575 free( ptr );
576 }
577 }
578 else
579 {
580 dm_log_write( __FILE__,
581 __LINE__,
582 LOG_INFO,
583 LOG_INFO,
584 "Error: IM001" );
585
586 __post_internal_error( &connection -> error,
587 ERROR_IM001, NULL,
588 connection -> environment -> requested_version );
589
590 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
591 }
592 }
593 else
594 {
595 if ( CHECK_SQLSETCONNECTOPTION( connection ))
596 {
597 ret = SQLSETCONNECTOPTION( connection,
598 connection -> driver_dbc,
599 option,
600 value );
601 }
602 else if ( CHECK_SQLSETCONNECTATTR( connection ))
603 {
604 SQLINTEGER string_length;
605
606 switch( option )
607 {
608 case SQL_ATTR_CURRENT_CATALOG:
609 case SQL_ATTR_TRACEFILE:
610 case SQL_ATTR_TRANSLATE_LIB:
611 string_length = SQL_NTS;
612 break;
613
614 default:
615 string_length = 0;
616 break;
617 }
618 ret = SQLSETCONNECTATTR( connection,
619 connection -> driver_dbc,
620 option,
621 value,
622 string_length );
623 }
624 else
625 {
626 dm_log_write( __FILE__,
627 __LINE__,
628 LOG_INFO,
629 LOG_INFO,
630 "Error: IM001" );
631
632 __post_internal_error( &connection -> error,
633 ERROR_IM001, NULL,
634 connection -> environment -> requested_version );
635
636 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
637 }
638 }
639
640 if ( log_info.log_flag )
641 {
642 sprintf( connection -> msg,
643 "\n\t\tExit:[%s]",
644 __get_return_status( ret, s1 ));
645
646 dm_log_write( __FILE__,
647 __LINE__,
648 LOG_INFO,
649 LOG_INFO,
650 connection -> msg );
651 }
652 }
653
654 /*
655 * catch this
656 */
657
658 if ( option == SQL_ATTR_USE_BOOKMARKS && SQL_SUCCEEDED( ret ))
659 {
660 connection -> bookmarks_on = (SQLUINTEGER) value;
661 }
662
663 return function_return( SQL_HANDLE_DBC, connection, ret );
664}
665