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: SQLSetStmtAttrW.c,v 1.10 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLSetStmtAttrW.c,v $
33 * Revision 1.10 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.9 2009/02/04 09:30:02 lurcher
37 * Fix some SQLINTEGER/SQLLEN conflicts
38 *
39 * Revision 1.8 2008/08/29 08:01:39 lurcher
40 * Alter the way W functions are passed to the driver
41 *
42 * Revision 1.7 2007/02/28 15:37:48 lurcher
43 * deal with drivers that call internal W functions and end up in the driver manager. controlled by the --enable-handlemap configure arg
44 *
45 * Revision 1.6 2006/04/18 10:24:47 lurcher
46 * Add a couple of changes from Mark Vanderwiel
47 *
48 * Revision 1.5 2003/10/30 18:20:46 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.4 2003/03/05 09:48:45 lurcher
56 *
57 * Add some 64 bit fixes
58 *
59 * Revision 1.3 2002/12/05 17:44:31 lurcher
60 *
61 * Display unknown return values in return logging
62 *
63 * Revision 1.2 2002/05/28 13:30:34 lurcher
64 *
65 * Tidy up for AIX
66 *
67 * Revision 1.1.1.1 2001/10/17 16:40:07 lurcher
68 *
69 * First upload to SourceForge
70 *
71 * Revision 1.4 2001/08/08 17:05:17 nick
72 *
73 * Add support for attribute setting in the ini files
74 *
75 * Revision 1.3 2001/07/03 09:30:41 nick
76 *
77 * Add ability to alter size of displayed message in the log
78 *
79 * Revision 1.2 2001/04/12 17:43:36 nick
80 *
81 * Change logging and added autotest to odbctest
82 *
83 * Revision 1.1 2000/12/31 20:30:54 nick
84 *
85 * Add UNICODE support
86 *
87 *
88 *
89 **********************************************************************/
90
91#include <config.h>
92#include "drivermanager.h"
93
94static char const rcsid[]= "$RCSfile: SQLSetStmtAttrW.c,v $";
95
96SQLRETURN SQLSetStmtAttrW( SQLHSTMT statement_handle,
97 SQLINTEGER attribute,
98 SQLPOINTER value,
99 SQLINTEGER string_length )
100{
101 DMHSTMT statement = (DMHSTMT) statement_handle;
102 SQLRETURN ret;
103 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
104 SQLWCHAR buffer[ 512 ];
105
106 /*
107 * check statement
108 */
109
110 if ( !__validate_stmt( statement ))
111 {
112 dm_log_write( __FILE__,
113 __LINE__,
114 LOG_INFO,
115 LOG_INFO,
116 "Error: SQL_INVALID_HANDLE" );
117
118#ifdef WITH_HANDLE_REDIRECT
119 {
120 DMHSTMT parent_statement;
121
122 parent_statement = find_parent_handle( statement, SQL_HANDLE_STMT );
123
124 if ( parent_statement ) {
125 dm_log_write( __FILE__,
126 __LINE__,
127 LOG_INFO,
128 LOG_INFO,
129 "Info: found parent handle" );
130
131 if ( CHECK_SQLSETSTMTATTRW( parent_statement -> connection ))
132 {
133 dm_log_write( __FILE__,
134 __LINE__,
135 LOG_INFO,
136 LOG_INFO,
137 "Info: calling redirected driver function" );
138
139 return SQLSETSTMTATTRW( parent_statement -> connection,
140 statement_handle,
141 attribute,
142 value,
143 string_length );
144 }
145 }
146 }
147#endif
148 return SQL_INVALID_HANDLE;
149 }
150
151 function_entry( statement );
152
153 if ( log_info.log_flag )
154 {
155 sprintf( statement -> msg, "\n\t\tEntry:\
156\n\t\t\tStatement = %p\
157\n\t\t\tAttribute = %s\
158\n\t\t\tValue = %p\
159\n\t\t\tStrLen = %d",
160 statement,
161 __stmt_attr_as_string( s1, attribute ),
162 value,
163 (int)string_length );
164
165 dm_log_write( __FILE__,
166 __LINE__,
167 LOG_INFO,
168 LOG_INFO,
169 statement -> msg );
170 }
171
172 thread_protect( SQL_HANDLE_STMT, statement );
173
174 /*
175 * check states
176 */
177
178 if ( attribute == SQL_ATTR_CONCURRENCY ||
179 attribute == SQL_ATTR_CURSOR_TYPE ||
180 attribute == SQL_ATTR_SIMULATE_CURSOR ||
181 attribute == SQL_ATTR_USE_BOOKMARKS ||
182 attribute == SQL_ATTR_CURSOR_SCROLLABLE ||
183 attribute == SQL_ATTR_CURSOR_SENSITIVITY )
184 {
185 if ( statement -> state == STATE_S2 ||
186 statement -> state == STATE_S3 )
187 {
188 dm_log_write( __FILE__,
189 __LINE__,
190 LOG_INFO,
191 LOG_INFO,
192 "Error: HY011" );
193
194 __post_internal_error( &statement -> error,
195 ERROR_HY011, NULL,
196 statement -> connection -> environment -> requested_version );
197
198 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
199 }
200 else if ( statement -> state == STATE_S4 ||
201 statement -> state == STATE_S5 ||
202 statement -> state == STATE_S6 ||
203 statement -> state == STATE_S7 )
204 {
205 dm_log_write( __FILE__,
206 __LINE__,
207 LOG_INFO,
208 LOG_INFO,
209 "Error: 24000" );
210
211 __post_internal_error( &statement -> error,
212 ERROR_24000, NULL,
213 statement -> connection -> environment -> requested_version );
214
215 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
216 }
217 else if ( statement -> state == STATE_S8 ||
218 statement -> state == STATE_S9 ||
219 statement -> state == STATE_S10 ||
220 statement -> state == STATE_S11 ||
221 statement -> state == STATE_S12 ||
222 statement -> state == STATE_S13 ||
223 statement -> state == STATE_S14 ||
224 statement -> state == STATE_S15 )
225 {
226 if ( statement -> prepared )
227 {
228 dm_log_write( __FILE__,
229 __LINE__,
230 LOG_INFO,
231 LOG_INFO,
232 "Error: HY011" );
233
234 __post_internal_error( &statement -> error,
235 ERROR_HY011, NULL,
236 statement -> connection -> environment -> requested_version );
237
238 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
239 }
240 else
241 {
242 dm_log_write( __FILE__,
243 __LINE__,
244 LOG_INFO,
245 LOG_INFO,
246 "Error: HY010" );
247
248 __post_internal_error( &statement -> error,
249 ERROR_HY010, NULL,
250 statement -> connection -> environment -> requested_version );
251
252 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
253 }
254 }
255 }
256 else
257 {
258 if ( statement -> state == STATE_S8 ||
259 statement -> state == STATE_S9 ||
260 statement -> state == STATE_S10 ||
261 statement -> state == STATE_S11 ||
262 statement -> state == STATE_S12 )
263 {
264 dm_log_write( __FILE__,
265 __LINE__,
266 LOG_INFO,
267 LOG_INFO,
268 "Error: HY010" );
269
270 __post_internal_error( &statement -> error,
271 ERROR_HY010, NULL,
272 statement -> connection -> environment -> requested_version );
273
274 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
275 }
276 }
277
278 if ( statement -> connection -> unicode_driver ||
279 CHECK_SQLSETSTMTATTRW( statement -> connection ))
280 {
281 if ( !CHECK_SQLSETSTMTATTRW( statement -> connection ))
282 {
283 dm_log_write( __FILE__,
284 __LINE__,
285 LOG_INFO,
286 LOG_INFO,
287 "Error: IM001" );
288
289 __post_internal_error( &statement -> error,
290 ERROR_IM001, NULL,
291 statement -> connection -> environment -> requested_version );
292
293 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
294 }
295 }
296 else
297 {
298 if ( !CHECK_SQLSETSTMTATTR( statement -> connection ))
299 {
300 dm_log_write( __FILE__,
301 __LINE__,
302 LOG_INFO,
303 LOG_INFO,
304 "Error: IM001" );
305
306 __post_internal_error( &statement -> error,
307 ERROR_IM001, NULL,
308 statement -> connection -> environment -> requested_version );
309
310 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
311 }
312 }
313
314 /*
315 * map descriptors to our copies
316 */
317
318 if ( attribute == SQL_ATTR_APP_ROW_DESC )
319 {
320 DMHDESC desc = ( DMHDESC ) value;
321
322 /*
323 * needs to reset to implicit descriptor, this is safe
324 * without a validate, as the value is either null, or the
325 * same as a descriptor we know is valid
326 */
327
328 if ( desc == NULL || desc == statement -> implicit_ard )
329 {
330 DRV_SQLHDESC drv_desc = NULL;
331
332 ret = SQL_SUCCESS;
333
334 if ( desc == statement -> implicit_ard )
335 {
336 drv_desc = statement -> implicit_ard -> driver_desc;
337 }
338
339 if ( CHECK_SQLSETSTMTATTRW( statement -> connection ))
340 {
341 ret = SQLSETSTMTATTRW( statement -> connection,
342 statement -> driver_stmt,
343 attribute,
344 statement -> implicit_ard -> driver_desc,
345 0 );
346 }
347 else if ( CHECK_SQLSETSTMTATTR( statement -> connection ))
348 {
349 ret = SQLSETSTMTATTR( statement -> connection,
350 statement -> driver_stmt,
351 attribute,
352 drv_desc,
353 0 );
354 }
355 else
356 {
357 ret = SQLSETSTMTOPTION( statement -> connection,
358 statement -> driver_stmt,
359 attribute,
360 statement -> implicit_ard -> driver_desc );
361 }
362
363 if ( ret != SQL_SUCCESS )
364 {
365 if ( log_info.log_flag )
366 {
367 sprintf( statement -> msg,
368 "\n\t\tExit:[%s]",
369 __get_return_status( ret, s1 ));
370
371 dm_log_write( __FILE__,
372 __LINE__,
373 LOG_INFO,
374 LOG_INFO,
375 statement -> msg );
376 }
377
378 return function_return( SQL_HANDLE_STMT, statement, ret );
379 }
380
381 /*
382 * copy DM descriptor
383 */
384
385 statement -> apd = statement -> implicit_apd;
386
387 if ( log_info.log_flag )
388 {
389 sprintf( statement -> msg,
390 "\n\t\tExit:[%s]",
391 __get_return_status( ret, s1 ));
392
393 dm_log_write( __FILE__,
394 __LINE__,
395 LOG_INFO,
396 LOG_INFO,
397 statement -> msg );
398 }
399
400 return function_return( SQL_HANDLE_STMT, statement, ret );
401 }
402
403 if ( !__validate_desc( desc ))
404 {
405 thread_release( SQL_HANDLE_STMT, statement );
406
407 return SQL_INVALID_HANDLE;
408 }
409
410 if ( desc -> implicit &&
411 desc != statement -> implicit_ard )
412 {
413 dm_log_write( __FILE__,
414 __LINE__,
415 LOG_INFO,
416 LOG_INFO,
417 "Error: HY017" );
418
419 __post_internal_error( &statement -> error,
420 ERROR_HY017, NULL,
421 statement -> connection -> environment -> requested_version );
422
423 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
424 }
425
426 if ( desc -> connection !=
427 statement -> connection )
428 {
429 dm_log_write( __FILE__,
430 __LINE__,
431 LOG_INFO,
432 LOG_INFO,
433 "Error: HY024" );
434
435 __post_internal_error( &statement -> error,
436 ERROR_HY024, NULL,
437 statement -> connection -> environment -> requested_version );
438
439 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
440 }
441
442 /*
443 * set the value to the driver descriptor handle
444 */
445 value = ( SQLPOINTER ) desc -> driver_desc;
446 statement -> ard = desc;
447 desc -> associated_with = statement;
448 }
449
450 if ( attribute == SQL_ATTR_APP_PARAM_DESC )
451 {
452 DMHDESC desc = ( DMHDESC ) value;
453
454 /*
455 * needs to reset to implicit descriptor, this is safe
456 * without a validate, as the value is either null, or the
457 * same as a descriptor we know is valid
458 */
459
460 if ( desc == NULL || desc == statement -> implicit_apd )
461 {
462 DRV_SQLHDESC drv_desc = NULL;
463
464 ret = SQL_SUCCESS;
465
466 if ( desc == statement -> implicit_apd )
467 {
468 drv_desc = statement -> implicit_apd -> driver_desc;
469 }
470
471 if ( CHECK_SQLSETSTMTATTRW( statement -> connection ))
472 {
473 ret = SQLSETSTMTATTRW( statement -> connection,
474 statement -> driver_stmt,
475 attribute,
476 statement -> implicit_apd -> driver_desc,
477 0 );
478 }
479 else if ( CHECK_SQLSETSTMTATTR( statement -> connection ))
480 {
481 ret = SQLSETSTMTATTR( statement -> connection,
482 statement -> driver_stmt,
483 attribute,
484 statement -> implicit_apd -> driver_desc,
485 0 );
486 }
487 else
488 {
489 ret = SQLSETSTMTOPTION( statement -> connection,
490 statement -> driver_stmt,
491 attribute,
492 drv_desc );
493 }
494
495 if ( ret != SQL_SUCCESS )
496 {
497 if ( log_info.log_flag )
498 {
499 sprintf( statement -> msg,
500 "\n\t\tExit:[%s]",
501 __get_return_status( ret, s1 ));
502
503 dm_log_write( __FILE__,
504 __LINE__,
505 LOG_INFO,
506 LOG_INFO,
507 statement -> msg );
508 }
509
510 return function_return( SQL_HANDLE_STMT, statement, ret );
511 }
512
513 /*
514 * copy DM descriptor
515 */
516
517 statement -> apd = statement -> implicit_apd;
518
519 if ( log_info.log_flag )
520 {
521 sprintf( statement -> msg,
522 "\n\t\tExit:[%s]",
523 __get_return_status( ret, s1 ));
524
525 dm_log_write( __FILE__,
526 __LINE__,
527 LOG_INFO,
528 LOG_INFO,
529 statement -> msg );
530 }
531
532 return function_return( SQL_HANDLE_STMT, statement, ret );
533 }
534
535 if ( !__validate_desc( desc ))
536 {
537 sprintf( statement -> msg,
538 "\n\t\tExit:[%s]",
539 __get_return_status( SQL_INVALID_HANDLE, s1 ));
540
541 dm_log_write( __FILE__,
542 __LINE__,
543 LOG_INFO,
544 LOG_INFO,
545 statement -> msg );
546
547 thread_release( SQL_HANDLE_STMT, statement );
548
549 return SQL_INVALID_HANDLE;
550 }
551
552 if ( desc -> implicit &&
553 desc != statement -> implicit_apd )
554 {
555 dm_log_write( __FILE__,
556 __LINE__,
557 LOG_INFO,
558 LOG_INFO,
559 "Error: HY017" );
560
561 __post_internal_error( &statement -> error,
562 ERROR_HY017, NULL,
563 statement -> connection -> environment -> requested_version );
564
565 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
566 }
567
568 if ( desc -> connection !=
569 statement -> connection )
570 {
571 dm_log_write( __FILE__,
572 __LINE__,
573 LOG_INFO,
574 LOG_INFO,
575 "Error: HY024" );
576
577 __post_internal_error( &statement -> error,
578 ERROR_HY024, NULL,
579 statement -> connection -> environment -> requested_version );
580
581 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
582 }
583
584 /*
585 * set the value to the driver descriptor handle
586 */
587 value = ( SQLPOINTER ) desc -> driver_desc;
588 statement -> apd = desc;
589 desc -> associated_with = statement;
590 }
591
592 /*
593 * save for internal use
594 */
595
596 if ( attribute == SQL_ATTR_METADATA_ID )
597 {
598#ifdef HAVE_PTRDIFF_T
599 statement -> metadata_id = (ptrdiff_t) value;
600#else
601 statement -> metadata_id = (SQLINTEGER) value;
602#endif
603 }
604
605 if ( attribute == SQL_ATTR_IMP_ROW_DESC ||
606 attribute == SQL_ATTR_IMP_PARAM_DESC )
607 {
608 dm_log_write( __FILE__,
609 __LINE__,
610 LOG_INFO,
611 LOG_INFO,
612 "Error: HY017" );
613
614 __post_internal_error( &statement -> error,
615 ERROR_HY017, NULL,
616 statement -> connection -> environment -> requested_version );
617
618 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
619 }
620
621 /*
622 * is it a legitimate value
623 */
624 ret = dm_check_statement_attrs( statement, attribute, value );
625
626 if ( ret != SQL_SUCCESS )
627 {
628 dm_log_write( __FILE__,
629 __LINE__,
630 LOG_INFO,
631 LOG_INFO,
632 "Error: HY011" );
633
634 __post_internal_error( &statement -> error,
635 ERROR_HY024, NULL,
636 statement -> connection -> environment -> requested_version );
637
638 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
639 }
640
641 /*
642 * is it something overridden
643 */
644
645 value = __attr_override_wide( statement, SQL_HANDLE_STMT, attribute, value, &string_length, buffer );
646
647 /*
648 * does the call need mapping from 3 to 2
649 */
650
651 if ( attribute == SQL_ATTR_FETCH_BOOKMARK_PTR &&
652 statement -> connection -> driver_act_ver == SQL_OV_ODBC2 &&
653 CHECK_SQLEXTENDEDFETCH( statement -> connection ) &&
654 !CHECK_SQLFETCHSCROLL( statement -> connection ))
655 {
656 statement -> fetch_bm_ptr = (SQLULEN*) value;
657 ret = SQL_SUCCESS;
658 }
659 else if ( attribute == SQL_ATTR_ROW_STATUS_PTR &&
660 statement -> connection -> driver_act_ver == SQL_OV_ODBC2 )
661 {
662 statement -> row_st_arr = (SQLUSMALLINT*) value;
663 ret = SQL_SUCCESS;
664 }
665 else if ( attribute == SQL_ATTR_ROWS_FETCHED_PTR &&
666 statement -> connection -> driver_act_ver == SQL_OV_ODBC2 )
667 {
668 statement -> row_ct_ptr = (SQLULEN*) value;
669 ret = SQL_SUCCESS;
670 }
671 else if ( attribute == SQL_ATTR_ROW_ARRAY_SIZE &&
672 statement -> connection -> driver_act_ver == SQL_OV_ODBC2 )
673 {
674 ret = SQLSETSTMTATTRW( statement -> connection,
675 statement -> driver_stmt,
676 SQL_ROWSET_SIZE,
677 value,
678 string_length );
679 }
680 else
681 {
682 if ( statement -> connection -> unicode_driver )
683 {
684 ret = SQLSETSTMTATTRW( statement -> connection,
685 statement -> driver_stmt,
686 attribute,
687 value,
688 string_length );
689 }
690 else
691 {
692 /*
693 * I can't find any string values, so we don't need to translate
694 */
695
696 ret = SQLSETSTMTATTR( statement -> connection,
697 statement -> driver_stmt,
698 attribute,
699 value,
700 string_length );
701 }
702 }
703
704 /*
705 * take notice of this
706 */
707
708 if ( attribute == SQL_ATTR_USE_BOOKMARKS && SQL_SUCCEEDED( ret ))
709 {
710 statement -> bookmarks_on = (SQLULEN) value;
711 }
712
713 if ( log_info.log_flag )
714 {
715 sprintf( statement -> msg,
716 "\n\t\tExit:[%s]",
717 __get_return_status( ret, s1 ));
718
719 dm_log_write( __FILE__,
720 __LINE__,
721 LOG_INFO,
722 LOG_INFO,
723 statement -> msg );
724 }
725
726 return function_return( SQL_HANDLE_STMT, statement, ret );
727}
728