1 /*
2  *  info.c
3  *
4  *  $Id: info.c 5714 2000-01-27 22:47:49Z GT $
5  *
6  *  Information 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 
41 #include	<stdio.h>
42 #include	<ctype.h>
43 
44 #define SECT1			"ODBC Data Sources"
45 #define SECT2			"Default"
46 #define MAX_ENTRIES		1024
47 
48 extern char * _iodbcdm_getinifile (char *buf, int size);
49 extern char * _iodbcdm_getkeyvalbydsn (char *dsn, int dsnlen, char *keywd, char *value, int size);
50 
51 static int
stricmp(const char * s1,const char * s2)52 stricmp (const char *s1, const char *s2)
53 {
54   int cmp;
55 
56   while (*s1)
57     {
58       if ((cmp = toupper (*s1) - toupper (*s2)) != 0)
59 	return cmp;
60       s1++;
61       s2++;
62     }
63   return (*s2) ? -1 : 0;
64 }
65 
66 static int
SectSorter(const void * p1,const void * p2)67 SectSorter (const void *p1, const void *p2)
68 {
69   char **s1 = (char **) p1;
70   char **s2 = (char **) p2;
71 
72   return stricmp (*s1, *s2);
73 }
74 
75 
76 RETCODE SQL_API
SQLDataSources(HENV henv,UWORD fDir,UCHAR FAR * szDSN,SWORD cbDSNMax,SWORD FAR * pcbDSN,UCHAR FAR * szDesc,SWORD cbDescMax,SWORD FAR * pcbDesc)77 SQLDataSources (
78     HENV henv,
79     UWORD fDir,
80     UCHAR FAR * szDSN,
81     SWORD cbDSNMax,
82     SWORD FAR * pcbDSN,
83     UCHAR FAR * szDesc,
84     SWORD cbDescMax,
85     SWORD FAR * pcbDesc)
86 {
87   GENV_t FAR *genv = (GENV_t FAR *) henv;
88   char *path;
89   char buf[1024];
90   FILE *fp;
91   int i;
92   static int cur_entry = -1;
93   static int num_entries = 0;
94   static char **sect = NULL;
95 
96   if (henv == SQL_NULL_HENV)
97     {
98       return SQL_INVALID_HANDLE;
99     }
100   /* check argument */
101   if (cbDSNMax < 0 || cbDescMax < 0)
102     {
103       PUSHSQLERR (genv->herr, en_S1090);
104 
105       return SQL_ERROR;
106     }
107   if (fDir != SQL_FETCH_FIRST
108       && fDir != SQL_FETCH_NEXT)
109     {
110       PUSHSQLERR (genv->herr, en_S1103);
111 
112       return SQL_ERROR;
113     }
114   if (cur_entry < 0 || fDir == SQL_FETCH_FIRST)
115     {
116       cur_entry = 0;
117       num_entries = 0;
118 
119 
120       /*
121        *  Open the odbc.ini file
122        */
123       path = (char *) _iodbcdm_getinifile (buf, sizeof (buf));
124       if ((fp = fopen (path, "r")) == NULL)
125 	{
126 	  return SQL_NO_DATA_FOUND;
127 	}
128       /*
129        *  Free old section list
130        */
131       if (sect)
132 	{
133 	  for (i = 0; i < MAX_ENTRIES; i++)
134 	    if (sect[i])
135 	      free (sect[i]);
136 	  free (sect);
137 	}
138       if ((sect = (char **) calloc (MAX_ENTRIES, sizeof (char *))) == NULL)
139 	{
140 	  PUSHSQLERR (genv->herr, en_S1011);
141 
142 	  return SQL_ERROR;
143 	}
144       /*
145        *  Build a dynamic list of sections
146        */
147       while (1)
148 	{
149 	  char *str, *p;
150 
151 	  str = fgets (buf, sizeof (buf), fp);
152 
153 	  if (str == NULL)
154 	    break;
155 
156 	  if (*str == '[')
157 	    {
158 	      str++;
159 	      for (p = str; *p; p++)
160 		if (*p == ']')
161 		  *p = '\0';
162 
163 	      if (!strcmp (str, SECT1))
164 		continue;
165 	      if (!strcmp (str, SECT2))
166 		continue;
167 
168 	      /*
169 	       *  Add this section to the comma separated list
170 	       */
171 	      if (num_entries >= MAX_ENTRIES)
172 		break;		/* Skip the rest */
173 
174 	      sect[num_entries++] = (char *) strdup (str);
175 	    }
176 	}
177 
178       /*
179        *  Sort all entries so we can present a nice list
180        */
181       if (num_entries > 1)
182 	qsort (sect, num_entries, sizeof (char *), SectSorter);
183     }
184   /*
185    *  Try to get to the next item
186    */
187   if (cur_entry >= num_entries)
188     {
189       cur_entry = 0;		/* Next time, start all over again */
190       return SQL_NO_DATA_FOUND;
191     }
192   /*
193    *  Copy DSN information
194    */
195   STRNCPY (szDSN, sect[cur_entry], cbDSNMax);
196 /*
197 glt???  pcbDSN = strlen(szDSN);
198 */
199   /*
200    *  And find the description that goes with this entry
201    */
202   _iodbcdm_getkeyvalbydsn (sect[cur_entry], strlen (sect[cur_entry]),
203       "Description", (char*) szDesc, cbDescMax);
204 /*
205 glt???  pcbDesc = strlen(szDesc);
206 */
207   /*
208    *  Next record
209    */
210   cur_entry++;
211 
212   return SQL_SUCCESS;
213 }
214 
215 
216 RETCODE SQL_API
SQLDrivers(HENV henv,UWORD fDir,UCHAR FAR * szDrvDesc,SWORD cbDrvDescMax,SWORD FAR * pcbDrvDesc,UCHAR FAR * szDrvAttr,SWORD cbDrvAttrMax,SWORD FAR * pcbDrvAttr)217 SQLDrivers (
218     HENV henv,
219     UWORD fDir,
220     UCHAR FAR * szDrvDesc,
221     SWORD cbDrvDescMax,
222     SWORD FAR * pcbDrvDesc,
223     UCHAR FAR * szDrvAttr,
224     SWORD cbDrvAttrMax,
225     SWORD FAR * pcbDrvAttr)
226 {
227   GENV_t FAR *genv = (GENV_t FAR *) henv;
228 
229   if (henv == SQL_NULL_HENV)
230     {
231       return SQL_INVALID_HANDLE;
232     }
233 
234   if (cbDrvDescMax < 0 || cbDrvAttrMax < 0 || cbDrvAttrMax == 1)
235     {
236       PUSHSQLERR (genv->herr, en_S1090);
237 
238       return SQL_ERROR;
239     }
240 
241   if (fDir != SQL_FETCH_FIRST || fDir != SQL_FETCH_NEXT)
242     {
243       PUSHSQLERR (genv->herr, en_S1103);
244 
245       return SQL_ERROR;
246     }
247 
248 /*********************/
249   return SQL_NO_DATA_FOUND;
250 }
251 
252 
253 RETCODE SQL_API
SQLGetInfo(HDBC hdbc,UWORD fInfoType,PTR rgbInfoValue,SWORD cbInfoValueMax,SWORD FAR * pcbInfoValue)254 SQLGetInfo (
255     HDBC hdbc,
256     UWORD fInfoType,
257     PTR rgbInfoValue,
258     SWORD cbInfoValueMax,
259     SWORD FAR * pcbInfoValue)
260 {
261   DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
262   ENV_t FAR *penv;
263   STMT_t FAR *pstmt = NULL;
264   STMT_t FAR *tpstmt;
265   HPROC hproc;
266   RETCODE retcode = SQL_SUCCESS;
267 
268   DWORD dword;
269   int size = 0, len = 0;
270   char buf[16] = {'\0'};
271 
272   if (hdbc == SQL_NULL_HDBC || pdbc->henv == SQL_NULL_HENV)
273     {
274       return SQL_INVALID_HANDLE;
275     }
276 
277   if (cbInfoValueMax < 0)
278     {
279       PUSHSQLERR (pdbc->herr, en_S1090);
280 
281       return SQL_ERROR;
282     }
283 
284   if (				/* fInfoType < SQL_INFO_FIRST || */
285       (fInfoType > SQL_INFO_LAST
286 	  && fInfoType < SQL_INFO_DRIVER_START))
287     {
288       PUSHSQLERR (pdbc->herr, en_S1096);
289 
290       return SQL_ERROR;
291     }
292 
293   if (fInfoType == SQL_ODBC_VER)
294     {
295       sprintf (buf, "%02d.%02d",
296 	  (ODBCVER) >> 8, 0x00FF & (ODBCVER));
297 
298 
299       if (rgbInfoValue != NULL
300 	  && cbInfoValueMax > 0)
301 	{
302 	  len = STRLEN (buf);
303 
304 	  if (len < cbInfoValueMax - 1)
305 	    {
306 	      len = cbInfoValueMax - 1;
307 	      PUSHSQLERR (pdbc->herr, en_01004);
308 
309 	      retcode = SQL_SUCCESS_WITH_INFO;
310 	    }
311 
312 	  STRNCPY (rgbInfoValue, buf, len);
313 	  ((char FAR *) rgbInfoValue)[len] = '\0';
314 	}
315 
316       if (pcbInfoValue != NULL)
317 	{
318 	  *pcbInfoValue = (SWORD) len;
319 	}
320 
321       return retcode;
322     }
323 
324   if (pdbc->state == en_dbc_allocated || pdbc->state == en_dbc_needdata)
325     {
326       PUSHSQLERR (pdbc->herr, en_08003);
327 
328       return SQL_ERROR;
329     }
330 
331   switch (fInfoType)
332      {
333      case SQL_DRIVER_HDBC:
334        dword = (DWORD) (pdbc->dhdbc);
335        size = sizeof (dword);
336        break;
337 
338      case SQL_DRIVER_HENV:
339        penv = (ENV_t FAR *) (pdbc->henv);
340        dword = (DWORD) (penv->dhenv);
341        size = sizeof (dword);
342        break;
343 
344      case SQL_DRIVER_HLIB:
345        penv = (ENV_t FAR *) (pdbc->henv);
346        dword = (DWORD) (penv->hdll);
347        size = sizeof (dword);
348        break;
349 
350      case SQL_DRIVER_HSTMT:
351        if (rgbInfoValue != NULL)
352 	 {
353 	   pstmt = *((STMT_t FAR **) rgbInfoValue);
354 	 }
355 
356        for (tpstmt = (STMT_t FAR *) (pdbc->hstmt);
357 	   tpstmt != NULL;
358 	   tpstmt = tpstmt->next)
359 	 {
360 	   if (tpstmt == pstmt)
361 	     {
362 	       break;
363 	     }
364 	 }
365 
366        if (tpstmt == NULL)
367 	 {
368 	   PUSHSQLERR (pdbc->herr, en_S1009);
369 
370 	   return SQL_ERROR;
371 	 }
372 
373        dword = (DWORD) (pstmt->dhstmt);
374        size = sizeof (dword);
375        break;
376 
377      default:
378        break;
379      }
380 
381   if (size)
382     {
383       if (rgbInfoValue != NULL)
384 	{
385 	  *((DWORD *) rgbInfoValue) = dword;
386 	}
387 
388       if (pcbInfoValue != NULL)
389 	{
390 	  *(pcbInfoValue) = (SWORD) size;
391 	}
392 
393       return SQL_SUCCESS;
394     }
395 
396   hproc = _iodbcdm_getproc (hdbc, en_GetInfo);
397 
398   if (hproc == SQL_NULL_HPROC)
399     {
400       PUSHSQLERR (pdbc->herr, en_IM001);
401 
402       return SQL_ERROR;
403     }
404 
405   CALL_DRIVER (hdbc, retcode, hproc, en_GetInfo,
406     (pdbc->dhdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue))
407 
408   if (retcode == SQL_ERROR
409       && fInfoType == SQL_DRIVER_ODBC_VER)
410     {
411       STRCPY (buf, "01.00");
412 
413       if (rgbInfoValue != NULL
414 	  && cbInfoValueMax > 0)
415 	{
416 	  len = STRLEN (buf);
417 
418 	  if (len < cbInfoValueMax - 1)
419 	    {
420 	      len = cbInfoValueMax - 1;
421 	      PUSHSQLERR (pdbc->herr, en_01004);
422 	    }
423 
424 	  STRNCPY (rgbInfoValue, buf, len);
425 	  ((char FAR *) rgbInfoValue)[len] = '\0';
426 	}
427 
428       if (pcbInfoValue != NULL)
429 	{
430 	  *pcbInfoValue = (SWORD) len;
431 	}
432 
433       /* what should we return in this case ???? */
434     }
435 
436   return retcode;
437 }
438 
439 
440 RETCODE SQL_API
SQLGetFunctions(HDBC hdbc,UWORD fFunc,UWORD FAR * pfExists)441 SQLGetFunctions (
442     HDBC hdbc,
443     UWORD fFunc,
444     UWORD FAR * pfExists)
445 {
446   DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
447   HPROC hproc;
448   RETCODE retcode;
449 
450   if (hdbc == SQL_NULL_HDBC)
451     {
452       return SQL_INVALID_HANDLE;
453     }
454 
455   if (fFunc > SQL_EXT_API_LAST)
456     {
457       PUSHSQLERR (pdbc->herr, en_S1095);
458 
459       return SQL_ERROR;
460     }
461 
462   if (pdbc->state == en_dbc_allocated
463       || pdbc->state == en_dbc_needdata)
464     {
465       PUSHSQLERR (pdbc->herr, en_S1010);
466 
467       return SQL_ERROR;
468     }
469 
470   if (pfExists == NULL)
471     {
472       return SQL_SUCCESS;
473     }
474 
475   hproc = _iodbcdm_getproc (hdbc, en_GetFunctions);
476 
477   if (hproc != SQL_NULL_HPROC)
478     {
479       CALL_DRIVER (hdbc, retcode, hproc, en_GetFunctions,
480 	(pdbc->dhdbc, fFunc, pfExists))
481 
482       return retcode;
483     }
484 
485   if (fFunc == SQL_API_SQLSETPARAM)
486     {
487       fFunc = SQL_API_SQLBINDPARAMETER;
488     }
489 
490   if (fFunc != SQL_API_ALL_FUNCTIONS)
491     {
492       hproc = _iodbcdm_getproc (hdbc, fFunc);
493 
494       if (hproc == SQL_NULL_HPROC)
495 	{
496 	  *pfExists = (UWORD) 0;
497 	}
498       else
499 	{
500 	  *pfExists = (UWORD) 1;
501 	}
502 
503       return SQL_SUCCESS;
504     }
505 
506   for (fFunc = 0; fFunc < 100; fFunc++)
507     {
508       hproc = _iodbcdm_getproc (hdbc, fFunc);
509 
510       if (hproc == SQL_NULL_HPROC)
511 	{
512 	  pfExists[fFunc] = (UWORD) 0;
513 	}
514       else
515 	{
516 	  pfExists[fFunc] = (UWORD) 1;
517 	}
518     }
519 
520   return SQL_SUCCESS;
521 }
522