1/*
2 *  odbc3.c
3 *
4 *  $Id: odbc3.c,v 1.32 2007/09/04 06:25:24 source Exp $
5 *
6 *  ODBC 3.x functions
7 *
8 *  The iODBC driver manager.
9 *
10 *  Copyright (C) 1996-2006 by OpenLink Software <iodbc@openlinksw.com>
11 *  All Rights Reserved.
12 *
13 *  This software is released under the terms of either of the following
14 *  licenses:
15 *
16 *      - GNU Library General Public License (see LICENSE.LGPL)
17 *      - The BSD License (see LICENSE.BSD).
18 *
19 *  Note that the only valid version of the LGPL license as far as this
20 *  project is concerned is the original GNU Library General Public License
21 *  Version 2, dated June 1991.
22 *
23 *  While not mandated by the BSD license, any patches you make to the
24 *  iODBC source code may be contributed back into the iODBC project
25 *  at your discretion. Contributions will benefit the Open Source and
26 *  Data Access community as a whole. Submissions may be made at:
27 *
28 *      http://www.iodbc.org
29 *
30 *
31 *  GNU Library Generic Public License Version 2
32 *  ============================================
33 *  This library is free software; you can redistribute it and/or
34 *  modify it under the terms of the GNU Library General Public
35 *  License as published by the Free Software Foundation; only
36 *  Version 2 of the License dated June 1991.
37 *
38 *  This library is distributed in the hope that it will be useful,
39 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
40 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41 *  Library General Public License for more details.
42 *
43 *  You should have received a copy of the GNU Library General Public
44 *  License along with this library; if not, write to the Free
45 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
46 *
47 *
48 *  The BSD License
49 *  ===============
50 *  Redistribution and use in source and binary forms, with or without
51 *  modification, are permitted provided that the following conditions
52 *  are met:
53 *
54 *  1. Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 *  2. Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in
58 *     the documentation and/or other materials provided with the
59 *     distribution.
60 *  3. Neither the name of OpenLink Software Inc. nor the names of its
61 *     contributors may be used to endorse or promote products derived
62 *     from this software without specific prior written permission.
63 *
64 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
65 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
66 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
67 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
68 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
69 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
70 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
71 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
72 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
73 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
74 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75 */
76
77
78#include "iodbc.h"
79
80#include <sql.h>
81#include <sqlext.h>
82#include <iodbcext.h>
83
84#if (ODBCVER >= 0x300)
85#include <sqlucode.h>
86
87#include <unicode.h>
88
89#include <dlproc.h>
90
91#include <herr.h>
92#include <henv.h>
93#include <hdesc.h>
94#include <hdbc.h>
95#include <hstmt.h>
96
97#include <itrace.h>
98
99
100/*
101 * SQL_ATTR_CONNECTION_POOLING value
102 */
103SQLINTEGER _iodbcdm_attr_connection_pooling = SQL_CP_DEFAULT;
104
105
106/*
107 *  Externals
108 */
109SQLRETURN SQLAllocEnv_Internal (SQLHENV * phenv, int odbc_ver);
110SQLRETURN SQLFreeEnv_Internal (SQLHENV henv);
111SQLRETURN SQLAllocConnect_Internal (SQLHENV henv, SQLHDBC * phdbc);
112SQLRETURN SQLFreeConnect_Internal (SQLHDBC hdbc, int ver);
113SQLRETURN SQLAllocStmt_Internal (SQLHDBC hdbc, SQLHSTMT * phstmt);
114SQLRETURN SQLFreeStmt_Internal (SQLHSTMT hstmt, SQLUSMALLINT fOption);
115SQLRETURN SQLTransact_Internal (SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT fType);
116
117RETCODE SQL_API
118SQLAllocHandle_Internal (
119    SQLSMALLINT	  handleType,
120    SQLHANDLE 	  inputHandle,
121    SQLHANDLE	* outputHandlePtr)
122{
123  switch (handleType)
124    {
125    case SQL_HANDLE_ENV:
126      return SQLAllocEnv_Internal (outputHandlePtr, 0);
127
128    case SQL_HANDLE_DBC:
129      {
130	GENV (genv, inputHandle);
131
132	if (!IS_VALID_HENV (genv))
133	  {
134	    return SQL_INVALID_HANDLE;
135	  }
136	CLEAR_ERRORS (genv);
137	if (genv->odbc_ver == 0)
138	  {
139	    PUSHSQLERR (genv->herr, en_HY010);
140	    return SQL_ERROR;
141	  }
142
143	return SQLAllocConnect_Internal (inputHandle, outputHandlePtr);
144      }
145
146    case SQL_HANDLE_STMT:
147      {
148	CONN (con, inputHandle);
149
150	if (!IS_VALID_HDBC (con))
151	  {
152	    return SQL_INVALID_HANDLE;
153	  }
154	CLEAR_ERRORS (con);
155
156        return SQLAllocStmt_Internal (inputHandle, outputHandlePtr);
157      }
158
159    case SQL_HANDLE_DESC:
160      {
161	CONN (con, inputHandle);
162	HPROC hproc = SQL_NULL_HPROC;
163	RETCODE retcode;
164	DESC_t *new_desc;
165
166	if (!IS_VALID_HDBC (con))
167	  {
168	    return SQL_INVALID_HANDLE;
169	  }
170	CLEAR_ERRORS (con);
171
172	if (((ENV_t *)(con->henv))->dodbc_ver == SQL_OV_ODBC2)
173	  {
174	    PUSHSQLERR (con->herr, en_HYC00);
175	    return SQL_ERROR;
176	  }
177	if (!outputHandlePtr)
178	  {
179	    PUSHSQLERR (con->herr, en_HY009);
180	    return SQL_ERROR;
181	  }
182
183	hproc = _iodbcdm_getproc (con, en_AllocHandle);
184
185	if (hproc == SQL_NULL_HPROC)
186	  {
187	    PUSHSQLERR (con->herr, en_IM001);
188	    return SQL_ERROR;
189	  }
190
191	new_desc = (DESC_t *) MEM_ALLOC (sizeof (DESC_t));
192	if (!new_desc)
193	  {
194	    PUSHSQLERR (con->herr, en_HY001);
195	    return SQL_ERROR;
196	  }
197	memset (new_desc, 0, sizeof (DESC_t));
198	CALL_DRIVER (con, con, retcode, hproc,
199	    (handleType, con->dhdbc, &new_desc->dhdesc));
200
201	if (!SQL_SUCCEEDED (retcode))
202	  {
203	    MEM_FREE (new_desc);
204	    return SQL_ERROR;
205	  }
206
207	new_desc->type = SQL_HANDLE_DESC;
208	new_desc->hdbc = con;
209	new_desc->hstmt = NULL;
210	new_desc->herr = NULL;
211	new_desc->desc_cip = 0;
212	*outputHandlePtr = new_desc;
213
214	new_desc->next = (DESC_t *) con->hdesc;
215	con->hdesc = new_desc;
216
217	return SQL_SUCCESS;
218      }
219
220    default:
221      if (IS_VALID_HDBC (inputHandle))
222	{
223	  CONN (con, inputHandle);
224	  PUSHSQLERR (con->herr, en_HY092);
225	  return SQL_ERROR;
226	}
227      else if (IS_VALID_HENV (inputHandle))
228	{
229	  GENV (genv, inputHandle);
230	  PUSHSQLERR (genv->herr, en_HY092);
231	  return SQL_ERROR;
232	}
233      return SQL_INVALID_HANDLE;
234    }
235}
236
237
238RETCODE SQL_API
239SQLAllocHandle (
240    SQLSMALLINT	  handleType,
241    SQLHANDLE	  inputHandle,
242    SQLHANDLE	* outputHandlePtr)
243{
244  int retcode = SQL_SUCCESS;
245
246  if (handleType == SQL_HANDLE_ENV)
247    {
248      /*
249       *  One time initialization
250       */
251      Init_iODBC();
252
253      ODBC_LOCK ();
254
255      retcode = SQLAllocEnv_Internal (outputHandlePtr, 0);
256
257      /*
258       * Start tracing
259       */
260      TRACE (trace_SQLAllocHandle (TRACE_ENTER,
261	    handleType, inputHandle, outputHandlePtr));
262
263      TRACE (trace_SQLAllocHandle (TRACE_LEAVE,
264	    handleType, inputHandle, outputHandlePtr));
265
266      ODBC_UNLOCK ();
267
268      return retcode;
269    }
270
271  ODBC_LOCK ();
272
273  TRACE (trace_SQLAllocHandle (TRACE_ENTER,
274	handleType, inputHandle, outputHandlePtr));
275
276  retcode =
277      SQLAllocHandle_Internal (handleType, inputHandle, outputHandlePtr);
278
279  TRACE (trace_SQLAllocHandle (TRACE_LEAVE,
280	handleType, inputHandle, outputHandlePtr));
281
282  ODBC_UNLOCK ();
283
284  return retcode;
285}
286
287
288RETCODE SQL_API
289SQLAllocHandleStd (
290  SQLSMALLINT handleType,
291  SQLHANDLE inputHandle,
292  SQLHANDLE * outputHandlePtr)
293{
294  int retcode = SQL_SUCCESS;
295
296  if (handleType == SQL_HANDLE_ENV)
297    {
298      /*
299       *  One time initialization
300       */
301      Init_iODBC();
302
303      ODBC_LOCK ();
304
305      retcode = SQLAllocEnv_Internal (outputHandlePtr, SQL_OV_ODBC3);
306
307      /*
308       * Start tracing
309       */
310      TRACE (trace_SQLAllocHandle (TRACE_ENTER,
311	    handleType, inputHandle, outputHandlePtr));
312
313      TRACE (trace_SQLAllocHandle (TRACE_LEAVE,
314	    handleType, inputHandle, outputHandlePtr));
315
316      ODBC_UNLOCK ();
317
318      return retcode;
319    }
320
321  ODBC_LOCK ();
322
323  TRACE (trace_SQLAllocHandle (TRACE_ENTER,
324	handleType, inputHandle, outputHandlePtr));
325
326  retcode =
327      SQLAllocHandle_Internal (handleType, inputHandle, outputHandlePtr);
328
329  TRACE (trace_SQLAllocHandle (TRACE_LEAVE,
330	handleType, inputHandle, outputHandlePtr));
331
332  ODBC_UNLOCK ();
333
334  return retcode;
335}
336
337
338/**** SQLFreeHandle ****/
339
340extern unsigned long _iodbc_env_counter;
341
342static RETCODE
343_SQLFreeHandle_ENV (
344  SQLSMALLINT		  handleType,
345  SQLHANDLE		  handle)
346{
347  int retcode = SQL_SUCCESS;
348
349  ODBC_LOCK ();
350
351  TRACE (trace_SQLFreeHandle (TRACE_ENTER, handleType, handle));
352
353  retcode = SQLFreeEnv_Internal ((SQLHENV) handle);
354
355  TRACE (trace_SQLFreeHandle (TRACE_LEAVE, handleType, handle));
356
357  MEM_FREE (handle);
358
359  /*
360   *  Close trace after last environment handle is freed
361   */
362  if (--_iodbc_env_counter == 0)
363    trace_stop();
364
365  ODBC_UNLOCK ();
366
367  return retcode;
368}
369
370
371static RETCODE
372_SQLFreeHandle_DBC (
373  SQLSMALLINT		  handleType,
374  SQLHANDLE		  handle)
375{
376  ENTER_HDBC ((SQLHDBC) handle, 1,
377      trace_SQLFreeHandle (TRACE_ENTER, handleType, handle));
378
379  retcode = SQLFreeConnect_Internal ((SQLHDBC) handle, 3);
380
381  LEAVE_HDBC ((SQLHDBC) handle, 1,
382      trace_SQLFreeHandle (TRACE_LEAVE, handleType, handle);
383      MEM_FREE (handle)
384  );
385}
386
387static RETCODE
388_SQLFreeHandle_STMT (
389  SQLSMALLINT		  handleType,
390  SQLHANDLE		  handle)
391{
392  ENTER_STMT ((SQLHSTMT) handle,
393      trace_SQLFreeHandle (TRACE_ENTER, handleType, handle));
394
395  retcode = SQLFreeStmt_Internal ((SQLHSTMT) handle, SQL_DROP);
396
397  LEAVE_STMT ((SQLHSTMT) handle,
398      trace_SQLFreeHandle (TRACE_LEAVE, handleType, handle);
399      _iodbcdm_dropstmt ((SQLHSTMT) handle);
400  );
401}
402
403static RETCODE
404_SQLFreeHandle_DESC (
405  SQLSMALLINT		  handleType,
406  SQLHANDLE		  handle)
407{
408  DESC (pdesc, handle);
409  CONN (pdbc, pdesc->hdbc);
410  HPROC hproc;
411  RETCODE retcode = SQL_SUCCESS;
412  DESC_t *curr_desc;
413
414  if (IS_VALID_HSTMT (pdesc->hstmt))
415    {				/* the desc handle is implicit */
416      PUSHSQLERR (pdesc->herr, en_HY017);
417      return SQL_ERROR;
418    }
419  CLEAR_ERRORS (pdesc);
420
421  /* remove it from the dbc's list */
422  curr_desc = (DESC_t *) pdbc->hdesc;
423  while (curr_desc)
424    {
425      if (curr_desc == pdesc)
426	{
427	  pdbc->hdesc = pdesc->next;
428	  break;
429	}
430      if (curr_desc->next == pdesc)
431	{
432	  curr_desc->next = pdesc->next;
433	  break;
434	}
435      curr_desc = curr_desc->next;
436    }
437  if (!curr_desc)
438    return SQL_INVALID_HANDLE;
439
440  /* and call the driver's function */
441  hproc = SQL_NULL_HPROC;
442  if (pdesc->dhdesc)
443    {				/* the driver has descriptors */
444      hproc = _iodbcdm_getproc (pdbc, en_FreeHandle);
445      if (hproc == SQL_NULL_HPROC)
446	{
447	  PUSHSQLERR (pdesc->herr, en_IM001);
448	  retcode = SQL_ERROR;
449	}
450      else
451	CALL_DRIVER (pdbc, pdesc, retcode, hproc,
452	    (handleType, pdesc->dhdesc));
453    }
454
455  _iodbcdm_freesqlerrlist (pdesc->herr);
456
457  /* invalidate the handle */
458  pdesc->type = 0;
459
460  return retcode;
461}
462
463
464RETCODE SQL_API
465SQLFreeHandle (
466  SQLSMALLINT		  handleType,
467  SQLHANDLE		  handle)
468{
469  switch (handleType)
470    {
471    case SQL_HANDLE_ENV:
472      return _SQLFreeHandle_ENV (handleType, handle);
473
474    case SQL_HANDLE_DBC:
475      return _SQLFreeHandle_DBC (handleType, handle);
476
477    case SQL_HANDLE_STMT:
478      return _SQLFreeHandle_STMT (handleType, handle);
479
480    case SQL_HANDLE_DESC:
481      {
482	ENTER_DESC ((SQLHDESC) handle,
483	    trace_SQLFreeHandle (TRACE_ENTER, handleType, handle));
484
485	retcode = _SQLFreeHandle_DESC (handleType, handle);
486
487	LEAVE_DESC ((SQLHDESC) handle,
488	    trace_SQLFreeHandle (TRACE_LEAVE, handleType, handle);
489	    MEM_FREE (handle);
490        );
491      }
492      break;
493
494    default:
495      if (IS_VALID_HDBC (handle))
496	{
497	  CONN (con, handle);
498	  PUSHSQLERR (con->herr, en_HY092);
499	  return SQL_ERROR;
500	}
501      else if (IS_VALID_HENV (handle))
502	{
503	  GENV (genv, handle);
504	  PUSHSQLERR (genv->herr, en_HY092);
505	  return SQL_ERROR;
506	}
507    }
508
509  return SQL_INVALID_HANDLE;
510}
511
512
513/**** SQLSetEnvAttr ****/
514
515static RETCODE
516SQLSetEnvAttr_Internal (SQLHENV environmentHandle,
517    SQLINTEGER Attribute,
518    SQLPOINTER ValuePtr,
519    SQLINTEGER StringLength)
520{
521  GENV (genv, environmentHandle);
522
523  StringLength = StringLength; /*UNUSED*/
524
525  if (genv != NULL && genv->hdbc)
526    {
527      PUSHSQLERR (genv->herr, en_HY010);
528      return SQL_ERROR;
529    }
530
531  switch (Attribute)
532    {
533    case SQL_ATTR_CONNECTION_POOLING:
534      switch ((SQLINTEGER) (SQLULEN) ValuePtr)
535	{
536	case SQL_CP_OFF:
537	case SQL_CP_ONE_PER_DRIVER:
538	case SQL_CP_ONE_PER_HENV:
539          _iodbcdm_attr_connection_pooling = (SQLINTEGER) (SQLULEN) ValuePtr;
540	  return SQL_SUCCESS;
541
542	default:
543	  if (genv)
544	    PUSHSQLERR (genv->herr, en_HY024);
545	  return SQL_ERROR;
546	}
547
548    case SQL_ATTR_CP_MATCH:
549      switch ((SQLINTEGER) (SQLULEN) ValuePtr)
550	{
551	case SQL_CP_STRICT_MATCH:
552	case SQL_CP_RELAXED_MATCH:
553          genv->cp_match = (SQLINTEGER) (SQLULEN) ValuePtr;
554	  return SQL_SUCCESS;
555
556	default:
557	  PUSHSQLERR (genv->herr, en_HY024);
558	  return SQL_ERROR;
559	}
560
561    case SQL_ATTR_ODBC_VERSION:
562      switch ((SQLINTEGER) (SQLULEN) ValuePtr)
563	{
564	case SQL_OV_ODBC2:
565	case SQL_OV_ODBC3:
566	  genv->odbc_ver = (SQLINTEGER) (SQLULEN) ValuePtr;
567	  return (SQL_SUCCESS);
568
569	default:
570	  PUSHSQLERR (genv->herr, en_HY024);
571	  return SQL_ERROR;
572	}
573
574    case SQL_ATTR_OUTPUT_NTS:
575      switch ((SQLINTEGER) (SQLULEN) ValuePtr)
576	{
577	case SQL_TRUE:
578	  return SQL_SUCCESS;
579
580	case SQL_FALSE:
581	  PUSHSQLERR (genv->herr, en_HYC00);
582	  return SQL_ERROR;
583
584	default:
585	  PUSHSQLERR (genv->herr, en_HY024);
586	  return SQL_ERROR;
587	}
588
589    default:
590      PUSHSQLERR (genv->herr, en_HY092);
591      return SQL_ERROR;
592    }
593}
594
595
596RETCODE SQL_API
597SQLSetEnvAttr (
598  SQLHENV		  EnvironmentHandle,
599  SQLINTEGER		  Attribute,
600  SQLPOINTER		  ValuePtr,
601  SQLINTEGER		  StringLength)
602{
603  if (Attribute == SQL_ATTR_CONNECTION_POOLING)
604    {
605	SQLRETURN retcode = SQL_SUCCESS;
606
607	/* ENTER_HENV without EnvironmentHandle check */
608	ODBC_LOCK ();
609	TRACE (trace_SQLSetEnvAttr (TRACE_ENTER,
610	    EnvironmentHandle,
611	    Attribute,
612	    ValuePtr, StringLength));
613
614        retcode = SQLSetEnvAttr_Internal (
615	      EnvironmentHandle,
616	      Attribute,
617	      ValuePtr, StringLength);
618
619	/* LEAVE_HENV without done: label */
620	TRACE (trace_SQLSetEnvAttr (TRACE_LEAVE,
621	    EnvironmentHandle,
622	    Attribute,
623	    ValuePtr, StringLength));
624	ODBC_UNLOCK ();
625	return retcode;
626    }
627  else
628    {
629      ENTER_HENV (EnvironmentHandle,
630        trace_SQLSetEnvAttr (TRACE_ENTER,
631	    EnvironmentHandle,
632	    Attribute,
633	    ValuePtr, StringLength));
634
635      retcode = SQLSetEnvAttr_Internal (
636	    EnvironmentHandle,
637	    Attribute,
638	    ValuePtr, StringLength);
639
640      LEAVE_HENV (EnvironmentHandle,
641        trace_SQLSetEnvAttr (TRACE_LEAVE,
642	    EnvironmentHandle,
643	    Attribute,
644	    ValuePtr, StringLength));
645   }
646}
647
648
649static RETCODE
650SQLGetEnvAttr_Internal (
651  SQLHENV		  environmentHandle,
652  SQLINTEGER		  Attribute,
653  SQLPOINTER		  ValuePtr,
654  SQLINTEGER		  BufferLength,
655  SQLINTEGER		* StringLengthPtr)
656{
657  GENV (genv, environmentHandle);
658  SQLRETURN retcode = SQL_SUCCESS;
659
660  if (Attribute != SQL_ATTR_CONNECTION_POOLING &&
661      Attribute != SQL_ATTR_CP_MATCH &&
662      Attribute != SQL_ATTR_ODBC_VERSION &&
663      Attribute != SQL_ATTR_OUTPUT_NTS &&
664      Attribute != SQL_ATTR_WCHAR_SIZE)
665    {
666      PUSHSQLERR (genv->herr, en_HY092);
667      return SQL_ERROR;
668    }
669
670  /* ODBC DM env attributes */
671  if (Attribute == SQL_ATTR_ODBC_VERSION)
672    {
673      if (ValuePtr)
674	*((SQLINTEGER *) ValuePtr) = genv->odbc_ver;
675      return SQL_SUCCESS;
676    }
677  if (Attribute == SQL_ATTR_CONNECTION_POOLING)
678    {
679      if (ValuePtr)
680	*((SQLUINTEGER *) ValuePtr) = _iodbcdm_attr_connection_pooling;
681      return SQL_SUCCESS;
682    }
683  if (Attribute == SQL_ATTR_CP_MATCH)
684    {
685      if (ValuePtr)
686	*((SQLUINTEGER *) ValuePtr) = genv->cp_match;
687      return SQL_SUCCESS;
688    }
689  if (Attribute == SQL_ATTR_OUTPUT_NTS)
690    {
691      if (ValuePtr)
692	*((SQLINTEGER *) ValuePtr) = SQL_TRUE;
693      return SQL_SUCCESS;
694    }
695  if (Attribute == SQL_ATTR_WCHAR_SIZE)
696    {
697      if (ValuePtr)
698	*((SQLINTEGER *) ValuePtr) = sizeof(wchar_t);
699       return SQL_SUCCESS;
700     }
701
702  /* fall back to the first driver */
703  if (IS_VALID_HDBC (genv->hdbc))
704    {
705      CONN (con, genv->hdbc);
706      HPROC hproc = _iodbcdm_getproc (con, en_GetEnvAttr);
707      if (hproc != SQL_NULL_HPROC)
708	{
709	  ENVR (env, con->henv);
710	  CALL_DRIVER (con, genv, retcode, hproc,
711	      (env->dhenv, Attribute, ValuePtr, BufferLength,
712		  StringLengthPtr));
713	  return retcode;
714	}
715      else
716	{			/* possibly an ODBC2 driver */
717	  PUSHSQLERR (genv->herr, en_IM001);
718	  return SQL_ERROR;
719	}
720    }
721  else
722    {
723      switch ((SQLINTEGER) Attribute)
724	{
725	case SQL_ATTR_CONNECTION_POOLING:
726	  if (ValuePtr)
727	    *((SQLINTEGER *) ValuePtr) = SQL_CP_OFF;
728	  break;
729
730	case SQL_ATTR_CP_MATCH:
731	  if (ValuePtr)
732	    *((SQLINTEGER *) ValuePtr) = SQL_CP_STRICT_MATCH;
733	  break;
734
735	case SQL_ATTR_ODBC_VERSION:
736	  if (ValuePtr)
737	    *((SQLINTEGER *) ValuePtr) = genv->odbc_ver;
738	  break;
739	}
740    }
741  return SQL_SUCCESS;
742}
743
744
745RETCODE SQL_API
746SQLGetEnvAttr (
747  SQLHENV		  EnvironmentHandle,
748  SQLINTEGER		  Attribute,
749  SQLPOINTER		  ValuePtr,
750  SQLINTEGER		  BufferLength,
751  SQLINTEGER		* StringLengthPtr)
752{
753  if (Attribute == SQL_ATTR_CONNECTION_POOLING)
754    {
755	SQLRETURN retcode = SQL_SUCCESS;
756
757	/* ENTER_HENV without EnvironmentHandle check */
758	ODBC_LOCK ();
759	TRACE (trace_SQLGetEnvAttr (TRACE_ENTER,
760	    EnvironmentHandle,
761	    Attribute,
762	    ValuePtr, BufferLength, StringLengthPtr));
763
764        retcode = SQLGetEnvAttr_Internal (
765	      EnvironmentHandle,
766	      Attribute,
767	      ValuePtr, BufferLength, StringLengthPtr);
768
769	/* LEAVE_HENV without done: label */
770	TRACE (trace_SQLGetEnvAttr (TRACE_LEAVE,
771	    EnvironmentHandle,
772	    Attribute,
773	    ValuePtr, BufferLength, StringLengthPtr));
774	ODBC_UNLOCK ();
775	return retcode;
776    }
777  else
778    {
779      ENTER_HENV (EnvironmentHandle,
780        trace_SQLGetEnvAttr (TRACE_ENTER,
781  	    EnvironmentHandle,
782	    Attribute,
783	    ValuePtr, BufferLength, StringLengthPtr));
784
785      retcode = SQLGetEnvAttr_Internal (
786  	    EnvironmentHandle,
787	    Attribute,
788	    ValuePtr, BufferLength, StringLengthPtr);
789
790      LEAVE_HENV (EnvironmentHandle,
791        trace_SQLGetEnvAttr (TRACE_LEAVE,
792  	    EnvironmentHandle,
793	    Attribute,
794	    ValuePtr, BufferLength, StringLengthPtr));
795    }
796}
797
798
799RETCODE SQL_API
800SQLGetStmtAttr_Internal (
801  SQLHSTMT		  statementHandle,
802  SQLINTEGER		  Attribute,
803  SQLPOINTER		  ValuePtr,
804  SQLINTEGER		  BufferLength,
805  SQLINTEGER		* StringLengthPtr,
806  SQLCHAR		  waMode)
807{
808  STMT (stmt, statementHandle);
809  CONN (pdbc, stmt->hdbc);
810  ENVR (penv, pdbc->henv);
811  HPROC hproc = SQL_NULL_HPROC;
812  SQLRETURN retcode = SQL_SUCCESS;
813
814  waMode = waMode; /*UNUSED*/
815
816  switch (Attribute)
817    {
818    case SQL_ATTR_IMP_PARAM_DESC:
819
820      if (ValuePtr)
821	{
822	  if (IS_VALID_HDESC (stmt->desc[IMP_PARAM_DESC]))
823	    *((SQLHANDLE *) ValuePtr) = (SQLHANDLE *) stmt->desc[IMP_PARAM_DESC];
824	  else if (IS_VALID_HDESC (stmt->imp_desc[IMP_PARAM_DESC]))
825	    *((SQLHANDLE *) ValuePtr) = (SQLHANDLE *) stmt->imp_desc[IMP_PARAM_DESC];
826	  else
827	    {
828	      PUSHSQLERR (stmt->herr, en_IM001);
829	      return SQL_ERROR;
830	    }
831	}
832      if (StringLengthPtr)
833	*StringLengthPtr = SQL_IS_POINTER;
834      return SQL_SUCCESS;
835
836    case SQL_ATTR_APP_PARAM_DESC:
837
838      if (ValuePtr)
839	{
840	  if (IS_VALID_HDESC (stmt->desc[APP_PARAM_DESC]))
841	    *((SQLHANDLE *) ValuePtr) = (SQLHANDLE *) stmt->desc[APP_PARAM_DESC];
842	  else if (IS_VALID_HDESC (stmt->imp_desc[APP_PARAM_DESC]))
843	    *((SQLHANDLE *) ValuePtr) = (SQLHANDLE *) stmt->imp_desc[APP_PARAM_DESC];
844	  else
845	    {
846	      PUSHSQLERR (stmt->herr, en_IM001);
847	      return SQL_ERROR;
848	    }
849	}
850      if (StringLengthPtr)
851	*StringLengthPtr = SQL_IS_POINTER;
852      return SQL_SUCCESS;
853
854    case SQL_ATTR_IMP_ROW_DESC:
855
856      if (ValuePtr)
857	{
858	  if (IS_VALID_HDESC (stmt->desc[IMP_ROW_DESC]))
859	    *((SQLHANDLE *) ValuePtr) = (SQLHANDLE *) stmt->desc[IMP_ROW_DESC];
860	  else if (IS_VALID_HDESC (stmt->imp_desc[IMP_ROW_DESC]))
861	    *((SQLHANDLE *) ValuePtr) = (SQLHANDLE *) stmt->imp_desc[IMP_ROW_DESC];
862	  else
863	    {
864	      PUSHSQLERR (stmt->herr, en_IM001);
865	      return SQL_ERROR;
866	    }
867	}
868      if (StringLengthPtr)
869	*StringLengthPtr = SQL_IS_POINTER;
870      return SQL_SUCCESS;
871
872    case SQL_ATTR_APP_ROW_DESC:
873
874      if (ValuePtr)
875	{
876	  if (IS_VALID_HDESC (stmt->desc[APP_ROW_DESC]))
877	    *((SQLHANDLE *) ValuePtr) = (SQLHANDLE *) stmt->desc[APP_ROW_DESC];
878	  else if (IS_VALID_HDESC (stmt->imp_desc[APP_ROW_DESC]))
879	    *((SQLHANDLE *) ValuePtr) = (SQLHANDLE *) stmt->imp_desc[APP_ROW_DESC];
880	  else
881	    {
882	      PUSHSQLERR (stmt->herr, en_IM001);
883	      return SQL_ERROR;
884	    }
885	}
886      if (StringLengthPtr)
887	*StringLengthPtr = SQL_IS_POINTER;
888      return SQL_SUCCESS;
889
890    case SQL_ATTR_ROW_ARRAY_SIZE:
891      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
892	{
893          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
894            penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute,
895            ValuePtr, BufferLength, StringLengthPtr));
896          if (hproc == SQL_NULL_HPROC)
897            {
898	      PUSHSQLERR (stmt->herr, en_IM001);
899	      return SQL_ERROR;
900            }
901	  return retcode;
902	}
903      else
904	{			/* an ODBC2 driver */
905	  if (ValuePtr)
906	    *((SQLUINTEGER *) ValuePtr) = stmt->row_array_size;
907	  return SQL_SUCCESS;
908	}
909
910    case SQL_ATTR_ENABLE_AUTO_IPD:
911    case SQL_ATTR_CURSOR_SENSITIVITY:
912    case SQL_ATTR_CURSOR_SCROLLABLE:
913    case SQL_ATTR_PARAM_BIND_TYPE:
914    case SQL_ATTR_PARAM_OPERATION_PTR:
915    case SQL_ATTR_PARAM_STATUS_PTR:
916    case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
917    case SQL_ATTR_ROW_BIND_OFFSET_PTR:
918    case SQL_ATTR_ROW_OPERATION_PTR:
919
920      CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
921        penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute,
922        ValuePtr, BufferLength, StringLengthPtr));
923      if (hproc == SQL_NULL_HPROC)
924        {
925          PUSHSQLERR (stmt->herr, en_IM001);
926	  return SQL_ERROR;
927        }
928      return retcode;
929
930    case SQL_ATTR_FETCH_BOOKMARK_PTR:
931
932      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
933	{
934          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
935            penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute,
936            ValuePtr, BufferLength, StringLengthPtr));
937          if (hproc == SQL_NULL_HPROC)
938            {
939	      PUSHSQLERR (stmt->herr, en_IM001);
940	      return SQL_ERROR;
941            }
942	  return retcode;
943	}
944      else
945	{			/* an ODBC2 driver */
946	  if (ValuePtr)
947	    *((SQLPOINTER *) ValuePtr) = stmt->fetch_bookmark_ptr;
948	  return SQL_SUCCESS;
949	}
950
951    case SQL_ATTR_ROWS_FETCHED_PTR:
952
953      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
954	{
955          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
956            penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute,
957            ValuePtr, BufferLength, StringLengthPtr));
958          if (hproc == SQL_NULL_HPROC)
959            {
960	      PUSHSQLERR (stmt->herr, en_IM001);
961	      return SQL_ERROR;
962            }
963	  return retcode;
964	}
965      else
966	{			/* an ODBC2 driver */
967	  if (ValuePtr)
968	    *((SQLPOINTER *) ValuePtr) = stmt->rows_fetched_ptr;
969	  return SQL_SUCCESS;
970	}
971
972    case SQL_ATTR_METADATA_ID:
973
974      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
975	{
976          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
977            penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute,
978            ValuePtr, BufferLength, StringLengthPtr));
979          if (hproc == SQL_NULL_HPROC)
980            {
981	      PUSHSQLERR (stmt->herr, en_IM001);
982	      return SQL_ERROR;
983            }
984	  return retcode;
985	}
986      else
987	{			/* an ODBC2 driver */
988	  if (ValuePtr)
989	    *((SQLUINTEGER *) ValuePtr) = SQL_FALSE;
990	  return SQL_SUCCESS;
991	}
992
993    case SQL_ATTR_PARAMS_PROCESSED_PTR:
994
995      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
996	{
997          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
998            penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute,
999            ValuePtr, BufferLength, StringLengthPtr));
1000          if (hproc == SQL_NULL_HPROC)
1001            {
1002	      PUSHSQLERR (stmt->herr, en_IM001);
1003	      return SQL_ERROR;
1004            }
1005	  return retcode;
1006	}
1007      else
1008	{			/* an ODBC2 driver */
1009	  if (ValuePtr)
1010	    *((SQLUINTEGER **) ValuePtr) = (SQLUINTEGER *) stmt->params_processed_ptr;
1011	  return SQL_SUCCESS;
1012	}
1013
1014    case SQL_ATTR_PARAMSET_SIZE:
1015
1016      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1017	{
1018          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1019            penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute,
1020            ValuePtr, BufferLength, StringLengthPtr));
1021          if (hproc == SQL_NULL_HPROC)
1022            {
1023	      PUSHSQLERR (stmt->herr, en_IM001);
1024	      return SQL_ERROR;
1025            }
1026	  return retcode;
1027	}
1028      else
1029	{			/* an ODBC2 driver */
1030	  if (ValuePtr)
1031	    *((SQLUINTEGER *) ValuePtr) = stmt->paramset_size;
1032	  return SQL_SUCCESS;
1033	}
1034
1035    case SQL_ATTR_ROW_STATUS_PTR:
1036
1037      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1038	{
1039          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1040            penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute,
1041            ValuePtr, BufferLength, StringLengthPtr));
1042          if (hproc == SQL_NULL_HPROC)
1043            {
1044	      PUSHSQLERR (stmt->herr, en_IM001);
1045	      return SQL_ERROR;
1046            }
1047	  return retcode;
1048	}
1049      else
1050	{			/* an ODBC2 driver */
1051	  if (ValuePtr)
1052	    *((SQLUINTEGER **) ValuePtr) = stmt->row_status_allocated == SQL_FALSE ?
1053		(SQLUINTEGER *) stmt->row_status_ptr :
1054		NULL;
1055	  return SQL_SUCCESS;
1056	}
1057
1058    case SQL_ATTR_ASYNC_ENABLE:
1059    case SQL_ATTR_MAX_ROWS:
1060    case SQL_ATTR_QUERY_TIMEOUT:
1061    case SQL_ATTR_CONCURRENCY:
1062    case SQL_ROWSET_SIZE:
1063    case SQL_ATTR_CURSOR_TYPE:
1064    case SQL_ATTR_KEYSET_SIZE:
1065    case SQL_ATTR_NOSCAN:
1066    case SQL_ATTR_RETRIEVE_DATA:
1067    case SQL_ATTR_ROW_BIND_TYPE:
1068    case SQL_ATTR_ROW_NUMBER:
1069    case SQL_ATTR_SIMULATE_CURSOR:
1070    case SQL_ATTR_USE_BOOKMARKS:
1071    case SQL_ATTR_MAX_LENGTH:
1072
1073      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1074	{
1075          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1076            penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute,
1077            ValuePtr, BufferLength, StringLengthPtr));
1078          if (hproc == SQL_NULL_HPROC)
1079            {
1080	      PUSHSQLERR (stmt->herr, en_IM001);
1081	      return SQL_ERROR;
1082            }
1083	  return retcode;
1084	}
1085      else
1086	{			/* an ODBC2 driver */
1087	  if ((hproc = _iodbcdm_getproc (stmt->hdbc, en_GetStmtOption))
1088	     != SQL_NULL_HPROC)
1089	    {
1090	      CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
1091		  (stmt->dhstmt, Attribute, ValuePtr));
1092	      return retcode;
1093	    }
1094	  else
1095	  if ((hproc = _iodbcdm_getproc (stmt->hdbc, en_GetStmtOptionA))
1096	     != SQL_NULL_HPROC)
1097	    {
1098	      CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
1099		  (stmt->dhstmt, Attribute, ValuePtr));
1100	      return retcode;
1101	    }
1102	  else
1103	    {
1104	      PUSHSQLERR (stmt->herr, en_IM001);
1105	      return SQL_ERROR;
1106	    }
1107	}
1108
1109    default:
1110      CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1111        penv->unicode_driver, en_GetStmtAttr, (stmt->dhstmt, Attribute, ValuePtr,
1112        BufferLength, StringLengthPtr));
1113      if (hproc == SQL_NULL_HPROC)
1114        {
1115          PUSHSQLERR (stmt->herr, en_IM001);
1116	  return SQL_ERROR;
1117        }
1118      return retcode;
1119    }
1120  return SQL_SUCCESS;
1121}
1122
1123
1124RETCODE SQL_API
1125SQLGetStmtAttr (
1126  SQLHSTMT		  statementHandle,
1127  SQLINTEGER		  Attribute,
1128  SQLPOINTER		  ValuePtr,
1129  SQLINTEGER		  BufferLength,
1130  SQLINTEGER		* StringLengthPtr)
1131{
1132  ENTER_STMT (statementHandle,
1133    trace_SQLGetStmtAttr (TRACE_ENTER,
1134    	statementHandle,
1135	Attribute,
1136	ValuePtr, BufferLength, StringLengthPtr));
1137
1138  retcode = SQLGetStmtAttr_Internal(statementHandle, Attribute, ValuePtr,
1139    BufferLength, StringLengthPtr, 'A');
1140
1141  LEAVE_STMT (statementHandle,
1142    trace_SQLGetStmtAttr (TRACE_LEAVE,
1143    	statementHandle,
1144	Attribute,
1145	ValuePtr, BufferLength, StringLengthPtr));
1146}
1147
1148
1149RETCODE SQL_API
1150SQLGetStmtAttrA (
1151  SQLHSTMT		  statementHandle,
1152  SQLINTEGER		  Attribute,
1153  SQLPOINTER		  ValuePtr,
1154  SQLINTEGER		  BufferLength,
1155  SQLINTEGER		* StringLengthPtr)
1156{
1157  ENTER_STMT (statementHandle,
1158    trace_SQLGetStmtAttr (TRACE_ENTER,
1159    	statementHandle,
1160	Attribute,
1161	ValuePtr, BufferLength, StringLengthPtr));
1162
1163  retcode = SQLGetStmtAttr_Internal(statementHandle, Attribute, ValuePtr,
1164    BufferLength, StringLengthPtr, 'A');
1165
1166  LEAVE_STMT (statementHandle,
1167    trace_SQLGetStmtAttr (TRACE_LEAVE,
1168    	statementHandle,
1169	Attribute,
1170	ValuePtr, BufferLength, StringLengthPtr));
1171}
1172
1173
1174RETCODE SQL_API
1175SQLGetStmtAttrW (
1176  SQLHSTMT		  statementHandle,
1177  SQLINTEGER 		  Attribute,
1178  SQLPOINTER 		  ValuePtr,
1179  SQLINTEGER 		  BufferLength,
1180  SQLINTEGER		* StringLengthPtr)
1181{
1182  ENTER_STMT (statementHandle,
1183    trace_SQLGetStmtAttrW (TRACE_ENTER,
1184    	statementHandle,
1185	Attribute,
1186	ValuePtr, BufferLength, StringLengthPtr));
1187
1188  retcode = SQLGetStmtAttr_Internal (
1189  	statementHandle,
1190	Attribute,
1191	ValuePtr, BufferLength, StringLengthPtr,
1192	'W');
1193
1194  LEAVE_STMT (statementHandle,
1195    trace_SQLGetStmtAttrW (TRACE_LEAVE,
1196    	statementHandle,
1197	Attribute,
1198	ValuePtr, BufferLength, StringLengthPtr));
1199}
1200
1201
1202/**** SQLSetStmtAttr ****/
1203
1204RETCODE SQL_API
1205SQLSetStmtAttr_Internal (
1206  SQLHSTMT		  statementHandle,
1207  SQLINTEGER		  Attribute,
1208  SQLPOINTER		  ValuePtr,
1209  SQLINTEGER		  StringLength,
1210  SQLCHAR		  waMode)
1211{
1212  STMT (stmt, statementHandle);
1213  CONN (pdbc, stmt->hdbc);
1214  ENVR (penv, pdbc->henv);
1215  HPROC hproc = SQL_NULL_HPROC;
1216  SQLRETURN retcode = SQL_SUCCESS;
1217
1218  waMode = waMode; /*UNUSED*/
1219
1220  if (stmt->state == en_stmt_needdata)
1221    {
1222      PUSHSQLERR (stmt->herr, en_HY010);
1223      return SQL_ERROR;
1224    }
1225
1226  switch (Attribute)
1227    {
1228
1229    case SQL_ATTR_APP_PARAM_DESC:
1230
1231      if (ValuePtr == SQL_NULL_HDESC || ValuePtr == stmt->imp_desc[APP_PARAM_DESC])
1232	{
1233	  HDESC hdesc = ValuePtr == SQL_NULL_HDESC ? ValuePtr : stmt->imp_desc[APP_PARAM_DESC]->dhdesc;
1234
1235          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1236            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1237            hdesc, StringLength));
1238          if (hproc == SQL_NULL_HPROC)
1239            {
1240	      PUSHSQLERR (stmt->herr, en_IM001);
1241	      return SQL_ERROR;
1242            }
1243	  if (!SQL_SUCCEEDED (retcode))
1244	    return SQL_ERROR;
1245
1246	  stmt->desc[APP_PARAM_DESC] = SQL_NULL_HDESC;
1247	  return SQL_SUCCESS;
1248	}
1249
1250      if (!IS_VALID_HDESC (ValuePtr))
1251	{
1252	  PUSHSQLERR (stmt->herr, en_HY024);
1253	  return SQL_ERROR;
1254	}
1255      else
1256	{
1257	  DESC (pdesc, ValuePtr);
1258	  if (pdesc->hdbc != stmt->hdbc || IS_VALID_HSTMT (pdesc->hstmt))
1259	    {
1260	      PUSHSQLERR (stmt->herr, en_HY017);
1261	      return SQL_ERROR;
1262	    }
1263
1264          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1265            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1266            pdesc->dhdesc, StringLength));
1267          if (hproc == SQL_NULL_HPROC)
1268            {
1269	      PUSHSQLERR (stmt->herr, en_IM001);
1270	      return SQL_ERROR;
1271            }
1272	  if (!SQL_SUCCEEDED (retcode))
1273	    return SQL_ERROR;
1274
1275	  stmt->desc[APP_PARAM_DESC] = (DESC_t *) ValuePtr;
1276	  return SQL_SUCCESS;
1277	}
1278
1279    case SQL_ATTR_APP_ROW_DESC:
1280
1281      if (ValuePtr == SQL_NULL_HDESC || ValuePtr == stmt->imp_desc[APP_ROW_DESC])
1282	{
1283	  HDESC hdesc = ValuePtr == SQL_NULL_HDESC ? ValuePtr : stmt->imp_desc[APP_ROW_DESC]->dhdesc;
1284
1285          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1286            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1287            hdesc, StringLength));
1288          if (hproc == SQL_NULL_HPROC)
1289            {
1290	      PUSHSQLERR (stmt->herr, en_IM001);
1291	      return SQL_ERROR;
1292            }
1293	  if (!SQL_SUCCEEDED (retcode))
1294	    return SQL_ERROR;
1295
1296	  stmt->desc[APP_ROW_DESC] = SQL_NULL_HDESC;
1297	  return SQL_SUCCESS;
1298	}
1299
1300      if (!IS_VALID_HDESC (ValuePtr))
1301	{
1302	  PUSHSQLERR (stmt->herr, en_HY024);
1303	  return SQL_ERROR;
1304	}
1305      else
1306	{
1307	  DESC (pdesc, ValuePtr);
1308	  if (pdesc->hdbc != stmt->hdbc || IS_VALID_HSTMT (pdesc->hstmt))
1309	    {
1310	      PUSHSQLERR (stmt->herr, en_HY017);
1311	      return SQL_ERROR;
1312	    }
1313
1314          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1315            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1316            pdesc->dhdesc, StringLength));
1317          if (hproc == SQL_NULL_HPROC)
1318            {
1319	      PUSHSQLERR (stmt->herr, en_IM001);
1320	      return SQL_ERROR;
1321            }
1322	  if (!SQL_SUCCEEDED (retcode))
1323	    return SQL_ERROR;
1324
1325	  stmt->desc[APP_ROW_DESC] = (DESC_t *) ValuePtr;
1326	  return SQL_SUCCESS;
1327	}
1328
1329    case SQL_ATTR_CURSOR_SCROLLABLE:
1330    case SQL_ATTR_CURSOR_SENSITIVITY:
1331    case SQL_ATTR_ENABLE_AUTO_IPD:
1332    case SQL_ATTR_METADATA_ID:
1333    case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
1334    case SQL_ATTR_PARAM_BIND_TYPE:
1335    case SQL_ATTR_PARAM_OPERATION_PTR:
1336    case SQL_ATTR_PARAM_STATUS_PTR:
1337    case SQL_ATTR_ROW_BIND_OFFSET_PTR:
1338    case SQL_ATTR_ROW_OPERATION_PTR:
1339
1340
1341      CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1342        penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1343        ValuePtr, StringLength));
1344      if (hproc == SQL_NULL_HPROC)
1345        {
1346          PUSHSQLERR (stmt->herr, en_IM001);
1347          return SQL_ERROR;
1348        }
1349      return retcode;
1350
1351    case SQL_ATTR_ROWS_FETCHED_PTR:
1352
1353      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1354	{
1355
1356          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1357            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1358            ValuePtr, StringLength));
1359          if (hproc == SQL_NULL_HPROC)
1360            {
1361	      PUSHSQLERR (stmt->herr, en_IM001);
1362	      return SQL_ERROR;
1363            }
1364
1365          return retcode;
1366	}
1367      else
1368	{			/* an ODBC2 driver */
1369	  stmt->rows_fetched_ptr = ValuePtr;
1370	  return SQL_SUCCESS;
1371	}
1372
1373    case SQL_ATTR_FETCH_BOOKMARK_PTR:
1374
1375      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1376	{
1377          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1378            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1379            ValuePtr, StringLength));
1380          if (hproc == SQL_NULL_HPROC)
1381            {
1382	      PUSHSQLERR (stmt->herr, en_IM001);
1383	      return SQL_ERROR;
1384            }
1385
1386          return retcode;
1387	}
1388      else
1389	{			/* an ODBC2 driver */
1390	  stmt->fetch_bookmark_ptr = ValuePtr;
1391	  return SQL_SUCCESS;
1392	}
1393
1394    case SQL_ATTR_PARAMS_PROCESSED_PTR:
1395
1396      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1397	{
1398          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1399            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1400            ValuePtr, StringLength));
1401          if (hproc == SQL_NULL_HPROC)
1402            {
1403	      PUSHSQLERR (stmt->herr, en_IM001);
1404	      return SQL_ERROR;
1405            }
1406
1407          return retcode;
1408	}
1409      else
1410	{			/* an ODBC2 driver */
1411	  stmt->params_processed_ptr = ValuePtr;
1412	  return SQL_SUCCESS;
1413	}
1414
1415    case SQL_ATTR_PARAMSET_SIZE:
1416
1417      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1418	{
1419          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1420            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1421            ValuePtr, StringLength));
1422          if (hproc == SQL_NULL_HPROC)
1423            {
1424	      PUSHSQLERR (stmt->herr, en_IM001);
1425	      return SQL_ERROR;
1426            }
1427
1428          return retcode;
1429	}
1430      else
1431	{			/* an ODBC2 driver */
1432	  stmt->paramset_size = (SQLUINTEGER) (SQLULEN) ValuePtr;
1433	  return SQL_SUCCESS;
1434	}
1435
1436    case SQL_ATTR_ROW_ARRAY_SIZE:
1437
1438      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1439	{
1440          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1441            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1442            ValuePtr, StringLength));
1443          if (hproc == SQL_NULL_HPROC)
1444            {
1445	      PUSHSQLERR (stmt->herr, en_IM001);
1446	      return SQL_ERROR;
1447            }
1448
1449          if (SQL_SUCCEEDED (retcode))
1450            {
1451              stmt->rowset_size = Attribute;
1452              if (retcode == SQL_SUCCESS_WITH_INFO)
1453                {
1454                  SQLUINTEGER data;
1455                  if (SQLGetStmtAttr_Internal (statementHandle, SQL_ROWSET_SIZE, &data,
1456                        0, NULL, 'A') == SQL_SUCCESS)
1457                    stmt->rowset_size = data;
1458                }
1459            }
1460          return retcode;
1461	}
1462      else
1463	{			/* an ODBC2 driver */
1464	  if ((SQLUINTEGER) (SQLULEN) ValuePtr < 1)
1465	    {
1466	      PUSHSQLERR (stmt->herr, en_HY024);
1467	      return SQL_ERROR;
1468	    }
1469	  stmt->row_array_size = (SQLUINTEGER) (SQLULEN) ValuePtr;
1470
1471	  /* reallocate the row_status_ptr */
1472	  if (stmt->row_status_ptr && stmt->row_status_allocated == SQL_TRUE)
1473	    {
1474	      MEM_FREE (stmt->row_status_ptr);
1475	      stmt->row_status_allocated = SQL_FALSE;
1476	    }
1477	  stmt->row_status_ptr = MEM_ALLOC (sizeof (SQLUINTEGER) * stmt->row_array_size);
1478	  if (!stmt->row_status_ptr)
1479	    {
1480	      PUSHSQLERR (stmt->herr, en_HY001);
1481	      return SQL_ERROR;
1482	    }
1483	  stmt->row_status_allocated = SQL_TRUE;
1484
1485	  /*
1486	   *  Tell the driver the rowset size has changed
1487	   */
1488	  if ((hproc = _iodbcdm_getproc (stmt->hdbc, en_SetStmtOption))
1489	      != SQL_NULL_HPROC)
1490	    {
1491	      CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
1492		  (stmt->dhstmt, SQL_ROWSET_SIZE, stmt->row_array_size));
1493
1494              if (SQL_SUCCEEDED (retcode))
1495                {
1496                  stmt->rowset_size = Attribute;;
1497                  if (retcode == SQL_SUCCESS_WITH_INFO)
1498                    {
1499                      SQLUINTEGER data;
1500                      if (SQLGetStmtOption_Internal (statementHandle, SQL_ROWSET_SIZE,
1501                            &data) == SQL_SUCCESS)
1502                        stmt->rowset_size = data;
1503                    }
1504                }
1505	      return retcode;
1506	    }
1507	  else
1508	  if ((hproc = _iodbcdm_getproc (stmt->hdbc, en_SetStmtOptionA))
1509	      != SQL_NULL_HPROC)
1510	    {
1511	      CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
1512		  (stmt->dhstmt, SQL_ROWSET_SIZE, stmt->row_array_size));
1513
1514              if (SQL_SUCCEEDED (retcode))
1515                {
1516                  stmt->rowset_size = Attribute;;
1517                  if (retcode == SQL_SUCCESS_WITH_INFO)
1518                    {
1519                      SQLUINTEGER data;
1520                      if (SQLGetStmtOption_Internal (statementHandle, SQL_ROWSET_SIZE,
1521                           &data) == SQL_SUCCESS)
1522                        stmt->rowset_size = data;
1523                    }
1524                }
1525	      return retcode;
1526	    }
1527	  else
1528	    {
1529	      PUSHSQLERR (stmt->herr, en_IM001);
1530	      return SQL_ERROR;
1531	    }
1532
1533	  return SQL_SUCCESS;
1534	}
1535
1536    case SQL_ATTR_ROW_STATUS_PTR:
1537
1538      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1539	{
1540          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1541            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1542            ValuePtr, StringLength));
1543          if (hproc == SQL_NULL_HPROC)
1544            {
1545	      PUSHSQLERR (stmt->herr, en_IM001);
1546	      return SQL_ERROR;
1547            }
1548
1549          return retcode;
1550	}
1551      else
1552	{			/* an ODBC2 driver */
1553	  /* free the implicit row status ptr (if any) */
1554	  if (stmt->row_status_ptr && stmt->row_status_allocated == SQL_TRUE)
1555	    {
1556	      MEM_FREE (stmt->row_status_ptr);
1557	      stmt->row_status_allocated = SQL_FALSE;
1558	    }
1559	  stmt->row_status_ptr = ValuePtr;
1560	  return SQL_SUCCESS;
1561	}
1562
1563    case SQL_ATTR_ASYNC_ENABLE:
1564    case SQL_ATTR_CONCURRENCY:
1565    case SQL_ATTR_CURSOR_TYPE:
1566    case SQL_ATTR_KEYSET_SIZE:
1567    case SQL_ATTR_MAX_ROWS:
1568    case SQL_ATTR_NOSCAN:
1569    case SQL_ATTR_QUERY_TIMEOUT:
1570    case SQL_ATTR_RETRIEVE_DATA:
1571    case SQL_ATTR_ROW_BIND_TYPE:
1572    case SQL_ATTR_ROW_NUMBER:
1573    case SQL_ATTR_SIMULATE_CURSOR:
1574    case SQL_ATTR_USE_BOOKMARKS:
1575    case SQL_ROWSET_SIZE:
1576    case SQL_ATTR_MAX_LENGTH:
1577
1578      if (((ENV_t *) ((DBC_t *) stmt->hdbc)->henv)->dodbc_ver == SQL_OV_ODBC3)
1579	{
1580          CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc,
1581            penv->unicode_driver, en_SetStmtAttr, (stmt->dhstmt, Attribute,
1582            ValuePtr, StringLength));
1583          if (hproc == SQL_NULL_HPROC)
1584            {
1585	      PUSHSQLERR (stmt->herr, en_IM001);
1586	      return SQL_ERROR;
1587            }
1588
1589          if (Attribute == SQL_ATTR_ROW_BIND_TYPE && SQL_SUCCEEDED (retcode))
1590            stmt->bind_type = Attribute;
1591
1592          return retcode;
1593	}
1594      else
1595	{			/* an ODBC2 driver */
1596	  if ((hproc = _iodbcdm_getproc (stmt->hdbc, en_SetStmtOption))
1597	      != SQL_NULL_HPROC)
1598	    {
1599	      CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
1600		  (stmt->dhstmt, Attribute, ValuePtr));
1601              if (Attribute == SQL_ATTR_ROW_BIND_TYPE && SQL_SUCCEEDED (retcode))
1602                stmt->bind_type = Attribute;
1603	      return retcode;
1604	    }
1605	  else
1606	  if ((hproc = _iodbcdm_getproc (stmt->hdbc, en_SetStmtOptionA))
1607	      != SQL_NULL_HPROC)
1608	    {
1609	      CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
1610		  (stmt->dhstmt, Attribute, ValuePtr));
1611              if (Attribute == SQL_ATTR_ROW_BIND_TYPE && SQL_SUCCEEDED (retcode))
1612                stmt->bind_type = Attribute;
1613	      return retcode;
1614	    }
1615	  else
1616	    {
1617	      PUSHSQLERR (stmt->herr, en_IM001);
1618	      return SQL_ERROR;
1619	    }
1620	}
1621    default:
1622      if ((hproc = _iodbcdm_getproc (stmt->hdbc, en_SetStmtOption))
1623         != SQL_NULL_HPROC)
1624	{
1625	  CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
1626	      (stmt->dhstmt, Attribute, ValuePtr));
1627	  return retcode;
1628	}
1629      else
1630      if ((hproc = _iodbcdm_getproc (stmt->hdbc, en_SetStmtOptionA))
1631         != SQL_NULL_HPROC)
1632	{
1633	  CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
1634	      (stmt->dhstmt, Attribute, ValuePtr));
1635
1636	  return retcode;
1637	}
1638      else
1639	{
1640	  PUSHSQLERR (stmt->herr, en_IM001);
1641
1642	  return SQL_ERROR;
1643	}
1644    }
1645
1646  return SQL_SUCCESS;
1647}
1648
1649
1650RETCODE SQL_API
1651SQLSetStmtAttr (
1652  SQLHSTMT 		  statementHandle,
1653  SQLINTEGER		  Attribute,
1654  SQLPOINTER		  ValuePtr,
1655  SQLINTEGER		  StringLength)
1656{
1657  ENTER_STMT (statementHandle,
1658    trace_SQLSetStmtAttr (TRACE_ENTER,
1659    	statementHandle,
1660	Attribute,
1661	ValuePtr,
1662	StringLength));
1663
1664  retcode =  SQLSetStmtAttr_Internal(
1665  	statementHandle,
1666	Attribute,
1667	ValuePtr,
1668	StringLength,
1669	'A');
1670
1671  LEAVE_STMT (statementHandle,
1672    trace_SQLSetStmtAttr (TRACE_LEAVE,
1673    	statementHandle,
1674	Attribute,
1675	ValuePtr,
1676	StringLength));
1677}
1678
1679
1680RETCODE SQL_API
1681SQLSetStmtAttrA (
1682  SQLHSTMT		  statementHandle,
1683  SQLINTEGER		  Attribute,
1684  SQLPOINTER		  ValuePtr,
1685  SQLINTEGER		  StringLength)
1686{
1687  ENTER_STMT (statementHandle,
1688    trace_SQLSetStmtAttr (TRACE_ENTER,
1689    	statementHandle,
1690	Attribute,
1691	ValuePtr,
1692	StringLength));
1693
1694  retcode =  SQLSetStmtAttr_Internal(
1695  	statementHandle,
1696	Attribute,
1697	ValuePtr,
1698	StringLength,
1699	'A');
1700
1701  LEAVE_STMT (statementHandle,
1702    trace_SQLSetStmtAttr (TRACE_LEAVE,
1703    	statementHandle,
1704	Attribute,
1705	ValuePtr,
1706	StringLength));
1707}
1708
1709
1710RETCODE SQL_API
1711SQLSetStmtAttrW (
1712  SQLHSTMT		  statementHandle,
1713  SQLINTEGER		  Attribute,
1714  SQLPOINTER		  ValuePtr,
1715  SQLINTEGER		  StringLength)
1716{
1717  ENTER_STMT (statementHandle,
1718    trace_SQLSetStmtAttrW (TRACE_ENTER,
1719    	statementHandle,
1720	Attribute,
1721	ValuePtr,
1722	StringLength));
1723
1724  retcode =  SQLSetStmtAttr_Internal(
1725  	statementHandle,
1726	Attribute,
1727	ValuePtr,
1728	StringLength,
1729	'W');
1730
1731  LEAVE_STMT (statementHandle,
1732    trace_SQLSetStmtAttrW (TRACE_LEAVE,
1733    	statementHandle,
1734	Attribute,
1735	ValuePtr,
1736	StringLength));
1737}
1738
1739
1740static RETCODE
1741SQLSetConnectAttr_Internal (
1742  SQLHDBC		  connectionHandle,
1743  SQLINTEGER		  Attribute,
1744  SQLPOINTER		  ValuePtr,
1745  SQLINTEGER		  StringLength,
1746  SQLCHAR		  waMode)
1747{
1748  CONN (con, connectionHandle);
1749  ENVR (penv, con->henv);
1750  HPROC hproc = SQL_NULL_HPROC;
1751  HPROC hproc2 = SQL_NULL_HPROC;
1752  SQLRETURN retcode = SQL_SUCCESS;
1753  void * _ValuePtr = NULL;
1754  SWORD unicode_driver = (penv ? penv->unicode_driver : 0);
1755  SQLUINTEGER odbc_ver;
1756  SQLUINTEGER dodbc_ver;
1757
1758  odbc_ver = ((GENV_t *) con->genv)->odbc_ver;
1759  dodbc_ver = (penv != SQL_NULL_HENV) ? penv->dodbc_ver : odbc_ver;
1760
1761  if (con->state == en_dbc_needdata)
1762    {
1763      PUSHSQLERR (con->herr, en_HY010);
1764      return SQL_ERROR;
1765    }
1766
1767  if (penv &&
1768      ((unicode_driver && waMode != 'W')
1769       || (!unicode_driver && waMode == 'W')))
1770    {
1771      switch(Attribute)
1772        {
1773        case SQL_ATTR_CURRENT_CATALOG:
1774        case SQL_ATTR_TRACEFILE:
1775        case SQL_ATTR_TRANSLATE_LIB:
1776
1777          if (waMode != 'W')
1778            {
1779            /* ansi=>unicode*/
1780              _ValuePtr = dm_SQL_A2W((SQLCHAR *) ValuePtr, StringLength);
1781            }
1782          else
1783            {
1784            /* unicode=>ansi*/
1785              StringLength = (StringLength != SQL_NTS) ? (SQLINTEGER) (StringLength / sizeof(wchar_t)) : SQL_NTS;
1786              _ValuePtr = dm_SQL_W2A((SQLWCHAR *) ValuePtr, StringLength);
1787            }
1788          ValuePtr = _ValuePtr;
1789          StringLength = SQL_NTS;
1790          break;
1791        }
1792    }
1793
1794  GET_UHPROC(con, hproc2, en_SetConnectOption, unicode_driver);
1795
1796  if (dodbc_ver == SQL_OV_ODBC3 &&
1797      (  odbc_ver == SQL_OV_ODBC3
1798       || (odbc_ver == SQL_OV_ODBC2 && hproc2 == SQL_NULL_HPROC)))
1799    {
1800      CALL_UDRIVER(con, con, retcode, hproc, unicode_driver,
1801        en_SetConnectAttr, (con->dhdbc, Attribute, ValuePtr, StringLength));
1802      if (hproc != SQL_NULL_HPROC)
1803        return retcode;
1804    }
1805
1806  switch (Attribute)
1807    {
1808
1809    case SQL_ATTR_AUTO_IPD:
1810      PUSHSQLERR (con->herr, en_HY092);
1811      return SQL_ERROR;
1812
1813    default:
1814      retcode = _iodbcdm_SetConnectOption (con, Attribute,
1815      	  (SQLULEN) ValuePtr, waMode);
1816      return retcode;
1817    }
1818}
1819
1820
1821RETCODE SQL_API
1822SQLSetConnectAttr (
1823  SQLHDBC		  connectionHandle,
1824  SQLINTEGER		  Attribute,
1825  SQLPOINTER		  ValuePtr,
1826  SQLINTEGER		  StringLength)
1827{
1828  ENTER_HDBC (connectionHandle, 0,
1829    trace_SQLSetConnectAttr (TRACE_ENTER,
1830    	connectionHandle,
1831	Attribute,
1832	ValuePtr, StringLength));
1833
1834  retcode = SQLSetConnectAttr_Internal (
1835  	connectionHandle,
1836	Attribute,
1837	ValuePtr, StringLength,
1838	'A');
1839
1840  LEAVE_HDBC (connectionHandle, 0,
1841    trace_SQLSetConnectAttr (TRACE_LEAVE,
1842    	connectionHandle,
1843	Attribute,
1844	ValuePtr, StringLength));
1845}
1846
1847
1848RETCODE SQL_API
1849SQLSetConnectAttrA (
1850  SQLHDBC		  connectionHandle,
1851  SQLINTEGER		  Attribute,
1852  SQLPOINTER		  ValuePtr,
1853  SQLINTEGER		  StringLength)
1854{
1855  ENTER_HDBC (connectionHandle, 0,
1856    trace_SQLSetConnectAttr (TRACE_ENTER,
1857    	connectionHandle,
1858	Attribute,
1859	ValuePtr, StringLength));
1860
1861  retcode = SQLSetConnectAttr_Internal (
1862  	connectionHandle,
1863	Attribute,
1864	ValuePtr, StringLength,
1865	'A');
1866
1867  LEAVE_HDBC (connectionHandle, 0,
1868    trace_SQLSetConnectAttr (TRACE_LEAVE,
1869    	connectionHandle,
1870	Attribute,
1871	ValuePtr, StringLength));
1872}
1873
1874
1875RETCODE SQL_API
1876SQLSetConnectAttrW (
1877  SQLHDBC		  connectionHandle,
1878  SQLINTEGER		  Attribute,
1879  SQLPOINTER		  ValuePtr,
1880  SQLINTEGER		  StringLength)
1881{
1882  ENTER_HDBC (connectionHandle, 0,
1883    trace_SQLSetConnectAttrW (TRACE_ENTER,
1884    	connectionHandle,
1885	Attribute,
1886	ValuePtr, StringLength));
1887
1888  retcode = SQLSetConnectAttr_Internal (
1889  	connectionHandle,
1890	Attribute,
1891	ValuePtr, StringLength,
1892	'W');
1893
1894  LEAVE_HDBC (connectionHandle, 0,
1895    trace_SQLSetConnectAttrW (TRACE_LEAVE,
1896    	connectionHandle,
1897	Attribute,
1898	ValuePtr, StringLength));
1899}
1900
1901
1902static RETCODE
1903SQLGetConnectAttr_Internal (
1904  SQLHDBC		  connectionHandle,
1905  SQLINTEGER		  Attribute,
1906  SQLPOINTER		  ValuePtr,
1907  SQLINTEGER		  StringLength,
1908  SQLINTEGER		* StringLengthPtr,
1909  SQLCHAR 		  waMode)
1910{
1911  CONN (con, connectionHandle);
1912  ENVR (penv, con->henv);
1913  HPROC hproc = SQL_NULL_HPROC;
1914  HPROC hproc2 = SQL_NULL_HPROC;
1915  RETCODE retcode = SQL_SUCCESS;
1916  void * _Value = NULL;
1917  void * valueOut = ValuePtr;
1918  SWORD unicode_driver = (penv ? penv->unicode_driver : 0);
1919  SQLUINTEGER odbc_ver;
1920  SQLUINTEGER dodbc_ver;
1921
1922  odbc_ver = ((GENV_t *) con->genv)->odbc_ver;
1923  dodbc_ver = (penv != SQL_NULL_HENV) ? penv->dodbc_ver : odbc_ver;
1924
1925  if (con->state == en_dbc_needdata)
1926    {
1927      PUSHSQLERR (con->herr, en_HY010);
1928      return SQL_ERROR;
1929    }
1930
1931  if (penv &&
1932      ((unicode_driver && waMode != 'W')
1933       || (!unicode_driver && waMode == 'W')))
1934    {
1935      switch(Attribute)
1936        {
1937        case SQL_ATTR_CURRENT_CATALOG:
1938        case SQL_ATTR_TRACEFILE:
1939        case SQL_ATTR_TRANSLATE_LIB:
1940
1941          if (waMode != 'W')
1942            {
1943            /* ansi=>unicode*/
1944              StringLength *= sizeof(wchar_t);
1945              if ((_Value = malloc(StringLength + 1)) == NULL)
1946	        {
1947                  PUSHSQLERR (con->herr, en_HY001);
1948                  return SQL_ERROR;
1949                }
1950            }
1951          else
1952            {
1953            /* unicode=>ansi*/
1954              StringLength /= sizeof(wchar_t);
1955              if ((_Value = malloc(StringLength + 1)) == NULL)
1956	        {
1957                  PUSHSQLERR (con->herr, en_HY001);
1958                  return SQL_ERROR;
1959                }
1960            }
1961          valueOut = _Value;
1962          break;
1963        }
1964    }
1965
1966  GET_UHPROC(con, hproc2, en_GetConnectOption, unicode_driver);
1967
1968  if (dodbc_ver == SQL_OV_ODBC3 &&
1969      (  odbc_ver == SQL_OV_ODBC3
1970       || (odbc_ver == SQL_OV_ODBC2 && hproc2 == SQL_NULL_HPROC)))
1971    {
1972      CALL_UDRIVER(con, con, retcode, hproc, unicode_driver,
1973        en_GetConnectAttr, (con->dhdbc, Attribute, valueOut, StringLength,
1974        StringLengthPtr));
1975    }
1976
1977  if (hproc != SQL_NULL_HPROC)
1978    {
1979      if (ValuePtr
1980          && SQL_SUCCEEDED (retcode)
1981          && ((unicode_driver && waMode != 'W')
1982              || (!unicode_driver && waMode == 'W')))
1983        {
1984          switch(Attribute)
1985            {
1986            case SQL_ATTR_CURRENT_CATALOG:
1987            case SQL_ATTR_TRACEFILE:
1988            case SQL_ATTR_TRANSLATE_LIB:
1989              if (waMode != 'W')
1990                {
1991                /* ansi<=unicode*/
1992		  SQLSMALLINT retlen;
1993
1994                  dm_StrCopyOut2_W2A ((SQLWCHAR *) valueOut,
1995			(SQLCHAR *) ValuePtr,
1996			StringLength / sizeof(wchar_t), &retlen);
1997                  if (StringLengthPtr)
1998                    *StringLengthPtr = retlen;
1999                }
2000              else
2001                {
2002                /* unicode<=ansi*/
2003		  SQLSMALLINT retlen;
2004
2005                  dm_StrCopyOut2_A2W ((SQLCHAR *) valueOut,
2006			(SQLWCHAR *) ValuePtr,
2007			StringLength, &retlen);
2008                  if (StringLengthPtr)
2009                    *StringLengthPtr = retlen * sizeof(wchar_t);
2010                }
2011            }
2012        }
2013      MEM_FREE(_Value);
2014      return retcode;
2015    }
2016  MEM_FREE(_Value);
2017
2018  retcode = _iodbcdm_GetConnectOption (con, Attribute, ValuePtr, waMode);
2019  if (!SQL_SUCCEEDED (retcode))
2020    return retcode;
2021
2022  if (StringLengthPtr)
2023    {
2024      *StringLengthPtr = 0;
2025      if (ValuePtr)
2026	switch (Attribute)
2027	  {
2028	  case SQL_ATTR_CURRENT_CATALOG:
2029	  case SQL_ATTR_TRACEFILE:
2030	  case SQL_ATTR_TRANSLATE_LIB:
2031	    if (waMode != 'W')
2032	      *StringLengthPtr = STRLEN (ValuePtr);
2033	    else
2034	      *StringLengthPtr = WCSLEN (ValuePtr) * sizeof(wchar_t);
2035	  }
2036    }
2037  return retcode;
2038}
2039
2040
2041RETCODE SQL_API
2042SQLGetConnectAttr (
2043  SQLHDBC 		  connectionHandle,
2044  SQLINTEGER 		  Attribute,
2045  SQLPOINTER 		  ValuePtr,
2046  SQLINTEGER 		  StringLength,
2047  SQLINTEGER		* StringLengthPtr)
2048{
2049  ENTER_HDBC (connectionHandle, 0,
2050    trace_SQLGetConnectAttr (TRACE_ENTER,
2051  	connectionHandle,
2052	Attribute,
2053	ValuePtr, StringLength, StringLengthPtr));
2054
2055  retcode =  SQLGetConnectAttr_Internal(
2056  	connectionHandle,
2057	Attribute,
2058	ValuePtr, StringLength, StringLengthPtr,
2059	'A');
2060
2061  LEAVE_HDBC (connectionHandle, 0,
2062    trace_SQLGetConnectAttr (TRACE_LEAVE,
2063  	connectionHandle,
2064	Attribute,
2065	ValuePtr, StringLength, StringLengthPtr));
2066}
2067
2068
2069RETCODE SQL_API
2070SQLGetConnectAttrA (
2071  SQLHDBC 		  connectionHandle,
2072  SQLINTEGER 		  Attribute,
2073  SQLPOINTER 		  ValuePtr,
2074  SQLINTEGER 		  StringLength,
2075  SQLINTEGER		* StringLengthPtr)
2076{
2077  ENTER_HDBC (connectionHandle, 0,
2078    trace_SQLGetConnectAttr (TRACE_ENTER,
2079  	connectionHandle,
2080	Attribute,
2081	ValuePtr, StringLength, StringLengthPtr));
2082
2083  retcode =  SQLGetConnectAttr_Internal(
2084  	connectionHandle,
2085	Attribute,
2086	ValuePtr, StringLength, StringLengthPtr,
2087	'A');
2088
2089  LEAVE_HDBC (connectionHandle, 0,
2090    trace_SQLGetConnectAttr (TRACE_LEAVE,
2091  	connectionHandle,
2092	Attribute,
2093	ValuePtr, StringLength, StringLengthPtr));
2094}
2095
2096
2097RETCODE SQL_API
2098SQLGetConnectAttrW (SQLHDBC connectionHandle,
2099    SQLINTEGER Attribute,
2100    SQLPOINTER ValuePtr,
2101    SQLINTEGER StringLength,
2102    SQLINTEGER * StringLengthPtr)
2103{
2104  ENTER_HDBC (connectionHandle, 0,
2105    trace_SQLGetConnectAttrW (TRACE_ENTER,
2106  	connectionHandle,
2107	Attribute,
2108	ValuePtr, StringLength, StringLengthPtr));
2109
2110  retcode =  SQLGetConnectAttr_Internal(
2111  	connectionHandle,
2112	Attribute,
2113	ValuePtr, StringLength, StringLengthPtr,
2114	'W');
2115
2116  LEAVE_HDBC (connectionHandle, 0,
2117    trace_SQLGetConnectAttrW (TRACE_LEAVE,
2118  	connectionHandle,
2119	Attribute,
2120	ValuePtr, StringLength, StringLengthPtr));
2121}
2122
2123
2124RETCODE SQL_API
2125SQLGetDescField_Internal (
2126  SQLHDESC		  descriptorHandle,
2127  SQLSMALLINT		  RecNumber,
2128  SQLSMALLINT		  FieldIdentifier,
2129  SQLPOINTER		  ValuePtr,
2130  SQLINTEGER		  BufferLength,
2131  SQLINTEGER		* StringLengthPtr,
2132  SQLCHAR 		  waMode)
2133{
2134  DESC (desc, descriptorHandle);
2135  CONN (pdbc, desc->hdbc);
2136  ENVR (penv, pdbc->henv);
2137  HPROC hproc = SQL_NULL_HPROC;
2138  SQLRETURN retcode = SQL_SUCCESS;
2139  void * valueOut = ValuePtr;
2140  void * _ValuePtr = NULL;
2141
2142  if ((penv->unicode_driver && waMode != 'W')
2143      || (!penv->unicode_driver && waMode == 'W'))
2144    {
2145      switch(FieldIdentifier)
2146        {
2147        case SQL_DESC_BASE_COLUMN_NAME:
2148        case SQL_DESC_BASE_TABLE_NAME:
2149        case SQL_DESC_CATALOG_NAME:
2150        case SQL_DESC_LABEL:
2151        case SQL_DESC_LITERAL_PREFIX:
2152        case SQL_DESC_LITERAL_SUFFIX:
2153        case SQL_DESC_LOCAL_TYPE_NAME:
2154        case SQL_DESC_NAME:
2155        case SQL_DESC_SCHEMA_NAME:
2156        case SQL_DESC_TABLE_NAME:
2157        case SQL_DESC_TYPE_NAME:
2158          if (waMode != 'W')
2159            {
2160            /* ansi=>unicode*/
2161              BufferLength *= sizeof(wchar_t);
2162              if ((_ValuePtr = malloc(BufferLength + 1)) == NULL)
2163	        {
2164                  PUSHSQLERR (desc->herr, en_HY001);
2165                  return SQL_ERROR;
2166                }
2167            }
2168          else
2169            {
2170            /* unicode=>ansi*/
2171              BufferLength /= sizeof(wchar_t);
2172              if ((_ValuePtr = malloc(BufferLength + 1)) == NULL)
2173    	        {
2174                  PUSHSQLERR (desc->herr, en_HY001);
2175                  return SQL_ERROR;
2176                }
2177            }
2178          valueOut = _ValuePtr;
2179          break;
2180        }
2181    }
2182
2183  CALL_UDRIVER(desc->hdbc, desc, retcode, hproc, penv->unicode_driver,
2184    en_GetDescField, (desc->dhdesc, RecNumber, FieldIdentifier, valueOut,
2185    BufferLength, StringLengthPtr));
2186
2187  if (hproc == SQL_NULL_HPROC)
2188    {
2189      MEM_FREE(_ValuePtr);
2190      PUSHSQLERR (desc->herr, en_IM001);
2191      return SQL_ERROR;
2192    }
2193
2194  if (ValuePtr
2195      && SQL_SUCCEEDED (retcode)
2196      && ((penv->unicode_driver && waMode != 'W')
2197          || (!penv->unicode_driver && waMode == 'W')))
2198    {
2199      switch(FieldIdentifier)
2200        {
2201        case SQL_DESC_BASE_COLUMN_NAME:
2202        case SQL_DESC_BASE_TABLE_NAME:
2203        case SQL_DESC_CATALOG_NAME:
2204        case SQL_DESC_LABEL:
2205        case SQL_DESC_LITERAL_PREFIX:
2206        case SQL_DESC_LITERAL_SUFFIX:
2207        case SQL_DESC_LOCAL_TYPE_NAME:
2208        case SQL_DESC_NAME:
2209        case SQL_DESC_SCHEMA_NAME:
2210        case SQL_DESC_TABLE_NAME:
2211        case SQL_DESC_TYPE_NAME:
2212          if (waMode != 'W')
2213            {
2214            /* ansi<=unicode*/
2215	      SQLSMALLINT retlen;
2216
2217              dm_StrCopyOut2_W2A ((SQLWCHAR *) valueOut,
2218		(SQLCHAR *) ValuePtr,
2219		BufferLength / sizeof(wchar_t), &retlen);
2220	      if (StringLengthPtr)
2221                *StringLengthPtr = retlen;
2222            }
2223          else
2224            {
2225            /* unicode<=ansi*/
2226	      SQLSMALLINT retlen;
2227
2228              dm_StrCopyOut2_A2W ((SQLCHAR *) valueOut,
2229		(SQLWCHAR *) ValuePtr,
2230		BufferLength, &retlen);
2231              if (StringLengthPtr)
2232                *StringLengthPtr = retlen * sizeof(wchar_t);
2233            }
2234          break;
2235        }
2236    }
2237
2238  MEM_FREE(_ValuePtr);
2239
2240  return retcode;
2241}
2242
2243
2244RETCODE SQL_API
2245SQLGetDescField (
2246  SQLHDESC		  descriptorHandle,
2247  SQLSMALLINT		  RecNumber,
2248  SQLSMALLINT		  FieldIdentifier,
2249  SQLPOINTER		  ValuePtr,
2250  SQLINTEGER		  BufferLength,
2251  SQLINTEGER		* StringLengthPtr)
2252{
2253  ENTER_DESC (descriptorHandle,
2254    trace_SQLGetDescField (TRACE_ENTER,
2255    	descriptorHandle,
2256	RecNumber,
2257	FieldIdentifier,
2258	ValuePtr, BufferLength, StringLengthPtr));
2259
2260  retcode = SQLGetDescField_Internal(
2261  	descriptorHandle,
2262	RecNumber,
2263	FieldIdentifier,
2264	ValuePtr, BufferLength, StringLengthPtr,
2265	'A');
2266
2267  LEAVE_DESC (descriptorHandle,
2268    trace_SQLGetDescField (TRACE_LEAVE,
2269    	descriptorHandle,
2270	RecNumber,
2271	FieldIdentifier,
2272	ValuePtr, BufferLength, StringLengthPtr));
2273}
2274
2275
2276RETCODE SQL_API
2277SQLGetDescFieldA (
2278  SQLHDESC		  descriptorHandle,
2279  SQLSMALLINT		  RecNumber,
2280  SQLSMALLINT		  FieldIdentifier,
2281  SQLPOINTER		  ValuePtr,
2282  SQLINTEGER		  BufferLength,
2283  SQLINTEGER		* StringLengthPtr)
2284{
2285  ENTER_DESC (descriptorHandle,
2286    trace_SQLGetDescField (TRACE_ENTER,
2287    	descriptorHandle,
2288	RecNumber,
2289	FieldIdentifier,
2290	ValuePtr, BufferLength, StringLengthPtr));
2291
2292  retcode = SQLGetDescField_Internal (
2293  	descriptorHandle,
2294	RecNumber,
2295	FieldIdentifier,
2296	ValuePtr, BufferLength, StringLengthPtr,
2297	'A');
2298
2299  LEAVE_DESC (descriptorHandle,
2300    trace_SQLGetDescField (TRACE_LEAVE,
2301    	descriptorHandle,
2302	RecNumber,
2303	FieldIdentifier,
2304	ValuePtr, BufferLength, StringLengthPtr));
2305}
2306
2307
2308RETCODE SQL_API
2309SQLGetDescFieldW (
2310  SQLHDESC		  descriptorHandle,
2311  SQLSMALLINT		  RecNumber,
2312  SQLSMALLINT		  FieldIdentifier,
2313  SQLPOINTER		  ValuePtr,
2314  SQLINTEGER		  BufferLength,
2315  SQLINTEGER		* StringLengthPtr)
2316{
2317  ENTER_DESC (descriptorHandle,
2318    trace_SQLGetDescFieldW (TRACE_ENTER,
2319    	descriptorHandle,
2320	RecNumber,
2321	FieldIdentifier,
2322	ValuePtr, BufferLength, StringLengthPtr));
2323
2324  retcode = SQLGetDescField_Internal (
2325  	descriptorHandle,
2326	RecNumber,
2327	FieldIdentifier,
2328	ValuePtr, BufferLength, StringLengthPtr,
2329	'W');
2330
2331  LEAVE_DESC (descriptorHandle,
2332    trace_SQLGetDescFieldW (TRACE_LEAVE,
2333    	descriptorHandle,
2334	RecNumber,
2335	FieldIdentifier,
2336	ValuePtr, BufferLength, StringLengthPtr));
2337}
2338
2339
2340RETCODE SQL_API
2341SQLSetDescField_Internal (
2342  SQLHDESC		  descriptorHandle,
2343  SQLSMALLINT		  RecNumber,
2344  SQLSMALLINT		  FieldIdentifier,
2345  SQLPOINTER		  ValuePtr,
2346  SQLINTEGER		  BufferLength,
2347  SQLCHAR		  waMode)
2348{
2349  DESC (desc, descriptorHandle);
2350  CONN (pdbc, desc->hdbc);
2351  ENVR (penv, pdbc->henv);
2352  HPROC hproc = SQL_NULL_HPROC;
2353  SQLRETURN retcode = SQL_SUCCESS;
2354  void * _ValuePtr = NULL;
2355
2356  if ((penv->unicode_driver && waMode != 'W')
2357      || (!penv->unicode_driver && waMode == 'W'))
2358    {
2359      switch(FieldIdentifier)
2360        {
2361        case SQL_DESC_BASE_COLUMN_NAME:
2362        case SQL_DESC_BASE_TABLE_NAME:
2363        case SQL_DESC_CATALOG_NAME:
2364        case SQL_DESC_LABEL:
2365        case SQL_DESC_LITERAL_PREFIX:
2366        case SQL_DESC_LITERAL_SUFFIX:
2367        case SQL_DESC_LOCAL_TYPE_NAME:
2368        case SQL_DESC_NAME:
2369        case SQL_DESC_SCHEMA_NAME:
2370        case SQL_DESC_TABLE_NAME:
2371        case SQL_DESC_TYPE_NAME:
2372          if (waMode != 'W')
2373            {
2374            /* ansi=>unicode*/
2375              _ValuePtr = dm_SQL_A2W((SQLCHAR *) ValuePtr, BufferLength);
2376            }
2377          else
2378            {
2379            /* unicode=>ansi*/
2380              BufferLength = (BufferLength != SQL_NTS) ? (SQLINTEGER) (BufferLength / sizeof(wchar_t)) : SQL_NTS;
2381              _ValuePtr = dm_SQL_W2A((SQLWCHAR *) ValuePtr, BufferLength);
2382            }
2383          ValuePtr = _ValuePtr;
2384          BufferLength = SQL_NTS;
2385          break;
2386        }
2387    }
2388  CALL_UDRIVER(desc->hdbc, desc, retcode, hproc, penv->unicode_driver,
2389    en_SetDescField, (desc->dhdesc, RecNumber, FieldIdentifier, ValuePtr,
2390    BufferLength));
2391
2392  MEM_FREE(_ValuePtr);
2393
2394  if (hproc == SQL_NULL_HPROC)
2395    {
2396      PUSHSQLERR (desc->herr, en_IM001);
2397      return SQL_ERROR;
2398    }
2399
2400  return retcode;
2401}
2402
2403
2404RETCODE SQL_API
2405SQLSetDescField (
2406  SQLHDESC		  descriptorHandle,
2407  SQLSMALLINT		  RecNumber,
2408  SQLSMALLINT		  FieldIdentifier,
2409  SQLPOINTER		  ValuePtr,
2410  SQLINTEGER		  BufferLength)
2411{
2412  ENTER_DESC (descriptorHandle,
2413      trace_SQLSetDescField (TRACE_ENTER,
2414	  descriptorHandle,
2415	  RecNumber, FieldIdentifier, ValuePtr, BufferLength));
2416
2417  retcode = SQLSetDescField_Internal (descriptorHandle,
2418      RecNumber, FieldIdentifier, ValuePtr, BufferLength, 'A');
2419
2420  LEAVE_DESC (descriptorHandle,
2421      trace_SQLSetDescField (TRACE_LEAVE,
2422	  descriptorHandle,
2423	  RecNumber, FieldIdentifier, ValuePtr, BufferLength));
2424}
2425
2426
2427RETCODE SQL_API
2428SQLSetDescFieldA (
2429  SQLHDESC		  descriptorHandle,
2430  SQLSMALLINT		  RecNumber,
2431  SQLSMALLINT		  FieldIdentifier,
2432  SQLPOINTER		  ValuePtr,
2433  SQLINTEGER		  BufferLength)
2434{
2435  ENTER_DESC (descriptorHandle,
2436      trace_SQLSetDescField (TRACE_ENTER,
2437	  descriptorHandle,
2438	  RecNumber, FieldIdentifier, ValuePtr, BufferLength));
2439
2440  retcode = SQLSetDescField_Internal (descriptorHandle,
2441      RecNumber, FieldIdentifier, ValuePtr, BufferLength, 'A');
2442
2443  LEAVE_DESC (descriptorHandle,
2444      trace_SQLSetDescField (TRACE_LEAVE,
2445	  descriptorHandle,
2446	  RecNumber, FieldIdentifier, ValuePtr, BufferLength));
2447}
2448
2449
2450RETCODE SQL_API
2451SQLSetDescFieldW (
2452  SQLHDESC		  descriptorHandle,
2453  SQLSMALLINT		  RecNumber,
2454  SQLSMALLINT		  FieldIdentifier,
2455  SQLPOINTER		  ValuePtr,
2456  SQLINTEGER		  BufferLength)
2457{
2458  ENTER_DESC (descriptorHandle,
2459      trace_SQLSetDescFieldW (TRACE_ENTER,
2460	  descriptorHandle,
2461	  RecNumber, FieldIdentifier, ValuePtr, BufferLength));
2462
2463  retcode = SQLSetDescField_Internal (descriptorHandle,
2464      RecNumber, FieldIdentifier, ValuePtr, BufferLength, 'W');
2465
2466  LEAVE_DESC (descriptorHandle,
2467      trace_SQLSetDescFieldW (TRACE_LEAVE,
2468	  descriptorHandle,
2469	  RecNumber, FieldIdentifier, ValuePtr, BufferLength));
2470}
2471
2472
2473RETCODE SQL_API
2474SQLGetDescRec_Internal (
2475  SQLHDESC		  descriptorHandle,
2476  SQLSMALLINT 		  RecNumber,
2477  SQLPOINTER 		  Name,
2478  SQLSMALLINT 		  BufferLength,
2479  SQLSMALLINT		* StringLengthPtr,
2480  SQLSMALLINT		* TypePtr,
2481  SQLSMALLINT 		* SubTypePtr,
2482  SQLLEN		* LengthPtr,
2483  SQLSMALLINT		* PrecisionPtr,
2484  SQLSMALLINT		* ScalePtr,
2485  SQLSMALLINT		* NullablePtr,
2486  SQLCHAR 		  waMode)
2487{
2488  DESC (desc, descriptorHandle);
2489  CONN (pdbc, desc->hdbc);
2490  ENVR (penv, pdbc->henv);
2491  HPROC hproc = SQL_NULL_HPROC;
2492  SQLRETURN retcode = SQL_SUCCESS;
2493  void * nameOut = Name;
2494  void * _Name = NULL;
2495
2496  if ((penv->unicode_driver && waMode != 'W')
2497      || (!penv->unicode_driver && waMode == 'W'))
2498    {
2499      if (waMode != 'W')
2500        {
2501        /* ansi=>unicode*/
2502          if ((_Name = malloc(BufferLength * sizeof(wchar_t) + 1)) == NULL)
2503            {
2504              PUSHSQLERR (desc->herr, en_HY001);
2505              return SQL_ERROR;
2506            }
2507        }
2508      else
2509        {
2510        /* unicode=>ansi*/
2511          if ((_Name = malloc(BufferLength + 1)) == NULL)
2512            {
2513              PUSHSQLERR (desc->herr, en_HY001);
2514              return SQL_ERROR;
2515            }
2516        }
2517      nameOut = _Name;
2518    }
2519
2520  CALL_UDRIVER(desc->hdbc, desc, retcode, hproc, penv->unicode_driver,
2521    en_GetDescRec, (desc->dhdesc, RecNumber, nameOut, BufferLength,
2522    StringLengthPtr, TypePtr, SubTypePtr, LengthPtr, PrecisionPtr,
2523    ScalePtr, NullablePtr));
2524
2525  if (hproc == SQL_NULL_HPROC)
2526    {
2527      MEM_FREE(_Name);
2528      PUSHSQLERR (desc->herr, en_IM001);
2529      return SQL_ERROR;
2530    }
2531
2532  if (Name
2533      && SQL_SUCCEEDED (retcode)
2534      && ((penv->unicode_driver && waMode != 'W')
2535          || (!penv->unicode_driver && waMode == 'W')))
2536    {
2537      if (waMode != 'W')
2538        {
2539        /* ansi<=unicode*/
2540          dm_StrCopyOut2_W2A ((SQLWCHAR *) nameOut, (SQLCHAR *) Name, BufferLength, StringLengthPtr);
2541        }
2542      else
2543        {
2544        /* unicode<=ansi*/
2545          dm_StrCopyOut2_A2W ((SQLCHAR *) nameOut, (SQLWCHAR *) Name, BufferLength, StringLengthPtr);
2546        }
2547    }
2548
2549  MEM_FREE(_Name);
2550
2551  return retcode;
2552}
2553
2554
2555RETCODE SQL_API
2556SQLGetDescRec (
2557  SQLHDESC		  descriptorHandle,
2558  SQLSMALLINT		  RecNumber,
2559  SQLCHAR		* Name,
2560  SQLSMALLINT		  BufferLength,
2561  SQLSMALLINT		* StringLengthPtr,
2562  SQLSMALLINT		* TypePtr,
2563  SQLSMALLINT		* SubTypePtr,
2564  SQLLEN		* LengthPtr,
2565  SQLSMALLINT		* PrecisionPtr,
2566  SQLSMALLINT		* ScalePtr,
2567  SQLSMALLINT		* NullablePtr)
2568{
2569  ENTER_DESC (descriptorHandle,
2570    trace_SQLGetDescRec (TRACE_ENTER,
2571  	descriptorHandle,
2572	RecNumber,
2573	Name, BufferLength, StringLengthPtr,
2574	TypePtr,
2575	SubTypePtr,
2576	LengthPtr,
2577	PrecisionPtr,
2578	ScalePtr,
2579	NullablePtr));
2580
2581  retcode =  SQLGetDescRec_Internal(
2582  	descriptorHandle,
2583	RecNumber,
2584	Name, BufferLength, StringLengthPtr,
2585	TypePtr,
2586	SubTypePtr,
2587	LengthPtr,
2588	PrecisionPtr,
2589	ScalePtr,
2590	NullablePtr,
2591	'A');
2592
2593  LEAVE_DESC (descriptorHandle,
2594    trace_SQLGetDescRec (TRACE_LEAVE,
2595  	descriptorHandle,
2596	RecNumber,
2597	Name, BufferLength, StringLengthPtr,
2598	TypePtr,
2599	SubTypePtr,
2600	LengthPtr,
2601	PrecisionPtr,
2602	ScalePtr,
2603	NullablePtr));
2604}
2605
2606
2607RETCODE SQL_API
2608SQLGetDescRecA (
2609  SQLHDESC		  descriptorHandle,
2610  SQLSMALLINT		  RecNumber,
2611  SQLCHAR		* Name,
2612  SQLSMALLINT		  BufferLength,
2613  SQLSMALLINT		* StringLengthPtr,
2614  SQLSMALLINT		* TypePtr,
2615  SQLSMALLINT		* SubTypePtr,
2616  SQLLEN		* LengthPtr,
2617  SQLSMALLINT		* PrecisionPtr,
2618  SQLSMALLINT		* ScalePtr,
2619  SQLSMALLINT		* NullablePtr)
2620{
2621  ENTER_DESC (descriptorHandle,
2622    trace_SQLGetDescRec (TRACE_ENTER,
2623  	descriptorHandle,
2624	RecNumber,
2625	Name, BufferLength, StringLengthPtr,
2626	TypePtr,
2627	SubTypePtr,
2628	LengthPtr,
2629	PrecisionPtr,
2630	ScalePtr,
2631	NullablePtr));
2632
2633  retcode =  SQLGetDescRec_Internal(
2634  	descriptorHandle,
2635	RecNumber,
2636	Name, BufferLength, StringLengthPtr,
2637	TypePtr,
2638	SubTypePtr,
2639	LengthPtr,
2640	PrecisionPtr,
2641	ScalePtr,
2642	NullablePtr,
2643	'A');
2644
2645  LEAVE_DESC (descriptorHandle,
2646    trace_SQLGetDescRec (TRACE_LEAVE,
2647  	descriptorHandle,
2648	RecNumber,
2649	Name, BufferLength, StringLengthPtr,
2650	TypePtr,
2651	SubTypePtr,
2652	LengthPtr,
2653	PrecisionPtr,
2654	ScalePtr,
2655	NullablePtr));
2656}
2657
2658
2659RETCODE SQL_API
2660SQLGetDescRecW (
2661  SQLHDESC		  descriptorHandle,
2662  SQLSMALLINT		  RecNumber,
2663  SQLWCHAR		* Name,
2664  SQLSMALLINT		  BufferLength,
2665  SQLSMALLINT		* StringLengthPtr,
2666  SQLSMALLINT		* TypePtr,
2667  SQLSMALLINT		* SubTypePtr,
2668  SQLLEN		* LengthPtr,
2669  SQLSMALLINT		* PrecisionPtr,
2670  SQLSMALLINT		* ScalePtr,
2671  SQLSMALLINT		* NullablePtr)
2672{
2673  ENTER_DESC (descriptorHandle,
2674    trace_SQLGetDescRecW (TRACE_ENTER,
2675  	descriptorHandle,
2676	RecNumber,
2677	Name, BufferLength, StringLengthPtr,
2678	TypePtr,
2679	SubTypePtr,
2680	LengthPtr,
2681	PrecisionPtr,
2682	ScalePtr,
2683	NullablePtr));
2684
2685  retcode =  SQLGetDescRec_Internal(
2686  	descriptorHandle,
2687	RecNumber,
2688	Name, BufferLength, StringLengthPtr,
2689	TypePtr,
2690	SubTypePtr,
2691	LengthPtr,
2692	PrecisionPtr,
2693	ScalePtr,
2694	NullablePtr,
2695	'W');
2696
2697  LEAVE_DESC (descriptorHandle,
2698    trace_SQLGetDescRecW (TRACE_LEAVE,
2699  	descriptorHandle,
2700	RecNumber,
2701	Name, BufferLength, StringLengthPtr,
2702	TypePtr,
2703	SubTypePtr,
2704	LengthPtr,
2705	PrecisionPtr,
2706	ScalePtr,
2707	NullablePtr));
2708}
2709
2710
2711static RETCODE
2712SQLSetDescRec_Internal (
2713  SQLHDESC		  DescriptorHandle,
2714  SQLSMALLINT		  RecNumber,
2715  SQLSMALLINT		  Type,
2716  SQLSMALLINT		  SubType,
2717  SQLLEN		  Length,
2718  SQLSMALLINT		  Precision,
2719  SQLSMALLINT		  Scale,
2720  SQLPOINTER		  Data,
2721  SQLLEN		* StringLength,
2722  SQLLEN		* Indicator)
2723{
2724  DESC (desc, DescriptorHandle);
2725  HPROC hproc;
2726  RETCODE retcode;
2727
2728  hproc = _iodbcdm_getproc (desc->hdbc, en_SetDescRec);
2729  if (!hproc)
2730    {
2731      PUSHSQLERR (desc->herr, en_IM001);
2732      return SQL_ERROR;
2733    }
2734
2735  CALL_DRIVER (desc->hdbc, desc, retcode, hproc,
2736      (desc->dhdesc, RecNumber, Type, SubType, Length, Precision, Scale,
2737       Data, StringLength, Indicator));
2738
2739  return retcode;
2740}
2741
2742RETCODE SQL_API
2743SQLSetDescRec (
2744  SQLHDESC		  DescriptorHandle,
2745  SQLSMALLINT		  RecNumber,
2746  SQLSMALLINT		  Type,
2747  SQLSMALLINT		  SubType,
2748  SQLLEN		  Length,
2749  SQLSMALLINT		  Precision,
2750  SQLSMALLINT		  Scale,
2751  SQLPOINTER		  Data,
2752  SQLLEN		* StringLength,
2753  SQLLEN		* Indicator)
2754{
2755  ENTER_DESC (DescriptorHandle,
2756    trace_SQLSetDescRec (TRACE_ENTER,
2757  	DescriptorHandle, RecNumber, Type, SubType, Length, Precision,
2758  	Scale, Data, StringLength, Indicator));
2759
2760  retcode = SQLSetDescRec_Internal (
2761  	DescriptorHandle, RecNumber, Type, SubType, Length, Precision,
2762  	Scale, Data, StringLength, Indicator);
2763
2764  LEAVE_DESC (DescriptorHandle,
2765    trace_SQLSetDescRec (TRACE_LEAVE,
2766  	DescriptorHandle, RecNumber, Type, SubType, Length, Precision,
2767  	Scale, Data, StringLength, Indicator));
2768}
2769
2770
2771static RETCODE
2772SQLCopyDesc_Internal (
2773  SQLHDESC		  SourceDescHandle,
2774  SQLHDESC		  TargetDescHandle)
2775{
2776  DESC (desc, SourceDescHandle);
2777  DESC (desc1, TargetDescHandle);
2778  HPROC hproc;
2779  RETCODE retcode;
2780
2781  hproc = _iodbcdm_getproc (desc->hdbc, en_CopyDesc);
2782  if (!hproc)
2783    {
2784      PUSHSQLERR (desc->herr, en_IM001);
2785      return SQL_ERROR;
2786    }
2787
2788  CALL_DRIVER (desc->hdbc, desc, retcode, hproc,
2789      (desc->dhdesc, desc1->dhdesc));
2790
2791  return retcode;
2792}
2793
2794
2795RETCODE SQL_API
2796SQLCopyDesc (
2797  SQLHDESC		  SourceDescHandle,
2798  SQLHDESC		  TargetDescHandle)
2799{
2800  ENTER_DESC (SourceDescHandle,
2801    trace_SQLCopyDesc (TRACE_ENTER,
2802    	SourceDescHandle,
2803	TargetDescHandle));
2804
2805  retcode = SQLCopyDesc_Internal (
2806    	SourceDescHandle,
2807	TargetDescHandle);
2808
2809  LEAVE_DESC (SourceDescHandle,
2810    trace_SQLCopyDesc (TRACE_LEAVE,
2811    	SourceDescHandle,
2812	TargetDescHandle));
2813}
2814
2815
2816RETCODE SQL_API
2817SQLColAttribute_Internal (
2818  SQLHSTMT		  statementHandle,
2819  SQLUSMALLINT		  ColumnNumber,
2820  SQLUSMALLINT		  FieldIdentifier,
2821  SQLPOINTER		  CharacterAttributePtr,
2822  SQLSMALLINT		  BufferLength,
2823  SQLSMALLINT		* StringLengthPtr,
2824  SQLLEN		* NumericAttributePtr,
2825  SQLCHAR		  waMode)
2826{
2827  STMT (stmt, statementHandle);
2828  CONN (pdbc, stmt->hdbc);
2829  ENVR (penv, pdbc->henv);
2830  GENV (genv, pdbc->genv);
2831  HPROC hproc = SQL_NULL_HPROC;
2832  HPROC hproc2 = SQL_NULL_HPROC;
2833  SQLRETURN retcode = SQL_SUCCESS;
2834  void * charAttrOut = CharacterAttributePtr;
2835  void * _charAttr = NULL;
2836  SQLUINTEGER odbc_ver;
2837  SQLUINTEGER dodbc_ver;
2838
2839  odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
2840  dodbc_ver = (penv != SQL_NULL_HENV) ? penv->dodbc_ver : odbc_ver;
2841
2842  if ((penv->unicode_driver && waMode != 'W')
2843      || (!penv->unicode_driver && waMode == 'W'))
2844    {
2845      switch(FieldIdentifier)
2846        {
2847        case SQL_COLUMN_NAME:
2848
2849        case SQL_DESC_BASE_COLUMN_NAME:
2850        case SQL_DESC_BASE_TABLE_NAME:
2851        case SQL_DESC_CATALOG_NAME:
2852        case SQL_DESC_LABEL:
2853        case SQL_DESC_LITERAL_PREFIX:
2854        case SQL_DESC_LITERAL_SUFFIX:
2855        case SQL_DESC_LOCAL_TYPE_NAME:
2856        case SQL_DESC_NAME:
2857        case SQL_DESC_SCHEMA_NAME:
2858        case SQL_DESC_TABLE_NAME:
2859        case SQL_DESC_TYPE_NAME:
2860          if (waMode != 'W')
2861            {
2862            /* ansi=>unicode*/
2863              BufferLength *= sizeof(wchar_t);
2864              if ((_charAttr = malloc(BufferLength + 1)) == NULL)
2865                {
2866                  PUSHSQLERR (stmt->herr, en_HY001);
2867                  return SQL_ERROR;
2868                }
2869            }
2870          else
2871            {
2872            /* unicode=>ansi*/
2873              BufferLength /= sizeof(wchar_t);
2874              if ((_charAttr = malloc(BufferLength + 1)) == NULL)
2875                {
2876                  PUSHSQLERR (stmt->herr, en_HY001);
2877                  return SQL_ERROR;
2878                }
2879            }
2880          charAttrOut = _charAttr;
2881          break;
2882        }
2883    }
2884
2885  GET_UHPROC(stmt->hdbc, hproc2, en_ColAttributes, penv->unicode_driver);
2886
2887  if (dodbc_ver == SQL_OV_ODBC3 &&
2888      (  odbc_ver == SQL_OV_ODBC3
2889       || (odbc_ver == SQL_OV_ODBC2 && hproc2 == SQL_NULL_HPROC)))
2890    {
2891      CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc, penv->unicode_driver,
2892        en_ColAttribute, (stmt->dhstmt, ColumnNumber, FieldIdentifier,
2893        charAttrOut, BufferLength, StringLengthPtr, NumericAttributePtr));
2894    }
2895
2896  if (hproc != SQL_NULL_HPROC)
2897    {
2898    if (SQL_SUCCEEDED (retcode) && FieldIdentifier == SQL_DESC_CONCISE_TYPE)
2899      {
2900        SQLINTEGER *ptr = (SQLINTEGER *)NumericAttributePtr;
2901
2902	/*
2903	 *  Convert sql type to ODBC version of application
2904	 */
2905	if (ptr)
2906	  *ptr = _iodbcdm_map_sql_type (*ptr, genv->odbc_ver);
2907      }
2908
2909      if (CharacterAttributePtr
2910          && SQL_SUCCEEDED (retcode)
2911          &&  ((penv->unicode_driver && waMode != 'W')
2912              || (!penv->unicode_driver && waMode == 'W')))
2913        {
2914          switch(FieldIdentifier)
2915            {
2916            case SQL_COLUMN_NAME:
2917            case SQL_DESC_BASE_COLUMN_NAME:
2918            case SQL_DESC_BASE_TABLE_NAME:
2919            case SQL_DESC_CATALOG_NAME:
2920            case SQL_DESC_LABEL:
2921            case SQL_DESC_LITERAL_PREFIX:
2922            case SQL_DESC_LITERAL_SUFFIX:
2923            case SQL_DESC_LOCAL_TYPE_NAME:
2924            case SQL_DESC_NAME:
2925            case SQL_DESC_SCHEMA_NAME:
2926            case SQL_DESC_TABLE_NAME:
2927            case SQL_DESC_TYPE_NAME:
2928              if (waMode != 'W')
2929                {
2930                /* ansi<=unicode*/
2931                  dm_StrCopyOut2_W2A ((SQLWCHAR *) charAttrOut,
2932			(SQLCHAR *) CharacterAttributePtr,
2933			BufferLength / sizeof(wchar_t), StringLengthPtr);
2934                }
2935              else
2936                {
2937                /* unicode<=ansi*/
2938                  dm_StrCopyOut2_A2W ((SQLCHAR *) charAttrOut,
2939			(SQLWCHAR *) CharacterAttributePtr,
2940			BufferLength, StringLengthPtr);
2941                  if (StringLengthPtr)
2942                    *StringLengthPtr = *StringLengthPtr * sizeof(wchar_t);
2943                }
2944            }
2945        }
2946      MEM_FREE(_charAttr);
2947      return retcode;
2948    }
2949
2950
2951  if (ColumnNumber == 0)
2952    {
2953      char *szval = "";
2954      int isSz = 0;
2955      SQLINTEGER val = 0;
2956
2957      MEM_FREE(_charAttr);
2958
2959      switch (FieldIdentifier)
2960	{
2961	case SQL_DESC_AUTO_UNIQUE_VALUE:
2962	case SQL_DESC_CASE_SENSITIVE:
2963	case SQL_DESC_FIXED_PREC_SCALE:
2964	case SQL_DESC_UNSIGNED:
2965	  val = SQL_FALSE;
2966	  break;
2967
2968	case SQL_DESC_LABEL:
2969	case SQL_DESC_CATALOG_NAME:
2970	case SQL_DESC_LITERAL_PREFIX:
2971	case SQL_DESC_LITERAL_SUFFIX:
2972	case SQL_DESC_LOCAL_TYPE_NAME:
2973	case SQL_DESC_NAME:
2974	case SQL_DESC_SCHEMA_NAME:
2975	case SQL_DESC_TABLE_NAME:
2976	case SQL_DESC_TYPE_NAME:
2977	  isSz = 1;
2978	  break;
2979
2980	case SQL_DESC_CONCISE_TYPE:
2981	case SQL_DESC_TYPE:
2982	  val = SQL_BINARY;
2983	  break;
2984
2985	case SQL_DESC_COUNT:
2986	  hproc = _iodbcdm_getproc (stmt->hdbc, en_NumResultCols);
2987	  if (!hproc)
2988	    {
2989	      PUSHSQLERR (stmt->herr, en_IM001);
2990	      return SQL_ERROR;
2991	    }
2992	  CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
2993	      (stmt->dhstmt, NumericAttributePtr));
2994	  return retcode;
2995
2996	case SQL_DESC_LENGTH:
2997	case SQL_DESC_DATETIME_INTERVAL_CODE:
2998	case SQL_DESC_SCALE:
2999	  val = 0;
3000	  break;
3001
3002	case SQL_DESC_DISPLAY_SIZE:
3003	  val = 8;
3004	  break;
3005
3006	case SQL_DESC_NULLABLE:
3007	  val = SQL_NO_NULLS;
3008	  break;
3009
3010	case SQL_DESC_OCTET_LENGTH:
3011	case SQL_DESC_PRECISION:
3012	  val = 4;
3013	  break;
3014
3015	case SQL_DESC_SEARCHABLE:
3016	  val = SQL_PRED_NONE;
3017	  break;
3018
3019	case SQL_DESC_UNNAMED:
3020	  val = SQL_UNNAMED;
3021	  break;
3022
3023	case SQL_DESC_UPDATABLE:
3024	  val = SQL_ATTR_READONLY;
3025	  break;
3026
3027	default:
3028	  PUSHSQLERR (stmt->herr, en_HYC00);
3029	  return SQL_ERROR;
3030	}
3031      if (isSz)
3032	{
3033	  int len = STRLEN (szval), len1;
3034	  len1 = len > BufferLength ? BufferLength - 1 : len;
3035	  if (CharacterAttributePtr)
3036	    {
3037	      STRNCPY (CharacterAttributePtr, szval, len1);
3038	      ((SQLCHAR *) CharacterAttributePtr)[len1] = 0;
3039	    }
3040	  if (StringLengthPtr)
3041	    *StringLengthPtr = len;
3042	}
3043      else
3044	{
3045	  if (NumericAttributePtr)
3046	    *((SQLINTEGER *) NumericAttributePtr) = val;
3047	}
3048      return SQL_SUCCESS;
3049    }
3050  else
3051    {				/* all other */
3052      switch (FieldIdentifier)
3053	{
3054	case SQL_DESC_SCALE:
3055	  FieldIdentifier = SQL_COLUMN_SCALE;
3056	  break;
3057
3058	case SQL_DESC_LENGTH:
3059	  FieldIdentifier = SQL_COLUMN_LENGTH;
3060	  break;
3061
3062	case SQL_DESC_PRECISION:
3063	  FieldIdentifier = SQL_COLUMN_PRECISION;
3064	  break;
3065
3066	case SQL_DESC_COUNT:
3067	  FieldIdentifier = SQL_COLUMN_COUNT;
3068	  break;
3069
3070	case SQL_DESC_NAME:
3071	  FieldIdentifier = SQL_COLUMN_NAME;
3072	  break;
3073
3074	case SQL_DESC_NULLABLE:
3075	  FieldIdentifier = SQL_COLUMN_NULLABLE;
3076	  break;
3077
3078	case SQL_DESC_TYPE:
3079	  FieldIdentifier = SQL_COLUMN_TYPE;
3080	  break;
3081
3082	case SQL_DESC_BASE_COLUMN_NAME:
3083	case SQL_DESC_BASE_TABLE_NAME:
3084	case SQL_DESC_LITERAL_PREFIX:
3085	case SQL_DESC_LITERAL_SUFFIX:
3086	case SQL_DESC_LOCAL_TYPE_NAME:
3087	case SQL_DESC_NUM_PREC_RADIX:
3088	case SQL_DESC_OCTET_LENGTH:
3089	case SQL_DESC_UNNAMED:
3090          MEM_FREE(_charAttr);
3091	  PUSHSQLERR (stmt->herr, en_HY091);
3092	  return SQL_ERROR;
3093	}
3094
3095      CALL_UDRIVER(stmt->hdbc, stmt, retcode, hproc, penv->unicode_driver,
3096        en_ColAttributes, (stmt->dhstmt, ColumnNumber, FieldIdentifier,
3097        charAttrOut, BufferLength, StringLengthPtr, NumericAttributePtr));
3098
3099      if (hproc == SQL_NULL_HPROC)
3100        {
3101          MEM_FREE(_charAttr);
3102          PUSHSQLERR (stmt->herr, en_IM001);
3103          return SQL_ERROR;
3104        }
3105
3106    if (SQL_SUCCEEDED (retcode) && FieldIdentifier == SQL_DESC_CONCISE_TYPE)
3107      {
3108        SQLINTEGER *ptr = (SQLINTEGER *)NumericAttributePtr;
3109
3110	/*
3111	 *  Convert sql type to ODBC version of application
3112	 */
3113	if (ptr)
3114	  *ptr = _iodbcdm_map_sql_type (*ptr, genv->odbc_ver);
3115      }
3116
3117      if (CharacterAttributePtr
3118          && SQL_SUCCEEDED (retcode)
3119          && ((penv->unicode_driver && waMode != 'W')
3120              || (!penv->unicode_driver && waMode == 'W')))
3121        {
3122          switch(FieldIdentifier)
3123            {
3124            case SQL_COLUMN_QUALIFIER_NAME:
3125            case SQL_COLUMN_NAME:
3126            case SQL_COLUMN_LABEL:
3127            case SQL_COLUMN_OWNER_NAME:
3128            case SQL_COLUMN_TABLE_NAME:
3129            case SQL_COLUMN_TYPE_NAME:
3130
3131            case SQL_DESC_BASE_COLUMN_NAME:
3132            case SQL_DESC_BASE_TABLE_NAME:
3133            case SQL_DESC_LITERAL_PREFIX:
3134            case SQL_DESC_LITERAL_SUFFIX:
3135            case SQL_DESC_LOCAL_TYPE_NAME:
3136            case SQL_DESC_NAME:
3137              if (waMode != 'W')
3138                {
3139                /* ansi<=unicode*/
3140                  dm_StrCopyOut2_W2A ((SQLWCHAR *) charAttrOut,
3141			(SQLCHAR *) CharacterAttributePtr,
3142			BufferLength / sizeof(wchar_t), StringLengthPtr);
3143                }
3144              else
3145                {
3146                /* unicode<=ansi*/
3147                  dm_StrCopyOut2_A2W ((SQLCHAR *) charAttrOut,
3148			(SQLWCHAR *) CharacterAttributePtr,
3149			BufferLength, StringLengthPtr);
3150                  if (StringLengthPtr)
3151                    *StringLengthPtr = *StringLengthPtr * sizeof(wchar_t);
3152                }
3153            }
3154        }
3155      MEM_FREE(_charAttr);
3156      return retcode;
3157    }
3158}
3159
3160
3161RETCODE SQL_API
3162SQLColAttribute (
3163  SQLHSTMT		  statementHandle,
3164  SQLUSMALLINT		  ColumnNumber,
3165  SQLUSMALLINT		  FieldIdentifier,
3166  SQLPOINTER		  CharacterAttributePtr,
3167  SQLSMALLINT		  BufferLength,
3168  SQLSMALLINT		* StringLengthPtr,
3169  SQLLEN		* NumericAttributePtr)
3170{
3171  ENTER_STMT (statementHandle,
3172    trace_SQLColAttribute (TRACE_ENTER,
3173    	statementHandle,
3174	ColumnNumber,
3175	FieldIdentifier,
3176	CharacterAttributePtr, BufferLength, StringLengthPtr,
3177	NumericAttributePtr));
3178
3179  retcode = SQLColAttribute_Internal (
3180  	statementHandle,
3181	ColumnNumber,
3182	FieldIdentifier,
3183	CharacterAttributePtr, BufferLength, StringLengthPtr,
3184	NumericAttributePtr, 'A');
3185
3186  LEAVE_STMT (statementHandle,
3187    trace_SQLColAttribute (TRACE_LEAVE,
3188    	statementHandle,
3189	ColumnNumber,
3190	FieldIdentifier,
3191	CharacterAttributePtr, BufferLength, StringLengthPtr,
3192	NumericAttributePtr));
3193}
3194
3195
3196RETCODE SQL_API
3197SQLColAttributeA (
3198  SQLHSTMT		  statementHandle,
3199  SQLUSMALLINT		  ColumnNumber,
3200  SQLUSMALLINT		  FieldIdentifier,
3201  SQLPOINTER		  CharacterAttributePtr,
3202  SQLSMALLINT		  BufferLength,
3203  SQLSMALLINT		* StringLengthPtr,
3204  SQLLEN		* NumericAttributePtr)
3205{
3206  ENTER_STMT (statementHandle,
3207    trace_SQLColAttribute (TRACE_ENTER,
3208    	statementHandle,
3209	ColumnNumber,
3210	FieldIdentifier,
3211	CharacterAttributePtr, BufferLength, StringLengthPtr,
3212	NumericAttributePtr));
3213
3214  retcode = SQLColAttribute_Internal (
3215  	statementHandle,
3216	ColumnNumber,
3217	FieldIdentifier,
3218	CharacterAttributePtr, BufferLength, StringLengthPtr,
3219	NumericAttributePtr, 'A');
3220
3221  LEAVE_STMT (statementHandle,
3222    trace_SQLColAttribute (TRACE_LEAVE,
3223    	statementHandle,
3224	ColumnNumber,
3225	FieldIdentifier,
3226	CharacterAttributePtr, BufferLength, StringLengthPtr,
3227	NumericAttributePtr));
3228}
3229
3230
3231RETCODE SQL_API
3232SQLColAttributeW (
3233  SQLHSTMT		  statementHandle,
3234  SQLUSMALLINT		  ColumnNumber,
3235  SQLUSMALLINT		  FieldIdentifier,
3236  SQLPOINTER		  CharacterAttributePtr,
3237  SQLSMALLINT		  BufferLength,
3238  SQLSMALLINT		* StringLengthPtr,
3239  SQLLEN		* NumericAttributePtr)
3240{
3241  ENTER_STMT (statementHandle,
3242    trace_SQLColAttributeW (TRACE_ENTER,
3243    	statementHandle,
3244	ColumnNumber,
3245	FieldIdentifier,
3246	CharacterAttributePtr, BufferLength, StringLengthPtr,
3247	NumericAttributePtr));
3248
3249  retcode = SQLColAttribute_Internal (
3250  	statementHandle,
3251	ColumnNumber,
3252	FieldIdentifier,
3253	CharacterAttributePtr, BufferLength, StringLengthPtr,
3254	NumericAttributePtr,
3255	'W');
3256
3257  LEAVE_STMT (statementHandle,
3258    trace_SQLColAttributeW (TRACE_LEAVE,
3259    	statementHandle,
3260	ColumnNumber,
3261	FieldIdentifier,
3262	CharacterAttributePtr, BufferLength, StringLengthPtr,
3263	NumericAttributePtr));
3264}
3265
3266
3267static RETCODE
3268SQLEndTran_Internal (
3269  SQLSMALLINT		  handleType,
3270  SQLHANDLE		  Handle,
3271  SQLSMALLINT		  completionType)
3272{
3273  switch (handleType)
3274    {
3275    case SQL_HANDLE_DBC:
3276    case SQL_HANDLE_ENV:
3277      break;
3278    default:
3279      return SQL_INVALID_HANDLE;
3280    }
3281
3282  return SQLTransact_Internal (
3283      handleType == SQL_HANDLE_ENV ? Handle : SQL_NULL_HENV,
3284      handleType == SQL_HANDLE_DBC ? Handle : SQL_NULL_HDBC,
3285      completionType);
3286}
3287
3288
3289RETCODE SQL_API
3290SQLEndTran (
3291  SQLSMALLINT		  handleType,
3292  SQLHANDLE		  Handle,
3293  SQLSMALLINT		  completionType)
3294{
3295  SQLRETURN retcode = SQL_SUCCESS;
3296
3297  ODBC_LOCK ();
3298  TRACE (trace_SQLEndTran (TRACE_ENTER, handleType, Handle, completionType));
3299
3300  retcode = SQLEndTran_Internal (handleType, Handle, completionType);
3301
3302  TRACE (trace_SQLEndTran (TRACE_LEAVE, handleType, Handle, completionType));
3303  ODBC_UNLOCK ();
3304
3305  return retcode;
3306}
3307
3308
3309static RETCODE
3310SQLBulkOperations_Internal (
3311  SQLHSTMT		  statementHandle,
3312  SQLSMALLINT 		  Operation)
3313{
3314  STMT (stmt, statementHandle);
3315  HPROC hproc;
3316  RETCODE retcode;
3317
3318  switch (Operation)
3319    {
3320    case SQL_ADD:
3321    case SQL_UPDATE_BY_BOOKMARK:
3322    case SQL_DELETE_BY_BOOKMARK:
3323    case SQL_FETCH_BY_BOOKMARK:
3324      break;
3325    default:
3326      PUSHSQLERR (stmt->herr, en_HY092);
3327      return SQL_ERROR;
3328    }
3329
3330  hproc = _iodbcdm_getproc (stmt->hdbc, en_BulkOperations);
3331  if (hproc)
3332    {
3333      CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
3334	  (stmt->dhstmt, Operation));
3335
3336      if (Operation == SQL_FETCH_BY_BOOKMARK
3337          && SQL_SUCCEEDED (retcode))
3338        _iodbcdm_ConvBindData (stmt);
3339      return retcode;
3340    }
3341
3342  switch (Operation)
3343    {
3344    case SQL_ADD:
3345      retcode = _iodbcdm_SetPos (statementHandle,
3346		0, SQL_ADD, SQL_LOCK_NO_CHANGE);
3347      return retcode;
3348
3349    default:
3350      PUSHSQLERR (stmt->herr, en_HYC00);
3351      return SQL_ERROR;
3352    }
3353}
3354
3355
3356RETCODE SQL_API
3357SQLBulkOperations (
3358  SQLHSTMT		  StatementHandle,
3359  SQLSMALLINT 		  Operation)
3360{
3361  ENTER_STMT (StatementHandle,
3362    trace_SQLBulkOperations (TRACE_ENTER, StatementHandle, Operation));
3363
3364  retcode = SQLBulkOperations_Internal (StatementHandle, Operation);
3365
3366  LEAVE_STMT (StatementHandle,
3367    trace_SQLBulkOperations (TRACE_LEAVE, StatementHandle, Operation));
3368}
3369
3370
3371static RETCODE
3372SQLFetchScroll_Internal (
3373  SQLHSTMT		  statementHandle,
3374  SQLSMALLINT		  fetchOrientation,
3375  SQLLEN		  fetchOffset)
3376{
3377  STMT (stmt, statementHandle);
3378  HPROC hproc = SQL_NULL_HPROC;
3379  RETCODE retcode;
3380  CONN (pdbc, stmt->hdbc);
3381  HPROC hproc2 = SQL_NULL_HPROC;
3382  SQLUINTEGER odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
3383  SQLUINTEGER dodbc_ver = ((ENV_t *) pdbc->henv)->dodbc_ver;
3384
3385  /* check arguments */
3386  switch (fetchOrientation)
3387    {
3388    case SQL_FETCH_NEXT:
3389    case SQL_FETCH_PRIOR:
3390    case SQL_FETCH_FIRST:
3391    case SQL_FETCH_LAST:
3392    case SQL_FETCH_ABSOLUTE:
3393    case SQL_FETCH_RELATIVE:
3394    case SQL_FETCH_BOOKMARK:
3395      break;
3396
3397    default:
3398      PUSHSQLERR (stmt->herr, en_HY092);
3399      return SQL_ERROR;
3400    }
3401
3402  /* check state */
3403  if (stmt->asyn_on == en_NullProc)
3404    {
3405      switch (stmt->state)
3406	{
3407	case en_stmt_allocated:
3408	case en_stmt_prepared:
3409	case en_stmt_fetched:
3410	case en_stmt_needdata:
3411	case en_stmt_mustput:
3412	case en_stmt_canput:
3413	  PUSHSQLERR (stmt->herr, en_S1010);
3414	  return SQL_ERROR;
3415
3416	default:
3417	  break;
3418	}
3419    }
3420  else if (stmt->asyn_on != en_FetchScroll)
3421    {
3422      PUSHSQLERR (stmt->herr, en_S1010);
3423      return SQL_ERROR;
3424    }
3425
3426  hproc2 = _iodbcdm_getproc (stmt->hdbc, en_ExtendedFetch);
3427
3428  if (dodbc_ver == SQL_OV_ODBC3 &&
3429      (  odbc_ver == SQL_OV_ODBC3
3430       || (odbc_ver == SQL_OV_ODBC2 && hproc2 == SQL_NULL_HPROC)))
3431    {
3432      hproc = _iodbcdm_getproc (stmt->hdbc, en_FetchScroll);
3433      if (hproc)
3434        {
3435          CALL_DRIVER (stmt->hdbc, stmt, retcode, hproc,
3436	      (stmt->dhstmt, fetchOrientation, fetchOffset));
3437        }
3438    }
3439
3440  if (hproc == SQL_NULL_HPROC)
3441    {
3442      if (!stmt->row_status_ptr)
3443	{
3444	  PUSHSQLERR (stmt->herr, en_HYC00);
3445	  return SQL_ERROR;
3446	}
3447
3448      if (fetchOrientation == SQL_FETCH_BOOKMARK)
3449	{
3450	  if (fetchOffset)
3451	    {
3452	      PUSHSQLERR (stmt->herr, en_HYC00);
3453	      return SQL_ERROR;
3454	    }
3455	  retcode = _iodbcdm_ExtendedFetch (statementHandle, fetchOrientation,
3456	      stmt->fetch_bookmark_ptr ? *((SQLINTEGER *) stmt->fetch_bookmark_ptr)
3457	      : 0, (SQLULEN *) stmt->rows_fetched_ptr,
3458		(SQLUSMALLINT *) stmt->row_status_ptr);
3459	}
3460      else
3461	retcode =
3462	    _iodbcdm_ExtendedFetch (statementHandle, fetchOrientation,
3463	    fetchOffset, (SQLULEN *) stmt->rows_fetched_ptr,
3464	    (SQLUSMALLINT *) stmt->row_status_ptr);
3465    }
3466
3467  /* state transition */
3468  if (stmt->asyn_on == en_FetchScroll)
3469    {
3470      switch (retcode)
3471	{
3472	case SQL_SUCCESS:
3473	case SQL_SUCCESS_WITH_INFO:
3474	case SQL_NO_DATA_FOUND:
3475	case SQL_ERROR:
3476	  stmt->asyn_on = en_NullProc;
3477	  break;
3478
3479	case SQL_STILL_EXECUTING:
3480	default:
3481	  return retcode;
3482	}
3483    }
3484
3485  switch (stmt->state)
3486    {
3487    case en_stmt_cursoropen:
3488    case en_stmt_xfetched:
3489      switch (retcode)
3490	{
3491	case SQL_SUCCESS:
3492	case SQL_SUCCESS_WITH_INFO:
3493	case SQL_NO_DATA_FOUND:
3494	  stmt->state = en_stmt_xfetched;
3495	  stmt->cursor_state = en_stmt_cursor_xfetched;
3496	  break;
3497
3498	case SQL_STILL_EXECUTING:
3499	  stmt->asyn_on = en_FetchScroll;
3500	  break;
3501
3502	default:
3503	  break;
3504	}
3505      break;
3506
3507    default:
3508      break;
3509    }
3510
3511  return retcode;
3512}
3513
3514
3515RETCODE SQL_API
3516SQLFetchScroll (
3517  SQLHSTMT		  StatementHandle,
3518  SQLSMALLINT		  FetchOrientation,
3519  SQLLEN		  FetchOffset)
3520{
3521  ENTER_STMT (StatementHandle,
3522    trace_SQLFetchScroll (TRACE_ENTER,
3523    	StatementHandle,
3524	FetchOrientation,
3525	FetchOffset));
3526
3527  retcode = SQLFetchScroll_Internal (
3528  	StatementHandle,
3529	FetchOrientation,
3530	FetchOffset);
3531
3532  if (SQL_SUCCEEDED (retcode))
3533    _iodbcdm_ConvBindData ((STMT_t *) StatementHandle);
3534
3535  LEAVE_STMT (StatementHandle,
3536    trace_SQLFetchScroll (TRACE_LEAVE,
3537    	StatementHandle,
3538	FetchOrientation,
3539	FetchOffset));
3540}
3541
3542
3543SQLRETURN SQL_API
3544SQLBindParam (
3545    SQLHSTMT hstmt,
3546    SQLUSMALLINT ipar,
3547    SQLSMALLINT fCType,
3548    SQLSMALLINT fSqlType,
3549    SQLULEN cbParamDef,
3550    SQLSMALLINT ibScale,
3551    SQLPOINTER rgbValue,
3552    SQLLEN *pcbValue)
3553{
3554  return SQLBindParameter (hstmt, ipar, SQL_PARAM_INPUT, fCType, fSqlType, cbParamDef, ibScale, rgbValue, SQL_MAX_OPTION_STRING_LENGTH, pcbValue);
3555}
3556
3557
3558static SQLRETURN
3559SQLCloseCursor_Internal (SQLHSTMT hstmt)
3560{
3561  STMT (pstmt, hstmt);
3562  CONN (pdbc, pstmt->hdbc);
3563  HPROC hproc = SQL_NULL_HPROC;
3564  SQLRETURN retcode = SQL_SUCCESS;
3565  HPROC hproc2 = SQL_NULL_HPROC;
3566  SQLUINTEGER odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
3567  SQLUINTEGER dodbc_ver = ((ENV_t *) pdbc->henv)->dodbc_ver;
3568
3569  /* check state */
3570  if (pstmt->state >= en_stmt_needdata || pstmt->asyn_on != en_NullProc)
3571    {
3572      PUSHSQLERR (pstmt->herr, en_S1010);
3573
3574      return SQL_ERROR;
3575    }
3576
3577  hproc2 = _iodbcdm_getproc (pstmt->hdbc, en_FreeStmt);
3578
3579  if (dodbc_ver == SQL_OV_ODBC3 &&
3580      (  odbc_ver == SQL_OV_ODBC3
3581       || (odbc_ver == SQL_OV_ODBC2 && hproc2 == SQL_NULL_HPROC)))
3582    {
3583      hproc = _iodbcdm_getproc (pstmt->hdbc, en_CloseCursor);
3584      if (hproc)
3585        {
3586          CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
3587	      (pstmt->dhstmt));
3588        }
3589    }
3590
3591  if (hproc == SQL_NULL_HPROC)
3592    {
3593      hproc = _iodbcdm_getproc (pstmt->hdbc, en_FreeStmt);
3594
3595      if (hproc == SQL_NULL_HPROC)
3596	{
3597	  PUSHSQLERR (pstmt->herr, en_IM001);
3598	  return SQL_ERROR;
3599	}
3600
3601      CALL_DRIVER (pstmt->hdbc, pstmt, retcode, hproc,
3602	  (pstmt->dhstmt, SQL_CLOSE));
3603    }
3604
3605  if (retcode != SQL_SUCCESS
3606      && retcode != SQL_SUCCESS_WITH_INFO)
3607    {
3608      return retcode;
3609    }
3610
3611  /*
3612   *  State transition
3613   */
3614  pstmt->cursor_state = en_stmt_cursor_no;
3615
3616  switch (pstmt->state)
3617    {
3618    case en_stmt_allocated:
3619    case en_stmt_prepared:
3620      break;
3621
3622    case en_stmt_executed_with_info:
3623    case en_stmt_executed:
3624    case en_stmt_cursoropen:
3625    case en_stmt_fetched:
3626    case en_stmt_xfetched:
3627      if (pstmt->prep_state)
3628	pstmt->state = en_stmt_prepared;
3629      else
3630	pstmt->state = en_stmt_allocated;
3631      break;
3632
3633    default:
3634      break;
3635    }
3636
3637  return retcode;
3638}
3639
3640
3641SQLRETURN SQL_API
3642SQLCloseCursor (SQLHSTMT hstmt)
3643{
3644  ENTER_STMT (hstmt,
3645    trace_SQLCloseCursor (TRACE_ENTER, hstmt));
3646
3647  retcode = SQLCloseCursor_Internal (hstmt);
3648
3649  LEAVE_STMT (hstmt,
3650    trace_SQLCloseCursor (TRACE_LEAVE, hstmt));
3651}
3652
3653#endif	/* ODBCVER >= 0x0300 */
3654