1 /*
2  *  info.c
3  *
4  *  $Id$
5  *
6  *  Information functions
7  *
8  *  The iODBC driver manager.
9  *
10  *  Copyright (C) 1995 Ke Jin <kejin@empress.com>
11  *  Copyright (C) 1996-2021 OpenLink Software <iodbc@openlinksw.com>
12  *  All Rights Reserved.
13  *
14  *  This software is released under the terms of either of the following
15  *  licenses:
16  *
17  *      - GNU Library General Public License (see LICENSE.LGPL)
18  *      - The BSD License (see LICENSE.BSD).
19  *
20  *  Note that the only valid version of the LGPL license as far as this
21  *  project is concerned is the original GNU Library General Public License
22  *  Version 2, dated June 1991.
23  *
24  *  While not mandated by the BSD license, any patches you make to the
25  *  iODBC source code may be contributed back into the iODBC project
26  *  at your discretion. Contributions will benefit the Open Source and
27  *  Data Access community as a whole. Submissions may be made at:
28  *
29  *      http://www.iodbc.org
30  *
31  *
32  *  GNU Library Generic Public License Version 2
33  *  ============================================
34  *  This library is free software; you can redistribute it and/or
35  *  modify it under the terms of the GNU Library General Public
36  *  License as published by the Free Software Foundation; only
37  *  Version 2 of the License dated June 1991.
38  *
39  *  This library is distributed in the hope that it will be useful,
40  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
41  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
42  *  Library General Public License for more details.
43  *
44  *  You should have received a copy of the GNU Library General Public
45  *  License along with this library; if not, write to the Free
46  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
47  *
48  *
49  *  The BSD License
50  *  ===============
51  *  Redistribution and use in source and binary forms, with or without
52  *  modification, are permitted provided that the following conditions
53  *  are met:
54  *
55  *  1. Redistributions of source code must retain the above copyright
56  *     notice, this list of conditions and the following disclaimer.
57  *  2. Redistributions in binary form must reproduce the above copyright
58  *     notice, this list of conditions and the following disclaimer in
59  *     the documentation and/or other materials provided with the
60  *     distribution.
61  *  3. Neither the name of OpenLink Software Inc. nor the names of its
62  *     contributors may be used to endorse or promote products derived
63  *     from this software without specific prior written permission.
64  *
65  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
66  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
67  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
68  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
69  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
70  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
71  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
72  *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
73  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
74  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
75  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
76  */
77 
78 
79 #include <iodbc.h>
80 
81 #include <sql.h>
82 #include <sqlext.h>
83 #include <sqlucode.h>
84 #include <odbcinst.h>
85 
86 #include "unicode.h"
87 
88 #include "dlproc.h"
89 
90 #include "herr.h"
91 #include "henv.h"
92 #include "hdbc.h"
93 #include "hstmt.h"
94 
95 #include "itrace.h"
96 
97 #include <stdio.h>
98 #include <ctype.h>
99 
100 #ifdef WIN32
101 #define SECT1			"ODBC 32 bit Data Sources"
102 #define SECT2			"ODBC 32 bit Drivers"
103 #else
104 #define SECT1			"ODBC Data Sources"
105 #define SECT2			"ODBC Drivers"
106 #endif
107 
108 #define MAX_ENTRIES		1024
109 
110 
111 static int
stricmp(const char * s1,const char * s2)112 stricmp (const char *s1, const char *s2)
113 {
114   int cmp;
115 
116   while (*s1)
117     {
118       if ((cmp = toupper (*s1) - toupper (*s2)) != 0)
119 	return cmp;
120       s1++;
121       s2++;
122     }
123   return (*s2) ? -1 : 0;
124 }
125 
126 
127 static int
SectSorter(const void * p1,const void * p2)128 SectSorter (const void *p1, const void *p2)
129 {
130   const char **s1 = (const char **) p1;
131   const char **s2 = (const char **) p2;
132 
133   return stricmp (*s1, *s2);
134 }
135 
136 
137 SQLRETURN SQL_API
SQLDataSources_Internal(SQLHENV henv,SQLUSMALLINT fDir,SQLPOINTER szDSN,SQLSMALLINT cbDSNMax,SQLSMALLINT * pcbDSN,SQLPOINTER szDesc,SQLSMALLINT cbDescMax,SQLSMALLINT * pcbDesc,SQLCHAR waMode)138 SQLDataSources_Internal (
139   SQLHENV		  henv,
140   SQLUSMALLINT		  fDir,
141   SQLPOINTER		  szDSN,
142   SQLSMALLINT		  cbDSNMax,
143   SQLSMALLINT 		* pcbDSN,
144   SQLPOINTER		  szDesc,
145   SQLSMALLINT		  cbDescMax,
146   SQLSMALLINT 		* pcbDesc,
147   SQLCHAR		  waMode)
148 {
149   GENV (genv, henv);
150   char buffer[4096], desc[1024], *ptr;
151   int i, j, usernum = 0;
152   static int cur_entry = -1;
153   static int num_entries = 0;
154   static void **sect = NULL;
155   SQLUSMALLINT fDirOld = fDir;
156 
157   waMode = waMode; /*UNUSED*/
158 
159   /* check argument */
160   if (cbDSNMax < 0 || cbDescMax < 0)
161     {
162       PUSHSQLERR (genv->herr, en_S1090);
163       return SQL_ERROR;
164     }
165 
166   if (fDir != SQL_FETCH_FIRST && fDir != SQL_FETCH_NEXT &&
167       fDir != SQL_FETCH_FIRST_USER && fDir != SQL_FETCH_FIRST_SYSTEM)
168     {
169       PUSHSQLERR (genv->herr, en_S1103);
170       return SQL_ERROR;
171     }
172 
173   if (cur_entry < 0 || fDir == SQL_FETCH_FIRST ||
174       fDir == SQL_FETCH_FIRST_USER || fDir == SQL_FETCH_FIRST_SYSTEM)
175     {
176       cur_entry = 0;
177       num_entries = 0;
178 
179       /*
180        *  Free old section list
181        */
182       if (sect)
183 	{
184 	  for (i = 0; i < MAX_ENTRIES; i++)
185 	    if (sect[i])
186 	      free (sect[i]);
187 	  free (sect);
188 	}
189       if ((sect = (void **) calloc (MAX_ENTRIES, sizeof (void *))) == NULL)
190 	{
191 	  PUSHSQLERR (genv->herr, en_S1011);
192 	  return SQL_ERROR;
193 	}
194 
195       if (fDirOld == SQL_FETCH_FIRST)
196         fDir = SQL_FETCH_FIRST_USER;
197 
198       do {
199         SQLSetConfigMode (fDir == SQL_FETCH_FIRST_SYSTEM ? ODBC_SYSTEM_DSN : ODBC_USER_DSN);
200         SQLGetPrivateProfileString (SECT1, NULL, "", buffer, sizeof(buffer) / sizeof(SQLTCHAR), "odbc.ini");
201 
202         /* For each datasources */
203         for(ptr = buffer, i = 1 ; *ptr && i ; ptr += STRLEN(ptr) + 1)
204           {
205             /* Add this section to the datasources list */
206             if (fDirOld == SQL_FETCH_FIRST && fDir == SQL_FETCH_FIRST_SYSTEM)
207               {
208                 for(j = 0 ; j<usernum ; j++)
209                   {
210                     if(STREQ(sect[j<<1], ptr))
211                       j = usernum;
212                   }
213                 if(j == usernum + 1)
214                   continue;
215               }
216 
217             if ((num_entries << 1) >= MAX_ENTRIES)
218               {
219                 i = 0;
220                 break;
221               }			/* Skip the rest */
222 
223             /* Copy the datasource name */
224             sect[num_entries<<1] = STRDUP (ptr);
225 
226             /* ... and its description */
227             SQLSetConfigMode (fDir == SQL_FETCH_FIRST_SYSTEM ? ODBC_SYSTEM_DSN : ODBC_USER_DSN);
228             SQLGetPrivateProfileString (SECT1, ptr, "", desc, sizeof(desc) / sizeof(SQLTCHAR), "odbc.ini");
229             sect[(num_entries++<<1) + 1] = STRDUP (desc);
230           }
231 
232         switch(fDir)
233           {
234             case SQL_FETCH_FIRST_USER:
235               fDir = SQL_FETCH_FIRST_SYSTEM;
236               usernum = num_entries;
237               break;
238             case SQL_FETCH_FIRST_SYSTEM:
239               fDir = SQL_FETCH_FIRST;
240               break;
241           };
242       } while (fDir!=SQL_FETCH_FIRST && fDirOld==SQL_FETCH_FIRST);
243 
244       fDir = fDirOld;
245 
246       /*
247        *  Sort all entries so we can present a nice list
248        */
249       if (num_entries > 1)
250 	{
251           qsort (sect, num_entries, sizeof (char **) + sizeof (char **),
252             SectSorter);
253 	}
254     }
255 
256   /*
257    *  Try to get to the next item
258    */
259   if (cur_entry >= num_entries)
260     {
261       cur_entry = 0;		/* Next time, start all over again */
262       return SQL_NO_DATA_FOUND;
263     }
264 
265   /*
266    *  Copy DSN information
267    */
268   STRNCPY (szDSN, sect[cur_entry << 1], cbDSNMax);
269 
270   if (pcbDSN)
271     *pcbDSN = STRLEN (szDSN);
272 
273   /*
274    *  And find the description that goes with this entry
275    */
276   STRNCPY (szDesc, sect[(cur_entry << 1) + 1], cbDescMax);
277 
278   if (pcbDesc)
279     *pcbDesc = STRLEN (szDesc);
280 
281   /*
282    *  Next record
283    */
284   cur_entry++;
285 
286   return SQL_SUCCESS;
287 }
288 
289 
290 SQLRETURN SQL_API
SQLDataSources(SQLHENV henv,SQLUSMALLINT fDir,SQLCHAR * szDSN,SQLSMALLINT cbDSNMax,SQLSMALLINT * pcbDSN,SQLCHAR * szDesc,SQLSMALLINT cbDescMax,SQLSMALLINT * pcbDesc)291 SQLDataSources (
292   SQLHENV		  henv,
293   SQLUSMALLINT		  fDir,
294   SQLCHAR 		* szDSN,
295   SQLSMALLINT		  cbDSNMax,
296   SQLSMALLINT 		* pcbDSN,
297   SQLCHAR 		* szDesc,
298   SQLSMALLINT		  cbDescMax,
299   SQLSMALLINT 		* pcbDesc)
300 {
301   ENTER_HENV (henv,
302     trace_SQLDataSources (TRACE_ENTER,
303     	henv,
304 	fDir,
305 	szDSN, cbDSNMax, pcbDSN,
306 	szDesc, cbDescMax, pcbDesc));
307 
308   retcode = SQLDataSources_Internal (
309   	henv,
310 	fDir,
311 	szDSN, cbDSNMax, pcbDSN,
312 	szDesc, cbDescMax, pcbDesc,
313 	'A');
314 
315   LEAVE_HENV (henv,
316     trace_SQLDataSources (TRACE_LEAVE,
317     	henv,
318 	fDir,
319 	szDSN, cbDSNMax, pcbDSN,
320 	szDesc, cbDescMax, pcbDesc));
321 }
322 
323 
324 #if ODBCVER >= 0x0300
325 SQLRETURN SQL_API
SQLDataSourcesA(SQLHENV henv,SQLUSMALLINT fDir,SQLCHAR * szDSN,SQLSMALLINT cbDSNMax,SQLSMALLINT * pcbDSN,SQLCHAR * szDesc,SQLSMALLINT cbDescMax,SQLSMALLINT * pcbDesc)326 SQLDataSourcesA (
327   SQLHENV		  henv,
328   SQLUSMALLINT		  fDir,
329   SQLCHAR 		* szDSN,
330   SQLSMALLINT		  cbDSNMax,
331   SQLSMALLINT 		* pcbDSN,
332   SQLCHAR 		* szDesc,
333   SQLSMALLINT		  cbDescMax,
334   SQLSMALLINT		* pcbDesc)
335 {
336   ENTER_HENV (henv,
337     trace_SQLDataSources (TRACE_ENTER,
338     	henv,
339 	fDir,
340 	szDSN, cbDSNMax, pcbDSN,
341 	szDesc, cbDescMax, pcbDesc));
342 
343   retcode = SQLDataSources_Internal(
344   	henv,
345 	fDir,
346 	szDSN, cbDSNMax, pcbDSN,
347 	szDesc, cbDescMax, pcbDesc,
348 	'A');
349 
350   LEAVE_HENV (henv,
351     trace_SQLDataSources (TRACE_LEAVE,
352     	henv,
353 	fDir,
354 	szDSN, cbDSNMax, pcbDSN,
355 	szDesc, cbDescMax, pcbDesc));
356 }
357 
358 
359 SQLRETURN SQL_API
SQLDataSourcesW(SQLHENV henv,SQLUSMALLINT fDir,SQLWCHAR * szDSN,SQLSMALLINT cbDSNMax,SQLSMALLINT * pcbDSN,SQLWCHAR * szDesc,SQLSMALLINT cbDescMax,SQLSMALLINT * pcbDesc)360 SQLDataSourcesW (
361   SQLHENV		  henv,
362   SQLUSMALLINT		  fDir,
363   SQLWCHAR 		* szDSN,
364   SQLSMALLINT		  cbDSNMax,
365   SQLSMALLINT 		* pcbDSN,
366   SQLWCHAR 		* szDesc,
367   SQLSMALLINT		  cbDescMax,
368   SQLSMALLINT 		* pcbDesc)
369 {
370   SQLCHAR *_DSN = NULL;
371   SQLCHAR *_Desc = NULL;
372   GENV (glenv, henv);
373   DM_CONV *conv = &glenv->conv;
374 
375   ENTER_HENV (henv,
376     trace_SQLDataSourcesW (TRACE_ENTER,
377     	henv,
378 	fDir,
379 	szDSN, cbDSNMax, pcbDSN,
380 	szDesc, cbDescMax, pcbDesc));
381 
382   if (cbDSNMax > 0)
383     {
384       if ((_DSN = (SQLCHAR *) malloc (cbDSNMax * UTF8_MAX_CHAR_LEN + 1)) == NULL)
385 	{
386 	  PUSHSQLERR (genv->herr, en_S1001);
387 	  return SQL_ERROR;
388 	}
389     }
390 
391   if (cbDescMax > 0)
392     {
393       if ((_Desc = (SQLCHAR *) malloc (cbDescMax * UTF8_MAX_CHAR_LEN + 1)) == NULL)
394 	{
395 	  PUSHSQLERR (genv->herr, en_S1001);
396 	  return SQL_ERROR;
397 	}
398     }
399 
400   retcode = SQLDataSources_Internal (
401   	henv,
402 	fDir,
403 	_DSN, cbDSNMax * UTF8_MAX_CHAR_LEN, pcbDSN,
404 	_Desc, cbDescMax * UTF8_MAX_CHAR_LEN, pcbDesc,
405 	'W');
406 
407   if (SQL_SUCCEEDED (retcode))
408     {
409       dm_StrCopyOut2_U8toW_d2m (conv, _DSN, szDSN,
410 	cbDSNMax * DM_WCHARSIZE(conv), pcbDSN, NULL);
411       dm_StrCopyOut2_U8toW_d2m (conv, _Desc, szDesc,
412 	cbDescMax * DM_WCHARSIZE(conv), pcbDesc, NULL);
413     }
414 
415   MEM_FREE (_DSN);
416   MEM_FREE (_Desc);
417 
418   LEAVE_HENV (henv,
419     trace_SQLDataSourcesW (TRACE_LEAVE,
420     	henv,
421 	fDir,
422 	szDSN, cbDSNMax, pcbDSN,
423 	szDesc, cbDescMax, pcbDesc));
424 }
425 #endif
426 
427 
428 SQLRETURN SQL_API
SQLDrivers_Internal(SQLHENV henv,SQLUSMALLINT fDir,SQLPOINTER szDrvDesc,SQLSMALLINT cbDrvDescMax,SQLSMALLINT * pcbDrvDesc,SQLPOINTER szDrvAttr,SQLSMALLINT cbDrvAttrMax,SQLSMALLINT * pcbDrvAttr,SQLCHAR waMode)429 SQLDrivers_Internal (
430   SQLHENV		  henv,
431   SQLUSMALLINT		  fDir,
432   SQLPOINTER		  szDrvDesc,
433   SQLSMALLINT		  cbDrvDescMax,
434   SQLSMALLINT 		* pcbDrvDesc,
435   SQLPOINTER		  szDrvAttr,
436   SQLSMALLINT		  cbDrvAttrMax,
437   SQLSMALLINT 		* pcbDrvAttr,
438   SQLCHAR		  waMode)
439 {
440   GENV (genv, henv);
441   char buffer[4096], desc[1024], *ptr;
442   int i, j, usernum = 0;
443   static int cur_entry = -1;
444   static int num_entries = 0;
445   static void **sect = NULL;
446   SQLUSMALLINT fDirOld = fDir;
447 
448   waMode = waMode; /*UNUSED*/
449 
450   /* check argument */
451   if (cbDrvDescMax < 0 || cbDrvAttrMax < 0)
452     {
453       PUSHSQLERR (genv->herr, en_S1090);
454       return SQL_ERROR;
455     }
456 
457   if (fDir != SQL_FETCH_FIRST && fDir != SQL_FETCH_NEXT)
458     {
459       PUSHSQLERR (genv->herr, en_S1103);
460       return SQL_ERROR;
461     }
462 
463   if (cur_entry < 0 || fDir == SQL_FETCH_FIRST)
464     {
465       cur_entry = 0;
466       num_entries = 0;
467 
468       /*
469       *  Free old section list
470       */
471       if (sect)
472 	{
473 	  for (i = 0; i < MAX_ENTRIES; i++)
474 	    if (sect[i])
475 	      free (sect[i]);
476 	  free (sect);
477 	}
478       if ((sect = (void **) calloc (MAX_ENTRIES, sizeof (void *))) == NULL)
479 	{
480 	  PUSHSQLERR (genv->herr, en_S1011);
481 	  return SQL_ERROR;
482 	}
483 
484       if (fDirOld == SQL_FETCH_FIRST)
485         fDir = SQL_FETCH_FIRST_USER;
486 
487       do {
488         SQLSetConfigMode (fDir == SQL_FETCH_FIRST_SYSTEM ? ODBC_SYSTEM_DSN : ODBC_USER_DSN);
489         SQLGetPrivateProfileString (SECT2, NULL, "", buffer, sizeof(buffer) / sizeof(SQLTCHAR), "odbcinst.ini");
490 
491         /* For each datasources */
492         for(ptr = buffer, i = 1 ; *ptr && i ; ptr += STRLEN(ptr) + 1)
493           {
494             /* Add this section to the datasources list */
495             if (fDirOld == SQL_FETCH_FIRST && fDir == SQL_FETCH_FIRST_SYSTEM)
496               {
497                 for(j = 0 ; j<usernum ; j++)
498                   {
499                     if(STREQ(sect[j<<1], ptr))
500                       j = usernum;
501                   }
502                 if(j == usernum + 1)
503                   continue;
504               }
505 
506             if ((num_entries << 1) >= MAX_ENTRIES)
507               {
508                 i = 0;
509                 break;
510               }			/* Skip the rest */
511 
512             /* ... and its description */
513             SQLSetConfigMode (fDir == SQL_FETCH_FIRST_SYSTEM ? ODBC_SYSTEM_DSN : ODBC_USER_DSN);
514             SQLGetPrivateProfileString (SECT2, ptr, "", desc, sizeof(desc) / sizeof(SQLTCHAR), "odbcinst.ini");
515 
516             /* Check if the driver is installed */
517 				if(!STRCASEEQ(desc, "Installed"))
518 				  continue;
519 
520             /* Copy the driver name */
521             sect[num_entries<<1] = STRDUP (ptr);
522             sect[(num_entries++<<1) + 1] = STRDUP (desc);
523           }
524 
525         switch(fDir)
526           {
527             case SQL_FETCH_FIRST_USER:
528               fDir = SQL_FETCH_FIRST_SYSTEM;
529               usernum = num_entries;
530               break;
531             case SQL_FETCH_FIRST_SYSTEM:
532               fDir = SQL_FETCH_FIRST;
533               break;
534           };
535       } while (fDir!=SQL_FETCH_FIRST && fDirOld==SQL_FETCH_FIRST);
536 
537       fDir = fDirOld;
538 
539       /*
540        *  Sort all entries so we can present a nice list
541        */
542       if (num_entries > 1)
543 	{
544           qsort (sect, num_entries, sizeof (char **) + sizeof (char **),
545             SectSorter);
546 	}
547     }
548 
549   /*
550    *  Try to get to the next item
551    */
552   if (cur_entry >= num_entries)
553     {
554       cur_entry = 0;		/* Next time, start all over again */
555       return SQL_NO_DATA_FOUND;
556     }
557 
558   /*
559    *  Copy Driver information
560    */
561   STRNCPY (szDrvDesc, sect[cur_entry << 1], cbDrvDescMax);
562 
563   if (pcbDrvDesc)
564     *pcbDrvDesc = STRLEN (szDrvDesc);
565 
566   /*
567    *  And find the description that goes with this entry
568    */
569   STRNCPY (szDrvAttr, sect[(cur_entry << 1) + 1], cbDrvAttrMax);
570 
571   if (pcbDrvAttr)
572     *pcbDrvAttr = STRLEN (szDrvAttr);
573 
574   /*
575    *  Next record
576    */
577   cur_entry++;
578 
579   return SQL_SUCCESS;
580 }
581 
582 
583 SQLRETURN SQL_API
SQLDrivers(SQLHENV henv,SQLUSMALLINT fDir,SQLCHAR * szDrvDesc,SQLSMALLINT cbDrvDescMax,SQLSMALLINT * pcbDrvDesc,SQLCHAR * szDrvAttr,SQLSMALLINT cbDrvAttrMax,SQLSMALLINT * pcbDrvAttr)584 SQLDrivers (
585   SQLHENV		  henv,
586   SQLUSMALLINT		  fDir,
587   SQLCHAR 		* szDrvDesc,
588   SQLSMALLINT		  cbDrvDescMax,
589   SQLSMALLINT 		* pcbDrvDesc,
590   SQLCHAR 		* szDrvAttr,
591   SQLSMALLINT		  cbDrvAttrMax,
592   SQLSMALLINT 		* pcbDrvAttr)
593 {
594   ENTER_HENV (henv,
595     trace_SQLDrivers (TRACE_ENTER,
596   	henv,
597 	fDir,
598 	szDrvDesc, cbDrvDescMax, pcbDrvDesc,
599 	szDrvAttr, cbDrvAttrMax, pcbDrvAttr));
600 
601   retcode = SQLDrivers_Internal(
602   	henv,
603 	fDir,
604 	szDrvDesc, cbDrvDescMax, pcbDrvDesc,
605 	szDrvAttr, cbDrvAttrMax, pcbDrvAttr,
606 	'A');
607 
608   LEAVE_HENV (henv,
609     trace_SQLDrivers (TRACE_LEAVE,
610   	henv,
611 	fDir,
612 	szDrvDesc, cbDrvDescMax, pcbDrvDesc,
613 	szDrvAttr, cbDrvAttrMax, pcbDrvAttr));
614 }
615 
616 
617 #if ODBCVER >= 0x0300
618 SQLRETURN SQL_API
SQLDriversA(SQLHENV henv,SQLUSMALLINT fDir,SQLCHAR * szDrvDesc,SQLSMALLINT cbDrvDescMax,SQLSMALLINT * pcbDrvDesc,SQLCHAR * szDrvAttr,SQLSMALLINT cbDrvAttrMax,SQLSMALLINT * pcbDrvAttr)619 SQLDriversA (
620   SQLHENV		  henv,
621   SQLUSMALLINT		  fDir,
622   SQLCHAR  		* szDrvDesc,
623   SQLSMALLINT		  cbDrvDescMax,
624   SQLSMALLINT 	 	* pcbDrvDesc,
625   SQLCHAR  		* szDrvAttr,
626   SQLSMALLINT		  cbDrvAttrMax,
627   SQLSMALLINT 	 	* pcbDrvAttr)
628 {
629   ENTER_HENV (henv,
630     trace_SQLDrivers (TRACE_ENTER,
631   	henv,
632 	fDir,
633 	szDrvDesc, cbDrvDescMax, pcbDrvDesc,
634 	szDrvAttr, cbDrvAttrMax, pcbDrvAttr));
635 
636   retcode = SQLDrivers_Internal(
637   	henv,
638 	fDir,
639 	szDrvDesc, cbDrvDescMax, pcbDrvDesc,
640 	szDrvAttr, cbDrvAttrMax, pcbDrvAttr,
641 	'A');
642 
643   LEAVE_HENV (henv,
644     trace_SQLDrivers (TRACE_LEAVE,
645   	henv,
646 	fDir,
647 	szDrvDesc, cbDrvDescMax, pcbDrvDesc,
648 	szDrvAttr, cbDrvAttrMax, pcbDrvAttr));
649 }
650 
651 
652 SQLRETURN SQL_API
SQLDriversW(SQLHENV henv,SQLUSMALLINT fDir,SQLWCHAR * szDrvDesc,SQLSMALLINT cbDrvDescMax,SQLSMALLINT * pcbDrvDesc,SQLWCHAR * szDrvAttr,SQLSMALLINT cbDrvAttrMax,SQLSMALLINT * pcbDrvAttr)653 SQLDriversW (SQLHENV henv,
654     SQLUSMALLINT 	  fDir,
655     SQLWCHAR		* szDrvDesc,
656     SQLSMALLINT		  cbDrvDescMax,
657     SQLSMALLINT		* pcbDrvDesc,
658     SQLWCHAR		* szDrvAttr,
659     SQLSMALLINT		  cbDrvAttrMax,
660     SQLSMALLINT		* pcbDrvAttr)
661 {
662   SQLCHAR *_Driver = NULL;
663   SQLCHAR *_Attrs = NULL;
664   GENV (glenv, henv);
665   DM_CONV *conv = &glenv->conv;
666 
667   ENTER_HENV (henv,
668     trace_SQLDriversW (TRACE_ENTER,
669   	henv,
670 	fDir,
671 	szDrvDesc, cbDrvDescMax, pcbDrvDesc,
672 	szDrvAttr, cbDrvAttrMax, pcbDrvAttr));
673 
674   if (cbDrvDescMax > 0)
675     {
676       if ((_Driver = (SQLCHAR *) malloc (cbDrvDescMax * UTF8_MAX_CHAR_LEN + 1)) == NULL)
677 	{
678 	  PUSHSQLERR (genv->herr, en_S1001);
679 	  return SQL_ERROR;
680 	}
681     }
682 
683   if (cbDrvAttrMax > 0)
684     {
685       if ((_Attrs = (SQLCHAR *) malloc (cbDrvAttrMax * UTF8_MAX_CHAR_LEN + 1)) == NULL)
686 	{
687 	  PUSHSQLERR (genv->herr, en_S1001);
688 	  return SQL_ERROR;
689 	}
690     }
691 
692   retcode = SQLDrivers_Internal (
693   	henv,
694 	fDir,
695 	_Driver, cbDrvDescMax * UTF8_MAX_CHAR_LEN, pcbDrvDesc,
696 	_Attrs, cbDrvAttrMax * UTF8_MAX_CHAR_LEN, pcbDrvAttr,
697 	'W');
698 
699   if (SQL_SUCCEEDED (retcode))
700     {
701       dm_StrCopyOut2_U8toW_d2m (conv, _Driver, szDrvDesc,
702         cbDrvDescMax * DM_WCHARSIZE(conv), pcbDrvDesc, NULL);
703       dm_StrCopyOut2_U8toW_d2m (conv, _Attrs, szDrvAttr,
704         cbDrvAttrMax * DM_WCHARSIZE(conv), pcbDrvAttr, NULL);
705     }
706 
707   MEM_FREE (_Driver);
708   MEM_FREE (_Attrs);
709 
710   LEAVE_HENV (henv,
711     trace_SQLDriversW (TRACE_LEAVE,
712   	henv,
713 	fDir,
714 	szDrvDesc, cbDrvDescMax, pcbDrvDesc,
715 	szDrvAttr, cbDrvAttrMax, pcbDrvAttr));
716 }
717 #endif
718 
719 
720 SQLRETURN SQL_API
SQLGetInfo_Internal(SQLHDBC hdbc,SQLUSMALLINT fInfoType,SQLPOINTER rgbInfoValue,SQLSMALLINT cbInfoValueMax,SQLSMALLINT * pcbInfoValue,SQLCHAR waMode)721 SQLGetInfo_Internal (
722     SQLHDBC		  hdbc,
723     SQLUSMALLINT	  fInfoType,
724     SQLPOINTER		  rgbInfoValue,
725     SQLSMALLINT		  cbInfoValueMax,
726     SQLSMALLINT		* pcbInfoValue,
727     SQLCHAR		  waMode)
728 {
729   CONN (pdbc, hdbc);
730   ENVR (penv, pdbc->henv);
731   STMT (pstmt, NULL);
732   STMT (tpstmt, NULL);
733   HPROC hproc = SQL_NULL_HPROC;
734   SQLRETURN retcode = SQL_SUCCESS;
735   void * _InfoValue = NULL;
736   void * infoValueOut = rgbInfoValue;
737   SQLPOINTER ptr = 0;
738   SQLSMALLINT _cbInfoValueMax = cbInfoValueMax;
739   CONV_DIRECT conv_direct = CD_NONE;
740   DM_CONV *conv = &pdbc->conv;
741 
742   int size = 0, len = 0, ret = 0;
743   wchar_t buf[20] = {'\0'};
744 
745   if (cbInfoValueMax < 0)
746     {
747       PUSHSQLERR (pdbc->herr, en_S1090);
748       return SQL_ERROR;
749     }
750 
751 #if (ODBCVER < 0x0300)
752   if (				/* fInfoType < SQL_INFO_FIRST || */
753       (fInfoType > SQL_INFO_LAST
754 	  && fInfoType < SQL_INFO_DRIVER_START))
755     {
756       PUSHSQLERR (pdbc->herr, en_S1096);
757       return SQL_ERROR;
758     }
759 #endif
760   if (fInfoType == SQL_ODBC_VER
761 #if (ODBCVER >= 0x0300)
762   	|| fInfoType == SQL_DM_VER
763 #endif
764 	)
765     {
766 #if (ODBCVER >= 0x0300)
767       if (fInfoType == SQL_DM_VER)
768 	sprintf ((char*)buf, "%02d.%02d.%04d.%04d",
769 	  	SQL_SPEC_MAJOR, SQL_SPEC_MINOR, IODBC_BUILD / 10000, IODBC_BUILD % 10000);
770       else
771 #endif
772 	sprintf ((char*)buf, "%02d.%02d.0000", SQL_SPEC_MAJOR, SQL_SPEC_MINOR);
773       if(waMode == 'W')
774         {
775           void *prov = DM_U8toW(conv, (SQLCHAR *)buf, SQL_NTS);
776           if(prov)
777             {
778               DM_WCSNCPY(conv, buf, prov, sizeof(buf)/DM_WCHARSIZE(conv));
779               free(prov);
780             }
781           else
782             DM_SetWCharAt(conv, buf, 0, 0);
783         }
784 
785 
786       if (rgbInfoValue != NULL  && cbInfoValueMax > 0)
787 	{
788 	  len = (waMode != 'W' ? STRLEN (buf) : DM_WCSLEN(conv, buf));
789 
790 	  if (len > cbInfoValueMax - 1)
791 	    {
792 	      len = cbInfoValueMax - 1;
793 	      PUSHSQLERR (pdbc->herr, en_01004);
794 
795 	      retcode = SQL_SUCCESS_WITH_INFO;
796 	    }
797 
798 	  if (waMode != 'W')
799 	    {
800 	      STRNCPY (rgbInfoValue, buf, len);
801 	      ((char *) rgbInfoValue)[len] = '\0';
802 	    }
803 	  else
804 	    {
805 	      DM_WCSNCPY (conv, rgbInfoValue, buf, len);
806 	      DM_SetWCharAt(conv, rgbInfoValue, len, 0);
807 	    }
808 	}
809 
810       if (pcbInfoValue != NULL)
811 	{
812 	  *pcbInfoValue = (SWORD) len;
813 	}
814 
815       return retcode;
816     }
817 
818   if (pdbc->state == en_dbc_allocated || pdbc->state == en_dbc_needdata)
819     {
820       PUSHSQLERR (pdbc->herr, en_08003);
821 
822       return SQL_ERROR;
823     }
824 
825   switch (fInfoType)
826     {
827     case SQL_DRIVER_HDBC:
828       ptr = (SQLPOINTER) (pdbc->dhdbc);
829       size = sizeof (ptr);
830       break;
831 
832     case SQL_DRIVER_HENV:
833       penv = (ENV_t *) (pdbc->henv);
834       ptr = (SQLPOINTER) (penv->dhenv);
835       size = sizeof (ptr);
836       break;
837 
838     case SQL_DRIVER_HLIB:
839       penv = (ENV_t *) (pdbc->henv);
840       ptr = (SQLPOINTER) (penv->hdll);
841       size = sizeof (ptr);
842       break;
843 
844     case SQL_DRIVER_HSTMT:
845       if (rgbInfoValue != NULL)
846 	{
847 	  pstmt = *((STMT_t **) rgbInfoValue);
848 	}
849 
850       for (tpstmt = (STMT_t *) (pdbc->hstmt);
851 	  tpstmt != NULL;
852 	  tpstmt = tpstmt->next)
853 	{
854 	  if (tpstmt == pstmt)
855 	    {
856 	      break;
857 	    }
858 	}
859 
860       if (tpstmt == NULL)
861 	{
862 	  PUSHSQLERR (pdbc->herr, en_S1009);
863 
864 	  return SQL_ERROR;
865 	}
866 
867       ptr = (SQLPOINTER) (pstmt->dhstmt);
868       size = sizeof (ptr);
869       break;
870 
871     case SQL_DRIVER_NAME:
872     case SQL_DRIVER_ODBC_VER:
873     case SQL_DRIVER_VER:
874     case SQL_ODBC_INTERFACE_CONFORMANCE:
875       break;
876 
877     default:
878       /* NOTE : this was before the switch, just move here to let some information going through */
879       if (pdbc->state == en_dbc_allocated || pdbc->state == en_dbc_needdata)
880 	{
881 	  PUSHSQLERR (pdbc->herr, en_08003);
882 	  return SQL_ERROR;
883 	}
884     }
885 
886   if (size)
887     {
888       if (rgbInfoValue != NULL)
889 	{
890 	  rgbInfoValue = ptr;
891 	}
892 
893       if (pcbInfoValue != NULL)
894 	{
895 	  *(pcbInfoValue) = (SWORD) size;
896 	}
897 
898       return SQL_SUCCESS;
899     }
900 
901 #if (ODBCVER >= 0x0300)
902   /*
903    *  This was a temp value in ODBC 2
904    */
905   if (((ENV_t *) pdbc->henv)->dodbc_ver == SQL_OV_ODBC2 &&
906 	  fInfoType == SQL_OJ_CAPABILITIES)
907       fInfoType = 65003;
908 #endif /* ODBCVER >= 0x0300 */
909 
910   if (penv->unicode_driver && waMode != 'W')
911     conv_direct = CD_A2W;
912   else if (!penv->unicode_driver && waMode == 'W')
913     conv_direct = CD_W2A;
914   else if (waMode == 'W' && conv && conv->dm_cp!=conv->drv_cp)
915     conv_direct = CD_W2W;
916 
917   if (conv_direct != CD_NONE)
918     {
919       switch(fInfoType)
920         {
921         case SQL_ACCESSIBLE_PROCEDURES:
922         case SQL_ACCESSIBLE_TABLES:
923         case SQL_CATALOG_NAME:
924         case SQL_CATALOG_NAME_SEPARATOR:
925         case SQL_CATALOG_TERM:
926         case SQL_COLLATION_SEQ:
927         case SQL_COLUMN_ALIAS:
928         case SQL_DATA_SOURCE_NAME:
929         case SQL_DATA_SOURCE_READ_ONLY:
930         case SQL_DATABASE_NAME:
931         case SQL_DBMS_NAME:
932         case SQL_DBMS_VER:
933         case SQL_DESCRIBE_PARAMETER:
934         case SQL_DRIVER_NAME:
935         case SQL_DRIVER_ODBC_VER:
936         case SQL_DRIVER_VER:
937         case SQL_ODBC_VER:
938         case SQL_EXPRESSIONS_IN_ORDERBY:
939         case SQL_IDENTIFIER_QUOTE_CHAR:
940         case SQL_INTEGRITY:
941         case SQL_KEYWORDS:
942         case SQL_LIKE_ESCAPE_CLAUSE:
943         case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
944         case SQL_MULT_RESULT_SETS:
945         case SQL_MULTIPLE_ACTIVE_TXN:
946         case SQL_NEED_LONG_DATA_LEN:
947         case SQL_ORDER_BY_COLUMNS_IN_SELECT:
948         case SQL_PROCEDURE_TERM:
949         case SQL_PROCEDURES:
950         case SQL_ROW_UPDATES:
951         case SQL_SCHEMA_TERM:
952         case SQL_SEARCH_PATTERN_ESCAPE:
953         case SQL_SERVER_NAME:
954         case SQL_SPECIAL_CHARACTERS:
955         case SQL_TABLE_TERM:
956         case SQL_USER_NAME:
957         case SQL_XOPEN_CLI_YEAR:
958         case SQL_OUTER_JOINS:
959           if (conv_direct == CD_A2W || conv_direct == CD_W2W)
960             {
961               /* ansi<=unicode  OR  unicode<=unicode*/
962               if (conv_direct == CD_W2W)
963                 _cbInfoValueMax /= DM_WCHARSIZE(conv);
964 
965               if ((_InfoValue = malloc((_cbInfoValueMax + 1) * DRV_WCHARSIZE_ALLOC(conv))) == NULL)
966 	        {
967                   PUSHSQLERR (pdbc->herr, en_HY001);
968                   return SQL_ERROR;
969                 }
970               _cbInfoValueMax *=  DRV_WCHARSIZE_ALLOC(conv);
971             }
972           else if (conv_direct == CD_W2A)
973             {
974               /* unicode<=ansi*/
975               if ((_InfoValue = malloc(_cbInfoValueMax * MB_CUR_MAX + 1)) == NULL)
976 	        {
977                   PUSHSQLERR (pdbc->herr, en_HY001);
978                   return SQL_ERROR;
979                 }
980               _cbInfoValueMax /=  DM_WCHARSIZE(conv);
981             }
982 
983           infoValueOut = _InfoValue;
984           break;
985         }
986     }
987 
988   CALL_UDRIVER(hdbc, pdbc, retcode, hproc, penv->unicode_driver,
989     en_GetInfo, (pdbc->dhdbc, fInfoType, infoValueOut, _cbInfoValueMax,
990     pcbInfoValue));
991 
992   if (hproc == SQL_NULL_HPROC)
993     {
994       PUSHSQLERR (pdbc->herr, en_IM001);
995       return SQL_ERROR;
996     }
997 
998   if (retcode == SQL_ERROR  && fInfoType == SQL_DRIVER_ODBC_VER)
999     {
1000       if (waMode != 'W')
1001         {
1002           STRCPY (buf, "01.00");
1003 
1004           if (rgbInfoValue != NULL && cbInfoValueMax > 0)
1005 	    {
1006 	      len = STRLEN (buf);
1007 
1008 	      if (len > cbInfoValueMax - 1)
1009 	        {
1010 	          len = cbInfoValueMax - 1;
1011                   ret = -1;
1012 	        }
1013               else
1014                 {
1015                   ret = 0;
1016                 }
1017 
1018 	      STRNCPY (rgbInfoValue, buf, len);
1019 	      ((char *) rgbInfoValue)[len] = '\0';
1020 	    }
1021 
1022           if (pcbInfoValue != NULL)
1023             *pcbInfoValue = (SWORD) len;
1024         }
1025       else
1026         {
1027           int count;
1028           ret = dm_StrCopyOut2_A2W_d2m (conv, (SQLCHAR *) "01.00",
1029 		rgbInfoValue, cbInfoValueMax, NULL, &count);
1030           if (pcbInfoValue)
1031             *pcbInfoValue = (SQLSMALLINT)count;
1032         }
1033 
1034        if (ret == -1)
1035          {
1036            PUSHSQLERR (pdbc->herr, en_01004);
1037            retcode = SQL_SUCCESS_WITH_INFO;
1038          }
1039        else
1040          {
1041            retcode = SQL_SUCCESS;
1042          }
1043 
1044     }
1045   else if (rgbInfoValue && conv_direct != CD_NONE && SQL_SUCCEEDED (retcode))
1046     {
1047       int count;
1048       switch(fInfoType)
1049         {
1050         case SQL_ACCESSIBLE_PROCEDURES:
1051         case SQL_ACCESSIBLE_TABLES:
1052         case SQL_CATALOG_NAME:
1053         case SQL_CATALOG_NAME_SEPARATOR:
1054         case SQL_CATALOG_TERM:
1055         case SQL_COLLATION_SEQ:
1056         case SQL_COLUMN_ALIAS:
1057         case SQL_DATA_SOURCE_NAME:
1058         case SQL_DATA_SOURCE_READ_ONLY:
1059         case SQL_DATABASE_NAME:
1060         case SQL_DBMS_NAME:
1061         case SQL_DBMS_VER:
1062         case SQL_DESCRIBE_PARAMETER:
1063         case SQL_DRIVER_NAME:
1064         case SQL_DRIVER_ODBC_VER:
1065         case SQL_DRIVER_VER:
1066         case SQL_ODBC_VER:
1067         case SQL_EXPRESSIONS_IN_ORDERBY:
1068         case SQL_IDENTIFIER_QUOTE_CHAR:
1069         case SQL_INTEGRITY:
1070         case SQL_KEYWORDS:
1071         case SQL_LIKE_ESCAPE_CLAUSE:
1072         case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
1073         case SQL_MULT_RESULT_SETS:
1074         case SQL_MULTIPLE_ACTIVE_TXN:
1075         case SQL_NEED_LONG_DATA_LEN:
1076         case SQL_ORDER_BY_COLUMNS_IN_SELECT:
1077         case SQL_PROCEDURE_TERM:
1078         case SQL_PROCEDURES:
1079         case SQL_ROW_UPDATES:
1080         case SQL_SCHEMA_TERM:
1081         case SQL_SEARCH_PATTERN_ESCAPE:
1082         case SQL_SERVER_NAME:
1083         case SQL_SPECIAL_CHARACTERS:
1084         case SQL_TABLE_TERM:
1085         case SQL_USER_NAME:
1086         case SQL_XOPEN_CLI_YEAR:
1087         case SQL_OUTER_JOINS:
1088           if (conv_direct == CD_A2W)
1089             {
1090             /* ansi<=unicode*/
1091               ret = dm_StrCopyOut2_W2A_d2m (conv, infoValueOut,
1092 		(SQLCHAR *) rgbInfoValue, cbInfoValueMax, NULL, &count);
1093               if (pcbInfoValue)
1094                 *pcbInfoValue = (SQLSMALLINT)count;
1095             }
1096           else if (conv_direct == CD_W2A)
1097             {
1098             /* unicode<=ansi*/
1099               ret = dm_StrCopyOut2_A2W_d2m (conv, (SQLCHAR *) infoValueOut,
1100 		rgbInfoValue, cbInfoValueMax, NULL, &count);
1101               if (pcbInfoValue)
1102                 *pcbInfoValue = (SQLSMALLINT)count;
1103             }
1104           else if (conv_direct == CD_W2W)
1105             {
1106               /* unicode<=unicode*/
1107               ret = dm_StrCopyOut2_W2W_d2m (conv, infoValueOut,
1108 		rgbInfoValue, cbInfoValueMax, NULL, &count);
1109               if (pcbInfoValue)
1110                 *pcbInfoValue = (SQLSMALLINT)count;
1111             }
1112 
1113           if (ret == -1)
1114             {
1115               PUSHSQLERR (pdbc->herr, en_01004);
1116               retcode = SQL_SUCCESS_WITH_INFO;
1117             }
1118           break;
1119         }
1120     }
1121   MEM_FREE(_InfoValue);
1122 
1123   return retcode;
1124 }
1125 
1126 
1127 SQLRETURN SQL_API
SQLGetInfo(SQLHDBC hdbc,SQLUSMALLINT fInfoType,SQLPOINTER rgbInfoValue,SQLSMALLINT cbInfoValueMax,SQLSMALLINT * pcbInfoValue)1128 SQLGetInfo (SQLHDBC hdbc,
1129   SQLUSMALLINT		  fInfoType,
1130   SQLPOINTER		  rgbInfoValue,
1131   SQLSMALLINT		  cbInfoValueMax,
1132   SQLSMALLINT 		* pcbInfoValue)
1133 {
1134   ENTER_HDBC (hdbc, 0,
1135     trace_SQLGetInfo (TRACE_ENTER,
1136     	hdbc,
1137 	fInfoType,
1138 	rgbInfoValue, cbInfoValueMax, pcbInfoValue));
1139 
1140   retcode = SQLGetInfo_Internal(
1141   	hdbc,
1142 	fInfoType,
1143 	rgbInfoValue, cbInfoValueMax, pcbInfoValue,
1144 	'A');
1145 
1146   LEAVE_HDBC (hdbc, 0,
1147     trace_SQLGetInfo (TRACE_LEAVE,
1148     	hdbc,
1149 	fInfoType,
1150 	rgbInfoValue, cbInfoValueMax, pcbInfoValue));
1151 }
1152 
1153 
1154 #if ODBCVER >= 0x0300
1155 SQLRETURN SQL_API
SQLGetInfoA(SQLHDBC hdbc,SQLUSMALLINT fInfoType,SQLPOINTER rgbInfoValue,SQLSMALLINT cbInfoValueMax,SQLSMALLINT * pcbInfoValue)1156 SQLGetInfoA (SQLHDBC hdbc,
1157   SQLUSMALLINT		  fInfoType,
1158   SQLPOINTER		  rgbInfoValue,
1159   SQLSMALLINT		  cbInfoValueMax,
1160   SQLSMALLINT 		* pcbInfoValue)
1161 {
1162   ENTER_HDBC (hdbc, 0,
1163     trace_SQLGetInfo (TRACE_ENTER,
1164     	hdbc,
1165 	fInfoType,
1166 	rgbInfoValue, cbInfoValueMax, pcbInfoValue));
1167 
1168   retcode = SQLGetInfo_Internal(
1169   	hdbc,
1170 	fInfoType,
1171 	rgbInfoValue, cbInfoValueMax, pcbInfoValue,
1172 	'A');
1173 
1174   LEAVE_HDBC (hdbc, 0,
1175     trace_SQLGetInfo (TRACE_LEAVE,
1176     	hdbc,
1177 	fInfoType,
1178 	rgbInfoValue, cbInfoValueMax, pcbInfoValue));
1179 }
1180 
1181 
1182 SQLRETURN SQL_API
SQLGetInfoW(SQLHDBC hdbc,SQLUSMALLINT fInfoType,SQLPOINTER rgbInfoValue,SQLSMALLINT cbInfoValueMax,SQLSMALLINT * pcbInfoValue)1183 SQLGetInfoW (
1184   SQLHDBC		  hdbc,
1185   SQLUSMALLINT		  fInfoType,
1186   SQLPOINTER		  rgbInfoValue,
1187   SQLSMALLINT		  cbInfoValueMax,
1188   SQLSMALLINT 		* pcbInfoValue)
1189 {
1190   ENTER_HDBC (hdbc, 0,
1191     trace_SQLGetInfoW (TRACE_ENTER,
1192     	hdbc,
1193 	fInfoType,
1194 	rgbInfoValue, cbInfoValueMax, pcbInfoValue));
1195 
1196   retcode = SQLGetInfo_Internal (
1197   	hdbc,
1198 	fInfoType,
1199 	rgbInfoValue, cbInfoValueMax, pcbInfoValue,
1200 	'W');
1201 
1202   LEAVE_HDBC (hdbc, 0,
1203     trace_SQLGetInfoW (TRACE_LEAVE,
1204     	hdbc,
1205 	fInfoType,
1206 	rgbInfoValue, cbInfoValueMax, pcbInfoValue));
1207 }
1208 #endif
1209 
1210 
1211 static int FunctionNumbers[] =
1212 {
1213     0
1214 #define FUNCDEF(A,B,C)	,A
1215 #include "henv.ci"
1216 #undef FUNCDEF
1217 };
1218 
1219 
1220 
1221 static SQLRETURN
SQLGetFunctions_Internal(SQLHDBC hdbc,SQLUSMALLINT fFunc,SQLUSMALLINT * pfExists)1222 SQLGetFunctions_Internal (
1223   SQLHDBC		  hdbc,
1224   SQLUSMALLINT		  fFunc,
1225   SQLUSMALLINT		* pfExists)
1226 {
1227   CONN (pdbc, hdbc);
1228   HPROC hproc;
1229   SQLRETURN retcode;
1230   int i;
1231   UWORD functions2[100];
1232 #if (ODBCVER >= 0x0300)
1233   UWORD functions3[SQL_API_ODBC3_ALL_FUNCTIONS_SIZE];
1234 #endif
1235 
1236   if (pdbc->state == en_dbc_allocated
1237       || pdbc->state == en_dbc_needdata)
1238     {
1239       PUSHSQLERR (pdbc->herr, en_S1010);
1240 
1241       return SQL_ERROR;
1242     }
1243 
1244   if (pfExists == NULL)
1245     {
1246       return SQL_SUCCESS;
1247     }
1248 
1249   /*
1250    *  These functions are supported by the iODBC driver manager
1251    */
1252   if (fFunc == SQL_API_SQLDATASOURCES
1253       || fFunc == SQL_API_SQLDRIVERS
1254 #if (ODBCVER >= 0x0300)
1255       || fFunc == SQL_API_SQLGETENVATTR
1256       || fFunc == SQL_API_SQLSETENVATTR
1257 #endif
1258       )
1259     {
1260       *pfExists = (UWORD) 1;
1261       return SQL_SUCCESS;
1262     }
1263 
1264   /*
1265    *  Check if function number is within ODBC version context
1266    */
1267 #if (ODBCVER < 0x0300)
1268   if (fFunc > SQL_EXT_API_LAST)
1269     {
1270       PUSHSQLERR (pdbc->herr, en_S1095);
1271 
1272       return SQL_ERROR;
1273     }
1274 #endif
1275 
1276   /*
1277    *  In a ODBC 2.x driver context, the ODBC 3.x API calls are
1278    *  mapped by the driver manager.
1279    */
1280 #if (ODBCVER >= 0x0300)
1281   if (((ENV_t *) pdbc->henv)->dodbc_ver == SQL_OV_ODBC2)
1282     {
1283       switch (fFunc)
1284 	{
1285 	case SQL_API_ALL_FUNCTIONS:
1286 	case SQL_API_ODBC3_ALL_FUNCTIONS:
1287 	  break;
1288 
1289 	  /* Mapped ODBC3 app -> ODBC2 driver functions */
1290 	case SQL_API_SQLALLOCHANDLE:
1291 	case SQL_API_SQLFREEHANDLE:
1292 	case SQL_API_SQLSETCONNECTATTR:
1293 	case SQL_API_SQLGETCONNECTATTR:
1294 	case SQL_API_SQLGETSTMTATTR:
1295 	case SQL_API_SQLSETSTMTATTR:
1296 	case SQL_API_SQLCOLATTRIBUTE:
1297 	case SQL_API_SQLENDTRAN:
1298 	case SQL_API_SQLBULKOPERATIONS:
1299 	case SQL_API_SQLFETCHSCROLL:
1300 	case SQL_API_SQLGETDIAGREC:
1301 	case SQL_API_SQLGETDIAGFIELD:
1302 	  *pfExists = SQL_TRUE;
1303 	  return SQL_SUCCESS;
1304 
1305 	case SQL_API_SQLBINDPARAM:
1306 	  fFunc = SQL_API_SQLBINDPARAMETER;
1307 	  break;
1308 
1309 	default:
1310 	  if (fFunc > SQL_API_SQLBINDPARAMETER)
1311 	    {
1312 	      *pfExists = SQL_FALSE;
1313 
1314 	      return SQL_SUCCESS;
1315 	    }
1316 	  break;
1317 	}
1318     }
1319 #endif
1320 
1321 
1322   /*
1323    *  If the driver exports a SQLGetFunctions call, use it
1324    */
1325   hproc = _iodbcdm_getproc (pdbc, en_GetFunctions);
1326 
1327   if (hproc != SQL_NULL_HPROC)
1328     {
1329       CALL_DRIVER (hdbc, pdbc, retcode, hproc, (pdbc->dhdbc, fFunc, pfExists));
1330 
1331       return retcode;
1332     }
1333 
1334   /*
1335    *  Map deprecated functions
1336    */
1337   if (fFunc == SQL_API_SQLSETPARAM)
1338     {
1339       fFunc = SQL_API_SQLBINDPARAMETER;
1340     }
1341 
1342   /*
1343    *  Initialize intermediate result arrays
1344    */
1345   memset (functions2, '\0', sizeof (functions2));
1346 #if (ODBCVER > 0x0300)
1347   memset (functions3, '\0', sizeof (functions3));
1348 #endif
1349 
1350   /*
1351    *  Build result array by scanning for all API calls
1352    */
1353   for (i = 1; i < __LAST_API_FUNCTION__; i++)
1354     {
1355       int j = FunctionNumbers[i];
1356 
1357       hproc = _iodbcdm_getproc (pdbc, i);
1358 
1359       if (hproc != SQL_NULL_HPROC)
1360 	{
1361 	  if (j < 100)
1362 	    functions2[j] = 1;
1363 #if (ODBCVER >= 0x0300)
1364 	  functions3[j >> 4] |= (1 << (j & 0x000F));
1365 #endif
1366 	}
1367     }
1368 
1369   /*
1370    *  Finally return the information
1371    */
1372   if (fFunc == SQL_API_ALL_FUNCTIONS)
1373     {
1374       memcpy (pfExists, &functions2, sizeof (functions2));
1375     }
1376 #if (ODBCVER < 0x0300)
1377   else
1378     {
1379       *pfExists = functions2[fFunc];
1380     }
1381 #else
1382   else if (fFunc == SQL_API_ODBC3_ALL_FUNCTIONS)
1383     {
1384       memcpy (pfExists, &functions3, sizeof (functions3));
1385     }
1386   else
1387     {
1388       *pfExists = SQL_FUNC_EXISTS (functions3, fFunc);
1389     }
1390 #endif
1391 
1392   return SQL_SUCCESS;
1393 }
1394 
1395 
1396 SQLRETURN SQL_API
SQLGetFunctions(SQLHDBC hdbc,SQLUSMALLINT fFunc,SQLUSMALLINT * pfExists)1397 SQLGetFunctions (
1398   SQLHDBC		  hdbc,
1399   SQLUSMALLINT		  fFunc,
1400   SQLUSMALLINT	 	* pfExists)
1401 {
1402   ENTER_HDBC (hdbc, 0,
1403     trace_SQLGetFunctions (TRACE_ENTER,
1404     	hdbc,
1405 	fFunc,
1406 	pfExists));
1407 
1408   retcode = SQLGetFunctions_Internal (
1409     	hdbc,
1410 	fFunc,
1411 	pfExists);
1412 
1413   LEAVE_HDBC (hdbc, 0,
1414     trace_SQLGetFunctions (TRACE_LEAVE,
1415     	hdbc,
1416 	fFunc,
1417 	pfExists));
1418 }
1419