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: __handles.c,v 1.13 2009/05/15 15:23:56 lurcher Exp $ |
31 | * |
32 | * $Log: __handles.c,v $ |
33 | * Revision 1.13 2009/05/15 15:23:56 lurcher |
34 | * Fix pooled connection thread problems |
35 | * |
36 | * Revision 1.12 2009/02/18 17:59:08 lurcher |
37 | * Shift to using config.h, the compile lines were making it hard to spot warnings |
38 | * |
39 | * Revision 1.11 2009/02/17 09:47:44 lurcher |
40 | * Clear up a number of bugs |
41 | * |
42 | * Revision 1.10 2007/02/28 15:37:49 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.9 2006/05/31 17:35:34 lurcher |
46 | * Add unicode ODBCINST entry points |
47 | * |
48 | * Revision 1.8 2004/09/28 08:44:46 lurcher |
49 | * Fix memory leak in pthread descriptor code |
50 | * |
51 | * Revision 1.7 2004/07/24 17:55:37 lurcher |
52 | * Sync up CVS |
53 | * |
54 | * Revision 1.6 2003/06/04 12:49:45 lurcher |
55 | * |
56 | * Further PID logging tweeks |
57 | * |
58 | * Revision 1.5 2003/06/02 16:51:36 lurcher |
59 | * |
60 | * Add TracePid option |
61 | * |
62 | * Revision 1.4 2002/08/12 16:20:44 lurcher |
63 | * |
64 | * Make it try and find a working iconv set of encodings |
65 | * |
66 | * Revision 1.3 2002/08/12 13:17:52 lurcher |
67 | * |
68 | * Replicate the way the MS DM handles loading of driver libs, and allocating |
69 | * handles in the driver. usage counting in the driver means that dlopen is |
70 | * only called for the first use, and dlclose for the last. AllocHandle for |
71 | * the driver environment is only called for the first time per driver |
72 | * per application environment. |
73 | * |
74 | * Revision 1.2 2002/02/22 10:23:22 lurcher |
75 | * |
76 | * s/Trace File/TraceFile |
77 | * |
78 | * Revision 1.1.1.1 2001/10/17 16:40:07 lurcher |
79 | * |
80 | * First upload to SourceForge |
81 | * |
82 | * Revision 1.14 2001/06/25 12:55:15 nick |
83 | * |
84 | * Fix threading problem with multiple ENV's |
85 | * |
86 | * Revision 1.13 2001/06/04 15:24:49 nick |
87 | * |
88 | * Add port to MAC OSX and QT3 changes |
89 | * |
90 | * Revision 1.12 2001/05/15 13:33:44 jason |
91 | * |
92 | * Wrapped calls to stats with COLLECT_STATS |
93 | * |
94 | * Revision 1.11 2001/04/12 17:43:36 nick |
95 | * |
96 | * Change logging and added autotest to odbctest |
97 | * |
98 | * Revision 1.10 2001/03/02 14:24:23 nick |
99 | * |
100 | * Fix thread detection for Solaris |
101 | * |
102 | * Revision 1.9 2001/01/04 13:16:25 nick |
103 | * |
104 | * Add support for GNU portable threads and tidy up some UNICODE compile |
105 | * warnings |
106 | * |
107 | * Revision 1.8 2000/12/18 11:51:59 martin |
108 | * |
109 | * stats specific mode to uodbc_open_stats. |
110 | * |
111 | * Revision 1.7 2000/12/18 11:03:58 martin |
112 | * |
113 | * Add support for the collection and retrieval of handle statistics. |
114 | * |
115 | * Revision 1.6 2000/12/17 11:17:22 nick |
116 | * |
117 | * Remove typo |
118 | * |
119 | * Revision 1.5 2000/12/17 11:00:32 nick |
120 | * |
121 | * Add thread safe bits to pooling |
122 | * |
123 | * Revision 1.4 2000/11/29 17:53:59 nick |
124 | * |
125 | * Fix race condition |
126 | * |
127 | * Revision 1.3 2000/10/25 09:39:42 nick |
128 | * |
129 | * Clear handles out, to avoid reuse |
130 | * |
131 | * Revision 1.2 2000/09/08 08:58:17 nick |
132 | * |
133 | * Add SQL_DRIVER_HDESC to SQLGetinfo |
134 | * |
135 | * Revision 1.1.1.1 2000/09/04 16:42:52 nick |
136 | * Imported Sources |
137 | * |
138 | * Revision 1.16 2000/06/29 17:27:52 ngorham |
139 | * |
140 | * Add fast validate option |
141 | * |
142 | * Revision 1.15 2000/06/27 17:34:12 ngorham |
143 | * |
144 | * Fix a problem when the second part of the connect failed a seg fault |
145 | * was generated in the error reporting |
146 | * |
147 | * Revision 1.14 2001/03/28 23:09:57 ngorham |
148 | * |
149 | * Fix logging |
150 | * |
151 | * Revision 1.13 2000/03/11 15:55:47 ngorham |
152 | * |
153 | * A few more changes and bug fixes (see NEWS) |
154 | * |
155 | * Revision 1.12 2000/02/25 00:02:00 ngorham |
156 | * |
157 | * Add a patch to support IBM DB2, and Solaris threads |
158 | * |
159 | * Revision 1.11 2000/02/22 22:14:45 ngorham |
160 | * |
161 | * Added support for solaris threads |
162 | * Added check to overcome bug in PHP4 |
163 | * Fixed bug in descriptors and ODBC 3 drivers |
164 | * |
165 | * Revision 1.10 1999/12/11 13:01:57 ngorham |
166 | * |
167 | * Add some fixes to the Postgres driver for long types |
168 | * |
169 | * Revision 1.9 1999/12/01 09:20:07 ngorham |
170 | * |
171 | * Fix some threading problems |
172 | * |
173 | * Revision 1.8 1999/11/13 23:41:01 ngorham |
174 | * |
175 | * Alter the way DM logging works |
176 | * Upgrade the Postgres driver to 6.4.6 |
177 | * |
178 | * Revision 1.7 1999/11/10 03:51:34 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.6 1999/08/05 18:59:49 ngorham |
184 | * |
185 | * Typo error found by Greg Bentz |
186 | * |
187 | * Revision 1.5 1999/08/03 21:47:39 shandyb |
188 | * Moving to automake: changed files in DriverManager |
189 | * |
190 | * Revision 1.4 1999/07/10 21:10:17 ngorham |
191 | * |
192 | * Adjust error sqlstate from driver manager, depending on requested |
193 | * version (ODBC2/3) |
194 | * |
195 | * Revision 1.3 1999/07/04 21:05:08 ngorham |
196 | * |
197 | * Add LGPL Headers to code |
198 | * |
199 | * Revision 1.2 1999/06/30 23:56:56 ngorham |
200 | * |
201 | * Add initial thread safety code |
202 | * |
203 | * Revision 1.1.1.1 1999/05/29 13:41:09 sShandyb |
204 | * first go at it |
205 | * |
206 | * Revision 1.1.1.1 1999/05/27 18:23:18 pharvey |
207 | * Imported sources |
208 | * |
209 | * Revision 1.3 1999/05/09 23:27:11 nick |
210 | * All the API done now |
211 | * |
212 | * Revision 1.2 1999/05/03 19:50:43 nick |
213 | * Another check point |
214 | * |
215 | * Revision 1.1 1999/04/25 23:06:11 nick |
216 | * Initial revision |
217 | * |
218 | * |
219 | **********************************************************************/ |
220 | |
221 | #include <config.h> |
222 | #include <ctype.h> |
223 | #include "drivermanager.h" |
224 | #if defined ( COLLECT_STATS ) && defined( HAVE_SYS_SEM_H ) |
225 | #include "__stats.h" |
226 | #include <uodbc_stats.h> |
227 | #endif |
228 | |
229 | static char const rcsid[]= "$RCSfile: __handles.c,v $ $Revision: 1.13 $" ; |
230 | |
231 | /* |
232 | * these are used to enable us to check if a handle is |
233 | * valid without the danger of a seg-vio. |
234 | */ |
235 | |
236 | static DMHENV environment_root; |
237 | static DMHDBC connection_root; |
238 | static DMHSTMT statement_root; |
239 | static DMHDESC descriptor_root; |
240 | |
241 | |
242 | /* |
243 | * use just one mutex for all the lists, this avoids any issues |
244 | * with deadlocks, the performance issue should be minimal, if it |
245 | * turns out to be a problem, we can readdress this |
246 | * |
247 | * We also have a mutex to protect the connection pooling code |
248 | * |
249 | * If compiled with thread support the DM allows four different |
250 | * thread strategies: |
251 | * |
252 | * Level 0 - Only the DM internal structures are protected. |
253 | * The driver is assumed to take care of itself |
254 | * |
255 | * Level 1 - The driver is protected down to the statement level. |
256 | * Each statement will be protected, and the same for the connect |
257 | * level for connect functions. Note that descriptors are considered |
258 | * equal to statements when it comes to thread protection. |
259 | * |
260 | * Level 2 - The driver is protected at the connection level. Only |
261 | * one thread can be in a particular driver at one time. |
262 | * |
263 | * Level 3 - The driver is protected at the env level, only one thing |
264 | * at a time. |
265 | * |
266 | * By default the driver opens connections with lock level 0; drivers |
267 | * are expected to be thread safe now. This can be changed by adding |
268 | * the line |
269 | * |
270 | * Threading = N |
271 | * |
272 | * to the driver entry in odbcinst.ini, where N is the locking level |
273 | * (0-3) |
274 | * |
275 | */ |
276 | |
277 | #ifdef HAVE_LIBPTH |
278 | |
279 | #include <pth.h> |
280 | |
281 | static pth_mutex_t mutex_lists = PTH_MUTEX_INIT; |
282 | static pth_mutex_t mutex_env = PTH_MUTEX_INIT; |
283 | static pth_mutex_t mutex_pool = PTH_MUTEX_INIT; |
284 | static pth_mutex_t mutex_iconv = PTH_MUTEX_INIT; |
285 | static int pth_init_called = 0; |
286 | |
287 | static int local_mutex_entry( pth_mutex_t *mutex ) |
288 | { |
289 | if ( !pth_init_called ) |
290 | { |
291 | pth_init(); |
292 | pth_init_called = 1; |
293 | } |
294 | return pth_mutex_acquire( mutex, 0, NULL ); |
295 | } |
296 | |
297 | static int local_mutex_exit( pth_mutex_t *mutex ) |
298 | { |
299 | return pth_mutex_release( mutex ); |
300 | } |
301 | |
302 | #elif HAVE_LIBPTHREAD |
303 | |
304 | #include <pthread.h> |
305 | |
306 | static pthread_mutex_t mutex_lists = PTHREAD_MUTEX_INITIALIZER; |
307 | static pthread_mutex_t mutex_env = PTHREAD_MUTEX_INITIALIZER; |
308 | static pthread_mutex_t mutex_pool = PTHREAD_MUTEX_INITIALIZER; |
309 | static pthread_mutex_t mutex_iconv = PTHREAD_MUTEX_INITIALIZER; |
310 | |
311 | static int local_mutex_entry( pthread_mutex_t *mutex ) |
312 | { |
313 | return pthread_mutex_lock( mutex ); |
314 | } |
315 | |
316 | static int local_mutex_exit( pthread_mutex_t *mutex ) |
317 | { |
318 | return pthread_mutex_unlock( mutex ); |
319 | } |
320 | |
321 | #elif HAVE_LIBTHREAD |
322 | |
323 | #include <thread.h> |
324 | |
325 | static mutex_t mutex_lists; |
326 | static mutex_t mutex_env; |
327 | static mutex_t mutex_pool; |
328 | static mutex_t mutex_iconv; |
329 | |
330 | static int local_mutex_entry( mutex_t *mutex ) |
331 | { |
332 | return mutex_lock( mutex ); |
333 | } |
334 | |
335 | static int local_mutex_exit( mutex_t *mutex ) |
336 | { |
337 | return mutex_unlock( mutex ); |
338 | } |
339 | |
340 | #else |
341 | |
342 | #define local_mutex_entry(x) |
343 | #define local_mutex_exit(x) |
344 | |
345 | #endif |
346 | |
347 | /* |
348 | * protection for connection pooling |
349 | */ |
350 | |
351 | void mutex_pool_entry( void ) |
352 | { |
353 | local_mutex_entry( &mutex_pool ); |
354 | } |
355 | |
356 | void mutex_pool_exit( void ) |
357 | { |
358 | local_mutex_exit( &mutex_pool ); |
359 | } |
360 | |
361 | /* |
362 | * protection for iconv |
363 | */ |
364 | |
365 | void mutex_iconv_entry( void ) |
366 | { |
367 | local_mutex_entry( &mutex_iconv ); |
368 | } |
369 | |
370 | void mutex_iconv_exit( void ) |
371 | { |
372 | local_mutex_exit( &mutex_iconv ); |
373 | } |
374 | |
375 | /* |
376 | * protection for lib loading and counting, reuse the lists mutex as this |
377 | * is the lowest level protection the DM uses |
378 | */ |
379 | |
380 | void mutex_lib_entry( void ) |
381 | { |
382 | local_mutex_entry( &mutex_lists ); |
383 | } |
384 | |
385 | void mutex_lib_exit( void ) |
386 | { |
387 | local_mutex_exit( &mutex_lists ); |
388 | } |
389 | |
390 | /* |
391 | * allocate and register a environment handle |
392 | */ |
393 | |
394 | DMHENV __alloc_env( void ) |
395 | { |
396 | DMHENV environment = NULL; |
397 | |
398 | local_mutex_entry( &mutex_lists ); |
399 | |
400 | environment = calloc( sizeof( *environment ), 1 ); |
401 | |
402 | if ( environment ) |
403 | { |
404 | char tracing_string[ 64 ]; |
405 | char tracing_file[ 64 ]; |
406 | |
407 | #if defined ( COLLECT_STATS ) && defined( HAVE_SYS_SEM_H ) |
408 | if (uodbc_open_stats(&environment->sh, UODBC_STATS_WRITE) != 0) |
409 | { |
410 | ; |
411 | } |
412 | uodbc_update_stats(environment->sh, UODBC_STATS_TYPE_HENV, (void *)1); |
413 | #endif |
414 | |
415 | /* |
416 | * add to list of env handles |
417 | */ |
418 | |
419 | environment -> next_class_list = environment_root; |
420 | environment_root = environment; |
421 | environment -> type = HENV_MAGIC; |
422 | |
423 | SQLGetPrivateProfileString( "ODBC" , "Trace" , "No" , |
424 | tracing_string, sizeof( tracing_string ), |
425 | "odbcinst.ini" ); |
426 | |
427 | if ( tracing_string[ 0 ] == '1' || |
428 | toupper( tracing_string[ 0 ] ) == 'Y' || |
429 | ( toupper( tracing_string[ 0 ] ) == 'O' && |
430 | toupper( tracing_string[ 1 ] ) == 'N' )) |
431 | { |
432 | SQLGetPrivateProfileString( "ODBC" , "TraceFile" , "/tmp/sql.log" , |
433 | tracing_file, sizeof( tracing_file ), |
434 | "odbcinst.ini" ); |
435 | |
436 | /* |
437 | * start logging |
438 | */ |
439 | |
440 | SQLGetPrivateProfileString( "ODBC" , "TracePid" , "No" , |
441 | tracing_string, sizeof( tracing_string ), |
442 | "odbcinst.ini" ); |
443 | |
444 | if ( tracing_string[ 0 ] == '1' || |
445 | toupper( tracing_string[ 0 ] ) == 'Y' || |
446 | ( toupper( tracing_string[ 0 ] ) == 'O' && |
447 | toupper( tracing_string[ 1 ] ) == 'N' )) |
448 | { |
449 | dm_log_open( "ODBC" , tracing_file, 1 ); |
450 | } |
451 | else |
452 | { |
453 | dm_log_open( "ODBC" , tracing_file, 0 ); |
454 | } |
455 | |
456 | sprintf( environment -> msg, |
457 | "\n\t\tExit:[SQL_SUCCESS]\n\t\t\tEnvironment = %p" , environment ); |
458 | |
459 | dm_log_write( __FILE__, |
460 | __LINE__, |
461 | LOG_INFO, |
462 | LOG_INFO, environment -> msg ); |
463 | } |
464 | setup_error_head( &environment -> error, environment, |
465 | SQL_HANDLE_ENV ); |
466 | |
467 | } |
468 | |
469 | local_mutex_exit( &mutex_lists ); |
470 | |
471 | return environment; |
472 | } |
473 | |
474 | /* |
475 | * check that a env is real |
476 | */ |
477 | |
478 | int __validate_env( DMHENV env ) |
479 | { |
480 | #ifdef FAST_HANDLE_VALIDATE |
481 | |
482 | if ( env && *(( int * ) env ) == HENV_MAGIC ) |
483 | return 1; |
484 | else |
485 | return 0; |
486 | |
487 | #else |
488 | |
489 | DMHENV ptr; |
490 | int ret = 0; |
491 | |
492 | local_mutex_entry( &mutex_lists ); |
493 | |
494 | ptr = environment_root; |
495 | |
496 | while( ptr ) |
497 | { |
498 | if ( ptr == env ) |
499 | { |
500 | ret = 1; |
501 | break; |
502 | } |
503 | |
504 | ptr = ptr -> next_class_list; |
505 | } |
506 | |
507 | local_mutex_exit( &mutex_lists ); |
508 | |
509 | return ret; |
510 | |
511 | #endif |
512 | } |
513 | |
514 | /* |
515 | * remove from list |
516 | */ |
517 | |
518 | void __release_env( DMHENV environment ) |
519 | { |
520 | DMHENV last = NULL; |
521 | DMHENV ptr; |
522 | |
523 | local_mutex_entry( &mutex_lists ); |
524 | |
525 | ptr = environment_root; |
526 | |
527 | while( ptr ) |
528 | { |
529 | if ( environment == ptr ) |
530 | { |
531 | break; |
532 | } |
533 | last = ptr; |
534 | ptr = ptr -> next_class_list; |
535 | } |
536 | |
537 | if ( ptr ) |
538 | { |
539 | if ( last ) |
540 | { |
541 | last -> next_class_list = ptr -> next_class_list; |
542 | } |
543 | else |
544 | { |
545 | environment_root = ptr -> next_class_list; |
546 | } |
547 | } |
548 | |
549 | clear_error_head( &environment -> error ); |
550 | |
551 | /* |
552 | * free log |
553 | */ |
554 | |
555 | dm_log_close(); |
556 | |
557 | #if defined ( COLLECT_STATS ) && defined( HAVE_SYS_SEM_H ) |
558 | if (environment->sh) |
559 | uodbc_close_stats(environment->sh); |
560 | #endif |
561 | |
562 | /* |
563 | * clear just to make sure |
564 | */ |
565 | |
566 | memset( environment, 0, sizeof( *environment )); |
567 | |
568 | free( environment ); |
569 | |
570 | local_mutex_exit( &mutex_lists ); |
571 | } |
572 | |
573 | /* |
574 | * get the root, for use in SQLEndTran and SQLTransact |
575 | */ |
576 | |
577 | DMHDBC __get_dbc_root( void ) |
578 | { |
579 | return connection_root; |
580 | } |
581 | |
582 | /* |
583 | * allocate and register a connection handle |
584 | */ |
585 | |
586 | DMHDBC __alloc_dbc( void ) |
587 | { |
588 | DMHDBC connection = NULL; |
589 | |
590 | local_mutex_entry( &mutex_lists ); |
591 | |
592 | connection = calloc( sizeof( *connection ), 1 ); |
593 | |
594 | if ( connection ) |
595 | { |
596 | /* |
597 | * add to list of connection handles |
598 | */ |
599 | |
600 | connection -> next_class_list = connection_root; |
601 | connection_root = connection; |
602 | connection -> type = HDBC_MAGIC; |
603 | |
604 | setup_error_head( &connection -> error, connection, |
605 | SQL_HANDLE_DBC ); |
606 | |
607 | #ifdef HAVE_LIBPTH |
608 | pth_mutex_init( &connection -> mutex ); |
609 | /* |
610 | * for the moment protect at the environment level |
611 | */ |
612 | connection -> protection_level = TS_LEVEL3; |
613 | #elif HAVE_LIBPTHREAD |
614 | pthread_mutex_init( &connection -> mutex, NULL ); |
615 | /* |
616 | * for the moment protect at the environment level |
617 | */ |
618 | connection -> protection_level = TS_LEVEL3; |
619 | #elif HAVE_LIBTHREAD |
620 | mutex_init( &connection -> mutex, USYNC_THREAD, NULL ); |
621 | connection -> protection_level = TS_LEVEL3; |
622 | #endif |
623 | |
624 | #ifdef HAVE_ICONV |
625 | connection -> iconv_cd_uc_to_ascii = (iconv_t)(-1); |
626 | connection -> iconv_cd_ascii_to_uc = (iconv_t)(-1); |
627 | #endif |
628 | } |
629 | |
630 | local_mutex_exit( &mutex_lists ); |
631 | |
632 | return connection; |
633 | } |
634 | |
635 | /* |
636 | * adjust the threading level |
637 | */ |
638 | |
639 | void dbc_change_thread_support( DMHDBC connection, int level ) |
640 | { |
641 | #if defined ( HAVE_LIBPTHREAD ) || defined( HAVE_LIBTHREAD ) || defined( HAVE_LIBPTH ) |
642 | int old_level; |
643 | |
644 | if ( connection -> protection_level == level ) |
645 | return; |
646 | |
647 | old_level = connection -> protection_level; |
648 | connection -> protection_level = level; |
649 | |
650 | if ( level == TS_LEVEL3 ) |
651 | { |
652 | /* |
653 | * if we are moving from level 3 we may have to release the existing |
654 | * connection lock, and create the env lock |
655 | */ |
656 | if(old_level != TS_LEVEL0) |
657 | local_mutex_exit( &connection -> mutex ); |
658 | local_mutex_entry( &mutex_env ); |
659 | } |
660 | else if ( old_level == TS_LEVEL3 ) |
661 | { |
662 | /* |
663 | * if we are moving from level 3 we may have to create the new |
664 | * connection lock, and remove the env lock |
665 | */ |
666 | if(level != TS_LEVEL0) |
667 | local_mutex_entry( &connection -> mutex ); |
668 | local_mutex_exit( &mutex_env ); |
669 | } |
670 | |
671 | #endif |
672 | } |
673 | |
674 | /* |
675 | * check that a connection is real |
676 | */ |
677 | |
678 | int __validate_dbc( DMHDBC connection ) |
679 | { |
680 | #ifdef FAST_HANDLE_VALIDATE |
681 | |
682 | if ( connection && *(( int * ) connection ) == HDBC_MAGIC ) |
683 | return 1; |
684 | else |
685 | return 0; |
686 | |
687 | #else |
688 | |
689 | DMHDBC ptr; |
690 | int ret = 0; |
691 | |
692 | local_mutex_entry( &mutex_lists ); |
693 | |
694 | ptr = connection_root; |
695 | |
696 | while( ptr ) |
697 | { |
698 | if ( ptr == connection ) |
699 | { |
700 | ret = 1; |
701 | break; |
702 | } |
703 | |
704 | ptr = ptr -> next_class_list; |
705 | } |
706 | |
707 | local_mutex_exit( &mutex_lists ); |
708 | |
709 | return ret; |
710 | #endif |
711 | } |
712 | |
713 | /* |
714 | * remove from list |
715 | */ |
716 | |
717 | void __release_dbc( DMHDBC connection ) |
718 | { |
719 | DMHDBC last = NULL; |
720 | DMHDBC ptr; |
721 | |
722 | local_mutex_entry( &mutex_lists ); |
723 | |
724 | ptr = connection_root; |
725 | |
726 | while( ptr ) |
727 | { |
728 | if ( connection == ptr ) |
729 | { |
730 | break; |
731 | } |
732 | last = ptr; |
733 | ptr = ptr -> next_class_list; |
734 | } |
735 | |
736 | if ( ptr ) |
737 | { |
738 | if ( last ) |
739 | { |
740 | last -> next_class_list = ptr -> next_class_list; |
741 | } |
742 | else |
743 | { |
744 | connection_root = ptr -> next_class_list; |
745 | } |
746 | } |
747 | |
748 | clear_error_head( &connection -> error ); |
749 | |
750 | /* |
751 | * shutdown unicode |
752 | */ |
753 | |
754 | unicode_shutdown( connection ); |
755 | |
756 | #ifdef HAVE_LIBPTH |
757 | #elif HAVE_LIBPTHREAD |
758 | pthread_mutex_destroy( &connection -> mutex ); |
759 | #elif HAVE_LIBTHREAD |
760 | mutex_destroy( &connection -> mutex ); |
761 | #endif |
762 | |
763 | /* |
764 | * clear just to make sure |
765 | */ |
766 | |
767 | memset( connection, 0, sizeof( *connection )); |
768 | |
769 | free( connection ); |
770 | |
771 | local_mutex_exit( &mutex_lists ); |
772 | } |
773 | |
774 | /* |
775 | * allocate and register a statement handle |
776 | */ |
777 | |
778 | DMHSTMT __alloc_stmt( void ) |
779 | { |
780 | DMHSTMT statement = NULL; |
781 | |
782 | local_mutex_entry( &mutex_lists ); |
783 | |
784 | statement = calloc( sizeof( *statement ), 1 ); |
785 | |
786 | if ( statement ) |
787 | { |
788 | /* |
789 | * add to list of statement handles |
790 | */ |
791 | |
792 | statement -> next_class_list = statement_root; |
793 | #ifdef FAST_HANDLE_VALIDATE |
794 | if ( statement_root ) |
795 | { |
796 | statement_root -> prev_class_list = statement; |
797 | } |
798 | #endif |
799 | statement_root = statement; |
800 | statement -> type = HSTMT_MAGIC; |
801 | |
802 | setup_error_head( &statement -> error, statement, |
803 | SQL_HANDLE_STMT ); |
804 | |
805 | #ifdef HAVE_LIBPTH |
806 | pth_mutex_init( &statement -> mutex ); |
807 | #elif HAVE_LIBPTHREAD |
808 | pthread_mutex_init( &statement -> mutex, NULL ); |
809 | #elif HAVE_LIBTHREAD |
810 | mutex_init( &statement -> mutex, USYNC_THREAD, NULL ); |
811 | #endif |
812 | |
813 | } |
814 | |
815 | local_mutex_exit( &mutex_lists ); |
816 | |
817 | return statement; |
818 | } |
819 | |
820 | /* |
821 | * assigns a statements to the connection |
822 | */ |
823 | |
824 | void __register_stmt ( DMHDBC connection, DMHSTMT statement ) |
825 | { |
826 | local_mutex_entry( &mutex_lists ); |
827 | |
828 | connection -> statement_count ++; |
829 | statement -> connection = connection; |
830 | #ifdef FAST_HANDLE_VALIDATE |
831 | statement -> next_conn_list = connection -> statements; |
832 | connection -> statements = statement; |
833 | #endif |
834 | local_mutex_exit( &mutex_lists ); |
835 | } |
836 | |
837 | /* |
838 | * Sets statement state after commit or rollback transaction |
839 | */ |
840 | void __set_stmt_state ( DMHDBC connection, SQLSMALLINT cb_value ) |
841 | { |
842 | DMHSTMT statement; |
843 | SQLINTEGER stmt_remaining; |
844 | |
845 | local_mutex_entry( &mutex_lists ); |
846 | #ifdef FAST_HANDLE_VALIDATE |
847 | statement = connection -> statements; |
848 | while ( statement ) |
849 | { |
850 | if ( (statement -> state == STATE_S2 || |
851 | statement -> state == STATE_S3) && |
852 | cb_value == SQL_CB_DELETE ) |
853 | { |
854 | statement -> state = STATE_S1; |
855 | statement -> prepared = 0; |
856 | } |
857 | else if ( statement -> state == STATE_S4 || |
858 | statement -> state == STATE_S5 || |
859 | statement -> state == STATE_S6 || |
860 | statement -> state == STATE_S7 ) |
861 | { |
862 | if( !statement -> prepared && |
863 | (cb_value == SQL_CB_DELETE || |
864 | cb_value == SQL_CB_CLOSE) ) |
865 | { |
866 | statement -> state = STATE_S1; |
867 | } |
868 | else if( statement -> prepared ) |
869 | { |
870 | if( cb_value == SQL_CB_DELETE ) |
871 | { |
872 | statement -> state = STATE_S1; |
873 | statement -> prepared = 0; |
874 | } |
875 | else if( cb_value == SQL_CB_CLOSE ) |
876 | { |
877 | if ( statement -> state == STATE_S4 ) |
878 | statement -> state = STATE_S2; |
879 | else |
880 | statement -> state = STATE_S3; |
881 | } |
882 | } |
883 | } |
884 | statement = statement -> next_conn_list; |
885 | } |
886 | #else |
887 | statement = statement_root; |
888 | stmt_remaining = connection -> statement_count; |
889 | |
890 | while ( statement && stmt_remaining > 0 ) |
891 | { |
892 | if ( statement -> connection == connection ) |
893 | { |
894 | if ( (statement -> state == STATE_S2 || |
895 | statement -> state == STATE_S3) && |
896 | cb_value == SQL_CB_DELETE ) |
897 | { |
898 | statement -> state = STATE_S1; |
899 | statement -> prepared = 0; |
900 | } |
901 | else if ( statement -> state == STATE_S4 || |
902 | statement -> state == STATE_S5 || |
903 | statement -> state == STATE_S6 || |
904 | statement -> state == STATE_S7 ) |
905 | { |
906 | if( !statement -> prepared && |
907 | (cb_value == SQL_CB_DELETE || |
908 | cb_value == SQL_CB_CLOSE) ) |
909 | { |
910 | statement -> state = STATE_S1; |
911 | } |
912 | else if( statement -> prepared ) |
913 | { |
914 | if( cb_value == SQL_CB_DELETE ) |
915 | { |
916 | statement -> state = STATE_S1; |
917 | statement -> prepared = 0; |
918 | } |
919 | else if( cb_value == SQL_CB_CLOSE ) |
920 | { |
921 | if ( statement -> state == STATE_S4 ) |
922 | statement -> state = STATE_S2; |
923 | else |
924 | statement -> state = STATE_S3; |
925 | } |
926 | } |
927 | } |
928 | |
929 | stmt_remaining --; |
930 | } |
931 | |
932 | statement = statement -> next_class_list; |
933 | } |
934 | #endif |
935 | local_mutex_exit( &mutex_lists ); |
936 | } |
937 | |
938 | /* |
939 | * clear all statements on a DBC |
940 | */ |
941 | |
942 | int __clean_stmt_from_dbc( DMHDBC connection ) |
943 | { |
944 | DMHSTMT ptr, last; |
945 | int ret = 0; |
946 | |
947 | local_mutex_entry( &mutex_lists ); |
948 | #ifdef FAST_HANDLE_VALIDATE |
949 | while ( connection -> statements ) |
950 | { |
951 | ptr = connection -> statements; |
952 | last = connection -> statements -> prev_class_list; |
953 | |
954 | connection -> statements = ptr -> next_conn_list; |
955 | if ( last ) |
956 | { |
957 | last -> next_class_list = ptr -> next_class_list; |
958 | if ( last -> next_class_list ) |
959 | { |
960 | last -> next_class_list -> prev_class_list = last; |
961 | } |
962 | } |
963 | else |
964 | { |
965 | statement_root = ptr -> next_class_list; |
966 | if ( statement_root ) |
967 | { |
968 | statement_root -> prev_class_list = NULL; |
969 | } |
970 | } |
971 | clear_error_head( &ptr -> error ); |
972 | |
973 | #ifdef HAVE_LIBPTH |
974 | #elif HAVE_LIBPTHREAD |
975 | pthread_mutex_destroy( &ptr -> mutex ); |
976 | #elif HAVE_LIBTHREAD |
977 | mutex_destroy( &ptr -> mutex ); |
978 | #endif |
979 | free( ptr ); |
980 | } |
981 | #else |
982 | last = NULL; |
983 | ptr = statement_root; |
984 | |
985 | while( ptr ) |
986 | { |
987 | if ( ptr -> connection == connection ) |
988 | { |
989 | if ( last ) |
990 | { |
991 | last -> next_class_list = ptr -> next_class_list; |
992 | } |
993 | else |
994 | { |
995 | statement_root = ptr -> next_class_list; |
996 | } |
997 | clear_error_head( &ptr -> error ); |
998 | |
999 | #ifdef HAVE_LIBPTH |
1000 | #elif HAVE_LIBPTHREAD |
1001 | pthread_mutex_destroy( &ptr -> mutex ); |
1002 | #elif HAVE_LIBTHREAD |
1003 | mutex_destroy( &ptr -> mutex ); |
1004 | #endif |
1005 | free( ptr ); |
1006 | |
1007 | /* |
1008 | * go back to the start |
1009 | */ |
1010 | |
1011 | last = NULL; |
1012 | ptr = statement_root; |
1013 | } |
1014 | else |
1015 | { |
1016 | last = ptr; |
1017 | ptr = ptr -> next_class_list; |
1018 | } |
1019 | } |
1020 | #endif |
1021 | local_mutex_exit( &mutex_lists ); |
1022 | |
1023 | return ret; |
1024 | } |
1025 | |
1026 | int __check_stmt_from_dbc_v( DMHDBC connection, int statecount, ... ) |
1027 | { |
1028 | va_list ap; |
1029 | int states[ MAX_STATE_ARGS ]; |
1030 | DMHSTMT ptr; |
1031 | int found = 0; |
1032 | int i; |
1033 | |
1034 | va_start (ap, statecount); |
1035 | for ( i = 0; i < statecount; i ++ ) { |
1036 | states[ i ] = va_arg (ap, int ); |
1037 | } |
1038 | va_end (ap); |
1039 | |
1040 | local_mutex_entry( &mutex_lists ); |
1041 | #ifdef FAST_HANDLE_VALIDATE |
1042 | ptr = connection -> statements; |
1043 | while( !found && ptr ) |
1044 | { |
1045 | for ( i = 0; i < statecount; i ++ ) { |
1046 | if ( ptr -> state == states[ i ] ) { |
1047 | found = 1; |
1048 | break; |
1049 | } |
1050 | } |
1051 | |
1052 | ptr = ptr -> next_conn_list; |
1053 | } |
1054 | #else |
1055 | ptr = statement_root; |
1056 | while( !found && ptr ) |
1057 | { |
1058 | if ( ptr -> connection == connection ) |
1059 | { |
1060 | for ( i = 0; i < statecount; i ++ ) { |
1061 | if ( ptr -> state == states[ i ] ) { |
1062 | found = 1; |
1063 | break; |
1064 | } |
1065 | } |
1066 | } |
1067 | |
1068 | ptr = ptr -> next_class_list; |
1069 | } |
1070 | #endif |
1071 | local_mutex_exit( &mutex_lists ); |
1072 | |
1073 | return found; |
1074 | } |
1075 | |
1076 | /* |
1077 | * check if any statements on this connection are in a given state |
1078 | */ |
1079 | |
1080 | int __check_stmt_from_dbc( DMHDBC connection, int state ) |
1081 | { |
1082 | DMHSTMT ptr; |
1083 | int found = 0; |
1084 | |
1085 | local_mutex_entry( &mutex_lists ); |
1086 | #ifdef FAST_HANDLE_VALIDATE |
1087 | ptr = connection -> statements; |
1088 | while( ptr ) |
1089 | { |
1090 | if ( ptr -> state == state ) |
1091 | { |
1092 | found = 1; |
1093 | break; |
1094 | } |
1095 | |
1096 | ptr = ptr -> next_conn_list; |
1097 | } |
1098 | #else |
1099 | ptr = statement_root; |
1100 | while( ptr ) |
1101 | { |
1102 | if ( ptr -> connection == connection ) |
1103 | { |
1104 | if ( ptr -> state == state ) |
1105 | { |
1106 | found = 1; |
1107 | break; |
1108 | } |
1109 | } |
1110 | |
1111 | ptr = ptr -> next_class_list; |
1112 | } |
1113 | #endif |
1114 | local_mutex_exit( &mutex_lists ); |
1115 | |
1116 | return found; |
1117 | } |
1118 | |
1119 | int __check_stmt_from_desc( DMHDESC desc, int state ) |
1120 | { |
1121 | DMHDBC connection; |
1122 | DMHSTMT ptr; |
1123 | int found = 0; |
1124 | |
1125 | local_mutex_entry( &mutex_lists ); |
1126 | connection = desc -> connection; |
1127 | #ifdef FAST_HANDLE_VALIDATE |
1128 | ptr = connection -> statements; |
1129 | while( ptr ) |
1130 | { |
1131 | if ( ptr -> ipd == desc || ptr -> ird == desc || ptr -> apd == desc || ptr -> ard == desc ) |
1132 | { |
1133 | if ( ptr -> state == state ) |
1134 | { |
1135 | found = 1; |
1136 | break; |
1137 | } |
1138 | } |
1139 | |
1140 | ptr = ptr -> next_conn_list; |
1141 | } |
1142 | #else |
1143 | ptr = statement_root; |
1144 | while( ptr ) |
1145 | { |
1146 | if ( ptr -> connection == connection ) |
1147 | { |
1148 | if ( ptr -> ipd == desc || ptr -> ird == desc || ptr -> apd == desc || ptr -> ard == desc ) |
1149 | { |
1150 | if ( ptr -> state == state ) |
1151 | { |
1152 | found = 1; |
1153 | break; |
1154 | } |
1155 | } |
1156 | } |
1157 | |
1158 | ptr = ptr -> next_class_list; |
1159 | } |
1160 | #endif |
1161 | local_mutex_exit( &mutex_lists ); |
1162 | |
1163 | return found; |
1164 | } |
1165 | |
1166 | int __check_stmt_from_desc_ird( DMHDESC desc, int state ) |
1167 | { |
1168 | DMHDBC connection; |
1169 | DMHSTMT ptr; |
1170 | int found = 0; |
1171 | |
1172 | local_mutex_entry( &mutex_lists ); |
1173 | connection = desc -> connection; |
1174 | #ifdef FAST_HANDLE_VALIDATE |
1175 | ptr = connection -> statements; |
1176 | while( ptr ) |
1177 | { |
1178 | if ( ptr -> ird == desc ) |
1179 | { |
1180 | if ( ptr -> state == state ) |
1181 | { |
1182 | found = 1; |
1183 | break; |
1184 | } |
1185 | } |
1186 | |
1187 | ptr = ptr -> next_conn_list; |
1188 | } |
1189 | #else |
1190 | ptr = statement_root; |
1191 | while( ptr ) |
1192 | { |
1193 | if ( ptr -> connection == connection ) |
1194 | { |
1195 | if ( ptr -> ird == desc ) |
1196 | { |
1197 | if ( ptr -> state == state ) |
1198 | { |
1199 | found = 1; |
1200 | break; |
1201 | } |
1202 | } |
1203 | } |
1204 | |
1205 | ptr = ptr -> next_class_list; |
1206 | } |
1207 | #endif |
1208 | local_mutex_exit( &mutex_lists ); |
1209 | |
1210 | return found; |
1211 | } |
1212 | |
1213 | /* |
1214 | * check any statements that are associated with a descriptor |
1215 | */ |
1216 | |
1217 | /* |
1218 | * check that a statement is real |
1219 | */ |
1220 | |
1221 | int __validate_stmt( DMHSTMT statement ) |
1222 | { |
1223 | #ifdef FAST_HANDLE_VALIDATE |
1224 | |
1225 | if ( statement && *(( int * ) statement ) == HSTMT_MAGIC ) |
1226 | return 1; |
1227 | else |
1228 | return 0; |
1229 | |
1230 | #else |
1231 | |
1232 | DMHSTMT ptr; |
1233 | int ret = 0; |
1234 | |
1235 | local_mutex_entry( &mutex_lists ); |
1236 | |
1237 | ptr = statement_root; |
1238 | |
1239 | while( ptr ) |
1240 | { |
1241 | if ( ptr == statement ) |
1242 | { |
1243 | ret = 1; |
1244 | break; |
1245 | } |
1246 | |
1247 | ptr = ptr -> next_class_list; |
1248 | } |
1249 | |
1250 | local_mutex_exit( &mutex_lists ); |
1251 | |
1252 | return ret; |
1253 | |
1254 | #endif |
1255 | } |
1256 | |
1257 | /* |
1258 | * remove from list |
1259 | */ |
1260 | |
1261 | void __release_stmt( DMHSTMT statement ) |
1262 | { |
1263 | DMHSTMT last = NULL; |
1264 | DMHSTMT ptr; |
1265 | |
1266 | local_mutex_entry( &mutex_lists ); |
1267 | #ifdef FAST_HANDLE_VALIDATE |
1268 | /* |
1269 | * A check never mind |
1270 | */ |
1271 | if ( statement && ( *(( int * ) statement ) == HSTMT_MAGIC )) |
1272 | { |
1273 | ptr = statement; |
1274 | last = statement->prev_class_list; |
1275 | |
1276 | if ( statement -> connection ) |
1277 | { |
1278 | DMHDBC connection = statement -> connection; |
1279 | DMHSTMT conn_last = NULL; |
1280 | DMHSTMT conn_ptr = connection -> statements; |
1281 | while ( conn_ptr ) |
1282 | { |
1283 | if ( statement == conn_ptr ) |
1284 | { |
1285 | break; |
1286 | } |
1287 | conn_last = conn_ptr; |
1288 | conn_ptr = conn_ptr -> next_conn_list; |
1289 | } |
1290 | if ( conn_ptr ) |
1291 | { |
1292 | if ( conn_last ) |
1293 | { |
1294 | conn_last -> next_conn_list = conn_ptr -> next_conn_list; |
1295 | } |
1296 | else |
1297 | { |
1298 | connection -> statements = conn_ptr -> next_conn_list; |
1299 | } |
1300 | } |
1301 | } |
1302 | } |
1303 | else |
1304 | { |
1305 | ptr = NULL; |
1306 | last = NULL; |
1307 | } |
1308 | #else |
1309 | ptr = statement_root; |
1310 | |
1311 | while( ptr ) |
1312 | { |
1313 | if ( statement == ptr ) |
1314 | { |
1315 | break; |
1316 | } |
1317 | last = ptr; |
1318 | ptr = ptr -> next_class_list; |
1319 | } |
1320 | #endif |
1321 | if ( ptr ) |
1322 | { |
1323 | if ( last ) |
1324 | { |
1325 | last -> next_class_list = ptr -> next_class_list; |
1326 | #ifdef FAST_HANDLE_VALIDATE |
1327 | if ( last -> next_class_list ) |
1328 | { |
1329 | last -> next_class_list -> prev_class_list = last; |
1330 | } |
1331 | #endif |
1332 | } |
1333 | else |
1334 | { |
1335 | statement_root = ptr -> next_class_list; |
1336 | #ifdef FAST_HANDLE_VALIDATE |
1337 | if ( statement_root ) |
1338 | { |
1339 | statement_root -> prev_class_list = NULL; |
1340 | } |
1341 | #endif |
1342 | } |
1343 | } |
1344 | |
1345 | clear_error_head( &statement -> error ); |
1346 | |
1347 | #ifdef HAVE_LIBPTH |
1348 | #elif HAVE_LIBPTHREAD |
1349 | pthread_mutex_destroy( &statement -> mutex ); |
1350 | #elif HAVE_LIBTHREAD |
1351 | mutex_destroy( &statement -> mutex ); |
1352 | #endif |
1353 | |
1354 | /* |
1355 | * clear just to make sure |
1356 | */ |
1357 | |
1358 | memset( statement, 0, sizeof( *statement )); |
1359 | |
1360 | free( statement ); |
1361 | |
1362 | local_mutex_exit( &mutex_lists ); |
1363 | } |
1364 | |
1365 | /* |
1366 | * allocate and register a descriptor handle |
1367 | */ |
1368 | |
1369 | DMHDESC __alloc_desc( void ) |
1370 | { |
1371 | DMHDESC descriptor; |
1372 | |
1373 | local_mutex_entry( &mutex_lists ); |
1374 | |
1375 | descriptor = calloc( sizeof( *descriptor ), 1 ); |
1376 | |
1377 | if ( descriptor ) |
1378 | { |
1379 | /* |
1380 | * add to list of descriptor handles |
1381 | */ |
1382 | |
1383 | descriptor -> next_class_list = descriptor_root; |
1384 | #ifdef FAST_HANDLE_VALIDATE |
1385 | if ( descriptor_root ) |
1386 | { |
1387 | descriptor_root -> prev_class_list = descriptor; |
1388 | } |
1389 | #endif |
1390 | descriptor_root = descriptor; |
1391 | descriptor -> type = HDESC_MAGIC; |
1392 | |
1393 | setup_error_head( &descriptor -> error, descriptor, SQL_HANDLE_DESC ); |
1394 | |
1395 | #ifdef HAVE_LIBPTH |
1396 | pth_mutex_init( &descriptor -> mutex ); |
1397 | #elif HAVE_LIBPTHREAD |
1398 | pthread_mutex_init( &descriptor -> mutex, NULL ); |
1399 | #elif HAVE_LIBTHREAD |
1400 | mutex_init( &descriptor -> mutex, USYNC_THREAD, NULL ); |
1401 | #endif |
1402 | } |
1403 | |
1404 | local_mutex_exit( &mutex_lists ); |
1405 | |
1406 | return descriptor; |
1407 | } |
1408 | |
1409 | /* |
1410 | * check that a descriptor is real |
1411 | */ |
1412 | |
1413 | int __validate_desc( DMHDESC descriptor ) |
1414 | { |
1415 | #ifdef FAST_HANDLE_VALIDATE |
1416 | |
1417 | if ( descriptor && *(( int * ) descriptor ) == HDESC_MAGIC ) |
1418 | return 1; |
1419 | else |
1420 | return 0; |
1421 | |
1422 | #else |
1423 | |
1424 | DMHDESC ptr; |
1425 | int ret = 0; |
1426 | |
1427 | local_mutex_entry( &mutex_lists ); |
1428 | |
1429 | ptr = descriptor_root; |
1430 | |
1431 | while( ptr ) |
1432 | { |
1433 | if ( ptr == descriptor ) |
1434 | { |
1435 | ret = 1; |
1436 | break; |
1437 | } |
1438 | |
1439 | ptr = ptr -> next_class_list; |
1440 | } |
1441 | |
1442 | local_mutex_exit( &mutex_lists ); |
1443 | |
1444 | return ret; |
1445 | |
1446 | #endif |
1447 | } |
1448 | |
1449 | /* |
1450 | * clear all descriptors on a DBC |
1451 | */ |
1452 | |
1453 | int __clean_desc_from_dbc( DMHDBC connection ) |
1454 | { |
1455 | DMHDESC ptr, last; |
1456 | int ret = 0; |
1457 | |
1458 | local_mutex_entry( &mutex_lists ); |
1459 | last = NULL; |
1460 | ptr = descriptor_root; |
1461 | |
1462 | while( ptr ) |
1463 | { |
1464 | if ( ptr -> connection == connection ) |
1465 | { |
1466 | if ( last ) |
1467 | { |
1468 | last -> next_class_list = ptr -> next_class_list; |
1469 | #ifdef FAST_HANDLE_VALIDATE |
1470 | if ( last -> next_class_list ) |
1471 | { |
1472 | last -> next_class_list -> prev_class_list = last; |
1473 | } |
1474 | #endif |
1475 | } |
1476 | else |
1477 | { |
1478 | descriptor_root = ptr -> next_class_list; |
1479 | #ifdef FAST_HANDLE_VALIDATE |
1480 | if ( descriptor_root ) |
1481 | { |
1482 | descriptor_root -> prev_class_list = NULL; |
1483 | } |
1484 | #endif |
1485 | } |
1486 | clear_error_head( &ptr -> error ); |
1487 | |
1488 | #ifdef HAVE_LIBPTH |
1489 | #elif HAVE_LIBPTHREAD |
1490 | pthread_mutex_destroy( &ptr -> mutex ); |
1491 | #elif HAVE_LIBTHREAD |
1492 | mutex_destroy( &ptr -> mutex ); |
1493 | #endif |
1494 | free( ptr ); |
1495 | |
1496 | /* |
1497 | * go back to the start |
1498 | */ |
1499 | |
1500 | last = NULL; |
1501 | ptr = descriptor_root; |
1502 | } |
1503 | else |
1504 | { |
1505 | last = ptr; |
1506 | ptr = ptr -> next_class_list; |
1507 | } |
1508 | } |
1509 | |
1510 | local_mutex_exit( &mutex_lists ); |
1511 | |
1512 | return ret; |
1513 | } |
1514 | |
1515 | |
1516 | /* |
1517 | * remove from list |
1518 | */ |
1519 | |
1520 | void __release_desc( DMHDESC descriptor ) |
1521 | { |
1522 | DMHDESC last = NULL; |
1523 | DMHDESC ptr; |
1524 | DMHSTMT assoc_stmt; |
1525 | |
1526 | local_mutex_entry( &mutex_lists ); |
1527 | #ifdef FAST_HANDLE_VALIDATE |
1528 | /* |
1529 | * A check never mind |
1530 | */ |
1531 | if ( descriptor && ( *(( int * ) descriptor ) == HDESC_MAGIC )) |
1532 | { |
1533 | ptr = descriptor; |
1534 | last = descriptor->prev_class_list; |
1535 | } |
1536 | else |
1537 | { |
1538 | ptr = NULL; |
1539 | last = NULL; |
1540 | } |
1541 | #else |
1542 | ptr = descriptor_root; |
1543 | |
1544 | while( ptr ) |
1545 | { |
1546 | if ( descriptor == ptr ) |
1547 | { |
1548 | break; |
1549 | } |
1550 | last = ptr; |
1551 | ptr = ptr -> next_class_list; |
1552 | } |
1553 | #endif |
1554 | |
1555 | if ( ptr ) |
1556 | { |
1557 | if ( last ) |
1558 | { |
1559 | last -> next_class_list = ptr -> next_class_list; |
1560 | #ifdef FAST_HANDLE_VALIDATE |
1561 | if ( last -> next_class_list ) |
1562 | { |
1563 | last -> next_class_list -> prev_class_list = last; |
1564 | } |
1565 | #endif |
1566 | } |
1567 | else |
1568 | { |
1569 | descriptor_root = ptr -> next_class_list; |
1570 | #ifdef FAST_HANDLE_VALIDATE |
1571 | if ( descriptor_root ) |
1572 | { |
1573 | descriptor_root -> prev_class_list = NULL; |
1574 | } |
1575 | #endif |
1576 | } |
1577 | } |
1578 | |
1579 | clear_error_head( &descriptor -> error ); |
1580 | /* If there are any statements still pointing to this descriptor, revert them to implicit */ |
1581 | assoc_stmt = statement_root; |
1582 | while ( assoc_stmt ) |
1583 | { |
1584 | DMHDESC *pDesc[] = { |
1585 | &assoc_stmt -> ipd, &assoc_stmt -> apd, &assoc_stmt -> ird, &assoc_stmt -> ard |
1586 | }; |
1587 | DMHDESC impDesc[] = { |
1588 | assoc_stmt -> implicit_ipd, assoc_stmt -> implicit_apd, |
1589 | assoc_stmt -> implicit_ird, assoc_stmt -> implicit_ard |
1590 | }; |
1591 | int i; |
1592 | for ( i = 0; i < 4; i++ ) |
1593 | { |
1594 | if ( *pDesc[i] == descriptor ) |
1595 | { |
1596 | *pDesc[i] = impDesc[i]; |
1597 | } |
1598 | } |
1599 | assoc_stmt = assoc_stmt -> next_class_list; |
1600 | } |
1601 | |
1602 | #ifdef HAVE_LIBPTH |
1603 | #elif HAVE_LIBPTHREAD |
1604 | pthread_mutex_destroy( &descriptor -> mutex ); |
1605 | #elif HAVE_LIBTHREAD |
1606 | mutex_destroy( &descriptor -> mutex ); |
1607 | #endif |
1608 | |
1609 | /* |
1610 | * clear just to make sure |
1611 | */ |
1612 | |
1613 | memset( descriptor, 0, sizeof( *descriptor )); |
1614 | |
1615 | free( descriptor ); |
1616 | |
1617 | local_mutex_exit( &mutex_lists ); |
1618 | } |
1619 | |
1620 | #if defined ( HAVE_LIBPTHREAD ) || defined ( HAVE_LIBTHREAD ) || defined( HAVE_LIBPTH ) |
1621 | |
1622 | void thread_protect( int type, void *handle ) |
1623 | { |
1624 | DMHDBC connection; |
1625 | DMHSTMT statement; |
1626 | DMHDESC descriptor; |
1627 | |
1628 | switch( type ) |
1629 | { |
1630 | case SQL_HANDLE_ENV: |
1631 | local_mutex_entry( &mutex_env ); |
1632 | break; |
1633 | |
1634 | case SQL_HANDLE_DBC: |
1635 | connection = handle; |
1636 | if ( connection -> protection_level == TS_LEVEL3 ) |
1637 | { |
1638 | local_mutex_entry( &mutex_env ); |
1639 | } |
1640 | else if ( connection -> protection_level == TS_LEVEL2 || |
1641 | connection -> protection_level == TS_LEVEL1 ) |
1642 | { |
1643 | local_mutex_entry( &connection -> mutex ); |
1644 | } |
1645 | break; |
1646 | |
1647 | case SQL_HANDLE_STMT: |
1648 | statement = handle; |
1649 | if ( statement -> connection -> protection_level == TS_LEVEL3 ) |
1650 | { |
1651 | local_mutex_entry( &mutex_env ); |
1652 | } |
1653 | else if ( statement -> connection -> protection_level == TS_LEVEL2 ) |
1654 | { |
1655 | local_mutex_entry( &statement -> connection -> mutex ); |
1656 | } |
1657 | else if ( statement -> connection -> protection_level == TS_LEVEL1 ) |
1658 | { |
1659 | local_mutex_entry( &statement -> mutex ); |
1660 | } |
1661 | break; |
1662 | |
1663 | case SQL_HANDLE_DESC: |
1664 | descriptor = handle; |
1665 | if ( descriptor -> connection -> protection_level == TS_LEVEL3 ) |
1666 | { |
1667 | local_mutex_entry( &mutex_env ); |
1668 | } |
1669 | if ( descriptor -> connection -> protection_level == TS_LEVEL2 ) |
1670 | { |
1671 | local_mutex_entry( &descriptor -> connection -> mutex ); |
1672 | } |
1673 | if ( descriptor -> connection -> protection_level == TS_LEVEL1 ) |
1674 | { |
1675 | local_mutex_entry( &descriptor -> mutex ); |
1676 | } |
1677 | break; |
1678 | } |
1679 | } |
1680 | |
1681 | void thread_release( int type, void *handle ) |
1682 | { |
1683 | DMHDBC connection; |
1684 | DMHSTMT statement; |
1685 | DMHDESC descriptor; |
1686 | |
1687 | switch( type ) |
1688 | { |
1689 | case SQL_HANDLE_ENV: |
1690 | local_mutex_exit( &mutex_env ); |
1691 | break; |
1692 | |
1693 | case SQL_HANDLE_DBC: |
1694 | connection = handle; |
1695 | if ( connection -> protection_level == TS_LEVEL3 ) |
1696 | { |
1697 | local_mutex_exit( &mutex_env ); |
1698 | } |
1699 | else if ( connection -> protection_level == TS_LEVEL2 || |
1700 | connection -> protection_level == TS_LEVEL1 ) |
1701 | { |
1702 | local_mutex_exit( &connection -> mutex ); |
1703 | } |
1704 | break; |
1705 | |
1706 | case SQL_HANDLE_STMT: |
1707 | statement = handle; |
1708 | if ( statement -> connection -> protection_level == TS_LEVEL3 ) |
1709 | { |
1710 | local_mutex_exit( &mutex_env ); |
1711 | } |
1712 | else if ( statement -> connection -> protection_level == TS_LEVEL2 ) |
1713 | { |
1714 | local_mutex_exit( &statement -> connection -> mutex ); |
1715 | } |
1716 | else if ( statement -> connection -> protection_level == TS_LEVEL1 ) |
1717 | { |
1718 | local_mutex_exit( &statement -> mutex ); |
1719 | } |
1720 | break; |
1721 | |
1722 | case SQL_HANDLE_DESC: |
1723 | descriptor = handle; |
1724 | if ( descriptor -> connection -> protection_level == TS_LEVEL3 ) |
1725 | { |
1726 | local_mutex_exit( &mutex_env ); |
1727 | } |
1728 | else if ( descriptor -> connection -> protection_level == TS_LEVEL2 ) |
1729 | { |
1730 | local_mutex_exit( &descriptor -> connection -> mutex ); |
1731 | } |
1732 | else if ( descriptor -> connection -> protection_level == TS_LEVEL1 ) |
1733 | { |
1734 | local_mutex_exit( &descriptor -> mutex ); |
1735 | } |
1736 | break; |
1737 | } |
1738 | } |
1739 | |
1740 | #endif |
1741 | |
1742 | #ifdef WITH_HANDLE_REDIRECT |
1743 | |
1744 | /* |
1745 | * try and find a handle that has the suplied handle as the driver handle |
1746 | * there will be threading issues with this, so be carefull. |
1747 | * However it will normally only get used with "broken" drivers. |
1748 | */ |
1749 | |
1750 | |
1751 | void *find_parent_handle( DRV_SQLHANDLE drv_hand, int type ) |
1752 | { |
1753 | void *found_handle = NULL; |
1754 | |
1755 | local_mutex_entry( &mutex_lists ); |
1756 | |
1757 | switch( type ) { |
1758 | case SQL_HANDLE_DBC: |
1759 | { |
1760 | DMHDBC hand = connection_root; |
1761 | while( hand ) { |
1762 | if ( hand -> driver_dbc == drv_hand ) { |
1763 | found_handle = hand; |
1764 | break; |
1765 | } |
1766 | hand = hand -> next_class_list; |
1767 | } |
1768 | } |
1769 | break; |
1770 | |
1771 | case SQL_HANDLE_STMT: |
1772 | { |
1773 | DMHSTMT hand = statement_root; |
1774 | while( hand ) { |
1775 | if ( hand -> driver_stmt == drv_hand ) { |
1776 | found_handle = hand; |
1777 | break; |
1778 | } |
1779 | hand = hand -> next_class_list; |
1780 | } |
1781 | } |
1782 | break; |
1783 | |
1784 | case SQL_HANDLE_DESC: |
1785 | { |
1786 | DMHDESC hand = descriptor_root; |
1787 | while( hand ) { |
1788 | if ( hand -> driver_desc == drv_hand ) { |
1789 | found_handle = hand; |
1790 | break; |
1791 | } |
1792 | hand = hand -> next_class_list; |
1793 | } |
1794 | } |
1795 | break; |
1796 | |
1797 | default: |
1798 | break; |
1799 | } |
1800 | |
1801 | local_mutex_exit( &mutex_lists ); |
1802 | |
1803 | return found_handle; |
1804 | } |
1805 | |
1806 | #endif |
1807 | |