1 /*
2  *  hdbc.c
3  *
4  *  $Id: hdbc.c 2613 1999-06-01 15:32:12Z VZ $
5  *
6  *  Data source connect object management functions
7  *
8  *  The iODBC driver manager.
9  *
10  *  Copyright (C) 1995 by Ke Jin <kejin@empress.com>
11  *
12  *  This library is free software; you can redistribute it and/or
13  *  modify it under the terms of the GNU Library General Public
14  *  License as published by the Free Software Foundation; either
15  *  version 2 of the License, or (at your option) any later version.
16  *
17  *  This library is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  *  Library General Public License for more details.
21  *
22  *  You should have received a copy of the GNU Library General Public
23  *  License along with this library; if not, write to the Free
24  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  */
26 
27 #include	"config.h"
28 
29 #include	"isql.h"
30 #include	"isqlext.h"
31 
32 #include        "dlproc.h"
33 
34 #include	"herr.h"
35 #include	"henv.h"
36 #include	"hdbc.h"
37 #include	"hstmt.h"
38 
39 #include	"itrace.h"
40 #include	"stdio.h"
41 
42 extern	RETCODE	_iodbcdm_driverunload();
43 
44 
45 RETCODE SQL_API
SQLAllocConnect(HENV henv,HDBC FAR * phdbc)46 SQLAllocConnect (
47     HENV henv,
48     HDBC FAR * phdbc)
49 {
50   GENV_t FAR *genv = (GENV_t FAR *) henv;
51   DBC_t FAR *pdbc;
52 
53 #if (ODBCVER >= 0x0300)
54   if (henv == SQL_NULL_HENV || genv->type != SQL_HANDLE_ENV)
55 #else
56   if (henv == SQL_NULL_HENV)
57 #endif
58 
59     {
60       return SQL_INVALID_HANDLE;
61     }
62 
63   if (phdbc == NULL)
64     {
65       PUSHSQLERR (genv->herr, en_S1009);
66 
67       return SQL_ERROR;
68     }
69 
70   pdbc = (DBC_t FAR *) MEM_ALLOC (sizeof (DBC_t));
71 
72   if (pdbc == NULL)
73     {
74       *phdbc = SQL_NULL_HDBC;
75 
76       PUSHSQLERR (genv->herr, en_S1001);
77 
78       return SQL_ERROR;
79     }
80 
81 #if (ODBCVER >= 0x0300)
82   pdbc->type = SQL_HANDLE_DBC;
83 #endif
84 
85   /* insert this dbc entry into the link list */
86   pdbc->next = genv->hdbc;
87   genv->hdbc = pdbc;
88   pdbc->genv = henv;
89 
90   pdbc->henv = SQL_NULL_HENV;
91   pdbc->hstmt = SQL_NULL_HSTMT;
92   pdbc->herr = SQL_NULL_HERR;
93   pdbc->dhdbc = SQL_NULL_HDBC;
94   pdbc->state = en_dbc_allocated;
95   pdbc->trace = 0;
96   pdbc->tstm = NULL;
97   pdbc->tfile = NULL;
98 
99   /* set connect options to default values */
100   pdbc->access_mode = SQL_MODE_DEFAULT;
101   pdbc->autocommit = SQL_AUTOCOMMIT_DEFAULT;
102   pdbc->current_qualifier = NULL;
103   pdbc->login_timeout = 0UL;
104   pdbc->odbc_cursors = SQL_CUR_DEFAULT;
105   pdbc->packet_size = 0UL;
106   pdbc->quiet_mode = (UDWORD) NULL;
107   pdbc->txn_isolation = SQL_TXN_READ_UNCOMMITTED;
108   pdbc->cb_commit = (SWORD) SQL_CB_DELETE;
109   pdbc->cb_rollback = (SWORD) SQL_CB_DELETE;
110 
111   *phdbc = (HDBC) pdbc;
112 
113   return SQL_SUCCESS;
114 }
115 
116 
117 RETCODE SQL_API
SQLFreeConnect(HDBC hdbc)118 SQLFreeConnect (HDBC hdbc)
119 {
120   GENV_t FAR *genv;
121   DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
122   DBC_t FAR *tpdbc;
123 
124   if (hdbc == SQL_NULL_HDBC)
125     {
126       return SQL_INVALID_HANDLE;
127     }
128 
129   /* check state */
130   if (pdbc->state != en_dbc_allocated)
131     {
132       PUSHSQLERR (pdbc->herr, en_S1010);
133 
134       return SQL_ERROR;
135     }
136 
137   genv = (GENV_t FAR *) pdbc->genv;
138 
139   for (tpdbc = (DBC_t FAR *) genv->hdbc;
140       tpdbc != NULL;
141       tpdbc = tpdbc->next)
142     {
143       if (pdbc == tpdbc)
144 	{
145 	  genv->hdbc = pdbc->next;
146 	  break;
147 	}
148 
149       if (pdbc == tpdbc->next)
150 	{
151 	  tpdbc->next = pdbc->next;
152 	  break;
153 	}
154     }
155 
156   /* free this dbc */
157   _iodbcdm_driverunload (pdbc);
158   _iodbcdm_freesqlerrlist (pdbc->herr);
159 
160   if (pdbc->tfile)
161     {
162       MEM_FREE (pdbc->tfile);
163     }
164 
165   SQLSetConnectOption (pdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF);
166 
167   MEM_FREE (pdbc);
168 
169   return SQL_SUCCESS;
170 }
171 
172 
173 RETCODE SQL_API
SQLSetConnectOption(HDBC hdbc,UWORD fOption,UDWORD vParam)174 SQLSetConnectOption (
175     HDBC hdbc,
176     UWORD fOption,
177     UDWORD vParam)
178 {
179   DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
180   STMT_t FAR *pstmt;
181   HPROC hproc = SQL_NULL_HPROC;
182   int sqlstat = en_00000;
183   RETCODE retcode = SQL_SUCCESS;
184 
185   if (hdbc == SQL_NULL_HDBC)
186     {
187       return SQL_INVALID_HANDLE;
188     }
189 
190   /* check option */
191   if (fOption < SQL_CONN_OPT_MIN ||
192 	(fOption > SQL_CONN_OPT_MAX && fOption < SQL_CONNECT_OPT_DRVR_START))
193     {
194       PUSHSQLERR (pdbc->herr, en_S1092);
195 
196       return SQL_ERROR;
197     }
198 
199   /* check state of connection handle */
200   switch (pdbc->state)
201      {
202      case en_dbc_allocated:
203        if (fOption == SQL_TRANSLATE_DLL || fOption == SQL_TRANSLATE_OPTION)
204 	 {
205 	   /* This two options are only meaningful
206 	    * for specified driver. So, has to be
207 	    * set after a dirver has been loaded.
208 	    */
209 	   sqlstat = en_08003;
210 	   break;
211 	 }
212 
213        if (fOption >= SQL_CONNECT_OPT_DRVR_START && pdbc->henv == SQL_NULL_HENV)
214 	 /* An option only meaningful for drivers
215 	  * is passed before loading a driver.
216 	  * We classify this as an invalid option error.
217 	  * This is not documented by MS SDK guide.
218 	  */
219 	 {
220 	   sqlstat = en_S1092;
221 	   break;
222 	 }
223        break;
224 
225      case en_dbc_needdata:
226        sqlstat = en_S1010;
227        break;
228 
229      case en_dbc_connected:
230      case en_dbc_hstmt:
231        if (fOption == SQL_ODBC_CURSORS)
232 	 {
233 	   sqlstat = en_08002;
234 	 }
235        break;
236 
237      default:
238        break;
239      }
240 
241   /* check state of statement handle(s) */
242   for (pstmt = (STMT_t FAR *) pdbc->hstmt;
243       pstmt != NULL && sqlstat == en_00000;
244       pstmt = (STMT_t FAR *) pstmt->next)
245     {
246       if (pstmt->state >= en_stmt_needdata || pstmt->asyn_on != en_NullProc)
247 	{
248 	  sqlstat = en_S1010;
249 	}
250     }
251 
252   if (sqlstat != en_00000)
253     {
254       PUSHSQLERR (pdbc->herr, sqlstat);
255 
256       return SQL_ERROR;
257     }
258 
259   if (fOption == SQL_OPT_TRACE)
260     /* tracing flag can be set before and after connect
261      * and only meaningful for driver manager(actually
262      * there is only one tracing file under one global
263      * environment).
264      */
265     {
266       switch (vParam)
267 	 {
268 	 case SQL_OPT_TRACE_ON:
269 	   if (pdbc->tfile == NULL)
270 	     {
271 	       pdbc->tfile = (char FAR *) MEM_ALLOC (1 +
272 		   STRLEN (SQL_OPT_TRACE_FILE_DEFAULT));
273 
274 	       if (pdbc->tfile == NULL)
275 		 {
276 		   PUSHSQLERR (pdbc->herr, en_S1001);
277 
278 		   return SQL_ERROR;
279 		 }
280 
281 	       STRCPY (pdbc->tfile, SQL_OPT_TRACE_FILE_DEFAULT);
282 	     }
283 
284 	   if (pdbc->tstm == NULL)
285 	     {
286 
287 #if	defined(stderr) && defined(stdout)
288 	       if (STREQ (pdbc->tfile, "stderr"))
289 		 {
290 		   pdbc->tstm = stderr;
291 		 }
292 	       else if (STREQ (pdbc->tfile, "stdout"))
293 		 {
294 		   pdbc->tstm = stdout;
295 		 }
296 	       else
297 #endif
298 
299 		 {
300 		   pdbc->tstm
301 		       = fopen (pdbc->tfile, "a+");
302 		 }
303 
304 	       if (pdbc->tstm)
305 		 {
306 		   pdbc->trace = 1;
307 		 }
308 	       else
309 		 {
310 		   pdbc->trace = 0;
311 
312 		   sqlstat = en_IM013;
313 		   retcode = SQL_ERROR;
314 		 }
315 	     }
316 	   break;
317 
318 	 case SQL_OPT_TRACE_OFF:
319 	   if (pdbc->trace && pdbc->tstm)
320 	     {
321 
322 #if	defined(stderr) && defined(stdout)
323 	       if (stderr != (FILE FAR *) (pdbc->tstm)
324 		   && stdout != (FILE FAR *) (pdbc->tstm))
325 #endif
326 
327 		 {
328 		   fclose (pdbc->tstm);
329 		 }
330 	     }
331 	   pdbc->tstm = NULL;
332 	   pdbc->trace = 0;
333 	   break;
334 
335 	 default:
336 	   PUSHSQLERR (pdbc->herr, en_S1009);
337 	   retcode = SQL_ERROR;
338 	 }
339 
340       if (sqlstat != en_00000)
341 	{
342 	  PUSHSQLERR (pdbc->herr, sqlstat);
343 	}
344 
345       return retcode;
346     }
347 
348   if (fOption == SQL_OPT_TRACEFILE)
349     /* Tracing file can be set before and after connect
350      * and only meaningful for driver manager.
351      */
352     {
353       if (vParam == 0UL || ((char FAR *) vParam)[0] == 0)
354 	{
355 	  PUSHSQLERR (pdbc->herr, en_S1009);
356 
357 	  return SQL_ERROR;
358 	}
359 
360       if (pdbc->tfile && STREQ (pdbc->tfile, vParam))
361 	{
362 	  return SQL_SUCCESS;
363 	}
364 
365       if (pdbc->trace)
366 	{
367 	  PUSHSQLERR (pdbc->herr, en_IM014);
368 
369 	  return SQL_ERROR;
370 	}
371 
372       if (pdbc->tfile)
373 	{
374 	  MEM_FREE (pdbc->tfile);
375 	}
376 
377       pdbc->tfile = (char FAR *) MEM_ALLOC (1 + STRLEN (vParam));
378 
379       if (pdbc->tfile == NULL)
380 	{
381 	  PUSHSQLERR (pdbc->herr, en_S1001);
382 
383 	  return SQL_ERROR;
384 	}
385 
386       STRCPY (pdbc->tfile, vParam);
387 
388       return SQL_SUCCESS;
389     }
390 
391   if (pdbc->state != en_dbc_allocated)
392     {
393       /* If already connected, then, driver's odbc call
394        * will be invoked. Otherwise, we only save the options
395        * and delay the setting process until the connection
396        * been established.
397        */
398       hproc = _iodbcdm_getproc (hdbc, en_SetConnectOption);
399 
400       if (hproc == SQL_NULL_HPROC)
401 	{
402 	  PUSHSQLERR (pdbc->herr, en_IM001);
403 
404 	  return SQL_ERROR;
405 	}
406 
407       CALL_DRIVER (hdbc, retcode, hproc, en_SetConnectOption,
408         (pdbc->dhdbc, fOption, vParam))
409 
410       if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
411 	{
412 	  return retcode;
413 	}
414     }
415 
416   /*
417    * Now, either driver's odbc call was successed or
418    * driver has not been loaded yet. In the first case, we
419    * need flip flag for(such as access_mode, autocommit, ...)
420    * for our finit state machine. While in the second case,
421    * we need save option values(such as current_qualifier, ...)
422    * for delaied setting. So, ...
423    */
424 
425   /* No matter what state we are(i.e. allocated or connected, ..)
426    * we need to flip the flag.
427    */
428   switch (fOption)
429      {
430      case SQL_ACCESS_MODE:
431        pdbc->access_mode = vParam;
432        break;
433 
434      case SQL_AUTOCOMMIT:
435        pdbc->autocommit = vParam;
436        break;
437      }
438 
439   /* state transition */
440   if (pdbc->state != en_dbc_allocated)
441     {
442       return retcode;
443     }
444 
445   /* Only 'allocated' state is possible here, and we need to
446    * save the options for delaied setting.
447    */
448   switch (fOption)
449      {
450      case SQL_CURRENT_QUALIFIER:
451        if (pdbc->current_qualifier != NULL)
452 	 {
453 	   MEM_FREE (pdbc->current_qualifier);
454 	 }
455 
456        if (vParam == 0UL)
457 	 {
458 	   pdbc->current_qualifier = NULL;
459 
460 	   break;
461 	 }
462 
463        pdbc->current_qualifier
464 	   = (char FAR *) MEM_ALLOC (
465 	   STRLEN (vParam) + 1);
466 
467        if (pdbc->current_qualifier == NULL)
468 	 {
469 	   PUSHSQLERR (pdbc->herr, en_S1001);
470 	   return SQL_ERROR;
471 	 }
472 
473        STRCPY (pdbc->current_qualifier, vParam);
474        break;
475 
476      case SQL_LOGIN_TIMEOUT:
477        pdbc->login_timeout = vParam;
478        break;
479 
480      case SQL_ODBC_CURSORS:
481        pdbc->odbc_cursors = vParam;
482        break;
483 
484      case SQL_PACKET_SIZE:
485        pdbc->packet_size = vParam;
486        break;
487 
488      case SQL_QUIET_MODE:
489        pdbc->quiet_mode = vParam;
490        break;
491 
492      case SQL_TXN_ISOLATION:
493        pdbc->txn_isolation = vParam;
494        break;
495 
496      default:
497        /* Since we didn't save the option value for delaied
498         * setting, we should raise an error here.
499         */
500        break;
501      }
502 
503   return retcode;
504 }
505 
506 
507 RETCODE SQL_API
SQLGetConnectOption(HDBC hdbc,UWORD fOption,PTR pvParam)508 SQLGetConnectOption (
509     HDBC hdbc,
510     UWORD fOption,
511     PTR pvParam)
512 {
513   DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
514   int sqlstat = en_00000;
515   HPROC hproc = SQL_NULL_HPROC;
516   RETCODE retcode;
517 
518   if (hdbc == SQL_NULL_HDBC)
519     {
520       return SQL_INVALID_HANDLE;
521     }
522 
523   /* check option */
524   if (fOption < SQL_CONN_OPT_MIN ||
525 	(fOption > SQL_CONN_OPT_MAX && fOption < SQL_CONNECT_OPT_DRVR_START))
526     {
527       PUSHSQLERR (pdbc->herr, en_S1092);
528 
529       return SQL_ERROR;
530     }
531 
532   /* check state */
533   switch (pdbc->state)
534      {
535      case en_dbc_allocated:
536        if (fOption != SQL_ACCESS_MODE
537 	   && fOption != SQL_AUTOCOMMIT
538 	   && fOption != SQL_LOGIN_TIMEOUT
539 	   && fOption != SQL_OPT_TRACE
540 	   && fOption != SQL_OPT_TRACEFILE)
541 	 {
542 	   sqlstat = en_08003;
543 	 }
544        /* MS ODBC SDK document only
545         * allows SQL_ACCESS_MODE
546         * and SQL_AUTOCOMMIT in this
547         * dbc state. We allow another
548         * two options, because they
549         * are only meaningful for driver
550         * manager.
551         */
552        break;
553 
554      case en_dbc_needdata:
555        sqlstat = en_S1010;
556        break;
557 
558      default:
559        break;
560      }
561 
562   if (sqlstat != en_00000)
563     {
564       PUSHSQLERR (pdbc->herr, sqlstat);
565 
566       return SQL_ERROR;
567     }
568 
569   /* Tracing and tracing file options are only
570    * meaningful for driver manager
571    */
572   if (fOption == SQL_OPT_TRACE)
573     {
574       if (pdbc->trace)
575 	*((UDWORD *) pvParam) = (UDWORD) SQL_OPT_TRACE_ON;
576       else
577 	*((UDWORD *) pvParam) = (UDWORD) SQL_OPT_TRACE_OFF;
578 
579       return SQL_SUCCESS;
580     }
581 
582   if (fOption == SQL_OPT_TRACEFILE)
583     {
584       STRCPY (pvParam, pdbc->tfile);
585 
586       return SQL_ERROR;
587     }
588 
589   if (pdbc->state != en_dbc_allocated)
590     /* if already connected, we will invoke driver's function */
591     {
592       hproc = _iodbcdm_getproc (hdbc, en_GetConnectOption);
593 
594       if (hproc == SQL_NULL_HPROC)
595 	{
596 	  PUSHSQLERR (pdbc->herr, en_IM001);
597 
598 	  return SQL_ERROR;
599 	}
600 
601       CALL_DRIVER (hdbc, retcode, hproc, en_GetConnectOption,
602 	(pdbc->dhdbc, fOption, pvParam))
603 
604       return retcode;
605     }
606 
607   /* We needn't to handle options which are not allowed
608    * to be *get* at a allocated dbc state(and two tracing
609    * options which has been handled and returned). Thus,
610    * there are only two possible cases.
611    */
612   switch (fOption)
613      {
614      case SQL_ACCESS_MODE:
615        *((UDWORD *) pvParam) = pdbc->access_mode;
616        break;
617 
618      case SQL_AUTOCOMMIT:
619        *((UDWORD *) pvParam) = pdbc->autocommit;
620        break;
621 
622      case SQL_LOGIN_TIMEOUT:
623        *((UDWORD *) pvParam) = pdbc->login_timeout;
624        break;
625 
626      default:
627        break;
628      }
629 
630   return SQL_SUCCESS;
631 }
632 
633 
634 static RETCODE
_iodbcdm_transact(HDBC hdbc,UWORD fType)635 _iodbcdm_transact (
636     HDBC hdbc,
637     UWORD fType)
638 {
639   DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
640   STMT_t FAR *pstmt;
641   HPROC hproc;
642   RETCODE retcode;
643 
644   /* check state */
645   switch (pdbc->state)
646      {
647      case en_dbc_allocated:
648      case en_dbc_needdata:
649        PUSHSQLERR (pdbc->herr, en_08003);
650        return SQL_ERROR;
651 
652      case en_dbc_connected:
653        return SQL_SUCCESS;
654 
655      case en_dbc_hstmt:
656      default:
657        break;
658      }
659 
660   for (pstmt = (STMT_t FAR *) (pdbc->hstmt);
661       pstmt != NULL;
662       pstmt = pstmt->next)
663     {
664       if (pstmt->state >= en_stmt_needdata
665 	  || pstmt->asyn_on != en_NullProc)
666 	{
667 	  PUSHSQLERR (pdbc->herr, en_S1010);
668 
669 	  return SQL_ERROR;
670 	}
671     }
672 
673   hproc = _iodbcdm_getproc (hdbc, en_Transact);
674 
675   if (hproc == SQL_NULL_HPROC)
676     {
677       PUSHSQLERR (pdbc->herr, en_IM001);
678 
679       return SQL_ERROR;
680     }
681 
682   CALL_DRIVER (hdbc, retcode, hproc, en_Transact,
683     (SQL_NULL_HENV, pdbc->dhdbc, fType))
684 
685   /* state transition */
686   if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
687     {
688       return retcode;
689     }
690 
691   pdbc->state = en_dbc_hstmt;
692 
693   for (pstmt = (STMT_t FAR *) (pdbc->hstmt);
694       pstmt != NULL;
695       pstmt = pstmt->next)
696     {
697       switch (pstmt->state)
698 	 {
699 	 case en_stmt_prepared:
700 	   if (pdbc->cb_commit == SQL_CB_DELETE
701 	       || pdbc->cb_rollback == SQL_CB_DELETE)
702 	     {
703 	       pstmt->state = en_stmt_allocated;
704 	       pstmt->prep_state = 0;
705 	       break;
706 	     }
707 	   break;
708 
709 	 case en_stmt_executed:
710 	 case en_stmt_cursoropen:
711 	 case en_stmt_fetched:
712 	 case en_stmt_xfetched:
713 	   if (!pstmt->prep_state
714 	       && pdbc->cb_commit != SQL_CB_PRESERVE
715 	       && pdbc->cb_rollback != SQL_CB_PRESERVE)
716 	     {
717 	       pstmt->state = en_stmt_allocated;
718 	       pstmt->prep_state = 0;
719 	       pstmt->cursor_state = en_stmt_cursor_no;
720 	       break;
721 	     }
722 
723 	   if (pstmt->prep_state)
724 	     {
725 	       if (pdbc->cb_commit == SQL_CB_DELETE
726 		   || pdbc->cb_rollback == SQL_CB_DELETE)
727 		 {
728 		   pstmt->state = en_stmt_allocated;
729 		   pstmt->prep_state = 0;
730 		   pstmt->cursor_state = en_stmt_cursor_no;
731 		   break;
732 		 }
733 
734 	       if (pdbc->cb_commit == SQL_CB_CLOSE
735 		   || pdbc->cb_rollback == SQL_CB_CLOSE)
736 		 {
737 		   pstmt->state
738 		       = en_stmt_prepared;
739 		   pstmt->cursor_state
740 		       = en_stmt_cursor_no;
741 		   break;
742 		 }
743 	       break;
744 	     }
745 	   break;
746 
747 	 default:
748 	   break;
749 	 }
750     }
751 
752   return retcode;
753 }
754 
755 
756 RETCODE SQL_API
SQLTransact(HENV henv,HDBC hdbc,UWORD fType)757 SQLTransact (
758     HENV henv,
759     HDBC hdbc,
760     UWORD fType)
761 {
762   GENV_t FAR *genv = (GENV_t FAR *) henv;
763   DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
764   HERR herr;
765   RETCODE retcode = 0;
766 
767   if (hdbc != SQL_NULL_HDBC)
768     {
769       herr = pdbc->herr;
770     }
771   else if (henv != SQL_NULL_HENV)
772     {
773       herr = genv->herr;
774     }
775   else
776     {
777       return SQL_INVALID_HANDLE;
778     }
779 
780   /* check argument */
781   if (fType != SQL_COMMIT
782       && fType != SQL_ROLLBACK)
783     {
784       PUSHSQLERR (herr, en_S1012);
785 
786       return SQL_ERROR;
787     }
788 
789   if (hdbc != SQL_NULL_HDBC)
790     {
791       retcode = _iodbcdm_transact (hdbc, fType);
792     }
793   else
794     {
795       for (pdbc = (DBC_t FAR *) (genv->hdbc);
796 	  pdbc != NULL;
797 	  pdbc = pdbc->next)
798 	{
799 	  retcode |= _iodbcdm_transact (hdbc, fType);
800 	}
801     }
802 
803   if (retcode != SQL_SUCCESS
804       && retcode != SQL_SUCCESS_WITH_INFO)
805     {
806       /* fail on one of the connection */
807       return SQL_ERROR;
808     }
809 
810   return retcode;
811 }
812