1/*
2 *  result.c
3 *
4 *  $Id: result.c,v 1.29 2007/10/08 12:37:15 source Exp $
5 *
6 *  Prepare for getting query result
7 *
8 *  The iODBC driver manager.
9 *
10 *  Copyright (C) 1995 by Ke Jin <kejin@empress.com>
11 *  Copyright (C) 1996-2006 by 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#include <iodbc.h>
79
80#include <sql.h>
81#include <sqlext.h>
82#include <sqlucode.h>
83
84#include <unicode.h>
85
86#include <dlproc.h>
87
88#include <herr.h>
89#include <henv.h>
90#include <hdbc.h>
91#include <hstmt.h>
92
93#include <itrace.h>
94
95static SQLRETURN
96SQLBindCol_Internal (
97    SQLHSTMT hstmt,
98    SQLUSMALLINT icol,
99    SQLSMALLINT fCType,
100    SQLPOINTER rgbValue,
101    SQLLEN cbValueMax,
102    SQLLEN *pcbValue)
103{
104  STMT(pstmt, hstmt);
105  CONN (pdbc, pstmt->hdbc);
106  ENVR (penv, pdbc->henv);
107  HPROC hproc = SQL_NULL_HPROC;
108  SQLSMALLINT nCType;
109  SQLRETURN retcode;
110
111  /* check argument */
112  switch (fCType)
113    {
114    case SQL_C_DEFAULT:
115    case SQL_C_BIT:
116    case SQL_C_BINARY:
117    case SQL_C_CHAR:
118    case SQL_C_DATE:
119    case SQL_C_DOUBLE:
120    case SQL_C_FLOAT:
121    case SQL_C_LONG:
122    case SQL_C_SHORT:
123    case SQL_C_SLONG:
124    case SQL_C_SSHORT:
125    case SQL_C_STINYINT:
126    case SQL_C_TIME:
127    case SQL_C_TIMESTAMP:
128    case SQL_C_TINYINT:
129    case SQL_C_ULONG:
130    case SQL_C_USHORT:
131    case SQL_C_UTINYINT:
132#if (ODBCVER >= 0x0300)
133    case SQL_C_GUID:
134    case SQL_C_INTERVAL_DAY:
135    case SQL_C_INTERVAL_DAY_TO_HOUR:
136    case SQL_C_INTERVAL_DAY_TO_MINUTE:
137    case SQL_C_INTERVAL_DAY_TO_SECOND:
138    case SQL_C_INTERVAL_HOUR:
139    case SQL_C_INTERVAL_HOUR_TO_MINUTE:
140    case SQL_C_INTERVAL_HOUR_TO_SECOND:
141    case SQL_C_INTERVAL_MINUTE:
142    case SQL_C_INTERVAL_MINUTE_TO_SECOND:
143    case SQL_C_INTERVAL_MONTH:
144    case SQL_C_INTERVAL_SECOND:
145    case SQL_C_INTERVAL_YEAR:
146    case SQL_C_INTERVAL_YEAR_TO_MONTH:
147    case SQL_C_NUMERIC:
148    case SQL_C_SBIGINT:
149    case SQL_C_TYPE_DATE:
150    case SQL_C_TYPE_TIME:
151    case SQL_C_TYPE_TIMESTAMP:
152    case SQL_C_UBIGINT:
153    case SQL_C_WCHAR:
154#endif
155      break;
156
157    default:
158      PUSHSQLERR (pstmt->herr, en_S1003);
159      return SQL_ERROR;
160    }
161
162  if (cbValueMax < 0)
163    {
164      PUSHSQLERR (pstmt->herr, en_S1090);
165
166      return SQL_ERROR;
167    }
168
169  /* check state */
170  if (pstmt->state > en_stmt_needdata || pstmt->asyn_on != en_NullProc)
171    {
172      PUSHSQLERR (pstmt->herr, en_S1010);
173      return SQL_ERROR;
174    }
175
176  /*
177   *  Convert C type to ODBC version of driver
178   */
179  nCType = _iodbcdm_map_c_type (fCType, penv->dodbc_ver);
180
181  /* call driver's function */
182  hproc = _iodbcdm_getproc (pstmt->hdbc, en_BindCol);
183
184  if (hproc == SQL_NULL_HPROC)
185    {
186      PUSHSQLERR (pstmt->herr, en_IM001);
187
188      return SQL_ERROR;
189    }
190
191  if (icol != 0 && !penv->unicode_driver && nCType == SQL_C_WCHAR)
192    {
193      CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
194          (pstmt->dhstmt, icol, SQL_C_CHAR, rgbValue,
195           cbValueMax, pcbValue));
196    }
197  else
198    CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
199        (pstmt->dhstmt, icol, nCType, rgbValue, cbValueMax, pcbValue));
200
201  if (icol != 0 && !penv->unicode_driver && nCType == SQL_C_WCHAR
202      && SQL_SUCCEEDED (retcode))
203    {
204      BIND_t tbind;
205
206      tbind.bn_col = icol;
207      tbind.bn_type = nCType;
208      tbind.bn_data = rgbValue;
209      tbind.bn_size = cbValueMax;
210      tbind.bn_pInd = pcbValue;
211
212      if (rgbValue)
213        _iodbcdm_BindColumn (pstmt, &tbind);
214      else
215        _iodbcdm_UnBindColumn (pstmt, &tbind);
216    }
217
218  return retcode;
219}
220
221
222SQLRETURN SQL_API
223SQLBindCol (
224    SQLHSTMT hstmt,
225    SQLUSMALLINT icol,
226    SQLSMALLINT fCType,
227    SQLPOINTER rgbValue,
228    SQLLEN cbValueMax,
229    SQLLEN *pcbValue)
230{
231  ENTER_STMT (hstmt,
232      trace_SQLBindCol (TRACE_ENTER,
233	  hstmt, icol, fCType, rgbValue, cbValueMax, pcbValue));
234
235  retcode = SQLBindCol_Internal (
236      hstmt, icol, fCType, rgbValue, cbValueMax, pcbValue);
237
238  LEAVE_STMT (hstmt,
239      trace_SQLBindCol (TRACE_LEAVE,
240	  hstmt, icol, fCType, rgbValue, cbValueMax, pcbValue));
241}
242
243
244SQLRETURN SQL_API
245SQLGetCursorName_Internal (
246  SQLHSTMT 		  hstmt,
247  SQLCHAR 		* szCursor,
248  SQLSMALLINT 		  cbCursorMax,
249  SQLSMALLINT 	 	* pcbCursor,
250  char			  waMode)
251{
252  STMT(pstmt, hstmt);
253  CONN (pdbc, pstmt->hdbc);
254  ENVR (penv, pdbc->henv);
255  HPROC hproc = SQL_NULL_HPROC;
256  SQLRETURN retcode = SQL_SUCCESS;
257  void * cursorOut = szCursor;
258  void * _Cursor = NULL;
259
260  /* check argument */
261  if (cbCursorMax < (SWORD) 0)
262    {
263      PUSHSQLERR (pstmt->herr, en_S1090);
264
265      return SQL_ERROR;
266    }
267
268  /* check state */
269  if (pstmt->state >= en_stmt_needdata || pstmt->asyn_on != en_NullProc)
270    {
271      PUSHSQLERR (pstmt->herr, en_S1010);
272
273      return SQL_ERROR;
274    }
275
276  if (pstmt->state < en_stmt_cursoropen
277      && pstmt->cursor_state == en_stmt_cursor_no)
278    {
279      PUSHSQLERR (pstmt->herr, en_S1015);
280
281      return SQL_ERROR;
282    }
283
284  /* call driver's function */
285
286
287  if ((penv->unicode_driver && waMode != 'W')
288      || (!penv->unicode_driver && waMode == 'W'))
289    {
290      if (waMode != 'W')
291        {
292        /* ansi=>unicode*/
293          if ((_Cursor = malloc((cbCursorMax + 1) * sizeof(wchar_t))) == NULL)
294	    {
295              PUSHSQLERR (pstmt->herr, en_HY001);
296              return SQL_ERROR;
297            }
298        }
299      else
300        {
301        /* unicode=>ansi*/
302          if ((_Cursor = malloc(cbCursorMax + 1)) == NULL)
303	    {
304              PUSHSQLERR (pstmt->herr, en_HY001);
305              return SQL_ERROR;
306            }
307        }
308      cursorOut = _Cursor;
309    }
310
311  /* call driver */
312  CALL_UDRIVER(pstmt->hdbc, pstmt, retcode, hproc, penv->unicode_driver,
313    en_GetCursorName, (
314       pstmt->dhstmt,
315       cursorOut,
316       cbCursorMax,
317       pcbCursor));
318
319  if (hproc == SQL_NULL_HPROC)
320    {
321      MEM_FREE(_Cursor);
322      PUSHSQLERR (pstmt->herr, en_IM001);
323      return SQL_ERROR;
324    }
325
326  if (szCursor
327      && SQL_SUCCEEDED (retcode)
328      && ((penv->unicode_driver && waMode != 'W')
329          || (!penv->unicode_driver && waMode == 'W')))
330    {
331      if (waMode != 'W')
332        {
333        /* ansi<=unicode*/
334          dm_StrCopyOut2_W2A ((SQLWCHAR *) cursorOut, (SQLCHAR *) szCursor, cbCursorMax, NULL);
335        }
336      else
337        {
338        /* unicode<=ansi*/
339          dm_StrCopyOut2_A2W ((SQLCHAR *) cursorOut, (SQLWCHAR *) szCursor, cbCursorMax, NULL);
340        }
341    }
342
343  MEM_FREE(_Cursor);
344
345  return retcode;
346}
347
348
349SQLRETURN SQL_API
350SQLGetCursorName (
351  SQLHSTMT 		  hstmt,
352  SQLCHAR  		* szCursor,
353  SQLSMALLINT 		  cbCursorMax,
354  SQLSMALLINT 	 	* pcbCursor)
355{
356  ENTER_STMT (hstmt,
357    trace_SQLGetCursorName (TRACE_ENTER,
358    	hstmt,
359	szCursor, cbCursorMax, pcbCursor));
360
361  retcode = SQLGetCursorName_Internal(
362  	hstmt,
363	szCursor, cbCursorMax, pcbCursor,
364	'A');
365
366  LEAVE_STMT (hstmt,
367    trace_SQLGetCursorName (TRACE_LEAVE,
368    	hstmt,
369	szCursor, cbCursorMax, pcbCursor));
370}
371
372
373#if ODBCVER >= 0x0300
374SQLRETURN SQL_API
375SQLGetCursorNameA (
376  SQLHSTMT 		  hstmt,
377  SQLCHAR  		* szCursor,
378  SQLSMALLINT 		  cbCursorMax,
379  SQLSMALLINT 		* pcbCursor)
380{
381  ENTER_STMT (hstmt,
382    trace_SQLGetCursorName (TRACE_ENTER,
383    	hstmt,
384	szCursor, cbCursorMax, pcbCursor));
385
386  retcode = SQLGetCursorName_Internal(
387  	hstmt,
388	szCursor, cbCursorMax, pcbCursor,
389	'A');
390
391  LEAVE_STMT (hstmt,
392    trace_SQLGetCursorName (TRACE_LEAVE,
393    	hstmt,
394	szCursor, cbCursorMax, pcbCursor));
395}
396
397
398SQLRETURN SQL_API
399SQLGetCursorNameW (SQLHSTMT hstmt,
400    SQLWCHAR		* szCursor,
401    SQLSMALLINT		  cbCursorMax,
402    SQLSMALLINT 	* pcbCursor)
403{
404  ENTER_STMT (hstmt,
405    trace_SQLGetCursorNameW (TRACE_ENTER,
406    	hstmt,
407	szCursor, cbCursorMax, pcbCursor));
408
409  retcode = SQLGetCursorName_Internal(
410  	hstmt,
411	(SQLCHAR *) szCursor, cbCursorMax, pcbCursor,
412	'W');
413
414  LEAVE_STMT (hstmt,
415    trace_SQLGetCursorNameW (TRACE_LEAVE,
416    	hstmt,
417	szCursor, cbCursorMax, pcbCursor));
418}
419#endif
420
421
422static SQLRETURN
423SQLRowCount_Internal (
424  SQLHSTMT		  hstmt,
425  SQLLEN		* pcrow)
426{
427  STMT(pstmt, hstmt);
428  HPROC hproc;
429  SQLRETURN retcode;
430
431  /* check state */
432  if (pstmt->state >= en_stmt_needdata
433      || pstmt->state <= en_stmt_prepared
434      || pstmt->asyn_on != en_NullProc)
435    {
436      PUSHSQLERR (pstmt->herr, en_S1010);
437
438      return SQL_ERROR;
439    }
440
441  /* call driver */
442  hproc = _iodbcdm_getproc (pstmt->hdbc, en_RowCount);
443
444  if (hproc == SQL_NULL_HPROC)
445    {
446      PUSHSQLERR (pstmt->herr, en_IM001);
447
448      return SQL_ERROR;
449    }
450
451  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
452      (pstmt->dhstmt, pcrow));
453
454  return retcode;
455}
456
457
458SQLRETURN SQL_API
459SQLRowCount (
460  SQLHSTMT		  hstmt,
461  SQLLEN 		* pcrow)
462{
463  ENTER_STMT (hstmt,
464    trace_SQLRowCount (TRACE_ENTER, hstmt, pcrow));
465
466  retcode = SQLRowCount_Internal (hstmt, pcrow);
467
468  LEAVE_STMT (hstmt,
469    trace_SQLRowCount (TRACE_LEAVE, hstmt, pcrow));
470}
471
472
473SQLRETURN SQL_API
474_iodbcdm_NumResultCols (
475    SQLHSTMT		  hstmt,
476    SQLSMALLINT		* pccol)
477{
478  STMT (pstmt, hstmt);
479  HPROC hproc;
480  SQLRETURN retcode;
481  SWORD ccol;
482
483  /* check state */
484  if (pstmt->asyn_on == en_NullProc)
485    {
486      if (pstmt->state == en_stmt_allocated
487	  || pstmt->state >= en_stmt_needdata)
488	{
489	  PUSHSQLERR (pstmt->herr, en_S1010);
490
491	  return SQL_ERROR;
492	}
493    }
494  else if (pstmt->asyn_on != en_NumResultCols)
495    {
496      PUSHSQLERR (pstmt->herr, en_S1010);
497
498      return SQL_ERROR;
499    }
500
501  /* call driver */
502  hproc = _iodbcdm_getproc (pstmt->hdbc, en_NumResultCols);
503
504  if (hproc == SQL_NULL_HPROC)
505    {
506      PUSHSQLERR (pstmt->herr, en_IM001);
507
508      return SQL_ERROR;
509    }
510
511  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
512      (pstmt->dhstmt, &ccol));
513
514  /* state transition */
515  if (pstmt->asyn_on == en_NumResultCols)
516    {
517      switch (retcode)
518	{
519	case SQL_SUCCESS:
520	case SQL_SUCCESS_WITH_INFO:
521	case SQL_ERROR:
522	  pstmt->asyn_on = en_NullProc;
523
524	case SQL_STILL_EXECUTING:
525	default:
526	  break;
527	}
528    }
529
530  switch (retcode)
531    {
532    case SQL_SUCCESS:
533    case SQL_SUCCESS_WITH_INFO:
534      break;
535
536    case SQL_STILL_EXECUTING:
537      ccol = 0;
538      pstmt->asyn_on = en_NumResultCols;
539      break;
540
541    default:
542      ccol = 0;
543      break;
544    }
545
546  if (pccol)
547    {
548      *pccol = ccol;
549    }
550  return retcode;
551}
552
553
554SQLRETURN SQL_API
555SQLNumResultCols (
556  SQLHSTMT		  hstmt,
557  SQLSMALLINT 		* pccol)
558{
559  ENTER_STMT (hstmt,
560    trace_SQLNumResultCols (TRACE_ENTER, hstmt, pccol));
561
562  retcode = _iodbcdm_NumResultCols (hstmt, pccol);
563
564  LEAVE_STMT (hstmt,
565    trace_SQLNumResultCols (TRACE_LEAVE, hstmt, pccol));
566}
567
568
569SQLSMALLINT
570_iodbcdm_map_sql_type (int type, int odbcver)
571{
572  switch (type)
573    {
574      case SQL_DATE:
575      case SQL_TYPE_DATE:
576      	return (odbcver == SQL_OV_ODBC3) ?  SQL_TYPE_DATE : SQL_DATE;
577
578      case SQL_TIME:
579      case SQL_TYPE_TIME:
580      	return (odbcver == SQL_OV_ODBC3) ?  SQL_TYPE_TIME : SQL_TIME;
581
582      case SQL_TIMESTAMP:
583      case SQL_TYPE_TIMESTAMP:
584      	return (odbcver == SQL_OV_ODBC3) ?  SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
585    }
586
587    return type;
588}
589
590
591SQLSMALLINT
592_iodbcdm_map_c_type (int type, int odbcver)
593{
594  switch (type)
595    {
596      case SQL_C_DATE:
597      case SQL_C_TYPE_DATE:
598      	return (odbcver == SQL_OV_ODBC3) ?  SQL_C_TYPE_DATE : SQL_C_DATE;
599
600      case SQL_C_TIME:
601      case SQL_C_TYPE_TIME:
602      	return (odbcver == SQL_OV_ODBC3) ?  SQL_C_TYPE_TIME : SQL_C_TIME;
603
604      case SQL_C_TIMESTAMP:
605      case SQL_C_TYPE_TIMESTAMP:
606      	return (odbcver == SQL_OV_ODBC3) ?  SQL_C_TYPE_TIMESTAMP : SQL_C_TIMESTAMP;
607    }
608
609    return type;
610}
611
612
613SQLRETURN SQL_API
614SQLDescribeCol_Internal (
615    SQLHSTMT		  hstmt,
616    SQLUSMALLINT	  icol,
617    SQLPOINTER		  szColName,
618    SQLSMALLINT		  cbColNameMax,
619    SQLSMALLINT 	* pcbColName,
620    SQLSMALLINT 	* pfSqlType,
621    SQLULEN	 	* pcbColDef,
622    SQLSMALLINT 	* pibScale,
623    SQLSMALLINT 	* pfNullable,
624    SQLCHAR		  waMode)
625{
626  STMT(pstmt, hstmt);
627  CONN (pdbc, pstmt->hdbc);
628  ENVR (penv, pdbc->henv);
629  GENV (genv, pdbc->genv);
630  HPROC hproc = SQL_NULL_HPROC;
631  SQLRETURN retcode = SQL_SUCCESS;
632  void * _ColName = NULL;
633  void * colNameOut = szColName;
634  sqlstcode_t sqlstat = en_00000;
635
636  /* check arguments */
637  if (icol == 0)
638    {
639      sqlstat = en_S1002;
640    }
641  else if (cbColNameMax < 0)
642    {
643      sqlstat = en_S1090;
644    }
645
646  if (sqlstat != en_00000)
647    {
648      PUSHSQLERR (pstmt->herr, sqlstat);
649
650      return SQL_ERROR;
651    }
652#if (ODBCVER < 0x0300)
653  /* check state */
654  if (pstmt->asyn_on == en_NullProc)
655    {
656      if (pstmt->state == en_stmt_allocated
657	  || pstmt->state >= en_stmt_needdata)
658	{
659	  sqlstat = en_S1010;
660	}
661    }
662  else if (pstmt->asyn_on != en_DescribeCol)
663    {
664      sqlstat = en_S1010;
665    }
666#endif
667
668  if (sqlstat != en_00000)
669    {
670      PUSHSQLERR (pstmt->herr, sqlstat);
671
672      return SQL_ERROR;
673    }
674
675  /* call driver */
676    if (szColName != NULL && cbColNameMax > 0 &&
677    	((penv->unicode_driver && waMode != 'W') ||
678	(!penv->unicode_driver && waMode == 'W'))
679	)
680    {
681      if (waMode != 'W')
682        {
683        /* ansi=>unicode*/
684          if ((_ColName = _iodbcdm_alloc_param(pstmt, 0,
685          	             cbColNameMax * sizeof(wchar_t))) == NULL)
686	    {
687              PUSHSQLERR (pstmt->herr, en_HY001);
688              return SQL_ERROR;
689            }
690        }
691      else
692        {
693        /* unicode=>ansi*/
694          if ((_ColName = _iodbcdm_alloc_param(pstmt, 0, cbColNameMax)) == NULL)
695	    {
696              PUSHSQLERR (pstmt->herr, en_HY001);
697              return SQL_ERROR;
698            }
699        }
700      colNameOut = _ColName;
701    }
702
703  /* call driver */
704  CALL_UDRIVER(pstmt->hdbc, pstmt, retcode, hproc, penv->unicode_driver,
705    en_DescribeCol, (
706       pstmt->dhstmt,
707       icol,
708       colNameOut,
709       cbColNameMax,
710       pcbColName,
711       pfSqlType,
712       pcbColDef,
713       pibScale,
714       pfNullable));
715
716  if (hproc == SQL_NULL_HPROC)
717    {
718      _iodbcdm_FreeStmtParams(pstmt);
719      PUSHSQLERR (pstmt->herr, en_IM001);
720      return SQL_ERROR;
721    }
722
723  /*
724   *  Convert sql type to ODBC version of application
725   */
726  if (SQL_SUCCEEDED(retcode) && pfSqlType)
727    *pfSqlType = _iodbcdm_map_sql_type (*pfSqlType, genv->odbc_ver);
728
729  if (szColName
730      && SQL_SUCCEEDED (retcode)
731      && ((penv->unicode_driver && waMode != 'W')
732          || (!penv->unicode_driver && waMode == 'W')))
733    {
734      if (waMode != 'W')
735        {
736        /* ansi<=unicode*/
737          dm_StrCopyOut2_W2A ((SQLWCHAR *) colNameOut, (SQLCHAR *) szColName, cbColNameMax, NULL);
738        }
739      else
740        {
741        /* unicode<=ansi*/
742          dm_StrCopyOut2_A2W ((SQLCHAR *) colNameOut, (SQLWCHAR *) szColName, cbColNameMax, NULL);
743        }
744    }
745
746  if (retcode != SQL_STILL_EXECUTING)
747    _iodbcdm_FreeStmtParams(pstmt);
748
749  /* state transition */
750  if (pstmt->asyn_on == en_DescribeCol)
751    {
752      switch (retcode)
753	{
754	case SQL_SUCCESS:
755	case SQL_SUCCESS_WITH_INFO:
756	case SQL_ERROR:
757	  pstmt->asyn_on = en_NullProc;
758	  break;
759
760	default:
761	   return retcode;
762	}
763    }
764
765  switch (pstmt->state)
766    {
767    case en_stmt_prepared:
768    case en_stmt_cursoropen:
769    case en_stmt_fetched:
770    case en_stmt_xfetched:
771      if (retcode == SQL_STILL_EXECUTING)
772	{
773	  pstmt->asyn_on = en_DescribeCol;
774	}
775      break;
776
777    default:
778      break;
779    }
780
781  return retcode;
782}
783
784
785SQLRETURN SQL_API
786SQLDescribeCol (SQLHSTMT hstmt,
787    SQLUSMALLINT	  icol,
788    SQLCHAR		* szColName,
789    SQLSMALLINT		  cbColNameMax,
790    SQLSMALLINT		* pcbColName,
791    SQLSMALLINT		* pfSqlType,
792    SQLULEN		* pcbColDef,
793    SQLSMALLINT		* pibScale,
794    SQLSMALLINT		* pfNullable)
795{
796  ENTER_STMT (hstmt,
797    trace_SQLDescribeCol (TRACE_ENTER,
798    	hstmt,
799	icol,
800	szColName, cbColNameMax, pcbColName,
801	pfSqlType,
802	pcbColDef,
803	pibScale,
804	pfNullable));
805
806  retcode = SQLDescribeCol_Internal (
807  	hstmt,
808	icol,
809	szColName, cbColNameMax, pcbColName,
810	pfSqlType,
811	pcbColDef,
812	pibScale,
813	pfNullable,
814	'A');
815
816  LEAVE_STMT (hstmt,
817    trace_SQLDescribeCol (TRACE_LEAVE,
818    	hstmt,
819	icol,
820	szColName, cbColNameMax, pcbColName,
821	pfSqlType,
822	pcbColDef,
823	pibScale,
824	pfNullable));
825}
826
827
828#if ODBCVER >= 0x0300
829SQLRETURN SQL_API
830SQLDescribeColA (SQLHSTMT hstmt,
831    SQLUSMALLINT	  icol,
832    SQLCHAR		* szColName,
833    SQLSMALLINT		  cbColNameMax,
834    SQLSMALLINT		* pcbColName,
835    SQLSMALLINT		* pfSqlType,
836    SQLULEN		* pcbColDef,
837    SQLSMALLINT		* pibScale,
838    SQLSMALLINT		* pfNullable)
839{
840  ENTER_STMT (hstmt,
841    trace_SQLDescribeCol (TRACE_ENTER,
842    	hstmt,
843	icol,
844	szColName, cbColNameMax, pcbColName,
845	pfSqlType,
846	pcbColDef,
847	pibScale,
848	pfNullable));
849
850  retcode = SQLDescribeCol_Internal (
851  	hstmt,
852	icol,
853	szColName, cbColNameMax, pcbColName,
854	pfSqlType,
855	pcbColDef,
856	pibScale,
857	pfNullable,
858	'A');
859
860  LEAVE_STMT (hstmt,
861    trace_SQLDescribeCol (TRACE_LEAVE,
862    	hstmt,
863	icol,
864	szColName, cbColNameMax, pcbColName,
865	pfSqlType,
866	pcbColDef,
867	pibScale,
868	pfNullable));
869}
870
871
872SQLRETURN SQL_API
873SQLDescribeColW (
874  SQLHSTMT		  hstmt,
875  SQLUSMALLINT		  icol,
876  SQLWCHAR		* szColName,
877  SQLSMALLINT		  cbColNameMax,
878  SQLSMALLINT		* pcbColName,
879  SQLSMALLINT		* pfSqlType,
880  SQLULEN		* pcbColDef,
881  SQLSMALLINT		* pibScale,
882  SQLSMALLINT		* pfNullable)
883{
884  ENTER_STMT (hstmt,
885    trace_SQLDescribeColW (TRACE_ENTER,
886    	hstmt,
887	icol,
888	szColName, cbColNameMax, pcbColName,
889	pfSqlType,
890	pcbColDef,
891	pibScale,
892	pfNullable));
893
894  retcode = SQLDescribeCol_Internal (
895  	hstmt,
896	icol,
897	szColName, cbColNameMax, pcbColName,
898	pfSqlType,
899	pcbColDef,
900	pibScale,
901	pfNullable,
902	'W');
903
904  LEAVE_STMT (hstmt,
905    trace_SQLDescribeColW (TRACE_LEAVE,
906    	hstmt,
907	icol,
908	szColName, cbColNameMax, pcbColName,
909	pfSqlType,
910	pcbColDef,
911	pibScale,
912	pfNullable));
913}
914#endif
915
916
917SQLRETURN SQL_API
918SQLColAttributes_Internal (
919    SQLHSTMT		  hstmt,
920    SQLUSMALLINT	  icol,
921    SQLUSMALLINT	  fDescType,
922    SQLPOINTER		  rgbDesc,
923    SQLSMALLINT		  cbDescMax,
924    SQLSMALLINT	  	* pcbDesc,
925    SQLLEN 		* pfDesc,
926    SQLCHAR		  waMode)
927{
928  STMT(pstmt, hstmt);
929  CONN (pdbc, pstmt->hdbc);
930  ENVR (penv, pdbc->henv);
931  HPROC hproc2 = SQL_NULL_HPROC;
932  HPROC hproc3 = SQL_NULL_HPROC;
933  SQLRETURN retcode = SQL_SUCCESS;
934  void * _Desc = NULL;
935  void * descOut = rgbDesc;
936  sqlstcode_t sqlstat = en_00000;
937  SQLUSMALLINT new_attr = fDescType;
938  SQLUINTEGER odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
939  SQLUINTEGER dodbc_ver = ((ENV_t *) pdbc->henv)->dodbc_ver;
940
941  /* check arguments */
942  if (icol == 0 && fDescType != SQL_COLUMN_COUNT)
943    {
944      sqlstat = en_S1002;
945    }
946  else if (cbDescMax < 0)
947    {
948      sqlstat = en_S1090;
949    }
950#if (ODBCVER < 0x0300)
951  else if (			/* fDescType < SQL_COLATT_OPT_MIN || *//* turnoff warning */
952	(fDescType > SQL_COLATT_OPT_MAX
953	  && fDescType < SQL_COLUMN_DRIVER_START))
954    {
955      sqlstat = en_S1091;
956    }
957#endif /* ODBCVER < 0x0300 */
958
959  if (sqlstat != en_00000)
960    {
961      PUSHSQLERR (pstmt->herr, sqlstat);
962
963      return SQL_ERROR;
964    }
965
966  /* check state */
967  if (pstmt->asyn_on == en_NullProc)
968    {
969      if (pstmt->state == en_stmt_allocated
970	  || pstmt->state >= en_stmt_needdata)
971	{
972	  sqlstat = en_S1010;
973	}
974    }
975  else if (pstmt->asyn_on != en_ColAttributes)
976    {
977      sqlstat = en_S1010;
978    }
979
980  if (sqlstat != en_00000)
981    {
982      PUSHSQLERR (pstmt->herr, sqlstat);
983
984      return SQL_ERROR;
985    }
986
987  /* call driver */
988  if (rgbDesc != NULL && cbDescMax > 0 &&
989      ((penv->unicode_driver && waMode != 'W') ||
990       (!penv->unicode_driver && waMode == 'W')))
991    {
992      switch(fDescType)
993        {
994        case SQL_COLUMN_QUALIFIER_NAME:
995        case SQL_COLUMN_NAME:
996        case SQL_COLUMN_LABEL:
997        case SQL_COLUMN_OWNER_NAME:
998        case SQL_COLUMN_TABLE_NAME:
999        case SQL_COLUMN_TYPE_NAME:
1000
1001          if (waMode != 'W')
1002            {
1003            /* ansi=>unicode*/
1004              cbDescMax *= sizeof(wchar_t);
1005              if ((_Desc = _iodbcdm_alloc_param(pstmt, 0, cbDescMax)) == NULL)
1006	        {
1007                  PUSHSQLERR (pstmt->herr, en_HY001);
1008                  return SQL_ERROR;
1009                }
1010            }
1011          else
1012            {
1013            /* unicode=>ansi*/
1014              cbDescMax /= sizeof(wchar_t);
1015              if ((_Desc = _iodbcdm_alloc_param(pstmt, 0, cbDescMax)) == NULL)
1016	        {
1017                  PUSHSQLERR (pstmt->herr, en_HY001);
1018                  return SQL_ERROR;
1019                }
1020            }
1021          descOut = _Desc;
1022          break;
1023        }
1024    }
1025
1026#if (ODBCVER >= 0x0300)
1027  switch (new_attr)
1028    {
1029    case SQL_COLUMN_NAME:      new_attr = SQL_DESC_NAME;      break;
1030    case SQL_COLUMN_NULLABLE:  new_attr = SQL_DESC_NULLABLE;  break;
1031    case SQL_COLUMN_COUNT:     new_attr = SQL_DESC_COUNT;     break;
1032    }
1033#endif
1034
1035  if (penv->unicode_driver)
1036    {
1037      hproc2 = _iodbcdm_getproc (pdbc, en_ColAttributesW);
1038#if (ODBCVER >= 0x0300)
1039      hproc3 = _iodbcdm_getproc (pdbc, en_ColAttributeW);
1040#endif
1041
1042      if (odbc_ver == SQL_OV_ODBC2 &&
1043          (  dodbc_ver == SQL_OV_ODBC2
1044           || (dodbc_ver == SQL_OV_ODBC3 && hproc2 != SQL_NULL_HPROC)))
1045        hproc3 = SQL_NULL_HPROC;
1046
1047#if (ODBCVER >= 0x0300)
1048      if (hproc3 != SQL_NULL_HPROC)
1049        {
1050          CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc3, (
1051       	          pstmt->dhstmt,
1052       	          icol,
1053       	          new_attr,
1054       	          descOut,
1055       	          cbDescMax,
1056       	          pcbDesc,
1057       	          pfDesc));
1058        }
1059      else
1060#endif
1061        {
1062          if (hproc2 == SQL_NULL_HPROC)
1063            {
1064              _iodbcdm_FreeStmtParams(pstmt);
1065              PUSHSQLERR (pstmt->herr, en_IM001);
1066              return SQL_ERROR;
1067            }
1068
1069          CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc2, (
1070      	          pstmt->dhstmt,
1071      	          icol,
1072      	          fDescType,
1073      	          descOut,
1074      	          cbDescMax,
1075      	          pcbDesc,
1076      	          pfDesc));
1077        }
1078    }
1079  else
1080    {
1081      /* SQL_XXX */
1082      /* SQL_XXX_A */
1083      hproc2 = _iodbcdm_getproc (pdbc, en_ColAttributes);
1084      if (hproc2 == SQL_NULL_HPROC)
1085        hproc2 = _iodbcdm_getproc (pdbc, en_ColAttributesA);
1086#if (ODBCVER >= 0x0300)
1087      hproc3 = _iodbcdm_getproc (pdbc, en_ColAttribute);
1088      if (hproc3 == SQL_NULL_HPROC)
1089        hproc3 = _iodbcdm_getproc (pdbc, en_ColAttributeA);
1090#endif
1091
1092      if (odbc_ver == SQL_OV_ODBC2 &&
1093          (  dodbc_ver == SQL_OV_ODBC2
1094           || (dodbc_ver == SQL_OV_ODBC3 && hproc2 != SQL_NULL_HPROC)))
1095        hproc3 = SQL_NULL_HPROC;
1096
1097#if (ODBCVER >= 0x0300)
1098      if (hproc3 != SQL_NULL_HPROC)
1099        {
1100          CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc3, (
1101       	          pstmt->dhstmt,
1102       	          icol,
1103       	          new_attr,
1104       	          descOut,
1105       	          cbDescMax,
1106       	          pcbDesc,
1107       	          pfDesc));
1108        }
1109      else
1110#endif
1111        {
1112          if (hproc2 == SQL_NULL_HPROC)
1113            {
1114              _iodbcdm_FreeStmtParams(pstmt);
1115              PUSHSQLERR (pstmt->herr, en_IM001);
1116              return SQL_ERROR;
1117            }
1118
1119          CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc2, (
1120      	          pstmt->dhstmt,
1121      	          icol,
1122      	          fDescType,
1123      	          descOut,
1124      	          cbDescMax,
1125      	          pcbDesc,
1126      	          pfDesc));
1127        }
1128    }
1129
1130  if (rgbDesc
1131      && SQL_SUCCEEDED (retcode)
1132      && ((penv->unicode_driver && waMode != 'W')
1133          || (!penv->unicode_driver && waMode == 'W')))
1134    {
1135      switch(fDescType)
1136        {
1137        case SQL_COLUMN_QUALIFIER_NAME:
1138        case SQL_COLUMN_NAME:
1139        case SQL_COLUMN_LABEL:
1140        case SQL_COLUMN_OWNER_NAME:
1141        case SQL_COLUMN_TABLE_NAME:
1142        case SQL_COLUMN_TYPE_NAME:
1143          if (waMode != 'W')
1144            {
1145            /* ansi<=unicode*/
1146              dm_StrCopyOut2_W2A ((SQLWCHAR *) descOut, (SQLCHAR *) rgbDesc, cbDescMax / sizeof(wchar_t), pcbDesc);
1147            }
1148          else
1149            {
1150            /* unicode<=ansi*/
1151              dm_StrCopyOut2_A2W ((SQLCHAR *) descOut, (SQLWCHAR *) rgbDesc, cbDescMax, pcbDesc);
1152              if (pcbDesc)
1153                *pcbDesc = *pcbDesc * sizeof(wchar_t);
1154            }
1155        }
1156    }
1157
1158  if (retcode != SQL_STILL_EXECUTING)
1159    _iodbcdm_FreeStmtParams(pstmt);
1160
1161  /* state transition */
1162  if (pstmt->asyn_on == en_ColAttributes)
1163    {
1164      switch (retcode)
1165	{
1166	case SQL_SUCCESS:
1167	case SQL_SUCCESS_WITH_INFO:
1168	case SQL_ERROR:
1169	  pstmt->asyn_on = en_NullProc;
1170	  break;
1171
1172	default:
1173	   return retcode;
1174	}
1175    }
1176
1177  switch (pstmt->state)
1178    {
1179    case en_stmt_prepared:
1180    case en_stmt_cursoropen:
1181    case en_stmt_fetched:
1182    case en_stmt_xfetched:
1183      if (retcode == SQL_STILL_EXECUTING)
1184	{
1185	  pstmt->asyn_on = en_ColAttributes;
1186	}
1187      break;
1188
1189    default:
1190      break;
1191    }
1192
1193  return retcode;
1194}
1195
1196
1197RETCODE SQL_API
1198SQLColAttributes (
1199  SQLHSTMT 		  statementHandle,
1200  SQLUSMALLINT		  icol,
1201  SQLUSMALLINT		  fDescType,
1202  SQLPOINTER		  rgbDesc,
1203  SQLSMALLINT		  cbDescMax,
1204  SQLSMALLINT 		* pcbDesc,
1205  SQLLEN 		* pfDesc)
1206{
1207  ENTER_STMT (statementHandle,
1208    trace_SQLColAttributes (TRACE_ENTER,
1209    	statementHandle,
1210	icol,
1211	fDescType,
1212	rgbDesc, cbDescMax, pcbDesc,
1213	pfDesc));
1214
1215  retcode =  SQLColAttributes_Internal (
1216  	statementHandle,
1217	icol,
1218	fDescType,
1219	rgbDesc, cbDescMax, pcbDesc,
1220	pfDesc,
1221	'A');
1222
1223  LEAVE_STMT (statementHandle,
1224    trace_SQLColAttributes (TRACE_LEAVE,
1225    	statementHandle,
1226	icol,
1227	fDescType,
1228	rgbDesc, cbDescMax, pcbDesc,
1229	pfDesc));
1230}
1231
1232
1233#if ODBCVER >= 0x0300
1234RETCODE SQL_API
1235SQLColAttributesA (
1236  SQLHSTMT 		  statementHandle,
1237  SQLUSMALLINT		  icol,
1238  SQLUSMALLINT		  fDescType,
1239  SQLPOINTER		  rgbDesc,
1240  SQLSMALLINT		  cbDescMax,
1241  SQLSMALLINT 		* pcbDesc,
1242  SQLLEN		* pfDesc)
1243{
1244  ENTER_STMT (statementHandle,
1245    trace_SQLColAttributes (TRACE_ENTER,
1246    	statementHandle,
1247	icol,
1248	fDescType,
1249	rgbDesc, cbDescMax, pcbDesc,
1250	pfDesc));
1251
1252  retcode =  SQLColAttributes_Internal (
1253  	statementHandle,
1254	icol,
1255	fDescType,
1256	rgbDesc, cbDescMax, pcbDesc,
1257	pfDesc,
1258	'A');
1259
1260  LEAVE_STMT (statementHandle,
1261    trace_SQLColAttributes (TRACE_LEAVE,
1262    	statementHandle,
1263	icol,
1264	fDescType,
1265	rgbDesc, cbDescMax, pcbDesc,
1266	pfDesc));
1267}
1268
1269
1270RETCODE SQL_API
1271SQLColAttributesW (
1272  SQLHSTMT		  statementHandle,
1273  SQLUSMALLINT		  icol,
1274  SQLUSMALLINT		  fDescType,
1275  SQLPOINTER		  rgbDesc,
1276  SQLSMALLINT		  cbDescMax,
1277  SQLSMALLINT 		* pcbDesc,
1278  SQLLEN		* pfDesc)
1279{
1280  ENTER_STMT (statementHandle,
1281    trace_SQLColAttributesW (TRACE_ENTER,
1282    	statementHandle,
1283	icol,
1284	fDescType,
1285	rgbDesc, cbDescMax, pcbDesc,
1286	pfDesc));
1287
1288  retcode =  SQLColAttributes_Internal (
1289  	statementHandle,
1290	icol,
1291	fDescType,
1292	rgbDesc, cbDescMax, pcbDesc,
1293	pfDesc,
1294	'W');
1295
1296  LEAVE_STMT (statementHandle,
1297    trace_SQLColAttributesW (TRACE_LEAVE,
1298    	statementHandle,
1299	icol,
1300	fDescType,
1301	rgbDesc, cbDescMax, pcbDesc,
1302	pfDesc));
1303}
1304#endif
1305