1/*
2 *  prepare.c
3 *
4 *  $Id: prepare.c,v 1.25 2006/12/11 14:21:48 source Exp $
5 *
6 *  Prepare 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
96SQLRETURN SQL_API
97SQLPrepare_Internal (
98    SQLHSTMT hstmt,
99    SQLPOINTER szSqlStr,
100    SQLINTEGER cbSqlStr,
101    SQLCHAR waMode)
102{
103  STMT (pstmt, hstmt);
104  CONN (pdbc, pstmt->hdbc);
105  ENVR (penv, pdbc->henv);
106  HPROC hproc = SQL_NULL_HPROC;
107  SQLRETURN retcode = SQL_SUCCESS;
108  sqlstcode_t sqlstat = en_00000;
109  void * _SqlStr = NULL;
110
111  /* check state */
112  if (pstmt->asyn_on == en_NullProc)
113    {
114      /* not on asyn state */
115      switch (pstmt->state)
116	{
117	case en_stmt_fetched:
118	case en_stmt_xfetched:
119	  sqlstat = en_24000;
120	  break;
121
122	case en_stmt_needdata:
123	case en_stmt_mustput:
124	case en_stmt_canput:
125	  sqlstat = en_S1010;
126	  break;
127
128	default:
129	  break;
130	}
131    }
132  else if (pstmt->asyn_on != en_Prepare)
133    {
134      /* asyn on other */
135      sqlstat = en_S1010;
136    }
137
138  if (sqlstat != en_00000)
139    {
140      PUSHSQLERR (pstmt->herr, sqlstat);
141
142      return SQL_ERROR;
143    }
144
145  if (szSqlStr == NULL)
146    {
147      PUSHSQLERR (pstmt->herr, en_S1009);
148
149      return SQL_ERROR;
150    }
151
152  if (cbSqlStr < 0 && cbSqlStr != SQL_NTS)
153    {
154      PUSHSQLERR (pstmt->herr, en_S1090);
155
156      return SQL_ERROR;
157    }
158
159  if ((penv->unicode_driver && waMode != 'W')
160      || (!penv->unicode_driver && waMode == 'W'))
161    {
162      if (waMode != 'W')
163        {
164        /* ansi=>unicode*/
165          _SqlStr = _iodbcdm_conv_param_A2W(pstmt, 0, (SQLCHAR *) szSqlStr, cbSqlStr);
166        }
167      else
168        {
169        /* unicode=>ansi*/
170          _SqlStr = _iodbcdm_conv_param_W2A(pstmt, 0, (SQLWCHAR *) szSqlStr, cbSqlStr);
171        }
172      szSqlStr = _SqlStr;
173      cbSqlStr = SQL_NTS;
174    }
175
176  CALL_UDRIVER(pstmt->hdbc, pstmt, retcode, hproc, penv->unicode_driver,
177    en_Prepare, (
178       pstmt->dhstmt,
179       szSqlStr,
180       cbSqlStr));
181
182  if (hproc == SQL_NULL_HPROC)
183    {
184      _iodbcdm_FreeStmtParams(pstmt);
185      PUSHSQLERR (pstmt->herr, en_IM001);
186      return SQL_ERROR;
187    }
188
189  if (retcode != SQL_STILL_EXECUTING)
190    _iodbcdm_FreeStmtParams(pstmt);
191
192  /* stmt state transition */
193  if (pstmt->asyn_on == en_Prepare)
194    {
195      switch (retcode)
196	{
197	case SQL_SUCCESS:
198	case SQL_SUCCESS_WITH_INFO:
199	case SQL_ERROR:
200	  pstmt->asyn_on = en_NullProc;
201	   return retcode;
202
203	case SQL_STILL_EXECUTING:
204	default:
205	   return retcode;
206	}
207    }
208
209  switch (retcode)
210    {
211    case SQL_STILL_EXECUTING:
212      pstmt->asyn_on = en_Prepare;
213      break;
214
215    case SQL_SUCCESS:
216    case SQL_SUCCESS_WITH_INFO:
217      pstmt->state = en_stmt_prepared;
218      pstmt->prep_state = 1;
219      break;
220
221    case SQL_ERROR:
222      switch (pstmt->state)
223	{
224	case en_stmt_prepared:
225	case en_stmt_executed_with_info:
226	case en_stmt_executed:
227	  pstmt->state = en_stmt_allocated;
228	  pstmt->prep_state = 0;
229	  break;
230
231	default:
232	  break;
233	}
234
235    default:
236      break;
237    }
238
239  return retcode;
240}
241
242
243SQLRETURN SQL_API
244SQLPrepare (SQLHSTMT hstmt,
245    SQLCHAR * szSqlStr,
246    SQLINTEGER cbSqlStr)
247{
248  ENTER_STMT (hstmt,
249    trace_SQLPrepare (TRACE_ENTER, hstmt, szSqlStr, cbSqlStr));
250
251  retcode = SQLPrepare_Internal(hstmt, szSqlStr, cbSqlStr, 'A');
252
253  LEAVE_STMT (hstmt,
254    trace_SQLPrepare (TRACE_LEAVE, hstmt, szSqlStr, cbSqlStr));
255}
256
257
258#if ODBCVER >= 0x0300
259SQLRETURN SQL_API
260SQLPrepareA (SQLHSTMT hstmt,
261    SQLCHAR * szSqlStr,
262    SQLINTEGER cbSqlStr)
263{
264  ENTER_STMT (hstmt,
265    trace_SQLPrepare (TRACE_ENTER, hstmt, szSqlStr, cbSqlStr));
266
267  retcode = SQLPrepare_Internal(hstmt, szSqlStr, cbSqlStr, 'A');
268
269  LEAVE_STMT (hstmt,
270    trace_SQLPrepare (TRACE_LEAVE, hstmt, szSqlStr, cbSqlStr));
271}
272
273
274SQLRETURN SQL_API
275SQLPrepareW (SQLHSTMT hstmt,
276    SQLWCHAR * szSqlStr,
277    SQLINTEGER cbSqlStr)
278{
279  ENTER_STMT (hstmt,
280    trace_SQLPrepareW (TRACE_ENTER, hstmt, szSqlStr, cbSqlStr));
281
282  retcode = SQLPrepare_Internal(hstmt, szSqlStr, cbSqlStr, 'W');
283
284  LEAVE_STMT (hstmt,
285    trace_SQLPrepareW (TRACE_LEAVE, hstmt, szSqlStr, cbSqlStr));
286}
287#endif
288
289
290SQLRETURN SQL_API
291SQLSetCursorName_Internal (
292    SQLHSTMT hstmt,
293    SQLPOINTER szCursor,
294    SQLSMALLINT cbCursor,
295    SQLCHAR waMode)
296{
297  STMT (pstmt, hstmt);
298  CONN (pdbc, pstmt->hdbc);
299  ENVR (penv, pdbc->henv);
300  HPROC hproc = SQL_NULL_HPROC;
301  SQLRETURN retcode = SQL_SUCCESS;
302  sqlstcode_t sqlstat = en_00000;
303  void * _Cursor = NULL;
304
305  if (szCursor == NULL)
306    {
307      PUSHSQLERR (pstmt->herr, en_S1009);
308
309      return SQL_ERROR;
310    }
311
312  if (cbCursor < 0 && cbCursor != SQL_NTS)
313    {
314      PUSHSQLERR (pstmt->herr, en_S1090);
315
316      return SQL_ERROR;
317    }
318
319  /* check state */
320  if (pstmt->asyn_on != en_NullProc)
321    {
322      sqlstat = en_S1010;
323    }
324  else
325    {
326      switch (pstmt->state)
327	{
328	case en_stmt_executed_with_info:
329	case en_stmt_executed:
330	case en_stmt_cursoropen:
331	case en_stmt_fetched:
332	case en_stmt_xfetched:
333	  sqlstat = en_24000;
334	  break;
335
336	case en_stmt_needdata:
337	case en_stmt_mustput:
338	case en_stmt_canput:
339	  sqlstat = en_S1010;
340	  break;
341
342	default:
343	  break;
344	}
345    }
346
347  if (sqlstat != en_00000)
348    {
349      PUSHSQLERR (pstmt->herr, sqlstat);
350
351      return SQL_ERROR;
352    }
353
354  if ((penv->unicode_driver && waMode != 'W')
355      || (!penv->unicode_driver && waMode == 'W'))
356    {
357      if (waMode != 'W')
358        {
359        /* ansi=>unicode*/
360          _Cursor = dm_SQL_A2W ((SQLCHAR *) szCursor, cbCursor);
361        }
362      else
363        {
364        /* unicode=>ansi*/
365          _Cursor = dm_SQL_W2A ((SQLWCHAR *) szCursor, cbCursor);
366        }
367      szCursor = _Cursor;
368      cbCursor = SQL_NTS;
369    }
370
371  CALL_UDRIVER(pstmt->hdbc, pstmt, retcode, hproc, penv->unicode_driver,
372    en_SetCursorName, (
373       pstmt->dhstmt,
374       szCursor,
375       cbCursor));
376
377  MEM_FREE(_Cursor);
378
379  if (hproc == SQL_NULL_HPROC)
380    {
381      PUSHSQLERR (pstmt->herr, en_IM001);
382
383      return SQL_ERROR;
384    }
385
386  if (SQL_SUCCEEDED (retcode))
387    {
388      pstmt->cursor_state = en_stmt_cursor_named;
389    }
390
391  return retcode;
392}
393
394
395SQLRETURN SQL_API
396SQLSetCursorName (
397    SQLHSTMT		  hstmt,
398    SQLCHAR		* szCursor,
399    SQLSMALLINT		  cbCursor)
400{
401  ENTER_STMT (hstmt,
402    trace_SQLSetCursorName (TRACE_ENTER, hstmt, szCursor, cbCursor));
403
404  retcode = SQLSetCursorName_Internal(hstmt, szCursor, cbCursor, 'A');
405
406  LEAVE_STMT (hstmt,
407    trace_SQLSetCursorName (TRACE_LEAVE, hstmt, szCursor, cbCursor));
408}
409
410
411#if ODBCVER >= 0x0300
412SQLRETURN SQL_API
413SQLSetCursorNameA (
414    SQLHSTMT		  hstmt,
415    SQLCHAR		* szCursor,
416    SQLSMALLINT		  cbCursor)
417{
418  ENTER_STMT (hstmt,
419    trace_SQLSetCursorName (TRACE_ENTER, hstmt, szCursor, cbCursor));
420
421  retcode = SQLSetCursorName_Internal(hstmt, szCursor, cbCursor, 'A');
422
423  LEAVE_STMT (hstmt,
424    trace_SQLSetCursorName (TRACE_LEAVE, hstmt, szCursor, cbCursor));
425}
426
427
428SQLRETURN SQL_API
429SQLSetCursorNameW (
430  SQLHSTMT		  hstmt,
431  SQLWCHAR 		* szCursor,
432  SQLSMALLINT		  cbCursor)
433{
434  ENTER_STMT (hstmt,
435    trace_SQLSetCursorNameW (TRACE_ENTER, hstmt, szCursor, cbCursor));
436
437  retcode = SQLSetCursorName_Internal(hstmt, szCursor, cbCursor, 'W');
438
439  LEAVE_STMT (hstmt,
440    trace_SQLSetCursorNameW (TRACE_LEAVE, hstmt, szCursor, cbCursor));
441}
442#endif
443
444
445static SQLRETURN
446SQLBindParameter_Internal (
447    SQLHSTMT		  hstmt,
448    SQLUSMALLINT	  ipar,
449    SQLSMALLINT		  fParamType,
450    SQLSMALLINT		  fCType,
451    SQLSMALLINT		  fSqlType,
452    SQLULEN		  cbColDef,
453    SQLSMALLINT		  ibScale,
454    SQLPOINTER		  rgbValue,
455    SQLLEN		  cbValueMax,
456    SQLLEN		* pcbValue)
457{
458  STMT (pstmt, hstmt);
459  CONN (pdbc, pstmt->hdbc);
460  ENVR (penv, pdbc->henv);
461  HPROC hproc2 = SQL_NULL_HPROC;
462  HPROC hproc3 = SQL_NULL_HPROC;
463  SQLSMALLINT nCType;
464  SQLSMALLINT nSqlType;
465  sqlstcode_t sqlstat = en_00000;
466  SQLRETURN retcode = SQL_SUCCESS;
467  SQLUINTEGER odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
468  SQLUINTEGER dodbc_ver = ((ENV_t *) pdbc->henv)->dodbc_ver;
469
470
471#if (ODBCVER >= 0x0300)
472  if (0)
473#else
474  /* check param */
475  if (fSqlType > SQL_TYPE_MAX ||
476      (fSqlType < SQL_TYPE_MIN && fSqlType > SQL_TYPE_DRIVER_START))
477    /* Note: SQL_TYPE_DRIVER_START is a negative number
478     * So, we use ">" */
479#endif
480    {
481      sqlstat = en_S1004;
482    }
483  else if (ipar < 1)
484    {
485      sqlstat = en_S1093;
486    }
487  else if ((rgbValue == NULL && pcbValue == NULL)
488      && fParamType != SQL_PARAM_OUTPUT)
489    {
490      sqlstat = en_S1009;
491      /* This means, I allow output to nowhere
492       * (i.e. * junk output result). But I can't
493       * allow input from nowhere.
494       */
495    }
496/**********
497	else if( cbValueMax < 0L && cbValueMax != SQL_SETPARAM_VALUE_MAX )
498	{
499		sqlstat = en_S1090;
500	}
501**********/
502  else if (fParamType != SQL_PARAM_INPUT
503	&& fParamType != SQL_PARAM_OUTPUT
504      && fParamType != SQL_PARAM_INPUT_OUTPUT)
505    {
506      sqlstat = en_S1105;
507    }
508  else
509    {
510      switch (fCType)
511	{
512	case SQL_C_DEFAULT:
513	case SQL_C_BINARY:
514	case SQL_C_BIT:
515	case SQL_C_CHAR:
516	case SQL_C_DATE:
517	case SQL_C_DOUBLE:
518	case SQL_C_FLOAT:
519	case SQL_C_LONG:
520	case SQL_C_SHORT:
521	case SQL_C_SLONG:
522	case SQL_C_SSHORT:
523	case SQL_C_STINYINT:
524	case SQL_C_TIME:
525	case SQL_C_TIMESTAMP:
526	case SQL_C_TINYINT:
527	case SQL_C_ULONG:
528	case SQL_C_USHORT:
529	case SQL_C_UTINYINT:
530#if (ODBCVER >= 0x0300)
531	case SQL_C_GUID:
532	case SQL_C_INTERVAL_DAY:
533	case SQL_C_INTERVAL_DAY_TO_HOUR:
534	case SQL_C_INTERVAL_DAY_TO_MINUTE:
535	case SQL_C_INTERVAL_DAY_TO_SECOND:
536	case SQL_C_INTERVAL_HOUR:
537	case SQL_C_INTERVAL_HOUR_TO_MINUTE:
538	case SQL_C_INTERVAL_HOUR_TO_SECOND:
539	case SQL_C_INTERVAL_MINUTE:
540	case SQL_C_INTERVAL_MINUTE_TO_SECOND:
541	case SQL_C_INTERVAL_MONTH:
542	case SQL_C_INTERVAL_SECOND:
543	case SQL_C_INTERVAL_YEAR:
544	case SQL_C_INTERVAL_YEAR_TO_MONTH:
545	case SQL_C_NUMERIC:
546	case SQL_C_SBIGINT:
547	case SQL_C_TYPE_DATE:
548	case SQL_C_TYPE_TIME:
549	case SQL_C_TYPE_TIMESTAMP:
550	case SQL_C_UBIGINT:
551	case SQL_C_WCHAR:
552#endif
553	  break;
554
555	default:
556	  sqlstat = en_S1003;
557	  break;
558	}
559    }
560
561  if (sqlstat != en_00000)
562    {
563      PUSHSQLERR (pstmt->herr, sqlstat);
564
565      return SQL_ERROR;
566    }
567
568  /* check state */
569  if (pstmt->state >= en_stmt_needdata || pstmt->asyn_on != en_NullProc)
570    {
571      PUSHSQLERR (pstmt->herr, en_S1010);
572
573      retcode = SQL_ERROR;
574    }
575
576  /*
577   *  Convert C type to ODBC version of driver
578   */
579  nCType = _iodbcdm_map_c_type (fCType, penv->dodbc_ver);
580
581  /*
582   *  Convert SQL type to ODBC version of driver
583   */
584  nSqlType = _iodbcdm_map_sql_type (fSqlType, penv->dodbc_ver);
585
586  hproc2 = _iodbcdm_getproc (pstmt->hdbc, en_BindParameter);
587#if (ODBCVER >=0x0300)
588  hproc3 = _iodbcdm_getproc (pstmt->hdbc, en_BindParam);
589#endif
590
591  if (odbc_ver == SQL_OV_ODBC2 &&
592      (  dodbc_ver == SQL_OV_ODBC2
593       || (dodbc_ver == SQL_OV_ODBC3 && hproc2 != SQL_NULL_HPROC)))
594    hproc3 = SQL_NULL_HPROC;
595
596#if (ODBCVER >=0x0300)
597  if (fParamType == SQL_PARAM_INPUT && hproc3 != SQL_NULL_HPROC)
598    {
599      CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc3,
600	      (pstmt->dhstmt, ipar, nCType, nSqlType, cbColDef,
601	      ibScale, rgbValue, pcbValue));
602    }
603  else
604#endif
605    {
606      if (hproc2 == SQL_NULL_HPROC)
607        {
608          PUSHSQLERR (pstmt->herr, en_IM001);
609          return SQL_ERROR;
610        }
611      CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc2,
612          (pstmt->dhstmt, ipar, fParamType, nCType, nSqlType, cbColDef,
613	  ibScale, rgbValue, cbValueMax, pcbValue));
614    }
615
616  return retcode;
617}
618
619
620SQLRETURN SQL_API
621SQLBindParameter (
622    SQLHSTMT		  hstmt,
623    SQLUSMALLINT	  ipar,
624    SQLSMALLINT		  fParamType,
625    SQLSMALLINT		  fCType,
626    SQLSMALLINT		  fSqlType,
627    SQLULEN		  cbColDef,
628    SQLSMALLINT		  ibScale,
629    SQLPOINTER		  rgbValue,
630    SQLLEN		  cbValueMax,
631    SQLLEN		* pcbValue)
632{
633  ENTER_STMT (hstmt,
634    trace_SQLBindParameter (TRACE_ENTER,
635	hstmt, ipar, fParamType, fCType, fSqlType, cbColDef,
636	ibScale, rgbValue, cbValueMax, pcbValue));
637
638  retcode = SQLBindParameter_Internal (
639	hstmt, ipar, fParamType, fCType, fSqlType, cbColDef,
640	ibScale, rgbValue, cbValueMax, pcbValue);
641
642  LEAVE_STMT (hstmt,
643    trace_SQLBindParameter (TRACE_LEAVE,
644	hstmt, ipar, fParamType, fCType, fSqlType, cbColDef,
645	ibScale, rgbValue, cbValueMax, pcbValue));
646}
647
648
649static SQLRETURN
650SQLParamOptions_Internal (
651  SQLHSTMT		  hstmt,
652  SQLULEN		  crow,
653  SQLULEN 		* pirow)
654{
655  STMT (pstmt, hstmt);
656  HPROC hproc2 = SQL_NULL_HPROC;
657  HPROC hproc3 = SQL_NULL_HPROC;
658  SQLRETURN retcode;
659  CONN (pdbc, pstmt->hdbc);
660  SQLUINTEGER odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
661  SQLUINTEGER dodbc_ver = ((ENV_t *) pdbc->henv)->dodbc_ver;
662
663  if (crow == (SQLULEN) 0UL)
664    {
665      PUSHSQLERR (pstmt->herr, en_S1107);
666
667      return SQL_ERROR;
668    }
669
670  if (pstmt->state >= en_stmt_needdata || pstmt->asyn_on != en_NullProc)
671    {
672      PUSHSQLERR (pstmt->herr, en_S1010);
673
674      return SQL_ERROR;
675    }
676
677
678  hproc2 = _iodbcdm_getproc (pstmt->hdbc, en_ParamOptions);
679#if (ODBCVER >= 0x0300)
680  hproc3 = _iodbcdm_getproc (pstmt->hdbc, en_SetStmtAttr);
681#endif
682
683  if (odbc_ver == SQL_OV_ODBC2 &&
684      (  dodbc_ver == SQL_OV_ODBC2
685       || (dodbc_ver == SQL_OV_ODBC3 && hproc2 != SQL_NULL_HPROC)))
686    hproc3 = SQL_NULL_HPROC;
687
688#if (ODBCVER >= 0x0300)
689  if (hproc3 != SQL_NULL_HPROC)
690    {
691      CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc3,
692	  (pstmt->dhstmt, SQL_ATTR_PARAMSET_SIZE, crow, 0));
693      if (SQL_SUCCEEDED (retcode))
694	{
695	  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc3,
696	      (pstmt->dhstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, pirow, 0));
697	}
698    }
699  else
700#endif
701    {
702      if (hproc2 == SQL_NULL_HPROC)
703	{
704	  PUSHSQLERR (pstmt->herr, en_IM001);
705	  return SQL_ERROR;
706	}
707
708      CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc2,
709	  (pstmt->dhstmt, crow, pirow));
710    }
711
712  return retcode;
713}
714
715
716SQLRETURN SQL_API
717SQLParamOptions(
718  SQLHSTMT		  hstmt,
719  SQLULEN		  crow,
720  SQLULEN 		* pirow)
721{
722  ENTER_STMT (hstmt,
723    trace_SQLParamOptions (TRACE_ENTER, hstmt, crow, pirow));
724
725  retcode = SQLParamOptions_Internal (hstmt, crow, pirow);
726
727  LEAVE_STMT (hstmt,
728    trace_SQLParamOptions (TRACE_LEAVE, hstmt, crow, pirow));
729}
730
731
732static SQLRETURN
733SQLSetScrollOptions_Internal (
734  SQLHSTMT		  hstmt,
735  SQLUSMALLINT		  fConcurrency,
736  SQLLEN		  crowKeyset,
737  SQLUSMALLINT		  crowRowset)
738{
739  STMT (pstmt, hstmt);
740  CONN (pdbc, pstmt->hdbc);
741  HPROC hproc = SQL_NULL_HPROC;
742  sqlstcode_t sqlstat = en_00000;
743  SQLRETURN retcode = SQL_SUCCESS;
744  SQLUINTEGER odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
745  SQLUINTEGER dodbc_ver = ((ENV_t *) pdbc->henv)->dodbc_ver;
746
747  for (;;)
748    {
749      if (crowRowset == (UWORD) 0)
750	{
751	  sqlstat = en_S1107;
752	  break;
753	}
754
755      if (crowKeyset > (SDWORD) 0L && crowKeyset < (SDWORD) crowRowset)
756	{
757	  sqlstat = en_S1107;
758	  break;
759	}
760
761      if (crowKeyset < 1)
762	{
763	  if (crowKeyset != SQL_SCROLL_FORWARD_ONLY
764	      && crowKeyset != SQL_SCROLL_STATIC
765	      && crowKeyset != SQL_SCROLL_KEYSET_DRIVEN
766	      && crowKeyset != SQL_SCROLL_DYNAMIC)
767	    {
768	      sqlstat = en_S1107;
769	      break;
770	    }
771	}
772
773      if (fConcurrency != SQL_CONCUR_READ_ONLY
774	  && fConcurrency != SQL_CONCUR_LOCK
775	  && fConcurrency != SQL_CONCUR_ROWVER
776	  && fConcurrency != SQL_CONCUR_VALUES)
777	{
778	  sqlstat = en_S1108;
779	  break;
780	}
781
782#if (ODBCVER < 0x0300)
783      if (pstmt->state != en_stmt_allocated)
784	{
785	  sqlstat = en_S1010;
786	  break;
787	}
788#endif
789
790      hproc = _iodbcdm_getproc (pstmt->hdbc, en_SetScrollOptions);
791
792      if (dodbc_ver == SQL_OV_ODBC3 &&  odbc_ver == SQL_OV_ODBC3)
793        hproc = SQL_NULL_HPROC;
794
795      if (hproc != SQL_NULL_HPROC)
796        {
797	  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
798	      (pstmt->dhstmt, fConcurrency, crowKeyset, crowRowset));
799	}
800      else
801        {
802#if (ODBCVER >= 0x0300)
803	  SQLINTEGER InfoValue, InfoType, Value;
804	  HPROC hproc1 = _iodbcdm_getproc (pstmt->hdbc, en_SetStmtAttr);
805	  HPROC hproc2 = _iodbcdm_getproc (pstmt->hdbc, en_GetInfo);
806
807	  if (hproc1 == SQL_NULL_HPROC || hproc2 == SQL_NULL_HPROC)
808	    {
809	      PUSHSQLERR (pstmt->herr, en_IM001);
810	      return SQL_ERROR;
811	    }
812
813	  switch (crowKeyset)
814	    {
815	    case SQL_SCROLL_FORWARD_ONLY:
816	      InfoType = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
817	      Value = SQL_CURSOR_FORWARD_ONLY;
818	      break;
819
820	    case SQL_SCROLL_STATIC:
821	      InfoType = SQL_STATIC_CURSOR_ATTRIBUTES2;
822	      Value = SQL_CURSOR_STATIC;
823	      break;
824
825	    case SQL_SCROLL_DYNAMIC:
826	      InfoType = SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
827	      Value = SQL_CURSOR_DYNAMIC;
828	      break;
829
830	    case SQL_SCROLL_KEYSET_DRIVEN:
831	    default:
832	      InfoType = SQL_KEYSET_CURSOR_ATTRIBUTES2;
833	      Value = SQL_CURSOR_KEYSET_DRIVEN;
834	      break;
835	    }
836
837	  CALL_DRIVER (pstmt->hdbc, pdbc, retcode, hproc2,
838	      (pdbc->dhdbc, InfoType, &InfoValue, 0, NULL));
839
840	  if (retcode != SQL_SUCCESS)
841	    {
842	      return retcode;
843	    }
844
845	  switch (fConcurrency)
846	    {
847	    case SQL_CONCUR_READ_ONLY:
848	      if (!(InfoValue & SQL_CA2_READ_ONLY_CONCURRENCY))
849		{
850		  PUSHSQLERR (pstmt->herr, en_S1C00);
851		  return SQL_ERROR;
852		}
853	      break;
854
855	    case SQL_CONCUR_LOCK:
856	      if (!(InfoValue & SQL_CA2_LOCK_CONCURRENCY))
857		{
858		  PUSHSQLERR (pstmt->herr, en_S1C00);
859		  return SQL_ERROR;
860		}
861	      break;
862
863	    case SQL_CONCUR_ROWVER:
864	      if (!(InfoValue & SQL_CA2_OPT_ROWVER_CONCURRENCY))
865		{
866		  PUSHSQLERR (pstmt->herr, en_S1C00);
867		  return SQL_ERROR;
868		}
869	      break;
870
871	    case SQL_CONCUR_VALUES:
872	      if (!(InfoValue & SQL_CA2_OPT_VALUES_CONCURRENCY))
873		{
874		  PUSHSQLERR (pstmt->herr, en_S1C00);
875		  return SQL_ERROR;
876		}
877	      break;
878	    }
879
880	  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc1,
881	      (pstmt->dhstmt, SQL_ATTR_CURSOR_TYPE, Value, 0));
882
883	  if (retcode != SQL_SUCCESS)
884	    return retcode;
885
886	  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc1,
887	      (pstmt->dhstmt, SQL_ATTR_CONCURRENCY, fConcurrency, 0));
888
889	  if (retcode != SQL_SUCCESS)
890	    return retcode;
891
892	  if (crowKeyset > 0)
893	    {
894	      CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc1,
895		  (pstmt->dhstmt, SQL_ATTR_KEYSET_SIZE, crowKeyset, 0));
896
897	      if (retcode != SQL_SUCCESS)
898		return retcode;
899	    }
900
901	  CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc1,
902	      (pstmt->dhstmt, SQL_ROWSET_SIZE, crowRowset, 0));
903
904	  if (retcode != SQL_SUCCESS)
905	    return retcode;
906#else
907	  sqlstat = en_IM001;
908	  break;
909#endif
910	}
911
912      sqlstat = en_00000;
913      if (1)			/* turn off solaris warning message */
914	break;
915    }
916
917  if (sqlstat != en_00000)
918    {
919      PUSHSQLERR (pstmt->herr, sqlstat);
920
921      return SQL_ERROR;
922    }
923
924  return retcode;
925}
926
927
928SQLRETURN SQL_API
929SQLSetScrollOptions (
930  SQLHSTMT		  hstmt,
931  SQLUSMALLINT		  fConcurrency,
932  SQLLEN		  crowKeyset,
933  SQLUSMALLINT		  crowRowset)
934{
935  ENTER_STMT (hstmt,
936    trace_SQLSetScrollOptions (TRACE_ENTER,
937    	hstmt,
938	fConcurrency,
939	crowKeyset,
940	crowRowset));
941
942  retcode = SQLSetScrollOptions_Internal (
943    	hstmt,
944	fConcurrency,
945	crowKeyset,
946	crowRowset);
947
948  LEAVE_STMT (hstmt,
949    trace_SQLSetScrollOptions (TRACE_LEAVE,
950    	hstmt,
951	fConcurrency,
952	crowKeyset,
953	crowRowset));
954}
955
956
957SQLRETURN SQL_API
958SQLSetParam (
959  SQLHSTMT		  hstmt,
960  SQLUSMALLINT		  ipar,
961  SQLSMALLINT		  fCType,
962  SQLSMALLINT		  fSqlType,
963  SQLULEN		  cbColDef,
964  SQLSMALLINT		  ibScale,
965  SQLPOINTER		  rgbValue,
966  SQLLEN 		* pcbValue)
967{
968  return SQLBindParameter (hstmt,
969      ipar,
970      (SWORD) SQL_PARAM_INPUT_OUTPUT,
971      fCType,
972      fSqlType,
973      cbColDef,
974      ibScale,
975      rgbValue,
976      SQL_SETPARAM_VALUE_MAX,
977      pcbValue);
978}
979