1/*
2 *  execute.c
3 *
4 *  $Id: execute.c,v 1.24 2006/12/11 14:21:48 source Exp $
5 *
6 *  Invoke a query
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
79#include <iodbc.h>
80
81#include <sql.h>
82#include <sqlext.h>
83#include <sqlucode.h>
84
85#include <unicode.h>
86
87#include <dlproc.h>
88
89#include <herr.h>
90#include <henv.h>
91#include <hdbc.h>
92#include <hstmt.h>
93
94#include <itrace.h>
95
96void
97_iodbcdm_do_cursoropen (STMT_t * pstmt)
98{
99  SQLRETURN retcode;
100  SWORD ncol;
101
102  pstmt->state = en_stmt_executed;
103
104  retcode = _iodbcdm_NumResultCols ((SQLHSTMT) pstmt, &ncol);
105
106  if (SQL_SUCCEEDED (retcode))
107    {
108      if (ncol)
109	{
110	  pstmt->state = en_stmt_cursoropen;
111	  pstmt->cursor_state = en_stmt_cursor_opened;
112	}
113      else
114	{
115	  pstmt->state = en_stmt_executed;
116	  pstmt->cursor_state = en_stmt_cursor_no;
117	}
118    }
119}
120
121
122static SQLRETURN
123SQLExecute_Internal (SQLHSTMT hstmt)
124{
125  STMT (pstmt, hstmt);
126  HPROC hproc = SQL_NULL_HPROC;
127  SQLRETURN retcode;
128  sqlstcode_t sqlstat = en_00000;
129
130  /* check state */
131  if (pstmt->asyn_on == en_NullProc)
132    {
133      switch (pstmt->state)
134	{
135	case en_stmt_allocated:
136	  sqlstat = en_S1010;
137	  break;
138
139	case en_stmt_executed_with_info:
140	case en_stmt_executed:
141	  if (!pstmt->prep_state)
142	    {
143	      sqlstat = en_S1010;
144	    }
145	  break;
146
147	case en_stmt_cursoropen:
148	  if (!pstmt->prep_state)
149	    {
150	      sqlstat = en_S1010;
151	    }
152	  break;
153
154	case en_stmt_fetched:
155	case en_stmt_xfetched:
156	  if (!pstmt->prep_state)
157	    {
158	      sqlstat = en_S1010;
159	    }
160	  else
161	    {
162	      sqlstat = en_24000;
163	    }
164	  break;
165
166	case en_stmt_needdata:
167	case en_stmt_mustput:
168	case en_stmt_canput:
169	  sqlstat = en_S1010;
170	  break;
171
172	default:
173	  break;
174	}
175    }
176  else if (pstmt->asyn_on != en_Execute)
177    {
178      sqlstat = en_S1010;
179    }
180
181  if (sqlstat == en_00000)
182    {
183      hproc = _iodbcdm_getproc (pstmt->hdbc, en_Execute);
184
185      if (hproc == SQL_NULL_HPROC)
186	{
187	  sqlstat = en_IM001;
188	}
189    }
190
191  if (sqlstat != en_00000)
192    {
193      PUSHSQLERR (pstmt->herr, sqlstat);
194
195      return SQL_ERROR;
196    }
197
198  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc, (pstmt->dhstmt));
199
200  /* stmt state transition */
201  if (pstmt->asyn_on == en_Execute)
202    {
203      switch (retcode)
204	{
205	case SQL_SUCCESS:
206	case SQL_SUCCESS_WITH_INFO:
207	case SQL_NEED_DATA:
208	case SQL_ERROR:
209	  pstmt->asyn_on = en_NullProc;
210	  break;
211
212	case SQL_STILL_EXECUTING:
213	default:
214	  return retcode;
215	}
216    }
217
218  switch (pstmt->state)
219    {
220    case en_stmt_prepared:
221      switch (retcode)
222	{
223	case SQL_SUCCESS:
224	  _iodbcdm_do_cursoropen (pstmt);
225	  break;
226
227	case SQL_SUCCESS_WITH_INFO:
228	  pstmt->state = en_stmt_executed_with_info;
229	  break;
230
231	case SQL_NEED_DATA:
232	  pstmt->state = en_stmt_needdata;
233	  pstmt->need_on = en_Execute;
234	  break;
235
236	case SQL_STILL_EXECUTING:
237	  pstmt->asyn_on = en_Execute;
238	  break;
239
240	default:
241	  break;
242	}
243      break;
244
245    case en_stmt_executed:
246      switch (retcode)
247	{
248	case SQL_ERROR:
249	  pstmt->state = en_stmt_prepared;
250	  pstmt->cursor_state = en_stmt_cursor_no;
251	  break;
252
253	case SQL_NEED_DATA:
254	  pstmt->state = en_stmt_needdata;
255	  pstmt->need_on = en_Execute;
256	  break;
257
258	case SQL_STILL_EXECUTING:
259	  pstmt->asyn_on = en_Execute;
260	  break;
261
262	default:
263	  break;
264	}
265      break;
266
267    default:
268      break;
269    }
270
271  return retcode;
272}
273
274
275SQLRETURN SQL_API
276SQLExecute (SQLHSTMT hstmt)
277{
278  ENTER_STMT (hstmt,
279    trace_SQLExecute (TRACE_ENTER, hstmt));
280
281  retcode = SQLExecute_Internal (hstmt);
282
283  LEAVE_STMT (hstmt,
284    trace_SQLExecute (TRACE_LEAVE, hstmt));
285}
286
287
288SQLRETURN SQL_API
289SQLExecDirect_Internal (SQLHSTMT hstmt,
290    SQLPOINTER szSqlStr,
291    SQLINTEGER cbSqlStr,
292    SQLCHAR waMode)
293{
294  STMT (pstmt, hstmt);
295  CONN (pdbc, pstmt->hdbc);
296  ENVR (penv, pdbc->henv);
297  HPROC hproc = SQL_NULL_HPROC;
298  SQLRETURN retcode = SQL_SUCCESS;
299  sqlstcode_t sqlstat = en_00000;
300  void * _SqlStr = NULL;
301
302  /* check arguments */
303  if (szSqlStr == NULL)
304    {
305      sqlstat = en_S1009;
306    }
307  else if (cbSqlStr < 0 && cbSqlStr != SQL_NTS)
308    {
309      sqlstat = en_S1090;
310    }
311
312  if (sqlstat != en_00000)
313    {
314      PUSHSQLERR (pstmt->herr, sqlstat);
315
316      return SQL_ERROR;
317    }
318
319  /* check state */
320  if (pstmt->asyn_on == en_NullProc)
321    {
322      switch (pstmt->state)
323	{
324	case en_stmt_fetched:
325	case en_stmt_xfetched:
326	  sqlstat = en_24000;
327	  break;
328
329	case en_stmt_needdata:
330	case en_stmt_mustput:
331	case en_stmt_canput:
332	  sqlstat = en_S1010;
333	  break;
334
335	default:
336	  break;
337	}
338    }
339  else if (pstmt->asyn_on != en_ExecDirect)
340    {
341      sqlstat = en_S1010;
342    }
343
344  if (sqlstat != en_00000)
345    {
346      PUSHSQLERR (pstmt->herr, sqlstat);
347
348      return SQL_ERROR;
349    }
350
351  if ((penv->unicode_driver && waMode != 'W')
352      || (!penv->unicode_driver && waMode == 'W'))
353    {
354      if (waMode != 'W')
355        {
356        /* ansi=>unicode*/
357          _SqlStr = _iodbcdm_conv_param_A2W(pstmt, 0, (SQLCHAR *) szSqlStr, cbSqlStr);
358        }
359      else
360        {
361        /* unicode=>ansi*/
362          _SqlStr = _iodbcdm_conv_param_W2A(pstmt, 0, (SQLWCHAR *) szSqlStr, cbSqlStr);
363        }
364      szSqlStr = _SqlStr;
365      cbSqlStr = SQL_NTS;
366    }
367
368  CALL_UDRIVER(pstmt->hdbc, pstmt, retcode, hproc, penv->unicode_driver,
369    en_ExecDirect, (
370       pstmt->dhstmt,
371       szSqlStr,
372       cbSqlStr));
373
374  if (hproc == SQL_NULL_HPROC)
375    {
376      _iodbcdm_FreeStmtParams(pstmt);
377      PUSHSQLERR (pstmt->herr, en_IM001);
378      return SQL_ERROR;
379    }
380
381  if (retcode != SQL_STILL_EXECUTING)
382    _iodbcdm_FreeStmtParams(pstmt);
383
384  /* stmt state transition */
385  if (pstmt->asyn_on == en_ExecDirect)
386    {
387      switch (retcode)
388	{
389	case SQL_SUCCESS:
390	case SQL_SUCCESS_WITH_INFO:
391	case SQL_NEED_DATA:
392	case SQL_ERROR:
393	  pstmt->asyn_on = en_NullProc;
394	  break;
395
396	case SQL_STILL_EXECUTING:
397	default:
398	  return retcode;
399	}
400    }
401
402  if (pstmt->state <= en_stmt_executed)
403    {
404      switch (retcode)
405	{
406	case SQL_SUCCESS:
407	  _iodbcdm_do_cursoropen (pstmt);
408	  pstmt->prep_state = 1;
409	  break;
410
411	case SQL_SUCCESS_WITH_INFO:
412	  pstmt->state = en_stmt_executed_with_info;
413	  pstmt->prep_state = 1;
414	  break;
415
416	case SQL_NEED_DATA:
417	  pstmt->state = en_stmt_needdata;
418	  pstmt->need_on = en_ExecDirect;
419	  break;
420
421	case SQL_STILL_EXECUTING:
422	  pstmt->asyn_on = en_ExecDirect;
423	  break;
424
425	case SQL_ERROR:
426	  pstmt->state = en_stmt_allocated;
427	  pstmt->cursor_state = en_stmt_cursor_no;
428	  pstmt->prep_state = 0;
429	  break;
430
431	default:
432	  break;
433	}
434    }
435
436  return retcode;
437}
438
439
440SQLRETURN SQL_API
441SQLExecDirect (SQLHSTMT hstmt, SQLCHAR * szSqlStr, SQLINTEGER cbSqlStr)
442{
443  ENTER_STMT (hstmt,
444    trace_SQLExecDirect (TRACE_ENTER, hstmt, szSqlStr, cbSqlStr));
445
446  retcode = SQLExecDirect_Internal(hstmt, szSqlStr, cbSqlStr, 'A');
447
448  LEAVE_STMT (hstmt,
449    trace_SQLExecDirect (TRACE_LEAVE, hstmt, szSqlStr, cbSqlStr));
450}
451
452
453#if ODBCVER >= 0x0300
454SQLRETURN SQL_API
455SQLExecDirectA (SQLHSTMT hstmt, SQLCHAR * szSqlStr, SQLINTEGER cbSqlStr)
456{
457  ENTER_STMT (hstmt,
458    trace_SQLExecDirect (TRACE_ENTER, hstmt, szSqlStr, cbSqlStr));
459
460  retcode = SQLExecDirect_Internal(hstmt, szSqlStr, cbSqlStr, 'A');
461
462  LEAVE_STMT (hstmt,
463    trace_SQLExecDirect (TRACE_LEAVE, hstmt, szSqlStr, cbSqlStr));
464}
465
466
467SQLRETURN SQL_API
468SQLExecDirectW (SQLHSTMT hstmt, SQLWCHAR * szSqlStr, SQLINTEGER cbSqlStr)
469{
470  ENTER_STMT (hstmt,
471    trace_SQLExecDirectW (TRACE_ENTER, hstmt, szSqlStr, cbSqlStr));
472
473  retcode = SQLExecDirect_Internal(hstmt, szSqlStr, cbSqlStr, 'W');
474
475  LEAVE_STMT (hstmt,
476    trace_SQLExecDirectW (TRACE_LEAVE, hstmt, szSqlStr, cbSqlStr));
477}
478#endif
479
480
481static SQLRETURN
482SQLPutData_Internal (
483  SQLHSTMT		  hstmt,
484  SQLPOINTER		  rgbValue,
485  SQLLEN		  cbValue)
486{
487  STMT (pstmt, hstmt);
488  HPROC hproc;
489  SQLRETURN retcode;
490
491  /* check argument value */
492  if (rgbValue == NULL &&
493      (cbValue != SQL_DEFAULT_PARAM && cbValue != SQL_NULL_DATA))
494    {
495      PUSHSQLERR (pstmt->herr, en_S1009);
496
497      return SQL_ERROR;
498    }
499
500  /* check state */
501  if (pstmt->asyn_on == en_NullProc)
502    {
503      if (pstmt->state <= en_stmt_xfetched)
504	{
505	  PUSHSQLERR (pstmt->herr, en_S1010);
506
507	  return SQL_ERROR;
508	}
509    }
510  else if (pstmt->asyn_on != en_PutData)
511    {
512      PUSHSQLERR (pstmt->herr, en_S1010);
513
514      return SQL_ERROR;
515    }
516
517  /* call driver */
518  hproc = _iodbcdm_getproc (pstmt->hdbc, en_PutData);
519
520  if (hproc == SQL_NULL_HPROC)
521    {
522      PUSHSQLERR (pstmt->herr, en_IM001);
523
524      return SQL_ERROR;
525    }
526
527  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
528      (pstmt->dhstmt, rgbValue, cbValue));
529
530  /* state transition */
531  if (pstmt->asyn_on == en_PutData)
532    {
533      switch (retcode)
534	{
535	case SQL_SUCCESS:
536	case SQL_SUCCESS_WITH_INFO:
537	case SQL_ERROR:
538	  pstmt->asyn_on = en_NullProc;
539	  break;
540
541	case SQL_STILL_EXECUTING:
542	default:
543	  return retcode;
544	}
545    }
546
547  /* must in mustput or canput states */
548  switch (retcode)
549    {
550    case SQL_SUCCESS:
551    case SQL_SUCCESS_WITH_INFO:
552      pstmt->state = en_stmt_canput;
553      break;
554
555    case SQL_ERROR:
556      switch (pstmt->need_on)
557	{
558	case en_ExecDirect:
559	  pstmt->state = en_stmt_allocated;
560	  pstmt->need_on = en_NullProc;
561	  break;
562
563	case en_Execute:
564	  if (pstmt->prep_state)
565	    {
566	      pstmt->state = en_stmt_prepared;
567	      pstmt->need_on = en_NullProc;
568	    }
569	  break;
570
571	case en_SetPos:
572	  /* Is this possible ???? */
573	  pstmt->state = en_stmt_xfetched;
574	  break;
575
576	default:
577	  break;
578	}
579      break;
580
581    case SQL_STILL_EXECUTING:
582      pstmt->asyn_on = en_PutData;
583      break;
584
585    default:
586      break;
587    }
588
589  return retcode;
590}
591
592
593SQLRETURN SQL_API
594SQLPutData (
595  SQLHSTMT		  hstmt,
596  SQLPOINTER		  rgbValue,
597  SQLLEN		  cbValue)
598{
599  ENTER_STMT (hstmt,
600    trace_SQLPutData (TRACE_ENTER, hstmt, rgbValue, cbValue));
601
602  retcode = SQLPutData_Internal (hstmt, rgbValue, cbValue);
603
604  LEAVE_STMT (hstmt,
605    trace_SQLPutData (TRACE_LEAVE, hstmt, rgbValue, cbValue));
606}
607
608
609static SQLRETURN
610SQLParamData_Internal (SQLHSTMT hstmt, SQLPOINTER * prgbValue)
611{
612  STMT (pstmt, hstmt);
613  HPROC hproc;
614  SQLRETURN retcode;
615
616  /* check argument */
617
618  /* check state */
619  if (pstmt->asyn_on == en_NullProc)
620    {
621      if (pstmt->state <= en_stmt_xfetched)
622	{
623	  PUSHSQLERR (pstmt->herr, en_S1010);
624
625	  return SQL_ERROR;
626	}
627    }
628  else if (pstmt->asyn_on != en_ParamData)
629    {
630      PUSHSQLERR (pstmt->herr, en_S1010);
631
632      return SQL_ERROR;
633    }
634
635  /* call driver */
636  hproc = _iodbcdm_getproc (pstmt->hdbc, en_ParamData);
637
638  if (hproc == SQL_NULL_HPROC)
639    {
640      PUSHSQLERR (pstmt->herr, en_IM001);
641
642      return SQL_ERROR;
643    }
644
645  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc, (pstmt->dhstmt, prgbValue));
646
647  /* state transition */
648  if (pstmt->asyn_on == en_ParamData)
649    {
650      switch (retcode)
651	{
652	case SQL_SUCCESS:
653	case SQL_SUCCESS_WITH_INFO:
654	case SQL_ERROR:
655	  pstmt->asyn_on = en_NullProc;
656	  break;
657
658	case SQL_STILL_EXECUTING:
659	default:
660	  return retcode;
661	}
662    }
663
664  if (pstmt->state < en_stmt_needdata)
665    {
666      return retcode;
667    }
668
669  switch (retcode)
670    {
671    case SQL_ERROR:
672      switch (pstmt->need_on)
673	{
674	case en_ExecDirect:
675	  pstmt->state = en_stmt_allocated;
676	  break;
677
678	case en_Execute:
679	  pstmt->state = en_stmt_prepared;
680	  break;
681
682	case en_SetPos:
683	  pstmt->state = en_stmt_xfetched;
684	  pstmt->cursor_state = en_stmt_cursor_xfetched;
685	  break;
686
687	default:
688	  break;
689	}
690      pstmt->need_on = en_NullProc;
691      break;
692
693    case SQL_SUCCESS:
694    case SQL_SUCCESS_WITH_INFO:
695      switch (pstmt->state)
696	{
697	case en_stmt_needdata:
698	  pstmt->state = en_stmt_mustput;
699	  break;
700
701	case en_stmt_canput:
702	  switch (pstmt->need_on)
703	    {
704	    case en_SetPos:
705	      pstmt->state = en_stmt_xfetched;
706	      pstmt->cursor_state = en_stmt_cursor_xfetched;
707	      break;
708
709	    case en_ExecDirect:
710	    case en_Execute:
711	      _iodbcdm_do_cursoropen (pstmt);
712	      break;
713
714	    default:
715	      break;
716	    }
717	  break;
718
719	default:
720	  break;
721	}
722      pstmt->need_on = en_NullProc;
723      break;
724
725    case SQL_NEED_DATA:
726      pstmt->state = en_stmt_mustput;
727      break;
728
729    default:
730      break;
731    }
732
733  return retcode;
734}
735
736
737SQLRETURN SQL_API
738SQLParamData (SQLHSTMT hstmt, SQLPOINTER * prgbValue)
739{
740  ENTER_STMT (hstmt,
741    trace_SQLParamData (TRACE_ENTER, hstmt, prgbValue));
742
743  retcode = SQLParamData_Internal (hstmt, prgbValue);
744
745  LEAVE_STMT (hstmt,
746    trace_SQLParamData (TRACE_LEAVE, hstmt, prgbValue));
747}
748
749
750static SQLRETURN
751SQLNumParams_Internal (SQLHSTMT hstmt, SQLSMALLINT * pcpar)
752{
753  STMT (pstmt, hstmt);
754  HPROC hproc;
755  SQLRETURN retcode;
756
757  /* check argument */
758  if (!pcpar)
759    {
760      return SQL_SUCCESS;
761    }
762
763  /* check state */
764  if (pstmt->asyn_on == en_NullProc)
765    {
766      switch (pstmt->state)
767	{
768	case en_stmt_allocated:
769	case en_stmt_needdata:
770	case en_stmt_mustput:
771	case en_stmt_canput:
772	  PUSHSQLERR (pstmt->herr, en_S1010);
773	  return SQL_ERROR;
774
775	default:
776	  break;
777	}
778    }
779  else if (pstmt->asyn_on != en_NumParams)
780    {
781      PUSHSQLERR (pstmt->herr, en_S1010);
782
783      return SQL_ERROR;
784    }
785
786  /* call driver */
787  hproc = _iodbcdm_getproc (pstmt->hdbc, en_NumParams);
788
789  if (hproc == SQL_NULL_HPROC)
790    {
791      PUSHSQLERR (pstmt->herr, en_IM001);
792
793      return SQL_ERROR;
794    }
795
796  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc, (pstmt->dhstmt, pcpar));
797
798  /* state transition */
799  if (pstmt->asyn_on == en_NumParams)
800    {
801      switch (retcode)
802	{
803	case SQL_SUCCESS:
804	case SQL_SUCCESS_WITH_INFO:
805	case SQL_ERROR:
806	  break;
807
808	default:
809	  return retcode;
810	}
811    }
812
813  if (retcode == SQL_STILL_EXECUTING)
814    {
815      pstmt->asyn_on = en_NumParams;
816    }
817
818  return retcode;
819}
820
821
822SQLRETURN SQL_API
823SQLNumParams (SQLHSTMT hstmt, SQLSMALLINT * pcpar)
824{
825  ENTER_STMT (hstmt,
826    trace_SQLNumParams (TRACE_ENTER, hstmt, pcpar));
827
828  retcode = SQLNumParams_Internal (hstmt, pcpar);
829
830  LEAVE_STMT (hstmt,
831    trace_SQLNumParams (TRACE_LEAVE, hstmt, pcpar));
832}
833
834
835static SQLRETURN
836SQLDescribeParam_Internal (
837    SQLHSTMT		  hstmt,
838    SQLUSMALLINT	  ipar,
839    SQLSMALLINT		* pfSqlType,
840    SQLULEN		* pcbColDef,
841    SQLSMALLINT		* pibScale,
842    SQLSMALLINT 	* pfNullable)
843{
844  STMT (pstmt, hstmt);
845  CONN (pdbc, pstmt->hdbc);
846  GENV (genv, pdbc->genv);
847
848  HPROC hproc;
849  SQLRETURN retcode;
850
851  /* check argument */
852  if (ipar == 0)
853    {
854      PUSHSQLERR (pstmt->herr, en_S1093);
855
856      return SQL_ERROR;
857    }
858
859  /* check state */
860  if (pstmt->asyn_on == en_NullProc)
861    {
862      switch (pstmt->state)
863	{
864	case en_stmt_allocated:
865	case en_stmt_needdata:
866	case en_stmt_mustput:
867	case en_stmt_canput:
868	  PUSHSQLERR (pstmt->herr, en_S1010);
869	  return SQL_ERROR;
870
871	default:
872	  break;
873	}
874    }
875  else if (pstmt->asyn_on != en_DescribeParam)
876    {
877      PUSHSQLERR (pstmt->herr, en_S1010);
878
879      return SQL_ERROR;
880    }
881
882  /* call driver */
883  hproc = _iodbcdm_getproc (pstmt->hdbc, en_DescribeParam);
884
885  if (hproc == SQL_NULL_HPROC)
886    {
887      PUSHSQLERR (pstmt->herr, en_IM001);
888
889      return SQL_ERROR;
890    }
891
892  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
893      (pstmt->dhstmt, ipar, pfSqlType, pcbColDef, pibScale, pfNullable));
894
895  /*
896   *  Convert sql type to ODBC version of application
897   */
898  if (SQL_SUCCEEDED(retcode) && pfSqlType)
899    *pfSqlType = _iodbcdm_map_sql_type (*pfSqlType, genv->odbc_ver);
900
901
902  /* state transition */
903  if (pstmt->asyn_on == en_DescribeParam)
904    {
905      switch (retcode)
906	{
907	case SQL_SUCCESS:
908	case SQL_SUCCESS_WITH_INFO:
909	case SQL_ERROR:
910	  break;
911
912	default:
913	  return retcode;
914	}
915    }
916
917  if (retcode == SQL_STILL_EXECUTING)
918    {
919      pstmt->asyn_on = en_DescribeParam;
920    }
921
922  return retcode;
923}
924
925
926SQLRETURN SQL_API
927SQLDescribeParam (
928  SQLHSTMT		  hstmt,
929  SQLUSMALLINT		  ipar,
930  SQLSMALLINT 		* pfSqlType,
931  SQLULEN 		* pcbColDef,
932  SQLSMALLINT 		* pibScale,
933  SQLSMALLINT 		* pfNullable)
934{
935  ENTER_STMT (hstmt,
936    trace_SQLDescribeParam (TRACE_ENTER,
937      hstmt, ipar, pfSqlType,
938      pcbColDef, pibScale, pfNullable));
939
940  retcode = SQLDescribeParam_Internal ( hstmt, ipar, pfSqlType,
941      pcbColDef, pibScale, pfNullable);
942
943  LEAVE_STMT (hstmt,
944    trace_SQLDescribeParam (TRACE_LEAVE,
945      hstmt, ipar, pfSqlType,
946      pcbColDef, pibScale, pfNullable));
947}
948