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 
local_mutex_entry(pth_mutex_t * mutex)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 
local_mutex_exit(pth_mutex_t * mutex)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 
local_mutex_entry(pthread_mutex_t * mutex)311 static int local_mutex_entry( pthread_mutex_t *mutex )
312 {
313     return pthread_mutex_lock( mutex );
314 }
315 
local_mutex_exit(pthread_mutex_t * mutex)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 
local_mutex_entry(mutex_t * mutex)330 static int local_mutex_entry( mutex_t *mutex )
331 {
332     return mutex_lock( mutex );
333 }
334 
local_mutex_exit(mutex_t * mutex)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 
mutex_pool_entry(void)351 void mutex_pool_entry( void )
352 {
353     local_mutex_entry( &mutex_pool );
354 }
355 
mutex_pool_exit(void)356 void mutex_pool_exit( void )
357 {
358     local_mutex_exit( &mutex_pool );
359 }
360 
361 /*
362  * protection for iconv
363  */
364 
mutex_iconv_entry(void)365 void mutex_iconv_entry( void )
366 {
367     local_mutex_entry( &mutex_iconv );
368 }
369 
mutex_iconv_exit(void)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 
mutex_lib_entry(void)380 void mutex_lib_entry( void )
381 {
382     local_mutex_entry( &mutex_lists );
383 }
384 
mutex_lib_exit(void)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 
__alloc_env(void)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 
__validate_env(DMHENV env)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 
__release_env(DMHENV environment)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 
__get_dbc_root(void)577 DMHDBC __get_dbc_root( void )
578 {
579     return connection_root;
580 }
581 
582 /*
583  * allocate and register a connection handle
584  */
585 
__alloc_dbc(void)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 
dbc_change_thread_support(DMHDBC connection,int level)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 
__validate_dbc(DMHDBC connection)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 
__release_dbc(DMHDBC connection)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 
__alloc_stmt(void)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 
__register_stmt(DMHDBC connection,DMHSTMT statement)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  */
__set_stmt_state(DMHDBC connection,SQLSMALLINT cb_value)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 
__clean_stmt_from_dbc(DMHDBC connection)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 
__check_stmt_from_dbc_v(DMHDBC connection,int statecount,...)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 
__check_stmt_from_dbc(DMHDBC connection,int state)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 
__check_stmt_from_desc(DMHDESC desc,int state)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 
__check_stmt_from_desc_ird(DMHDESC desc,int state)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 
__validate_stmt(DMHSTMT statement)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 
__release_stmt(DMHSTMT statement)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 
__alloc_desc(void)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 
__validate_desc(DMHDESC descriptor)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 
__clean_desc_from_dbc(DMHDBC connection)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 
__release_desc(DMHDESC descriptor)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 
thread_protect(int type,void * handle)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 
thread_release(int type,void * handle)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 
find_parent_handle(DRV_SQLHANDLE drv_hand,int type)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