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: SQLAllocHandle.c,v 1.13 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLAllocHandle.c,v $
33 * Revision 1.13 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.12 2007/12/17 13:13:03 lurcher
37 * Fix a couple of descriptor typo's
38 *
39 * Revision 1.11 2007/02/12 11:49:34 lurcher
40 * Add QT4 support to existing GUI parts
41 *
42 * Revision 1.10 2006/06/28 08:08:41 lurcher
43 * Add timestamp with timezone to Postgres7.1 driver
44 *
45 * Revision 1.9 2005/11/21 17:25:43 lurcher
46 * A few DM fixes for Oracle's ODBC driver
47 *
48 * Revision 1.8 2005/11/08 09:37:10 lurcher
49 * Allow the driver and application to have different length handles
50 *
51 * Revision 1.7 2005/10/06 08:50:58 lurcher
52 * Fix problem with SQLDrivers not returning first entry
53 *
54 * Revision 1.6 2003/10/30 18:20:45 lurcher
55 *
56 * Fix broken thread protection
57 * Remove SQLNumResultCols after execute, lease S4/S% to driver
58 * Fix string overrun in SQLDriverConnect
59 * Add initial support for Interix
60 *
61 * Revision 1.5 2003/02/25 13:28:21 lurcher
62 *
63 * Allow errors on the drivers AllocHandle to be reported
64 * Fix a problem that caused errors to not be reported in the log
65 * Remove a redundant line from the spec file
66 *
67 * Revision 1.4 2002/12/12 18:21:21 lurcher
68 *
69 * Fix bug where if a SQLAllocHandle in the driver failed, the driver manager
70 * seg faulted
71 *
72 * Revision 1.3 2002/08/12 13:17:52 lurcher
73 *
74 * Replicate the way the MS DM handles loading of driver libs, and allocating
75 * handles in the driver. usage counting in the driver means that dlopen is
76 * only called for the first use, and dlclose for the last. AllocHandle for
77 * the driver environment is only called for the first time per driver
78 * per application environment.
79 *
80 * Revision 1.2 2002/07/25 09:30:26 lurcher
81 *
82 * Additional unicode and iconv changes
83 *
84 * Revision 1.1.1.1 2001/10/17 16:40:03 lurcher
85 *
86 * First upload to SourceForge
87 *
88 * Revision 1.13 2001/09/27 17:05:48 nick
89 *
90 * Assorted fixes and tweeks
91 *
92 * Revision 1.12 2001/08/08 17:05:17 nick
93 *
94 * Add support for attribute setting in the ini files
95 *
96 * Revision 1.11 2001/08/03 15:19:00 nick
97 *
98 * Add changes to set values before connect
99 *
100 * Revision 1.10 2001/07/31 12:03:46 nick
101 *
102 * Fix how the DM gets the CLI year for SQLGetInfo
103 * Fix small bug in strncasecmp
104 *
105 * Revision 1.9 2001/06/04 15:24:49 nick
106 *
107 * Add port to MAC OSX and QT3 changes
108 *
109 * Revision 1.8 2001/05/15 13:33:44 jason
110 *
111 * Wrapped calls to stats with COLLECT_STATS
112 *
113 * Revision 1.7 2001/04/12 17:43:35 nick
114 *
115 * Change logging and added autotest to odbctest
116 *
117 * Revision 1.6 2000/12/18 11:03:58 martin
118 *
119 * Add support for the collection and retrieval of handle statistics.
120 *
121 * Revision 1.5 2000/12/14 18:10:18 nick
122 *
123 * Add connection pooling
124 *
125 * Revision 1.4 2000/11/22 19:03:40 nick
126 *
127 * Fix problem with error status in SQLSpecialColumns
128 *
129 * Revision 1.3 2000/11/22 18:35:43 nick
130 *
131 * Check input handle before touching output handle
132 *
133 * Revision 1.2 2000/11/14 10:15:27 nick
134 *
135 * Add test for localtime_r
136 *
137 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
138 * Imported Sources
139 *
140 * Revision 1.19 2000/06/21 11:07:35 ngorham
141 *
142 * Stop Errors from SQLAllocHandle being lost
143 *
144 * Revision 1.18 2000/05/22 17:10:34 ngorham
145 *
146 * Fix problems with the FetchScroll -> ExtendedFetch Mapping
147 *
148 * Revision 1.17 2000/05/21 21:49:18 ngorham
149 *
150 * Assorted fixes
151 *
152 * Revision 1.16 2001/04/27 01:29:35 ngorham
153 *
154 * Added a couple of fixes from Tim Roepken
155 *
156 * Revision 1.15 2000/01/03 14:24:01 ngorham
157 *
158 * Fix bug where a failed alloc of a statement would dump core
159 *
160 * Revision 1.14 2000/01/01 18:21:16 ngorham
161 *
162 * Fix small bug where a invalid input handle to SQLAllocHandle can cause
163 * a seg fault.
164 *
165 * Revision 1.13 1999/12/01 09:20:07 ngorham
166 *
167 * Fix some threading problems
168 *
169 * Revision 1.12 1999/11/15 21:42:52 ngorham
170 *
171 * Remove some debug info
172 *
173 * Revision 1.11 1999/11/13 23:40:58 ngorham
174 *
175 * Alter the way DM logging works
176 * Upgrade the Postgres driver to 6.4.6
177 *
178 * Revision 1.10 1999/11/10 03:51:33 ngorham
179 *
180 * Update the error reporting in the DM to enable ODBC 3 and 2 calls to
181 * work at the same time
182 *
183 * Revision 1.9 1999/10/24 23:54:17 ngorham
184 *
185 * First part of the changes to the error reporting
186 *
187 * Revision 1.8 1999/10/20 23:01:41 ngorham
188 *
189 * Fixed problem with the connection counting
190 *
191 * Revision 1.7 1999/09/26 18:55:03 ngorham
192 *
193 * Fixed a problem where the cursor lib was being used by default
194 *
195 * Revision 1.6 1999/09/21 22:34:23 ngorham
196 *
197 * Improve performance by removing unneeded logging calls when logging is
198 * disabled
199 *
200 * Revision 1.5 1999/09/19 22:24:33 ngorham
201 *
202 * Added support for the cursor library
203 *
204 * Revision 1.4 1999/07/10 21:10:15 ngorham
205 *
206 * Adjust error sqlstate from driver manager, depending on requested
207 * version (ODBC2/3)
208 *
209 * Revision 1.3 1999/07/04 21:05:06 ngorham
210 *
211 * Add LGPL Headers to code
212 *
213 * Revision 1.2 1999/06/30 23:56:54 ngorham
214 *
215 * Add initial thread safety code
216 *
217 * Revision 1.1.1.1 1999/05/29 13:41:05 sShandyb
218 * first go at it
219 *
220 * Revision 1.3 1999/06/02 20:12:10 ngorham
221 *
222 * Fixed botched log entry, and removed the dos \r from the sql header files.
223 *
224 * Revision 1.2 1999/06/02 19:57:20 ngorham
225 *
226 * Added code to check if a attempt is being made to compile with a C++
227 * Compiler, and issue a message.
228 * Start work on the ODBC2-3 conversions.
229 *
230 * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey
231 * Imported sources
232 *
233 * Revision 1.4 1999/05/09 23:27:11 nick
234 * All the API done now
235 *
236 * Revision 1.3 1999/05/03 19:50:43 nick
237 * Another check point
238 *
239 * Revision 1.2 1999/04/30 16:22:47 nick
240 * Another checkpoint
241 *
242 * Revision 1.1 1999/04/25 23:02:41 nick
243 * Initial revision
244 *
245 *
246 **********************************************************************/
247
248#include <config.h>
249#include "drivermanager.h"
250#if defined ( COLLECT_STATS ) && defined( HAVE_SYS_SEM_H )
251#include "__stats.h"
252#include <uodbc_stats.h>
253#endif
254
255static char const rcsid[]= "$RCSfile: SQLAllocHandle.c,v $ $Revision: 1.13 $";
256
257/*
258 * connection pooling stuff
259 */
260
261extern int pooling_enabled;
262
263/*
264 * this is used so that it can be called without falling
265 * fowl of any other instances in any other modules.
266 */
267
268SQLRETURN __SQLAllocHandle( SQLSMALLINT handle_type,
269 SQLHANDLE input_handle,
270 SQLHANDLE *output_handle,
271 SQLINTEGER requested_version )
272{
273 switch( handle_type )
274 {
275 case SQL_HANDLE_ENV:
276 case SQL_HANDLE_SENV:
277 {
278 DMHENV environment;
279 char pooling_string[ 128 ];
280
281 if ( !output_handle )
282 {
283 return SQL_ERROR;
284 }
285
286 if ( input_handle )
287 {
288 return SQL_INVALID_HANDLE;
289 }
290
291 /*
292 * check connection pooling attributes
293 */
294
295 SQLGetPrivateProfileString( "ODBC", "Pooling", "0",
296 pooling_string, sizeof( pooling_string ),
297 "ODBCINST.INI" );
298
299 if ( pooling_string[ 0 ] == '1' ||
300 toupper( pooling_string[ 0 ] ) == 'Y' ||
301 ( toupper( pooling_string[ 0 ] ) == 'O' &&
302 toupper( pooling_string[ 1 ] ) == 'N' ))
303 {
304 pooling_enabled = 1;
305 }
306 else
307 {
308 pooling_enabled = 0;
309 }
310
311 if ( !( environment = __alloc_env()))
312 {
313 *output_handle = SQL_NULL_HENV;
314 return SQL_ERROR;
315 }
316 *output_handle = (SQLHANDLE) environment;
317
318 /*
319 * setup environment state
320 */
321
322 environment -> state = STATE_E1;
323 environment -> requested_version = requested_version;
324 environment -> version_set = !!requested_version;
325 environment -> sql_driver_count = -1;
326
327 /*
328 * if SQLAllocEnv is called then it's probable that
329 * the application wants ODBC2.X type behaviour
330 *
331 * In this case we don't need to set the version via
332 * SQLSetEnvAttr()
333 *
334 */
335
336 environment -> connection_count = 0;
337
338 return SQL_SUCCESS;
339 }
340 break;
341
342 case SQL_HANDLE_DBC:
343 {
344 DMHENV environment = (DMHENV) input_handle;
345 DMHDBC connection;
346
347 if ( !__validate_env( environment ))
348 {
349 dm_log_write( __FILE__,
350 __LINE__,
351 LOG_INFO,
352 LOG_INFO,
353 "Error: SQL_INVALID_HANDLE" );
354
355 return SQL_INVALID_HANDLE;
356 }
357
358 if ( output_handle )
359 *output_handle = SQL_NULL_HDBC;
360
361 thread_protect( SQL_HANDLE_ENV, environment );
362
363 function_entry(( void * ) input_handle );
364
365 if ( log_info.log_flag )
366 {
367 /*
368 * log that we are here
369 */
370
371 sprintf( environment -> msg,
372 "\n\t\tEntry:\n\t\t\tHandle Type = %d\n\t\t\tInput Handle = %p",
373 handle_type,
374 (void*)input_handle );
375
376 dm_log_write( __FILE__,
377 __LINE__,
378 LOG_INFO,
379 LOG_INFO,
380 environment -> msg );
381 }
382
383 if ( !output_handle )
384 {
385 dm_log_write( __FILE__,
386 __LINE__,
387 LOG_INFO,
388 LOG_INFO,
389 "Error: HY009" );
390
391 __post_internal_error( &environment -> error,
392 ERROR_HY009, NULL,
393 SQL_OV_ODBC3 );
394
395 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
396 }
397
398 /*
399 * check that a version has been requested
400 */
401
402 if ( environment -> requested_version == 0 )
403 {
404 dm_log_write( __FILE__,
405 __LINE__,
406 LOG_INFO,
407 LOG_INFO,
408 "Error: HY010" );
409
410 __post_internal_error( &environment -> error,
411 ERROR_HY010, NULL,
412 SQL_OV_ODBC3 );
413
414 *output_handle = SQL_NULL_HDBC;
415
416 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
417 }
418
419 connection = __alloc_dbc();
420 if ( !connection )
421 {
422 dm_log_write( __FILE__,
423 __LINE__,
424 LOG_INFO,
425 LOG_INFO,
426 "Error: HY013" );
427
428 __post_internal_error( &environment -> error,
429 ERROR_HY013, NULL,
430 environment -> requested_version );
431
432 *output_handle = SQL_NULL_HDBC;
433
434 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
435 }
436
437 /*
438 * sort out the states
439 */
440
441 connection -> state = STATE_C2;
442 if ( environment -> state == STATE_E1 )
443 {
444 environment -> state = STATE_E2;
445 }
446 environment -> connection_count ++;
447 connection -> environment = environment;
448
449 connection -> cursors = SQL_CUR_DEFAULT;
450 connection -> login_timeout = SQL_LOGIN_TIMEOUT_DEFAULT;
451 connection -> login_timeout_set = 0;
452 connection -> auto_commit = SQL_AUTOCOMMIT_ON;
453 connection -> auto_commit_set = 0;
454 connection -> async_enable = 0;
455 connection -> async_enable_set = 0;
456 connection -> auto_ipd = 0;
457 connection -> auto_ipd_set = 0;
458 connection -> connection_timeout = 0;
459 connection -> connection_timeout_set = 0;
460 connection -> metadata_id = 0;
461 connection -> metadata_id_set = 0;
462 connection -> packet_size = 0;
463 connection -> packet_size_set = 0;
464 connection -> quite_mode = 0;
465 connection -> quite_mode_set = 0;
466 connection -> txn_isolation = 0;
467 connection -> txn_isolation_set = 0;
468 strcpy( connection -> cli_year, "1995" );
469
470 connection -> env_attribute.count = 0;
471 connection -> env_attribute.list = NULL;
472 connection -> dbc_attribute.count = 0;
473 connection -> dbc_attribute.list = NULL;
474 connection -> stmt_attribute.count = 0;
475 connection -> stmt_attribute.list = NULL;
476 connection -> save_attr = NULL;
477
478#ifdef HAVE_ICONV
479 connection -> iconv_cd_uc_to_ascii = (iconv_t)-1;
480 connection -> iconv_cd_ascii_to_uc = (iconv_t)-1;
481 strcpy( connection -> unicode_string, DEFAULT_ICONV_ENCODING );
482#endif
483
484 *output_handle = (SQLHANDLE) connection;
485
486 if ( log_info.log_flag )
487 {
488 sprintf( environment -> msg,
489 "\n\t\tExit:[SQL_SUCCESS]\n\t\t\tOutput Handle = %p",
490 connection );
491
492 dm_log_write( __FILE__,
493 __LINE__,
494 LOG_INFO,
495 LOG_INFO,
496 environment -> msg );
497 }
498#if defined ( COLLECT_STATS ) && defined( HAVE_SYS_SEM_H )
499 uodbc_update_stats(environment->sh, UODBC_STATS_TYPE_HDBC,
500 (void *)1);
501#endif
502
503 thread_release( SQL_HANDLE_ENV, environment );
504 return SQL_SUCCESS;
505 }
506 break;
507
508 case SQL_HANDLE_STMT:
509 {
510 SQLRETURN ret, ret1;
511 DMHDBC connection = (DMHDBC) input_handle;
512 DMHSTMT statement;
513
514 if ( !__validate_dbc( connection ))
515 {
516 dm_log_write( __FILE__,
517 __LINE__,
518 LOG_INFO,
519 LOG_INFO,
520 "Error: SQL_INVALID_HANDLE" );
521
522 return SQL_INVALID_HANDLE;
523 }
524
525 if ( output_handle )
526 *output_handle = SQL_NULL_HSTMT;
527
528 thread_protect( SQL_HANDLE_DBC, connection );
529
530 function_entry(( void * ) input_handle );
531
532 if ( log_info.log_flag )
533 {
534 sprintf( connection -> msg,
535 "\n\t\tEntry:\n\t\t\tHandle Type = %d\n\t\t\tInput Handle = %p",
536 handle_type,
537 (void*)input_handle );
538
539 dm_log_write( __FILE__,
540 __LINE__,
541 LOG_INFO,
542 LOG_INFO,
543 connection -> msg );
544 }
545
546 if ( !output_handle )
547 {
548 dm_log_write( __FILE__,
549 __LINE__,
550 LOG_INFO,
551 LOG_INFO,
552 "Error: HY009" );
553
554 __post_internal_error( &connection -> error,
555 ERROR_HY009, NULL,
556 connection -> environment -> requested_version );
557
558 return function_return_nodrv( SQL_HANDLE_DBC, connection , SQL_ERROR );
559 }
560
561 if ( connection -> state == STATE_C1 ||
562 connection -> state == STATE_C2 ||
563 connection -> state == STATE_C3 )
564 {
565 dm_log_write( __FILE__,
566 __LINE__,
567 LOG_INFO,
568 LOG_INFO,
569 "Error: 08003" );
570
571 __post_internal_error( &connection -> error,
572 ERROR_08003, NULL,
573 connection -> environment -> requested_version );
574
575 *output_handle = SQL_NULL_HSTMT;
576
577 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
578 }
579
580 statement = __alloc_stmt();
581 if ( !statement )
582 {
583 dm_log_write( __FILE__,
584 __LINE__,
585 LOG_INFO,
586 LOG_INFO,
587 "Error: HY013" );
588
589 __post_internal_error( &connection -> error,
590 ERROR_HY013, NULL,
591 connection -> environment -> requested_version );
592
593 *output_handle = SQL_NULL_HSTMT;
594
595 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
596 }
597
598 /*
599 * pass the call on
600 */
601
602 if ( requested_version >= SQL_OV_ODBC3 )
603 {
604 if ( CHECK_SQLALLOCHANDLE( connection ))
605 {
606 ret = SQLALLOCHANDLE( connection,
607 SQL_HANDLE_STMT,
608 connection -> driver_dbc,
609 &statement -> driver_stmt,
610 statement );
611
612 if ( !SQL_SUCCEEDED( ret ))
613 __release_stmt( statement );
614 }
615 else if ( CHECK_SQLALLOCSTMT( connection ))
616 {
617 ret = SQLALLOCSTMT( connection,
618 connection -> driver_dbc,
619 &statement -> driver_stmt,
620 statement );
621
622 if ( !SQL_SUCCEEDED( ret ))
623 __release_stmt( statement );
624 }
625 else
626 {
627 dm_log_write( __FILE__,
628 __LINE__,
629 LOG_INFO,
630 LOG_INFO,
631 "Error: IM003" );
632
633 __post_internal_error( &connection -> error,
634 ERROR_IM003, NULL,
635 connection -> environment -> requested_version );
636
637 __release_stmt( statement );
638
639 *output_handle = SQL_NULL_HSTMT;
640
641 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
642 }
643 }
644 else
645 {
646 if ( CHECK_SQLALLOCSTMT( connection ))
647 {
648 ret = SQLALLOCSTMT( connection,
649 connection -> driver_dbc,
650 &statement -> driver_stmt,
651 statement );
652
653 if ( !SQL_SUCCEEDED( ret ))
654 __release_stmt( statement );
655 }
656 else if ( CHECK_SQLALLOCHANDLE( connection ))
657 {
658 ret = SQLALLOCHANDLE( connection,
659 SQL_HANDLE_STMT,
660 connection -> driver_dbc,
661 &statement -> driver_stmt,
662 statement );
663
664 if ( !SQL_SUCCEEDED( ret ))
665 __release_stmt( statement );
666 }
667 else
668 {
669 dm_log_write( __FILE__,
670 __LINE__,
671 LOG_INFO,
672 LOG_INFO,
673 "Error: IM003" );
674
675 __post_internal_error( &connection -> error,
676 ERROR_IM003, NULL,
677 connection -> environment -> requested_version );
678
679 __release_stmt( statement );
680
681 *output_handle = SQL_NULL_HSTMT;
682
683 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
684 }
685 }
686
687 if ( SQL_SUCCEEDED( ret ))
688 {
689 /*
690 * sort out the states
691 */
692
693 statement -> state = STATE_S1;
694 if ( connection -> state == STATE_C4 )
695 connection -> state = STATE_C5;
696
697 __register_stmt ( connection, statement );
698
699 *output_handle = (SQLHANDLE) statement;
700
701 statement -> metadata_id = SQL_FALSE;
702
703 /*
704 * if we are connected to a 3 driver then
705 * we need to get the 4 implicit descriptors
706 * so we know that they are valid
707 */
708
709 if ( connection -> driver_act_ver == 3 &&
710 CHECK_SQLGETSTMTATTR( connection ))
711 {
712 DRV_SQLHDESC desc;
713
714 /*
715 * ARD
716 */
717
718 ret1 = SQLGETSTMTATTR( connection,
719 statement -> driver_stmt,
720 SQL_ATTR_APP_ROW_DESC,
721 &desc,
722 sizeof( desc ),
723 NULL );
724
725 if ( SQL_SUCCEEDED( ret1 ))
726 {
727 /*
728 * allocate one of our descriptors
729 * to wrap around this
730 */
731 statement -> ard = __alloc_desc();
732 if ( !statement -> ard )
733 {
734 dm_log_write( __FILE__,
735 __LINE__,
736 LOG_INFO,
737 LOG_INFO,
738 "Error: HY013" );
739
740 __post_internal_error( &connection -> error,
741 ERROR_HY013, NULL,
742 connection -> environment -> requested_version );
743
744 __release_stmt( statement );
745
746 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
747 }
748 statement -> implicit_ard = statement -> ard;
749 statement -> ard -> implicit = 1;
750 statement -> ard -> associated_with = statement;
751 statement -> ard -> state = STATE_D1i;
752 statement -> ard -> driver_desc = desc;
753 statement -> ard -> connection = connection;
754 }
755
756 /*
757 * APD
758 */
759
760 ret1 = SQLGETSTMTATTR( connection,
761 statement -> driver_stmt,
762 SQL_ATTR_APP_PARAM_DESC,
763 &desc,
764 sizeof( desc ),
765 NULL );
766
767 if ( SQL_SUCCEEDED( ret1 ))
768 {
769 /*
770 * allocate one of our descriptors
771 * to wrap around this
772 */
773 statement -> apd = __alloc_desc();
774 if ( !statement -> apd )
775 {
776 dm_log_write( __FILE__,
777 __LINE__,
778 LOG_INFO,
779 LOG_INFO,
780 "Error: HY013" );
781
782 __post_internal_error( &connection -> error,
783 ERROR_HY013, NULL,
784 connection -> environment -> requested_version );
785
786 __release_stmt( statement );
787
788 *output_handle = SQL_NULL_HSTMT;
789
790 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
791 }
792 statement -> implicit_apd = statement -> apd;
793 statement -> apd -> implicit = 1;
794 statement -> apd -> associated_with = statement;
795 statement -> apd -> state = STATE_D1i;
796 statement -> apd -> driver_desc = desc;
797 statement -> apd -> connection = connection;
798 }
799
800 /*
801 * IRD
802 */
803
804 ret1 = SQLGETSTMTATTR( connection,
805 statement -> driver_stmt,
806 SQL_ATTR_IMP_ROW_DESC,
807 &desc,
808 sizeof( desc ),
809 NULL );
810
811 if ( SQL_SUCCEEDED( ret1 ))
812 {
813 /*
814 * allocate one of our descriptors
815 * to wrap around this
816 */
817 statement -> ird = __alloc_desc();
818 if ( !statement -> ird )
819 {
820 dm_log_write( __FILE__,
821 __LINE__,
822 LOG_INFO,
823 LOG_INFO,
824 "Error: HY013" );
825
826 __post_internal_error( &connection -> error,
827 ERROR_HY013, NULL,
828 connection -> environment -> requested_version );
829
830 __release_stmt( statement );
831
832 *output_handle = SQL_NULL_HSTMT;
833
834 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
835 }
836 statement -> implicit_ird = statement -> ird;
837 statement -> ird -> implicit = 1;
838 statement -> ird -> associated_with = statement;
839 statement -> ird -> state = STATE_D1i;
840 statement -> ird -> driver_desc = desc;
841 statement -> ird -> connection = connection;
842 }
843
844 /*
845 * IPD
846 */
847
848 ret1 = SQLGETSTMTATTR( connection,
849 statement -> driver_stmt,
850 SQL_ATTR_IMP_PARAM_DESC,
851 &desc,
852 sizeof( desc ),
853 NULL );
854
855 if ( SQL_SUCCEEDED( ret1 ))
856 {
857 /*
858 * allocate one of our descriptors
859 * to wrap around this
860 */
861 statement -> ipd = __alloc_desc();
862 if ( !statement -> ipd )
863 {
864 dm_log_write( __FILE__,
865 __LINE__,
866 LOG_INFO,
867 LOG_INFO,
868 "Error: HY013" );
869
870 __post_internal_error( &connection -> error,
871 ERROR_HY013, NULL,
872 connection -> environment -> requested_version );
873
874 __release_stmt( statement );
875
876 *output_handle = SQL_NULL_HSTMT;
877
878 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
879 }
880 statement -> implicit_ipd = statement -> ipd;
881 statement -> ipd -> implicit = 1;
882 statement -> ipd -> associated_with = statement;
883 statement -> ipd -> state = STATE_D1i;
884 statement -> ipd -> driver_desc = desc;
885 statement -> ipd -> connection = connection;
886 }
887 }
888 /* Driver may only have unicode API's */
889 else if ( CHECK_SQLGETSTMTATTRW( connection ))
890 {
891 DRV_SQLHDESC desc;
892
893 /*
894 * ARD
895 */
896
897 ret1 = SQLGETSTMTATTRW( connection,
898 statement -> driver_stmt,
899 SQL_ATTR_APP_ROW_DESC,
900 &desc,
901 sizeof( desc ),
902 NULL );
903
904 if ( SQL_SUCCEEDED( ret1 ))
905 {
906 /*
907 * allocate one of our descriptors
908 * to wrap around this
909 */
910 statement -> ard = __alloc_desc();
911 if ( !statement -> ard )
912 {
913 dm_log_write( __FILE__,
914 __LINE__,
915 LOG_INFO,
916 LOG_INFO,
917 "Error: HY013" );
918
919 __post_internal_error( &connection -> error,
920 ERROR_HY013, NULL,
921 connection -> environment -> requested_version );
922
923 __release_stmt( statement );
924
925 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
926 }
927 statement -> implicit_ard = statement -> ard;
928 statement -> ard -> implicit = 1;
929 statement -> ard -> associated_with = statement;
930 statement -> ard -> state = STATE_D1i;
931 statement -> ard -> driver_desc = desc;
932 statement -> ard -> connection = connection;
933 }
934
935 /*
936 * APD
937 */
938
939 ret1 = SQLGETSTMTATTRW( connection,
940 statement -> driver_stmt,
941 SQL_ATTR_APP_PARAM_DESC,
942 &desc,
943 sizeof( desc ),
944 NULL );
945
946 if ( SQL_SUCCEEDED( ret1 ))
947 {
948 /*
949 * allocate one of our descriptors
950 * to wrap around this
951 */
952 statement -> apd = __alloc_desc();
953 if ( !statement -> apd )
954 {
955 dm_log_write( __FILE__,
956 __LINE__,
957 LOG_INFO,
958 LOG_INFO,
959 "Error: HY013" );
960
961 __post_internal_error( &connection -> error,
962 ERROR_HY013, NULL,
963 connection -> environment -> requested_version );
964
965 __release_stmt( statement );
966
967 *output_handle = SQL_NULL_HSTMT;
968
969 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
970 }
971 statement -> implicit_apd = statement -> apd;
972 statement -> apd -> implicit = 1;
973 statement -> apd -> associated_with = statement;
974 statement -> apd -> state = STATE_D1i;
975 statement -> apd -> driver_desc = desc;
976 statement -> apd -> connection = connection;
977 }
978
979 /*
980 * IRD
981 */
982
983 ret1 = SQLGETSTMTATTRW( connection,
984 statement -> driver_stmt,
985 SQL_ATTR_IMP_ROW_DESC,
986 &desc,
987 sizeof( desc ),
988 NULL );
989
990 if ( SQL_SUCCEEDED( ret1 ))
991 {
992 /*
993 * allocate one of our descriptors
994 * to wrap around this
995 */
996 statement -> ird = __alloc_desc();
997 if ( !statement -> ird )
998 {
999 dm_log_write( __FILE__,
1000 __LINE__,
1001 LOG_INFO,
1002 LOG_INFO,
1003 "Error: HY013" );
1004
1005 __post_internal_error( &connection -> error,
1006 ERROR_HY013, NULL,
1007 connection -> environment -> requested_version );
1008
1009 __release_stmt( statement );
1010
1011 *output_handle = SQL_NULL_HSTMT;
1012
1013 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1014 }
1015 statement -> implicit_ird = statement -> ird;
1016 statement -> ird -> implicit = 1;
1017 statement -> ird -> associated_with = statement;
1018 statement -> ird -> state = STATE_D1i;
1019 statement -> ird -> driver_desc = desc;
1020 statement -> ird -> connection = connection;
1021 }
1022
1023 /*
1024 * IPD
1025 */
1026
1027 ret1 = SQLGETSTMTATTRW( connection,
1028 statement -> driver_stmt,
1029 SQL_ATTR_IMP_PARAM_DESC,
1030 &desc,
1031 sizeof( desc ),
1032 NULL );
1033
1034 if ( SQL_SUCCEEDED( ret1 ))
1035 {
1036 /*
1037 * allocate one of our descriptors
1038 * to wrap around this
1039 */
1040 statement -> ipd = __alloc_desc();
1041 if ( !statement -> ipd )
1042 {
1043 dm_log_write( __FILE__,
1044 __LINE__,
1045 LOG_INFO,
1046 LOG_INFO,
1047 "Error: HY013" );
1048
1049 __post_internal_error( &connection -> error,
1050 ERROR_HY013, NULL,
1051 connection -> environment -> requested_version );
1052
1053 __release_stmt( statement );
1054
1055 *output_handle = SQL_NULL_HSTMT;
1056
1057 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1058 }
1059 statement -> implicit_ipd = statement -> ipd;
1060 statement -> ipd -> implicit = 1;
1061 statement -> ipd -> associated_with = statement;
1062 statement -> ipd -> state = STATE_D1i;
1063 statement -> ipd -> driver_desc = desc;
1064 statement -> ipd -> connection = connection;
1065 }
1066 }
1067 }
1068
1069 /*
1070 * set any preset statement attributes
1071 */
1072
1073 if ( SQL_SUCCEEDED( ret ))
1074 {
1075 __set_attributes( statement, SQL_HANDLE_STMT );
1076 }
1077
1078 if ( log_info.log_flag )
1079 {
1080 sprintf( connection -> msg,
1081 "\n\t\tExit:[SQL_SUCCESS]\n\t\t\tOutput Handle = %p",
1082 statement );
1083
1084 dm_log_write( __FILE__,
1085 __LINE__,
1086 LOG_INFO,
1087 LOG_INFO,
1088 connection -> msg );
1089 }
1090#if defined ( COLLECT_STATS ) && defined( HAVE_SYS_SEM_H )
1091 uodbc_update_stats(connection->environment->sh,
1092 UODBC_STATS_TYPE_HSTMT, (void *)1);
1093#endif
1094
1095 return function_return( SQL_HANDLE_DBC, connection, ret );
1096 }
1097 break;
1098
1099 case SQL_HANDLE_DESC:
1100 {
1101 SQLRETURN ret;
1102 DMHDBC connection = (DMHDBC) input_handle;
1103 DMHDESC descriptor;
1104
1105 if ( !__validate_dbc( connection ))
1106 {
1107 dm_log_write( __FILE__,
1108 __LINE__,
1109 LOG_INFO,
1110 LOG_INFO,
1111 "Error: SQL_INVALID_HANDLE" );
1112
1113 return SQL_INVALID_HANDLE;
1114 }
1115
1116 if ( output_handle )
1117 *output_handle = SQL_NULL_HDESC;
1118
1119 thread_protect( SQL_HANDLE_DBC, connection );
1120
1121 function_entry(( void * ) input_handle );
1122
1123 if ( log_info.log_flag )
1124 {
1125 sprintf( connection -> msg,
1126 "\n\t\tEntry:\n\t\t\tHandle Type = %d\n\t\t\tInput Handle = %p",
1127 handle_type,
1128 (void*)input_handle );
1129
1130 dm_log_write( __FILE__,
1131 __LINE__,
1132 LOG_INFO,
1133 LOG_INFO,
1134 connection -> msg );
1135 }
1136
1137 if ( !output_handle )
1138 {
1139 dm_log_write( __FILE__,
1140 __LINE__,
1141 LOG_INFO,
1142 LOG_INFO,
1143 "Error: HY009" );
1144
1145 __post_internal_error( &connection -> error,
1146 ERROR_HY009, NULL,
1147 connection -> environment -> requested_version );
1148
1149 return function_return_nodrv( SQL_HANDLE_DBC, connection , SQL_ERROR );
1150 }
1151
1152 if ( connection -> state == STATE_C1 ||
1153 connection -> state == STATE_C2 ||
1154 connection -> state == STATE_C3 )
1155 {
1156 dm_log_write( __FILE__,
1157 __LINE__,
1158 LOG_INFO,
1159 LOG_INFO,
1160 "Error: 08003" );
1161
1162 __post_internal_error( &connection -> error,
1163 ERROR_08003, NULL,
1164 connection -> environment -> requested_version );
1165
1166 *output_handle = SQL_NULL_HDESC;
1167
1168 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
1169 }
1170
1171 descriptor = __alloc_desc();
1172 if ( !descriptor )
1173 {
1174 dm_log_write( __FILE__,
1175 __LINE__,
1176 LOG_INFO,
1177 LOG_INFO,
1178 "Error: HY013" );
1179
1180 __post_internal_error( &connection -> error,
1181 ERROR_HY013, NULL,
1182 connection -> environment -> requested_version );
1183
1184 *output_handle = SQL_NULL_HDESC;
1185
1186 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
1187 }
1188
1189 /*
1190 * pass the call on
1191 */
1192
1193 if ( CHECK_SQLALLOCHANDLE( connection ))
1194 {
1195 ret = SQLALLOCHANDLE( connection,
1196 SQL_HANDLE_DESC,
1197 connection -> driver_dbc,
1198 &descriptor -> driver_desc,
1199 NULL );
1200
1201 if ( !SQL_SUCCEEDED( ret ))
1202 __release_desc( descriptor );
1203 }
1204 else
1205 {
1206 dm_log_write( __FILE__,
1207 __LINE__,
1208 LOG_INFO,
1209 LOG_INFO,
1210 "Error: IM003" );
1211
1212 __post_internal_error( &connection -> error,
1213 ERROR_IM003, NULL,
1214 connection -> environment -> requested_version );
1215
1216 __release_desc( descriptor );
1217
1218 *output_handle = SQL_NULL_HDESC;
1219
1220 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
1221 }
1222
1223 if ( SQL_SUCCEEDED( ret ))
1224 {
1225 /*
1226 * sort out the states
1227 */
1228
1229 descriptor -> state = STATE_D1e;
1230 descriptor -> implicit = 0;
1231 descriptor -> associated_with = NULL;
1232
1233 connection -> statement_count ++;
1234
1235 descriptor -> connection = connection;
1236
1237 *output_handle = (SQLHANDLE) descriptor;
1238 }
1239
1240 if ( log_info.log_flag )
1241 {
1242 sprintf( connection -> msg,
1243 "\n\t\tExit:[SQL_SUCCESS]\n\t\t\tOutput Handle = %p",
1244 descriptor );
1245
1246 dm_log_write( __FILE__,
1247 __LINE__,
1248 LOG_INFO,
1249 LOG_INFO,
1250 connection -> msg );
1251 }
1252#if defined ( COLLECT_STATS ) && defined( HAVE_SYS_SEM_H )
1253 uodbc_update_stats(connection->environment->sh, UODBC_STATS_TYPE_HDESC,
1254 (void *)1);
1255#endif
1256
1257 return function_return( SQL_HANDLE_DBC, connection, ret );
1258 }
1259 break;
1260
1261 default:
1262 if ( __validate_env( (DMHENV) input_handle ))
1263 {
1264 DMHENV environment = (DMHENV) input_handle;
1265
1266 thread_protect( SQL_HANDLE_ENV, environment );
1267
1268 __post_internal_error( &environment -> error,
1269 ERROR_HY092, NULL,
1270 environment -> requested_version );
1271
1272 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
1273 }
1274 else if ( __validate_dbc( (DMHDBC) input_handle ))
1275 {
1276 DMHDBC connection = (DMHDBC) input_handle;
1277
1278 thread_protect( SQL_HANDLE_DBC, connection );
1279
1280 __post_internal_error( &connection -> error,
1281 ERROR_HY092, NULL,
1282 connection -> environment -> requested_version );
1283
1284 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
1285 }
1286 else
1287 {
1288 return SQL_INVALID_HANDLE;
1289 }
1290 break;
1291 }
1292}
1293
1294SQLRETURN SQLAllocHandle( SQLSMALLINT handle_type,
1295 SQLHANDLE input_handle,
1296 SQLHANDLE *output_handle )
1297{
1298 /*
1299 * setting a requested version to 0
1300 * indicates that we are ODBC3 and the application must
1301 * select ODBC2 or 3 explicitly
1302 */
1303
1304 return __SQLAllocHandle( handle_type,
1305 input_handle,
1306 output_handle,
1307 0 );
1308}
1309