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 | |
255 | static char const rcsid[]= "$RCSfile: SQLAllocHandle.c,v $ $Revision: 1.13 $" ; |
256 | |
257 | /* |
258 | * connection pooling stuff |
259 | */ |
260 | |
261 | extern 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 | |
268 | SQLRETURN __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 | |
1294 | SQLRETURN 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 | |