1/*
2 *  fetch.c
3 *
4 *  $Id: fetch.c,v 1.24 2006/12/11 14:21:48 source Exp $
5 *
6 *  Fetch 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
79#include <iodbc.h>
80
81#include <sql.h>
82#include <sqlext.h>
83#include <sqlucode.h>
84
85#include <dlproc.h>
86
87#include <herr.h>
88#include <henv.h>
89#include <hdbc.h>
90#include <hstmt.h>
91
92#include <itrace.h>
93#include <unicode.h>
94
95SQLRETURN
96SQLFetch_Internal (SQLHSTMT hstmt)
97{
98  STMT (pstmt, hstmt);
99  HPROC hproc = SQL_NULL_HPROC;
100  SQLRETURN retcode = SQL_SUCCESS;
101
102  /* check state */
103  if (pstmt->asyn_on == en_NullProc)
104    {
105      switch (pstmt->state)
106	{
107	case en_stmt_allocated:
108	case en_stmt_prepared:
109	case en_stmt_xfetched:
110	case en_stmt_needdata:
111	case en_stmt_mustput:
112	case en_stmt_canput:
113	  PUSHSQLERR (pstmt->herr, en_S1010);
114	  return SQL_ERROR;
115
116	case en_stmt_executed_with_info:
117	  _iodbcdm_do_cursoropen (pstmt);
118	  break;
119
120	default:
121	  break;
122	}
123    }
124  else if (pstmt->asyn_on != en_Fetch)
125    {
126      PUSHSQLERR (pstmt->herr, en_S1010);
127      return SQL_ERROR;
128    }
129
130#if (ODBCVER >= 0x0300)
131  if (((ENV_t *) ((DBC_t *) pstmt->hdbc)->henv)->dodbc_ver ==  SQL_OV_ODBC2
132      && ((GENV_t *) ((DBC_t *) pstmt->hdbc)->genv)->odbc_ver == SQL_OV_ODBC3)
133    {
134	/*
135	 *  Try to map SQLFetch to SQLExtendedFetch for ODBC3 app calling
136	 *  ODBC2 driver
137         *
138	 *  The rows_status_ptr must not be null because the SQLExtendedFetch
139	 *  requires it
140	 */
141      hproc = _iodbcdm_getproc (pstmt->hdbc, en_ExtendedFetch);
142
143      if (hproc)
144	{
145	  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
146	      (pstmt->dhstmt, SQL_FETCH_NEXT, 0, pstmt->rows_fetched_ptr,
147		  pstmt->row_status_ptr));
148	}
149    }
150#endif
151  if (hproc == SQL_NULL_HPROC)
152    {
153      hproc = _iodbcdm_getproc (pstmt->hdbc, en_Fetch);
154
155      if (hproc == SQL_NULL_HPROC)
156	{
157	  PUSHSQLERR (pstmt->herr, en_IM001);
158	  return SQL_ERROR;
159	}
160
161      CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
162	  (pstmt->dhstmt));
163    }
164
165  /* state transition */
166  if (pstmt->asyn_on == en_Fetch)
167    {
168      switch (retcode)
169	{
170	case SQL_SUCCESS:
171	case SQL_SUCCESS_WITH_INFO:
172	case SQL_NO_DATA_FOUND:
173	case SQL_ERROR:
174	  pstmt->asyn_on = en_NullProc;
175	  break;
176
177	case SQL_STILL_EXECUTING:
178	default:
179	  return retcode;
180	}
181    }
182
183  switch (pstmt->state)
184    {
185    case en_stmt_cursoropen:
186    case en_stmt_fetched:
187      switch (retcode)
188	{
189	case SQL_SUCCESS:
190	case SQL_SUCCESS_WITH_INFO:
191	  pstmt->state = en_stmt_fetched;
192	  pstmt->cursor_state = en_stmt_cursor_fetched;
193	  break;
194
195	case SQL_NO_DATA_FOUND:
196	  if (pstmt->prep_state)
197	    {
198	      pstmt->state = en_stmt_fetched;
199	    }
200	  else
201	    {
202	      pstmt->state = en_stmt_allocated;
203	    }
204	  pstmt->cursor_state = en_stmt_cursor_no;
205	  break;
206
207	case SQL_STILL_EXECUTING:
208	  pstmt->asyn_on = en_Fetch;
209	  break;
210
211	default:
212	  break;
213	}
214      break;
215
216    default:
217      break;
218    }
219
220  return retcode;
221}
222
223
224SQLRETURN SQL_API
225SQLFetch (SQLHSTMT hstmt)
226{
227  ENTER_STMT (hstmt,
228    trace_SQLFetch (TRACE_ENTER, hstmt));
229
230  retcode = SQLFetch_Internal (hstmt);
231
232  if (SQL_SUCCEEDED (retcode))
233    _iodbcdm_ConvBindData (pstmt);
234
235  LEAVE_STMT (hstmt,
236    trace_SQLFetch (TRACE_LEAVE, hstmt));
237}
238
239
240SQLRETURN SQL_API
241_iodbcdm_ExtendedFetch (
242    SQLHSTMT		  hstmt,
243    SQLUSMALLINT	  fFetchType,
244    SQLLEN		  irow,
245    SQLULEN	 	* pcrow,
246    SQLUSMALLINT 	* rgfRowStatus)
247{
248  STMT (pstmt, hstmt);
249  HPROC hproc = SQL_NULL_HPROC;
250  SQLRETURN retcode;
251
252  /* check fetch type */
253  if (fFetchType < SQL_FETCH_NEXT || fFetchType > SQL_FETCH_BOOKMARK)
254    {
255      /* Unlike MS driver manager(i.e. DM),
256       * we don't check driver's ODBC version
257       * against SQL_FETCH_RESUME (only 1.0)
258       * and SQL_FETCH_BOOKMARK (only 2.0).
259       */
260      PUSHSQLERR (pstmt->herr, en_S1106);
261
262      return SQL_ERROR;
263    }
264
265  /* check state */
266  if (pstmt->asyn_on == en_NullProc)
267    {
268      switch (pstmt->state)
269	{
270	case en_stmt_allocated:
271	case en_stmt_prepared:
272	case en_stmt_fetched:
273	case en_stmt_needdata:
274	case en_stmt_mustput:
275	case en_stmt_canput:
276	  PUSHSQLERR (pstmt->herr, en_S1010);
277	  return SQL_ERROR;
278
279	default:
280	  break;
281	}
282    }
283  else if (pstmt->asyn_on != en_ExtendedFetch)
284    {
285      PUSHSQLERR (pstmt->herr, en_S1010);
286      return SQL_ERROR;
287    }
288
289  if (fFetchType == SQL_FETCH_NEXT ||
290      fFetchType == SQL_FETCH_PRIOR ||
291      fFetchType == SQL_FETCH_FIRST || fFetchType == SQL_FETCH_LAST)
292    {
293      irow = 0;
294    }
295
296  hproc = _iodbcdm_getproc (pstmt->hdbc, en_ExtendedFetch);
297
298  if (hproc == SQL_NULL_HPROC)
299    {
300      PUSHSQLERR (pstmt->herr, en_IM001);
301
302      return SQL_ERROR;
303    }
304
305  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
306      (pstmt->dhstmt, fFetchType, irow, pcrow, rgfRowStatus));
307
308  /* state transition */
309  if (pstmt->asyn_on == en_ExtendedFetch)
310    {
311      switch (retcode)
312	{
313	case SQL_SUCCESS:
314	case SQL_SUCCESS_WITH_INFO:
315	case SQL_NO_DATA_FOUND:
316	case SQL_ERROR:
317	  pstmt->asyn_on = en_NullProc;
318	  break;
319
320	case SQL_STILL_EXECUTING:
321	default:
322	  return retcode;
323	}
324    }
325
326  switch (pstmt->state)
327    {
328    case en_stmt_cursoropen:
329    case en_stmt_xfetched:
330      switch (retcode)
331	{
332	case SQL_SUCCESS:
333	case SQL_SUCCESS_WITH_INFO:
334	case SQL_NO_DATA_FOUND:
335	  pstmt->state = en_stmt_xfetched;
336	  pstmt->cursor_state = en_stmt_cursor_xfetched;
337	  break;
338
339	case SQL_STILL_EXECUTING:
340	  pstmt->asyn_on = en_ExtendedFetch;
341	  break;
342
343	default:
344	  break;
345	}
346      break;
347
348    default:
349      break;
350    }
351
352  return retcode;
353}
354
355
356SQLRETURN SQL_API
357SQLExtendedFetch (
358  SQLHSTMT		  hstmt,
359  SQLUSMALLINT		  fFetchType,
360  SQLLEN		  irow,
361  SQLULEN 		* pcrow,
362  SQLUSMALLINT 		* rgfRowStatus)
363{
364  ENTER_STMT (hstmt,
365    trace_SQLExtendedFetch (TRACE_ENTER,
366    	hstmt, fFetchType, irow, pcrow, rgfRowStatus));
367
368  retcode =
369      _iodbcdm_ExtendedFetch (hstmt, fFetchType, irow, pcrow, rgfRowStatus);
370
371  if (SQL_SUCCEEDED (retcode))
372    _iodbcdm_ConvBindData (pstmt);
373
374  LEAVE_STMT (hstmt,
375    trace_SQLExtendedFetch (TRACE_LEAVE,
376    	hstmt, fFetchType, irow, pcrow, rgfRowStatus));
377}
378
379
380static SQLRETURN
381SQLGetData_Internal (
382  SQLHSTMT		  hstmt,
383  SQLUSMALLINT		  icol,
384  SQLSMALLINT		  fCType,
385  SQLPOINTER		  rgbValue,
386  SQLLEN		  cbValueMax,
387  SQLLEN 		* pcbValue)
388{
389  STMT (pstmt, hstmt);
390  CONN (pdbc, pstmt->hdbc);
391  ENVR (penv, pdbc->henv);
392  HPROC hproc;
393  SQLRETURN retcode = SQL_SUCCESS;
394  sqlstcode_t sqlstat = en_00000;
395  SQLSMALLINT nCType;
396
397  /* check argument */
398  if (rgbValue == NULL)
399    {
400      sqlstat = en_S1009;
401    }
402  else if (cbValueMax < 0)
403    {
404      sqlstat = en_S1090;
405    }
406  else
407    {
408      switch (fCType)
409	{
410	case SQL_C_DEFAULT:
411	case SQL_C_BINARY:
412	case SQL_C_BIT:
413	case SQL_C_CHAR:
414	case SQL_C_DATE:
415	case SQL_C_DOUBLE:
416	case SQL_C_FLOAT:
417	case SQL_C_LONG:
418	case SQL_C_SHORT:
419	case SQL_C_SLONG:
420	case SQL_C_SSHORT:
421	case SQL_C_STINYINT:
422	case SQL_C_TIME:
423	case SQL_C_TIMESTAMP:
424	case SQL_C_TINYINT:
425	case SQL_C_ULONG:
426	case SQL_C_USHORT:
427	case SQL_C_UTINYINT:
428#if (ODBCVER >= 0x0300)
429	case SQL_C_GUID:
430	case SQL_C_INTERVAL_DAY:
431	case SQL_C_INTERVAL_DAY_TO_HOUR:
432	case SQL_C_INTERVAL_DAY_TO_MINUTE:
433	case SQL_C_INTERVAL_DAY_TO_SECOND:
434	case SQL_C_INTERVAL_HOUR:
435	case SQL_C_INTERVAL_HOUR_TO_MINUTE:
436	case SQL_C_INTERVAL_HOUR_TO_SECOND:
437	case SQL_C_INTERVAL_MINUTE:
438	case SQL_C_INTERVAL_MINUTE_TO_SECOND:
439	case SQL_C_INTERVAL_MONTH:
440	case SQL_C_INTERVAL_SECOND:
441	case SQL_C_INTERVAL_YEAR:
442	case SQL_C_INTERVAL_YEAR_TO_MONTH:
443	case SQL_C_NUMERIC:
444	case SQL_C_SBIGINT:
445	case SQL_C_TYPE_DATE:
446	case SQL_C_TYPE_TIME:
447	case SQL_C_TYPE_TIMESTAMP:
448	case SQL_C_UBIGINT:
449	case SQL_C_WCHAR:
450#endif
451	  break;
452
453	default:
454	  sqlstat = en_S1003;
455	  break;
456	}
457    }
458
459  if (sqlstat != en_00000)
460    {
461      PUSHSQLERR (pstmt->herr, sqlstat);
462
463      return SQL_ERROR;
464    }
465
466  /* check state */
467  if (pstmt->asyn_on == en_NullProc)
468    {
469      switch (pstmt->state)
470	{
471	case en_stmt_allocated:
472	case en_stmt_prepared:
473	case en_stmt_needdata:
474	case en_stmt_mustput:
475	case en_stmt_canput:
476	  sqlstat = en_S1010;
477	  break;
478
479	case en_stmt_executed_with_info:
480	case en_stmt_executed:
481	case en_stmt_cursoropen:
482	  sqlstat = en_24000;
483	  break;
484
485	default:
486	  break;
487	}
488    }
489  else if (pstmt->asyn_on != en_GetData)
490    {
491      sqlstat = en_S1010;
492    }
493
494  if (sqlstat != en_00000)
495    {
496      PUSHSQLERR (pstmt->herr, sqlstat);
497
498      return SQL_ERROR;
499    }
500
501
502  /*
503   *  Convert C type to ODBC version of driver
504   */
505  nCType = _iodbcdm_map_c_type (fCType, penv->dodbc_ver);
506
507  if (!penv->unicode_driver && nCType == SQL_C_WCHAR)
508    {
509      nCType = SQL_C_CHAR;
510      cbValueMax /= sizeof(wchar_t);
511    }
512
513
514  /* call driver */
515  hproc = _iodbcdm_getproc (pstmt->hdbc, en_GetData);
516
517  if (hproc == SQL_NULL_HPROC)
518    {
519      PUSHSQLERR (pstmt->herr, en_IM001);
520      return SQL_ERROR;
521    }
522
523  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
524      (pstmt->dhstmt, icol, nCType, rgbValue, cbValueMax, pcbValue));
525
526  /* state transition */
527  if (pstmt->asyn_on == en_GetData)
528    {
529      switch (retcode)
530	{
531	case SQL_SUCCESS:
532	case SQL_SUCCESS_WITH_INFO:
533	case SQL_NO_DATA_FOUND:
534	case SQL_ERROR:
535	  pstmt->asyn_on = en_NullProc;
536	  break;
537
538	case SQL_STILL_EXECUTING:
539	default:
540	  return retcode;
541	}
542    }
543
544  switch (pstmt->state)
545    {
546    case en_stmt_fetched:
547    case en_stmt_xfetched:
548      if (retcode == SQL_STILL_EXECUTING)
549	{
550	  pstmt->asyn_on = en_GetData;
551	  break;
552	}
553      break;
554
555    default:
556      break;
557    }
558
559  if (!penv->unicode_driver && fCType == SQL_C_WCHAR)
560    {
561      wchar_t *buf = dm_SQL_A2W((SQLCHAR *) rgbValue, SQL_NTS);
562
563      if (buf != NULL)
564        WCSCPY(rgbValue, buf);
565
566      MEM_FREE(buf);
567      if (pcbValue)
568      	*pcbValue *= sizeof(wchar_t);
569    }
570
571  return retcode;
572}
573
574
575SQLRETURN SQL_API
576SQLGetData (
577    SQLHSTMT		  hstmt,
578    SQLUSMALLINT	  icol,
579    SQLSMALLINT		  fCType,
580    SQLPOINTER		  rgbValue,
581    SQLLEN		  cbValueMax,
582    SQLLEN 		* pcbValue)
583{
584  ENTER_STMT (hstmt,
585    trace_SQLGetData (TRACE_ENTER,
586    	hstmt,
587	icol,
588	fCType,
589    	rgbValue, cbValueMax, pcbValue));
590
591  retcode = SQLGetData_Internal (
592    	hstmt,
593	icol,
594	fCType,
595    	rgbValue, cbValueMax, pcbValue);
596
597  LEAVE_STMT (hstmt,
598    trace_SQLGetData (TRACE_LEAVE,
599    	hstmt,
600	icol,
601	fCType,
602    	rgbValue, cbValueMax, pcbValue));
603}
604
605
606static SQLRETURN
607SQLMoreResults_Internal (SQLHSTMT hstmt)
608{
609  STMT (pstmt, hstmt);
610  HPROC hproc;
611  SQLRETURN retcode;
612
613  /* check state */
614  if (pstmt->asyn_on == en_NullProc)
615    {
616      switch (pstmt->state)
617	{
618#if 0
619	case en_stmt_allocated:
620	case en_stmt_prepared:
621	  return SQL_NO_DATA_FOUND;
622#endif
623
624	case en_stmt_needdata:
625	case en_stmt_mustput:
626	case en_stmt_canput:
627	  PUSHSQLERR (pstmt->herr, en_S1010);
628	  return SQL_ERROR;
629
630	default:
631	  break;
632	}
633    }
634  else if (pstmt->asyn_on != en_MoreResults)
635    {
636      PUSHSQLERR (pstmt->herr, en_S1010);
637
638      return SQL_ERROR;
639    }
640
641  /* call driver */
642  hproc = _iodbcdm_getproc (pstmt->hdbc, en_MoreResults);
643
644  if (hproc == SQL_NULL_HPROC)
645    {
646      PUSHSQLERR (pstmt->herr, en_IM001);
647
648      return SQL_ERROR;
649    }
650
651  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
652      (pstmt->dhstmt));
653
654  /* state transition */
655  if (pstmt->asyn_on == en_MoreResults)
656    {
657      switch (retcode)
658	{
659	case SQL_SUCCESS:
660	case SQL_SUCCESS_WITH_INFO:
661	case SQL_NO_DATA_FOUND:
662	case SQL_ERROR:
663	  pstmt->asyn_on = en_NullProc;
664	  break;
665
666	case SQL_STILL_EXECUTING:
667	default:
668	  return retcode;
669	}
670    }
671
672  switch (pstmt->state)
673    {
674    case en_stmt_allocated:
675    case en_stmt_prepared:
676      /* driver should return SQL_NO_DATA_FOUND */
677	  if (pstmt->prep_state)
678	    {
679	      pstmt->state = en_stmt_cursoropen;
680	    }
681	  else
682	    {
683	      pstmt->state = en_stmt_prepared;
684	    }
685      break;
686
687    case en_stmt_executed_with_info:
688    	_iodbcdm_do_cursoropen (pstmt);
689	/* FALL THROUGH */
690
691    case en_stmt_executed:
692      if (retcode == SQL_NO_DATA_FOUND)
693	{
694	  if (pstmt->prep_state)
695	    {
696	      pstmt->state = en_stmt_prepared;
697	    }
698	  else
699	    {
700	      pstmt->state = en_stmt_cursoropen;
701	    }
702	}
703      else if (retcode == SQL_STILL_EXECUTING)
704	{
705	  pstmt->asyn_on = en_MoreResults;
706	}
707      break;
708
709    case en_stmt_cursoropen:
710    case en_stmt_fetched:
711    case en_stmt_xfetched:
712      if (retcode == SQL_SUCCESS)
713	{
714	  break;
715	}
716      else if (retcode == SQL_NO_DATA_FOUND)
717	{
718	  if (pstmt->prep_state)
719	    {
720	      pstmt->state = en_stmt_prepared;
721	    }
722	  else
723	    {
724	      pstmt->state = en_stmt_allocated;
725	    }
726	}
727      else if (retcode == SQL_STILL_EXECUTING)
728	{
729	  pstmt->asyn_on = en_MoreResults;
730	}
731      break;
732
733    default:
734      break;
735    }
736
737  return retcode;
738}
739
740
741SQLRETURN SQL_API
742SQLMoreResults (SQLHSTMT hstmt)
743{
744  ENTER_STMT (hstmt,
745    trace_SQLMoreResults (TRACE_ENTER, hstmt));
746
747  retcode = SQLMoreResults_Internal (hstmt);
748
749  LEAVE_STMT (hstmt,
750    trace_SQLMoreResults (TRACE_LEAVE, hstmt));
751}
752
753
754SQLRETURN SQL_API
755_iodbcdm_SetPos (
756  SQLHSTMT		  hstmt,
757  SQLSETPOSIROW		  irow,
758  SQLUSMALLINT		  fOption,
759  SQLUSMALLINT		  fLock)
760{
761  STMT (pstmt, hstmt);
762  HPROC hproc;
763  SQLRETURN retcode;
764  sqlstcode_t sqlstat = en_00000;
765
766  /* check argument value */
767  if (fOption > SQL_ADD || fLock > SQL_LOCK_UNLOCK)
768    {
769      PUSHSQLERR (pstmt->herr, en_S1009);
770      return SQL_ERROR;
771    }
772
773  /* check state */
774  if (pstmt->asyn_on == en_NullProc)
775    {
776      switch (pstmt->state)
777	{
778	case en_stmt_allocated:
779	case en_stmt_prepared:
780	case en_stmt_needdata:
781	case en_stmt_mustput:
782	case en_stmt_canput:
783	  sqlstat = en_S1010;
784	  break;
785
786	case en_stmt_executed_with_info:
787	case en_stmt_executed:
788	case en_stmt_cursoropen:
789	  sqlstat = en_24000;
790	  break;
791
792	default:
793	  break;
794	}
795    }
796  else if (pstmt->asyn_on != en_SetPos)
797    {
798      sqlstat = en_S1010;
799    }
800
801  if (sqlstat != en_00000)
802    {
803      PUSHSQLERR (pstmt->herr, sqlstat);
804
805      return SQL_ERROR;
806    }
807
808  /* call driver */
809  hproc = _iodbcdm_getproc (pstmt->hdbc, en_SetPos);
810
811  if (hproc == SQL_NULL_HPROC)
812    {
813      PUSHSQLERR (pstmt->herr, en_IM001);
814
815      return SQL_ERROR;
816    }
817
818  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
819      (pstmt->dhstmt, irow, fOption, fLock));
820
821  /* state transition */
822  if (pstmt->asyn_on == en_SetPos)
823    {
824      switch (retcode)
825	{
826	case SQL_SUCCESS:
827	case SQL_SUCCESS_WITH_INFO:
828	case SQL_NEED_DATA:
829	case SQL_ERROR:
830	  pstmt->asyn_on = en_NullProc;
831	  break;
832
833	case SQL_STILL_EXECUTING:
834	default:
835	  return retcode;
836	}
837    }
838
839  /* now, the only possible init state is 'xfetched' */
840  switch (retcode)
841    {
842    case SQL_SUCCESS:
843    case SQL_SUCCESS_WITH_INFO:
844      break;
845
846    case SQL_NEED_DATA:
847      pstmt->state = en_stmt_needdata;
848      pstmt->need_on = en_SetPos;
849      break;
850
851    case SQL_STILL_EXECUTING:
852      pstmt->asyn_on = en_SetPos;
853      break;
854
855    default:
856      break;
857    }
858
859  return retcode;
860}
861
862
863SQLRETURN SQL_API
864SQLSetPos (
865  SQLHSTMT		  hstmt,
866  SQLSETPOSIROW		  irow,
867  SQLUSMALLINT		  fOption,
868  SQLUSMALLINT		  fLock)
869{
870  ENTER_STMT (hstmt,
871    trace_SQLSetPos (TRACE_ENTER,
872      hstmt, irow, fOption, fLock));
873
874  retcode = _iodbcdm_SetPos (hstmt, irow, fOption, fLock);
875
876  LEAVE_STMT (hstmt,
877    trace_SQLSetPos (TRACE_LEAVE,
878      hstmt, irow, fOption, fLock));
879}
880