1/*
2 *  hstmt.c
3 *
4 *  $Id: hstmt.c 2613 1999-06-01 15:32:12Z VZ $
5 *
6 *  Query statement object management functions
7 *
8 *  The iODBC driver manager.
9 *
10 *  Copyright (C) 1995 by Ke Jin <kejin@empress.com>
11 *
12 *  This library is free software; you can redistribute it and/or
13 *  modify it under the terms of the GNU Library General Public
14 *  License as published by the Free Software Foundation; either
15 *  version 2 of the License, or (at your option) any later version.
16 *
17 *  This library is distributed in the hope that it will be useful,
18 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 *  Library General Public License for more details.
21 *
22 *  You should have received a copy of the GNU Library General Public
23 *  License along with this library; if not, write to the Free
24 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27#include	"config.h"
28
29#include	"isql.h"
30#include	"isqlext.h"
31
32#include        "dlproc.h"
33
34#include	"herr.h"
35#include	"henv.h"
36#include	"hdbc.h"
37#include	"hstmt.h"
38
39#include	"itrace.h"
40
41RETCODE SQL_API
42SQLAllocStmt (
43    HDBC hdbc,
44    HSTMT FAR * phstmt)
45{
46  DBC_t FAR *pdbc = (DBC_t FAR *) hdbc;
47  STMT_t FAR *pstmt = NULL;
48  HPROC hproc = SQL_NULL_HPROC;
49  RETCODE retcode = SQL_SUCCESS;
50
51#if (ODBCVER >= 0x0300)
52  if (hdbc == SQL_NULL_HDBC || pdbc->type != SQL_HANDLE_DBC)
53#else
54  if (hdbc == SQL_NULL_HDBC)
55#endif
56    {
57      return SQL_INVALID_HANDLE;
58    }
59
60  if (phstmt == NULL)
61    {
62      PUSHSQLERR (pdbc->herr, en_S1009);
63
64      return SQL_ERROR;
65    }
66
67  /* check state */
68  switch (pdbc->state)
69     {
70     case en_dbc_connected:
71     case en_dbc_hstmt:
72       break;
73
74     case en_dbc_allocated:
75     case en_dbc_needdata:
76       PUSHSQLERR (pdbc->herr, en_08003);
77       *phstmt = SQL_NULL_HSTMT;
78       return SQL_ERROR;
79
80     default:
81       return SQL_INVALID_HANDLE;
82     }
83
84  pstmt = (STMT_t FAR *) MEM_ALLOC (sizeof (STMT_t));
85
86  if (pstmt == NULL)
87    {
88      PUSHSQLERR (pdbc->herr, en_S1001);
89      *phstmt = SQL_NULL_HSTMT;
90
91      return SQL_ERROR;
92    }
93
94#if (ODBCVER >= 0x0300)
95  pstmt->type = SQL_HANDLE_STMT;
96#endif
97
98  /* initiate the object */
99  pstmt->herr = SQL_NULL_HERR;
100  pstmt->hdbc = hdbc;
101  pstmt->state = en_stmt_allocated;
102  pstmt->cursor_state = en_stmt_cursor_no;
103  pstmt->prep_state = 0;
104  pstmt->asyn_on = en_NullProc;
105  pstmt->need_on = en_NullProc;
106
107  /* call driver's function */
108
109#if (ODBCVER >= 0x0300)
110  hproc = _iodbcdm_getproc (hdbc, en_AllocHandle);
111
112  if (hproc)
113    {
114      CALL_DRIVER (pstmt->hdbc, hdbc, retcode, hproc, en_AllocHandle,
115        (SQL_HANDLE_STMT, pdbc->dhdbc, &(pstmt->dhstmt)))
116    }
117  else
118#endif
119
120    {
121      hproc = _iodbcdm_getproc (hdbc, en_AllocStmt);
122
123      if (hproc == SQL_NULL_HPROC)
124	{
125	  PUSHSQLERR (pstmt->herr, en_IM001);
126	  *phstmt = SQL_NULL_HSTMT;
127	  MEM_FREE (pstmt);
128
129	  return SQL_ERROR;
130	}
131
132      CALL_DRIVER (hdbc, retcode, hproc, en_AllocStmt,
133        (pdbc->dhdbc, &(pstmt->dhstmt)))
134    }
135
136  if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
137    {
138      *phstmt = SQL_NULL_HSTMT;
139      MEM_FREE (pstmt);
140
141      return retcode;
142    }
143
144  /* insert into list */
145  pstmt->next = pdbc->hstmt;
146  pdbc->hstmt = pstmt;
147
148  *phstmt = (HSTMT) pstmt;
149
150  /* state transition */
151  pdbc->state = en_dbc_hstmt;
152
153  return SQL_SUCCESS;
154}
155
156
157RETCODE
158_iodbcdm_dropstmt (HSTMT hstmt)
159{
160  STMT_t FAR *pstmt = (STMT_t FAR *) hstmt;
161  STMT_t FAR *tpstmt;
162  DBC_t FAR *pdbc;
163
164  if (hstmt == SQL_NULL_HSTMT)
165    {
166      return SQL_INVALID_HANDLE;
167    }
168
169  pdbc = (DBC_t FAR *) (pstmt->hdbc);
170
171  for (tpstmt = (STMT_t FAR *) pdbc->hstmt;
172      tpstmt != NULL;
173      tpstmt = tpstmt->next)
174    {
175      if (tpstmt == pstmt)
176	{
177	  pdbc->hstmt = (HSTMT) pstmt->next;
178	  break;
179	}
180
181      if (tpstmt->next == pstmt)
182	{
183	  tpstmt->next = pstmt->next;
184	  break;
185	}
186    }
187
188  if (tpstmt == NULL)
189    {
190      return SQL_INVALID_HANDLE;
191    }
192
193  _iodbcdm_freesqlerrlist (pstmt->herr);
194  MEM_FREE (hstmt);
195
196  return SQL_SUCCESS;
197}
198
199
200RETCODE SQL_API
201SQLFreeStmt (
202    HSTMT hstmt,
203    UWORD fOption)
204{
205  STMT_t FAR *pstmt = (STMT_t FAR *) hstmt;
206  STMT_t FAR *tpstmt;
207  DBC_t FAR *pdbc;
208
209  HPROC hproc = SQL_NULL_HPROC;
210  RETCODE retcode;
211
212  if (hstmt == SQL_NULL_HSTMT || pstmt->hdbc == SQL_NULL_HDBC)
213    {
214      return SQL_INVALID_HANDLE;
215    }
216
217  pdbc = (DBC_t FAR *) (pstmt->hdbc);
218
219  /* check option */
220  switch (fOption)
221     {
222     case SQL_DROP:
223     case SQL_CLOSE:
224     case SQL_UNBIND:
225     case SQL_RESET_PARAMS:
226       break;
227
228     default:
229       PUSHSQLERR (pstmt->herr, en_S1092);
230       return SQL_ERROR;
231     }
232
233  /* check state */
234  if (pstmt->state >= en_stmt_needdata || pstmt->asyn_on != en_NullProc)
235    {
236      PUSHSQLERR (pstmt->herr, en_S1010);
237
238      return SQL_ERROR;
239    }
240
241  hproc = SQL_NULL_HPROC;
242
243#if (ODBCVER >= 0x0300)
244  if (fOption == SQL_DROP)
245    {
246      hproc = _iodbcdm_getproc (pstmt->hdbc, en_FreeHandle);
247
248      if (hproc)
249	{
250	  CALL_DRIVER (pstmt->hdbc, retcode, hproc, en_FreeHandle,
251	    (SQL_HANDLE_STMT, pstmt->dhstmt))
252	}
253    }
254#endif
255
256  if (hproc == SQL_NULL_HPROC)
257    {
258      hproc = _iodbcdm_getproc (pstmt->hdbc, en_FreeStmt);
259
260      if (hproc == SQL_NULL_HPROC)
261	{
262	  PUSHSQLERR (pstmt->herr, en_IM001);
263
264	  return SQL_ERROR;
265	}
266
267      CALL_DRIVER (pstmt->hdbc, retcode, hproc, en_FreeStmt,
268	(pstmt->dhstmt, fOption))
269    }
270
271  if (retcode != SQL_SUCCESS
272      && retcode != SQL_SUCCESS_WITH_INFO)
273    {
274      return retcode;
275    }
276
277  /* state transition */
278  switch (fOption)
279     {
280     case SQL_DROP:
281       /* delet this object (ignore return) */
282       _iodbcdm_dropstmt (hstmt);
283       break;
284
285     case SQL_CLOSE:
286       pstmt->cursor_state = en_stmt_cursor_no;
287       /* This means cursor name set by
288        * SQLSetCursorName() call will also
289        * be erased.
290        */
291
292       switch (pstmt->state)
293	  {
294	  case en_stmt_allocated:
295	  case en_stmt_prepared:
296	    break;
297
298	  case en_stmt_executed:
299	  case en_stmt_cursoropen:
300	  case en_stmt_fetched:
301	  case en_stmt_xfetched:
302	    if (pstmt->prep_state)
303	      {
304		pstmt->state =
305		    en_stmt_prepared;
306	      }
307	    else
308	      {
309		pstmt->state =
310		    en_stmt_allocated;
311	      }
312	    break;
313
314	  default:
315	    break;
316	  }
317       break;
318
319     case SQL_UNBIND:
320     case SQL_RESET_PARAMS:
321     default:
322       break;
323     }
324
325  return retcode;
326}
327
328
329RETCODE SQL_API
330SQLSetStmtOption (
331    HSTMT hstmt,
332    UWORD fOption,
333    UDWORD vParam)
334{
335  STMT_t FAR *pstmt = (STMT_t FAR *) hstmt;
336  HPROC hproc;
337  int sqlstat = en_00000;
338  RETCODE retcode;
339
340  if (hstmt == SQL_NULL_HSTMT || pstmt->hdbc == SQL_NULL_HDBC)
341    {
342      return SQL_INVALID_HANDLE;
343    }
344
345  /* check option */
346  if (				/* fOption < SQL_STMT_OPT_MIN || */
347      fOption > SQL_STMT_OPT_MAX)
348    {
349      PUSHSQLERR (pstmt->herr, en_S1092);
350
351      return SQL_ERROR;
352    }
353
354  if (fOption == SQL_CONCURRENCY
355      || fOption == SQL_CURSOR_TYPE
356      || fOption == SQL_SIMULATE_CURSOR
357      || fOption == SQL_USE_BOOKMARKS)
358    {
359      if (pstmt->asyn_on != en_NullProc)
360	{
361	  if (pstmt->prep_state)
362	    {
363	      sqlstat = en_S1011;
364	    }
365	}
366      else
367	{
368	  switch (pstmt->state)
369	     {
370	     case en_stmt_prepared:
371	       sqlstat = en_S1011;
372	       break;
373
374	     case en_stmt_executed:
375	     case en_stmt_cursoropen:
376	     case en_stmt_fetched:
377	     case en_stmt_xfetched:
378	       sqlstat = en_24000;
379	       break;
380
381	     case en_stmt_needdata:
382	     case en_stmt_mustput:
383	     case en_stmt_canput:
384	       if (pstmt->prep_state)
385		 {
386		   sqlstat = en_S1011;
387		 }
388	       break;
389
390	     default:
391	       break;
392	     }
393	}
394    }
395  else
396    {
397      if (pstmt->asyn_on != en_NullProc)
398	{
399	  if (!pstmt->prep_state)
400	    {
401	      sqlstat = en_S1010;
402	    }
403	}
404      else
405	{
406	  if (pstmt->state >= en_stmt_needdata)
407	    {
408	      sqlstat = en_S1010;
409	    }
410	}
411    }
412
413  if (sqlstat != en_00000)
414    {
415      PUSHSQLERR (pstmt->herr, sqlstat);
416
417      return SQL_ERROR;
418    }
419
420  hproc = _iodbcdm_getproc (pstmt->hdbc, en_SetStmtOption);
421
422  if (hproc == SQL_NULL_HPROC)
423    {
424      PUSHSQLERR (pstmt->herr, en_IM001);
425
426      return SQL_ERROR;
427    }
428
429  CALL_DRIVER (pstmt->hdbc, retcode, hproc, en_SetStmtOption,
430    (pstmt->dhstmt, fOption, vParam))
431
432  return retcode;
433}
434
435
436RETCODE SQL_API
437SQLGetStmtOption (
438    HSTMT hstmt,
439    UWORD fOption,
440    PTR pvParam)
441{
442  STMT_t FAR *pstmt = (STMT_t *) hstmt;
443  HPROC hproc;
444  int sqlstat = en_00000;
445  RETCODE retcode;
446
447  if (hstmt == SQL_NULL_HSTMT || pstmt->hdbc == SQL_NULL_HDBC)
448    {
449      return SQL_INVALID_HANDLE;
450    }
451
452  /* check option */
453  if (				/* fOption < SQL_STMT_OPT_MIN || */
454      fOption > SQL_STMT_OPT_MAX)
455    {
456      PUSHSQLERR (pstmt->herr, en_S1092);
457
458      return SQL_ERROR;
459    }
460
461  /* check state */
462  if (pstmt->state >= en_stmt_needdata
463      || pstmt->asyn_on != en_NullProc)
464    {
465      sqlstat = en_S1010;
466    }
467  else
468    {
469      switch (pstmt->state)
470	 {
471	 case en_stmt_allocated:
472	 case en_stmt_prepared:
473	 case en_stmt_executed:
474	 case en_stmt_cursoropen:
475	   if (fOption == SQL_ROW_NUMBER || fOption == SQL_GET_BOOKMARK)
476	     {
477	       sqlstat = en_24000;
478	     }
479	   break;
480
481	 default:
482	   break;
483	 }
484    }
485
486  if (sqlstat != en_00000)
487    {
488      PUSHSQLERR (pstmt->herr, sqlstat);
489
490      return SQL_ERROR;
491    }
492
493  hproc = _iodbcdm_getproc (pstmt->hdbc, en_GetStmtOption);
494
495  if (hproc == SQL_NULL_HPROC)
496    {
497      PUSHSQLERR (pstmt->herr, en_IM001);
498      return SQL_ERROR;
499    }
500
501  CALL_DRIVER (pstmt->hdbc, retcode, hproc, en_GetStmtOption,
502    (pstmt->dhstmt, fOption, pvParam))
503
504  return retcode;
505}
506
507
508RETCODE SQL_API
509SQLCancel (HSTMT hstmt)
510{
511  STMT_t FAR *pstmt = (STMT_t FAR *) hstmt;
512  HPROC hproc;
513  RETCODE retcode;
514
515  if (hstmt == SQL_NULL_HSTMT || pstmt->hdbc == SQL_NULL_HDBC)
516    {
517      return SQL_INVALID_HANDLE;
518    }
519
520  /* check argument */
521  /* check state */
522
523  /* call driver */
524  hproc = _iodbcdm_getproc (pstmt->hdbc, en_Cancel);
525
526  if (hproc == SQL_NULL_HPROC)
527    {
528      PUSHSQLERR (pstmt->herr, en_IM001);
529
530      return SQL_ERROR;
531    }
532
533  CALL_DRIVER (pstmt->hdbc, retcode, hproc, en_Cancel,
534    (pstmt->dhstmt))
535
536  /* state transition */
537  if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO)
538    {
539      return retcode;
540    }
541
542  switch (pstmt->state)
543     {
544     case en_stmt_allocated:
545     case en_stmt_prepared:
546       break;
547
548     case en_stmt_executed:
549       if (pstmt->prep_state)
550	 {
551	   pstmt->state = en_stmt_prepared;
552	 }
553       else
554	 {
555	   pstmt->state = en_stmt_allocated;
556	 }
557       break;
558
559     case en_stmt_cursoropen:
560     case en_stmt_fetched:
561     case en_stmt_xfetched:
562       if (pstmt->prep_state)
563	 {
564	   pstmt->state = en_stmt_prepared;
565	 }
566       else
567	 {
568	   pstmt->state = en_stmt_allocated;
569	 }
570       break;
571
572     case en_stmt_needdata:
573     case en_stmt_mustput:
574     case en_stmt_canput:
575       switch (pstmt->need_on)
576	  {
577	  case en_ExecDirect:
578	    pstmt->state = en_stmt_allocated;
579	    break;
580
581	  case en_Execute:
582	    pstmt->state = en_stmt_prepared;
583	    break;
584
585	  case en_SetPos:
586	    pstmt->state = en_stmt_xfetched;
587	    break;
588
589	  default:
590	    break;
591	  }
592       pstmt->need_on = en_NullProc;
593       break;
594
595     default:
596       break;
597     }
598
599  return retcode;
600}
601