1/*
2 *  connect.c
3 *
4 *  $Id: connect.c 5545 2000-01-20 13:19:20Z GT $
5 *
6 *  Connect (load) driver
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
41extern	char*	_iodbcdm_getkeyvalbydsn();
42extern	char*	_iodbcdm_getkeyvalinstr();
43extern	RETCODE	_iodbcdm_driverunload();
44
45/*
46 *   Following id string is a copyright mark. Removing(i.e. use
47 *   souce code of this package without it or make it not appear
48 *   in the final object file) or modifing it without permission
49 *   from original author(kejin@empress.com) are copyright
50 *   violation.
51 */
52static	char sccsid[]
53	= "@(#)iODBC driver manager 2.5, Copyright(c) 1995 by Ke Jin";
54
55/* - Load driver share library( or increase its reference count
56 *   if it has already been loaded by another active connection)
57 * - Call driver's SQLAllocEnv() (for the first reference only)
58 * - Call driver's SQLAllocConnect()
59 * - Call driver's SQLSetConnectOption() (set login time out)
60 * - Increase the bookkeeping reference count
61 */
62static RETCODE
63_iodbcdm_driverload (
64    char FAR * path,
65    HDBC hdbc)
66{
67  DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
68  GENV_t FAR *genv;
69  ENV_t FAR *penv = NULL;
70  HDLL hdll;
71  HPROC hproc;
72  RETCODE retcode = SQL_SUCCESS;
73  int sqlstat = en_00000;
74
75  if (path == NULL || path[0] == '\0')
76    {
77      PUSHSQLERR (pdbc->herr, en_IM002);
78
79      return SQL_ERROR;
80    }
81
82  if (hdbc == SQL_NULL_HDBC || pdbc->genv == SQL_NULL_HENV)
83    {
84      return SQL_INVALID_HANDLE;
85    }
86
87  genv = (GENV_t FAR *) pdbc->genv;
88
89  /* This will either load the driver dll or increase its reference count */
90  hdll = _iodbcdm_dllopen ((char FAR *) path);
91
92  if (hdll == SQL_NULL_HDLL)
93    {
94      PUSHSYSERR (pdbc->herr, _iodbcdm_dllerror ());
95      PUSHSQLERR (pdbc->herr, en_IM003);
96      return SQL_ERROR;
97    }
98
99  penv = (ENV_t FAR *) (pdbc->henv);
100
101  if (penv != NULL)
102    {
103      if (penv->hdll != hdll)
104	{
105	  _iodbcdm_driverunload (hdbc);
106	}
107      else
108	{
109	  /*
110  	   * this will not unload the driver but only decrease its internal
111	   * reference count
112	   */
113	  _iodbcdm_dllclose (hdll);
114	}
115    }
116
117  if (penv == NULL)
118    {
119      /*
120       * find out whether this dll has already been loaded on another
121       * connection
122       */
123      for (penv = (ENV_t FAR *) genv->henv;
124	  penv != NULL;
125	  penv = (ENV_t FAR *) penv->next)
126	{
127	  if (penv->hdll == hdll)
128	    {
129	      /*
130  	       * this will not unload the driver but only decrease its internal
131	       * reference count
132	       */
133	      _iodbcdm_dllclose (hdll);
134	      break;
135	    }
136	}
137
138      if (penv == NULL)
139	/* no connection attaching with this dll */
140	{
141	  int i;
142
143	  /* create a new dll env instance */
144	  penv = (ENV_t FAR *) MEM_ALLOC (sizeof (ENV_t));
145
146	  if (penv == NULL)
147	    {
148	      _iodbcdm_dllclose (hdll);
149
150	      PUSHSQLERR (pdbc->herr, en_S1001);
151
152	      return SQL_ERROR;
153	    }
154
155	  for (i = 0; i < SQL_EXT_API_LAST + 1; i++)
156	    {
157	      (penv->dllproc_tab)[i] = SQL_NULL_HPROC;
158	    }
159
160	  pdbc->henv = penv;
161	  penv->hdll = hdll;
162
163	  /* call driver's SQLAllocHandle() or SQLAllocEnv() */
164
165#if (ODBCVER >= 0x0300)
166	  hproc = _iodbcdm_getproc (hdbc, en_AllocHandle);
167
168	  if (hproc)
169	    {
170	      CALL_DRIVER (hdbc, retcode, hproc, en_AllocHandle,
171		  (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(penv->dhenv)))
172	    }
173	  else			/* try driver's SQLAllocEnv() */
174#endif
175	    {
176	      hproc = _iodbcdm_getproc (hdbc, en_AllocEnv);
177
178	      if (hproc == SQL_NULL_HPROC)
179		{
180		  sqlstat = en_IM004;
181		}
182	      else
183		{
184		  CALL_DRIVER (hdbc, retcode, hproc,
185		      en_AllocEnv, (&(penv->dhenv)))
186		}
187	    }
188
189	  if (retcode == SQL_ERROR)
190	    {
191	      sqlstat = en_IM004;
192	    }
193
194	  if (sqlstat != en_00000)
195	    {
196	      _iodbcdm_dllclose (hdll);
197	      MEM_FREE (penv);
198	      PUSHSQLERR (pdbc->herr, en_IM004);
199
200	      return SQL_ERROR;
201	    }
202
203	  /* insert into dll env list */
204	  penv->next = (ENV_t FAR *) genv->henv;
205	  genv->henv = penv;
206
207	  /* initiate this new env entry */
208	  penv->refcount = 0;	/* we will increase it after
209				 * driver's SQLAllocConnect()
210				 * success
211				 */
212	}
213
214      pdbc->henv = penv;
215
216      if (pdbc->dhdbc == SQL_NULL_HDBC)
217	{
218
219#if (ODBCVER >= 0x0300)
220	  hproc = _iodbcdm_getproc (hdbc, en_AllocHandle);
221
222	  if (hproc)
223	    {
224	      CALL_DRIVER (hdbc, retcode, hproc, en_AllocHandle,
225		  (SQL_HANDLE_DBC, penv->dhenv, &(pdbc->dhdbc)))
226	    }
227	  else
228#endif
229
230	    {
231	      hproc = _iodbcdm_getproc (hdbc, en_AllocConnect);
232
233	      if (hproc == SQL_NULL_HPROC)
234		{
235		  sqlstat = en_IM005;
236		}
237	      else
238		{
239		  CALL_DRIVER (hdbc, retcode, hproc,
240		      en_AllocConnect, (penv->dhenv, &(pdbc->dhdbc)))
241		}
242	    }
243
244	  if (retcode == SQL_ERROR)
245	    {
246	      sqlstat = en_IM005;
247	    }
248
249	  if (sqlstat != en_00000)
250	    {
251	      _iodbcdm_driverunload (hdbc);
252
253	      pdbc->dhdbc = SQL_NULL_HDBC;
254	      PUSHSQLERR (pdbc->herr, en_IM005);
255
256	      return SQL_ERROR;
257	    }
258	}
259
260      pdbc->henv = penv;
261      penv->refcount++;		/* bookkeeping reference count on this driver */
262    }
263
264  /* driver's login timeout option must been set before
265   * its SQLConnect() call */
266  if (pdbc->login_timeout != 0UL)
267    {
268      hproc = _iodbcdm_getproc (hdbc, en_SetConnectOption);
269
270      if (hproc == SQL_NULL_HPROC)
271	{
272	  sqlstat = en_IM004;
273	}
274      else
275	{
276	  CALL_DRIVER (hdbc, retcode, hproc,
277	      en_SetConnectOption, (
278		  pdbc->dhdbc,
279		  SQL_LOGIN_TIMEOUT,
280		  pdbc->login_timeout))
281
282	      if (retcode == SQL_ERROR)
283	    {
284	      PUSHSQLERR (pdbc->herr, en_IM006);
285
286	      return SQL_SUCCESS_WITH_INFO;
287	    }
288	}
289    }
290
291  return SQL_SUCCESS;
292}
293
294
295/* - Call driver's SQLFreeConnect()
296 * - Call driver's SQLFreeEnv() ( for the last reference only)
297 * - Unload the share library( or decrease its reference
298 *   count if it is not the last referenct )
299 * - decrease bookkeeping reference count
300 * - state transition to allocated
301 */
302RETCODE
303_iodbcdm_driverunload (HDBC hdbc)
304{
305  DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
306  ENV_t FAR *penv;
307  ENV_t FAR *tpenv;
308  GENV_t FAR *genv;
309  HPROC hproc;
310  RETCODE retcode = SQL_SUCCESS;
311
312  if (hdbc == SQL_NULL_HDBC)
313    {
314      return SQL_INVALID_HANDLE;
315    }
316
317  /* no pointer check will be performed in this function */
318  penv = (ENV_t FAR *) pdbc->henv;
319  genv = (GENV_t FAR *) pdbc->genv;
320
321  if (penv == NULL || penv->hdll == SQL_NULL_HDLL)
322    {
323      return SQL_SUCCESS;
324    }
325
326#if (ODBCVER >= 0x0300)
327  hproc = _iodbcdm_getproc (hdbc, en_FreeHandle);
328
329  if (hproc)
330    {
331      CALL_DRIVER (hdbc, retcode, hproc, en_FreeHandle,
332	  (SQL_HANDLE_DBC, pdbc->dhdbc))
333    }
334  else
335#endif
336
337    {
338      hproc = _iodbcdm_getproc (hdbc, en_FreeConnect);
339
340      if (hproc != SQL_NULL_HPROC)
341	{
342	  CALL_DRIVER (hdbc, retcode, hproc,
343	      en_FreeConnect, (pdbc->dhdbc))
344
345	      pdbc->dhdbc = SQL_NULL_HDBC;
346	}
347    }
348
349  penv->refcount--;
350
351  if (!penv->refcount)
352    /* no other connections still attaching with this driver */
353    {
354
355#if (ODBCVER >= 0x0300)
356      hproc = _iodbcdm_getproc (hdbc, en_FreeHandle);
357
358      if (hproc)
359	{
360	  CALL_DRIVER (hdbc, retcode, hproc, en_FreeHandle,
361	      (SQL_HANDLE_ENV, penv->dhenv))
362	}
363      else
364#endif
365
366	{
367	  hproc = _iodbcdm_getproc (hdbc, en_FreeEnv);
368
369	  if (hproc != SQL_NULL_HPROC)
370	    {
371	      CALL_DRIVER (hdbc, retcode, hproc, en_FreeEnv,
372		  (penv->dhenv))
373
374		  penv->dhenv = SQL_NULL_HENV;
375	    }
376	}
377
378      _iodbcdm_dllclose (penv->hdll);
379
380      penv->hdll = SQL_NULL_HDLL;
381
382      for (tpenv = (ENV_t FAR *) genv->henv;
383	  tpenv != NULL;
384	  tpenv = (ENV_t FAR *) penv->next)
385	{
386	  if (tpenv == penv)
387	    {
388	      genv->henv = penv->next;
389	      break;
390	    }
391
392	  if (tpenv->next == penv)
393	    {
394	      tpenv->next = penv->next;
395	      break;
396	    }
397	}
398
399      MEM_FREE (penv);
400    }
401
402  pdbc->henv = SQL_NULL_HENV;
403  pdbc->hstmt = SQL_NULL_HSTMT;
404  /* pdbc->herr = SQL_NULL_HERR;
405     -- delay to DM's SQLFreeConnect() */
406  pdbc->dhdbc = SQL_NULL_HDBC;
407  pdbc->state = en_dbc_allocated;
408
409  /* set connect options to default values */
410	/**********
411	pdbc->access_mode	= SQL_MODE_DEFAULT;
412	pdbc->autocommit	= SQL_AUTOCOMMIT_DEFAULT;
413	pdbc->login_timeout 	= 0UL;
414	**********/
415  pdbc->odbc_cursors = SQL_CUR_DEFAULT;
416  pdbc->packet_size = 0UL;
417  pdbc->quiet_mode = (UDWORD) NULL;
418  pdbc->txn_isolation = SQL_TXN_READ_UNCOMMITTED;
419
420  if (pdbc->current_qualifier != NULL)
421    {
422      MEM_FREE (pdbc->current_qualifier);
423      pdbc->current_qualifier = NULL;
424    }
425
426  return SQL_SUCCESS;
427}
428
429
430static RETCODE
431_iodbcdm_dbcdelayset (HDBC hdbc)
432{
433  DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
434  ENV_t FAR *penv;
435  HPROC hproc;
436  RETCODE retcode = SQL_SUCCESS;
437  RETCODE ret;
438
439  penv = pdbc->henv;
440
441  hproc = _iodbcdm_getproc (hdbc, en_SetConnectOption);
442
443  if (hproc == SQL_NULL_HPROC)
444    {
445      PUSHSQLERR (pdbc->herr, en_IM006);
446
447      return SQL_SUCCESS_WITH_INFO;
448    }
449
450  if (pdbc->access_mode != SQL_MODE_DEFAULT)
451    {
452      CALL_DRIVER (hdbc, ret, hproc,
453	  en_SetConnectOption, (
454	      SQL_ACCESS_MODE,
455	      pdbc->access_mode))
456
457	  retcode |= ret;
458    }
459
460  if (pdbc->autocommit != SQL_AUTOCOMMIT_DEFAULT)
461    {
462      CALL_DRIVER (hdbc, ret, hproc,
463	  en_SetConnectOption, (
464	      pdbc->dhdbc,
465	      SQL_AUTOCOMMIT,
466	      pdbc->autocommit))
467
468	  retcode |= ret;
469    }
470
471  if (pdbc->current_qualifier != NULL)
472    {
473      CALL_DRIVER (hdbc, ret, hproc,
474	  en_SetConnectOption, (
475	      pdbc->dhdbc,
476	      SQL_CURRENT_QUALIFIER,
477	      pdbc->current_qualifier))
478
479	  retcode |= ret;
480    }
481
482  if (pdbc->packet_size != 0UL)
483    {
484      CALL_DRIVER (hdbc, ret, hproc,
485	  en_SetConnectOption, (
486	      pdbc->dhdbc,
487	      SQL_PACKET_SIZE,
488	      pdbc->packet_size))
489
490	  retcode |= ret;
491    }
492
493  if (pdbc->quiet_mode != (UDWORD) NULL)
494    {
495      CALL_DRIVER (hdbc, ret, hproc,
496	  en_SetConnectOption, (
497	      pdbc->dhdbc,
498	      SQL_QUIET_MODE,
499	      pdbc->quiet_mode))
500
501	  retcode |= ret;
502    }
503
504  if (pdbc->txn_isolation != SQL_TXN_READ_UNCOMMITTED)
505    {
506      CALL_DRIVER (hdbc, ret, hproc,
507	  en_SetConnectOption, (
508	      pdbc->dhdbc,
509	      SQL_TXN_ISOLATION,
510	      pdbc->txn_isolation))
511    }
512
513  /* check error code for driver's SQLSetConnectOption() call */
514  if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
515    {
516      PUSHSQLERR (pdbc->herr, en_IM006);
517
518      retcode = SQL_ERROR;
519    }
520
521  /* get cursor behavior on transaction commit or rollback */
522  hproc = _iodbcdm_getproc (hdbc, en_GetInfo);
523
524  if (hproc == SQL_NULL_HPROC)
525    {
526      PUSHSQLERR (pdbc->herr, en_01000);
527
528      return retcode;
529    }
530
531  CALL_DRIVER (hdbc, ret, hproc,
532      en_GetInfo, (
533	  pdbc->dhdbc,
534	  SQL_CURSOR_COMMIT_BEHAVIOR,
535	  (PTR) & (pdbc->cb_commit),
536	  sizeof (pdbc->cb_commit),
537	  NULL))
538
539      retcode |= ret;
540
541  CALL_DRIVER (hdbc, ret, hproc,
542      en_GetInfo, (
543	  pdbc->dhdbc,
544	  SQL_CURSOR_ROLLBACK_BEHAVIOR,
545	  (PTR) & (pdbc->cb_rollback),
546	  sizeof (pdbc->cb_rollback),
547	  NULL))
548
549      retcode |= ret;
550
551  if (retcode != SQL_SUCCESS
552      && retcode != SQL_SUCCESS_WITH_INFO)
553    {
554      return SQL_ERROR;
555    }
556
557  return retcode;
558}
559
560
561static RETCODE
562_iodbcdm_settracing (HDBC hdbc, char *dsn, int dsnlen)
563{
564  char buf[256];
565  char *ptr;
566  RETCODE setopterr = SQL_SUCCESS;
567
568  /* Get Driver's DLL path from specificed or default dsn section */
569  ptr = _iodbcdm_getkeyvalbydsn (dsn, dsnlen, "TraceFile",
570      (char FAR *) buf, sizeof (buf));
571
572  if (ptr == NULL || ptr[0] == '\0')
573    {
574      ptr = (char FAR *) (SQL_OPT_TRACE_FILE_DEFAULT);
575    }
576
577  setopterr |= SQLSetConnectOption (hdbc, SQL_OPT_TRACEFILE, (UDWORD) (ptr));
578
579  ptr = _iodbcdm_getkeyvalbydsn (dsn, dsnlen, "Trace",
580      (char FAR *) buf, sizeof (buf));
581
582  if (ptr != NULL)
583    {
584      UDWORD opt = (UDWORD) (-1L);
585
586      if (STREQ (ptr, "ON")
587	  || STREQ (ptr, "On")
588	  || STREQ (ptr, "on")
589	  || STREQ (ptr, "1"))
590	{
591	  opt = SQL_OPT_TRACE_ON;
592	}
593
594      if (STREQ (ptr, "OFF")
595	  || STREQ (ptr, "Off")
596	  || STREQ (ptr, "off")
597	  || STREQ (ptr, "0"))
598	{
599	  opt = SQL_OPT_TRACE_OFF;
600	}
601
602      if (opt != (UDWORD) (-1L))
603	{
604	  setopterr |= SQLSetConnectOption (hdbc,
605	      SQL_OPT_TRACE, opt);
606	}
607    }
608
609  return setopterr;
610}
611
612
613RETCODE SQL_API
614SQLConnect (
615    HDBC hdbc,
616    UCHAR FAR * szDSN,
617    SWORD cbDSN,
618    UCHAR FAR * szUID,
619    SWORD cbUID,
620    UCHAR FAR * szAuthStr,
621    SWORD cbAuthStr)
622{
623  DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
624  RETCODE retcode = SQL_SUCCESS;
625  RETCODE setopterr = SQL_SUCCESS;
626  char driver[1024] = {'\0'};	/* MS SDK Guide
627				 * specifies driver
628				 * path can't longer
629				 * than 255. */
630  char *ptr;
631  HPROC hproc;
632
633  if (hdbc == SQL_NULL_HDBC)
634    {
635      return SQL_INVALID_HANDLE;
636    }
637
638  /* check arguments */
639  if ((cbDSN < 0 && cbDSN != SQL_NTS)
640      || (cbUID < 0 && cbUID != SQL_NTS)
641      || (cbAuthStr < 0 && cbAuthStr != SQL_NTS)
642      || (cbDSN > SQL_MAX_DSN_LENGTH))
643    {
644      PUSHSQLERR (pdbc->herr, en_S1090);
645
646      return SQL_ERROR;
647    }
648
649  if (szDSN == NULL || cbDSN == 0)
650    {
651      PUSHSQLERR (pdbc->herr, en_IM002);
652
653      return SQL_ERROR;
654    }
655
656  /* check state */
657  if (pdbc->state != en_dbc_allocated)
658    {
659      PUSHSQLERR (pdbc->herr, en_08002);
660
661      return SQL_ERROR;
662    }
663
664  setopterr |= _iodbcdm_settracing (hdbc,
665      (char *) szDSN, cbDSN);
666
667  ptr = _iodbcdm_getkeyvalbydsn (szDSN, cbDSN, "Driver",
668      (char FAR *) driver, sizeof (driver));
669
670  if (ptr == NULL)
671    /* No specified or default dsn section or
672     * no driver specification in this dsn section */
673    {
674      PUSHSQLERR (pdbc->herr, en_IM002);
675
676      return SQL_ERROR;
677    }
678
679  retcode = _iodbcdm_driverload (driver, hdbc);
680
681  switch (retcode)
682     {
683     case SQL_SUCCESS:
684       break;
685
686     case SQL_SUCCESS_WITH_INFO:
687       setopterr = SQL_ERROR;
688       /* unsuccessed in calling driver's
689        * SQLSetConnectOption() to set login
690        * timeout.
691        */
692       break;
693
694     default:
695       return retcode;
696     }
697
698  hproc = _iodbcdm_getproc (hdbc, en_Connect);
699
700  if (hproc == SQL_NULL_HPROC)
701    {
702      _iodbcdm_driverunload (hdbc);
703
704      PUSHSQLERR (pdbc->herr, en_IM001);
705
706      return SQL_ERROR;
707    }
708
709  CALL_DRIVER (hdbc, retcode, hproc, en_Connect, (
710	  pdbc->dhdbc,
711	  szDSN, cbDSN,
712	  szUID, cbUID,
713	  szAuthStr, cbAuthStr))
714
715  if (retcode != SQL_SUCCESS
716      && retcode != SQL_SUCCESS_WITH_INFO)
717    {
718      /* not unload driver for retrive error
719       * messge from driver */
720		/*********
721		_iodbcdm_driverunload( hdbc );
722		**********/
723
724      return retcode;
725    }
726
727  /* state transition */
728  pdbc->state = en_dbc_connected;
729
730  /* do delaid option setting */
731  setopterr |= _iodbcdm_dbcdelayset (hdbc);
732
733  if (setopterr != SQL_SUCCESS)
734    {
735      return SQL_SUCCESS_WITH_INFO;
736    }
737
738  return retcode;
739}
740
741
742RETCODE SQL_API
743SQLDriverConnect (
744    HDBC hdbc,
745    SQLHWND hwnd,
746    UCHAR FAR * szConnStrIn,
747    SWORD cbConnStrIn,
748    UCHAR FAR * szConnStrOut,
749    SWORD cbConnStrOutMax,
750    SWORD FAR * pcbConnStrOut,
751    UWORD fDriverCompletion)
752{
753  DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
754  HDLL hdll;
755  char FAR *drv;
756  char drvbuf[1024];
757  char FAR *dsn;
758  char dsnbuf[SQL_MAX_DSN_LENGTH + 1];
759  UCHAR cnstr2drv[1024];
760
761  HPROC hproc;
762  HPROC dialproc;
763
764  int sqlstat = en_00000;
765  RETCODE retcode = SQL_SUCCESS;
766  RETCODE setopterr = SQL_SUCCESS;
767
768  if (hdbc == SQL_NULL_HDBC)
769    {
770      return SQL_INVALID_HANDLE;
771    }
772
773  /* check arguments */
774  if ((cbConnStrIn < 0 && cbConnStrIn != SQL_NTS)
775      || cbConnStrOutMax < 0)
776    {
777      PUSHSQLERR (pdbc->herr, en_S1090);
778
779      return SQL_ERROR;
780    }
781
782  /* check state */
783  if (pdbc->state != en_dbc_allocated)
784    {
785      PUSHSQLERR (pdbc->herr, en_08002);
786
787      return SQL_ERROR;
788    }
789
790  drv = _iodbcdm_getkeyvalinstr (szConnStrIn, cbConnStrIn,
791      "DRIVER", drvbuf, sizeof (drvbuf));
792
793  dsn = _iodbcdm_getkeyvalinstr (szConnStrIn, cbConnStrIn,
794      "DSN", dsnbuf, sizeof (dsnbuf));
795
796  switch (fDriverCompletion)
797     {
798     case SQL_DRIVER_NOPROMPT:
799       break;
800
801     case SQL_DRIVER_COMPLETE:
802     case SQL_DRIVER_COMPLETE_REQUIRED:
803       if (dsn != NULL || drv != NULL)
804	 {
805	   break;
806	 }
807       /* fall to next case */
808     case SQL_DRIVER_PROMPT:
809       /* Get data source dialog box function from
810        * current executable */
811       hdll = _iodbcdm_dllopen ((char FAR *) NULL);
812       dialproc = _iodbcdm_dllproc (hdll,
813	   "_iodbcdm_drvconn_dialbox");
814
815       if (dialproc == SQL_NULL_HPROC)
816	 {
817	   sqlstat = en_IM008;
818	   break;
819	 }
820
821       retcode = dialproc (
822	   hwnd,		/* window or display handle */
823	   dsnbuf,		/* input/output dsn buf */
824	   sizeof (dsnbuf),	/* buf size */
825	   &sqlstat);		/* error code */
826
827       if (retcode != SQL_SUCCESS)
828	 {
829	   break;
830	 }
831
832       if (cbConnStrIn == SQL_NTS)
833	 {
834	   cbConnStrIn = STRLEN (szConnStrIn);
835	 }
836
837       dsn = dsnbuf;
838
839       if (dsn[0] == '\0')
840	 {
841	   dsn = "default";
842	 }
843
844       if (cbConnStrIn > sizeof (cnstr2drv)
845	   - STRLEN (dsn) - STRLEN ("DSN=;") - 1)
846	 {
847	   sqlstat = en_S1001;	/* a lazy way to avoid
848				 * using heap memory */
849	   break;
850	 }
851
852       sprintf ((char*)cnstr2drv, "DSN=%s;", dsn);
853       cbConnStrIn += STRLEN (cnstr2drv);
854       STRNCAT (cnstr2drv, szConnStrIn, cbConnStrIn);
855       szConnStrIn = cnstr2drv;
856       break;
857
858     default:
859       sqlstat = en_S1110;
860       break;
861     }
862
863  if (sqlstat != en_00000)
864    {
865      PUSHSQLERR (pdbc->herr, sqlstat);
866
867      return SQL_ERROR;
868    }
869
870  if (dsn == NULL || dsn[0] == '\0')
871    {
872      dsn = "default";
873    }
874  else
875    /* if you want tracing, you must use a DSN */
876    {
877      setopterr |= _iodbcdm_settracing (hdbc,
878	  (char *) dsn, SQL_NTS);
879    }
880
881  if (drv == NULL || drv[0] == '\0')
882    {
883      drv = _iodbcdm_getkeyvalbydsn (dsn, SQL_NTS, "Driver",
884	  drvbuf, sizeof (drvbuf));
885    }
886
887  if (drv == NULL)
888    {
889      PUSHSQLERR (pdbc->herr, en_IM002);
890
891      return SQL_ERROR;
892    }
893
894  retcode = _iodbcdm_driverload (drv, hdbc);
895
896  switch (retcode)
897     {
898     case SQL_SUCCESS:
899       break;
900
901     case SQL_SUCCESS_WITH_INFO:
902       setopterr = SQL_ERROR;
903       /* unsuccessed in calling driver's
904        * SQLSetConnectOption() to set login
905        * timeout.
906        */
907       break;
908
909     default:
910       return retcode;
911     }
912
913  hproc = _iodbcdm_getproc (hdbc, en_DriverConnect);
914
915  if (hproc == SQL_NULL_HPROC)
916    {
917      _iodbcdm_driverunload (hdbc);
918
919      PUSHSQLERR (pdbc->herr, en_IM001);
920
921      return SQL_ERROR;
922    }
923
924  CALL_DRIVER (hdbc, retcode, hproc, en_DriverConnect, (
925	  pdbc->dhdbc, hwnd,
926	  szConnStrIn, cbConnStrIn,
927	  szConnStrOut, cbConnStrOutMax,
928	  pcbConnStrOut, fDriverCompletion))
929
930  if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
931    {
932      /* don't unload driver here for retrive
933       * error message from driver */
934		/********
935		_iodbcdm_driverunload( hdbc );
936		*********/
937
938      return retcode;
939    }
940
941  /* state transition */
942  pdbc->state = en_dbc_connected;
943
944  /* do delaid option setting */
945  setopterr |= _iodbcdm_dbcdelayset (hdbc);
946
947  if (setopterr != SQL_SUCCESS)
948    {
949      return SQL_SUCCESS_WITH_INFO;
950    }
951
952  return retcode;
953}
954
955
956RETCODE SQL_API
957SQLBrowseConnect (
958    HDBC hdbc,
959    UCHAR FAR * szConnStrIn,
960    SWORD cbConnStrIn,
961    UCHAR FAR * szConnStrOut,
962    SWORD cbConnStrOutMax,
963    SWORD FAR * pcbConnStrOut)
964{
965  DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
966  char FAR *drv;
967  char drvbuf[1024];
968  char FAR *dsn;
969  char dsnbuf[SQL_MAX_DSN_LENGTH + 1];
970
971  HPROC hproc;
972
973  RETCODE retcode = SQL_SUCCESS;
974  RETCODE setopterr = SQL_SUCCESS;
975
976  if (hdbc == SQL_NULL_HDBC)
977    {
978      return SQL_INVALID_HANDLE;
979    }
980
981  /* check arguments */
982  if ((cbConnStrIn < 0 && cbConnStrIn != SQL_NTS) || cbConnStrOutMax < 0)
983    {
984      PUSHSQLERR (pdbc->herr, en_S1090);
985
986      return SQL_ERROR;
987    }
988
989  if (pdbc->state == en_dbc_allocated)
990    {
991      drv = _iodbcdm_getkeyvalinstr (szConnStrIn, cbConnStrIn,
992	  "DRIVER", drvbuf, sizeof (drvbuf));
993
994      dsn = _iodbcdm_getkeyvalinstr (szConnStrIn, cbConnStrIn,
995	  "DSN", dsnbuf, sizeof (dsnbuf));
996
997      if (dsn == NULL || dsn[0] == '\0')
998	{
999	  dsn = "default";
1000	}
1001      else
1002	/* if you want tracing, you must use a DSN */
1003	{
1004	  setopterr |= _iodbcdm_settracing (hdbc,
1005	      (char *) dsn, SQL_NTS);
1006	}
1007
1008      if (drv == NULL || drv[0] == '\0')
1009	{
1010	  drv = _iodbcdm_getkeyvalbydsn (dsn, SQL_NTS, "Driver",
1011	      drvbuf, sizeof (drvbuf));
1012	}
1013
1014      if (drv == NULL)
1015	{
1016	  PUSHSQLERR (pdbc->herr, en_IM002);
1017
1018	  return SQL_ERROR;
1019	}
1020
1021      retcode = _iodbcdm_driverload (drv, hdbc);
1022
1023      switch (retcode)
1024	 {
1025	 case SQL_SUCCESS:
1026	   break;
1027
1028	 case SQL_SUCCESS_WITH_INFO:
1029	   setopterr = SQL_ERROR;
1030	   /* unsuccessed in calling driver's
1031	    * SQLSetConnectOption() to set login
1032	    * timeout.
1033	    */
1034	   break;
1035
1036	 default:
1037	   return retcode;
1038	 }
1039    }
1040  else if (pdbc->state != en_dbc_needdata)
1041    {
1042      PUSHSQLERR (pdbc->herr, en_08002);
1043
1044      return SQL_ERROR;
1045    }
1046
1047  hproc = _iodbcdm_getproc (hdbc, en_BrowseConnect);
1048
1049  if (hproc == SQL_NULL_HPROC)
1050    {
1051      _iodbcdm_driverunload (hdbc);
1052
1053      pdbc->state = en_dbc_allocated;
1054
1055      PUSHSQLERR (pdbc->herr, en_IM001);
1056
1057      return SQL_ERROR;
1058    }
1059
1060  CALL_DRIVER (hdbc, retcode, hproc, en_BrowseConnect, (
1061	  pdbc->dhdbc,
1062	  szConnStrIn, cbConnStrIn,
1063	  szConnStrOut, cbConnStrOutMax,
1064	  pcbConnStrOut))
1065
1066  switch (retcode)
1067     {
1068     case SQL_SUCCESS:
1069     case SQL_SUCCESS_WITH_INFO:
1070       pdbc->state = en_dbc_connected;
1071       setopterr |= _iodbcdm_dbcdelayset (hdbc);
1072       if (setopterr != SQL_SUCCESS)
1073	 {
1074	   retcode = SQL_SUCCESS_WITH_INFO;
1075	 }
1076       break;
1077
1078     case SQL_NEED_DATA:
1079       pdbc->state = en_dbc_needdata;
1080       break;
1081
1082     case SQL_ERROR:
1083       pdbc->state = en_dbc_allocated;
1084       /* but the driver will not unloaded
1085        * to allow application retrive err
1086        * message from driver
1087        */
1088       break;
1089
1090     default:
1091       break;
1092     }
1093
1094  return retcode;
1095}
1096
1097
1098RETCODE SQL_API
1099SQLDisconnect (HDBC hdbc)
1100{
1101  DBC_t FAR *pdbc = (DBC_t *) hdbc;
1102  STMT_t FAR *pstmt;
1103  RETCODE retcode;
1104  HPROC hproc;
1105
1106  int sqlstat = en_00000;
1107
1108  if (hdbc == SQL_NULL_HDBC)
1109    {
1110      return SQL_INVALID_HANDLE;
1111    }
1112
1113  /* check hdbc state */
1114  if (pdbc->state == en_dbc_allocated)
1115    {
1116      sqlstat = en_08003;
1117    }
1118
1119  /* check stmt(s) state */
1120  for (pstmt = (STMT_t FAR *) pdbc->hstmt;
1121      pstmt != NULL && sqlstat == en_00000;
1122      pstmt = (STMT_t FAR *) pstmt->next)
1123    {
1124      if (pstmt->state >= en_stmt_needdata
1125	  || pstmt->asyn_on != en_NullProc)
1126	/* In this case one need to call
1127	 * SQLCancel() first */
1128	{
1129	  sqlstat = en_S1010;
1130	}
1131    }
1132
1133  if (sqlstat == en_00000)
1134    {
1135      hproc = _iodbcdm_getproc (hdbc, en_Disconnect);
1136
1137      if (hproc == SQL_NULL_HPROC)
1138	{
1139	  sqlstat = en_IM001;
1140	}
1141    }
1142
1143  if (sqlstat != en_00000)
1144    {
1145      PUSHSQLERR (pdbc->herr, sqlstat);
1146
1147      return SQL_ERROR;
1148    }
1149
1150  CALL_DRIVER (hdbc, retcode, hproc, en_Disconnect, (
1151	  pdbc->dhdbc))
1152
1153  if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
1154    {
1155      /* diff from MS specs. We disallow
1156       * driver SQLDisconnect() return
1157       * SQL_SUCCESS_WITH_INFO and post
1158       * error message.
1159       */
1160      retcode = SQL_SUCCESS;
1161    }
1162  else
1163    {
1164      return retcode;
1165    }
1166
1167  /* free all statement handle(s) on this connection */
1168  for (; pdbc->hstmt;)
1169    {
1170      _iodbcdm_dropstmt (pdbc->hstmt);
1171    }
1172
1173  /* state transition */
1174  if (retcode == SQL_SUCCESS)
1175    {
1176      pdbc->state = en_dbc_allocated;
1177    }
1178
1179  return retcode;
1180}
1181
1182
1183RETCODE SQL_API
1184SQLNativeSql (
1185    HDBC hdbc,
1186    UCHAR FAR * szSqlStrIn,
1187    SDWORD cbSqlStrIn,
1188    UCHAR FAR * szSqlStr,
1189    SDWORD cbSqlStrMax,
1190    SDWORD FAR * pcbSqlStr)
1191{
1192  DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
1193  HPROC hproc;
1194  int sqlstat = en_00000;
1195  RETCODE retcode;
1196
1197  if (hdbc == SQL_NULL_HDBC)
1198    {
1199      return SQL_INVALID_HANDLE;
1200    }
1201
1202  /* check argument */
1203  if (szSqlStrIn == NULL)
1204    {
1205      sqlstat = en_S1009;
1206    }
1207  else if (cbSqlStrIn < 0 && cbSqlStrIn != SQL_NTS)
1208    {
1209      sqlstat = en_S1090;
1210    }
1211
1212  if (sqlstat != en_00000)
1213    {
1214      PUSHSQLERR (pdbc->herr, sqlstat);
1215
1216      return SQL_ERROR;
1217    }
1218
1219  /* check state */
1220  if (pdbc->state <= en_dbc_needdata)
1221    {
1222      PUSHSQLERR (pdbc->herr, en_08003);
1223
1224      return SQL_ERROR;
1225    }
1226
1227  /* call driver */
1228  hproc = _iodbcdm_getproc (hdbc, en_NativeSql);
1229
1230  if (hproc == SQL_NULL_HPROC)
1231    {
1232      PUSHSQLERR (pdbc->herr, en_IM001);
1233
1234      return SQL_ERROR;
1235    }
1236
1237  CALL_DRIVER (hdbc, retcode, hproc, en_NativeSql,
1238    (pdbc->dhdbc, szSqlStrIn, cbSqlStrIn, szSqlStr, cbSqlStrMax, pcbSqlStr))
1239
1240  return retcode;
1241}
1242