]> git.saurik.com Git - wxWidgets.git/blame - src/iodbc/hdbc.c
OnExit() is called for modules which were initialized even if the init of
[wxWidgets.git] / src / iodbc / hdbc.c
CommitLineData
1a6944fd
RR
1/** data source connect object management functions
2
7e616b10 3 Copyright (C) 1995 by Ke Jin <kejin@empress.com>
1a6944fd
RR
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14**/
15
16#include <../iodbc/iodbc.h>
17
18#include <../iodbc/isql.h>
19#include <../iodbc/isqlext.h>
20
21#include <../iodbc/dlproc.h>
22
23#include <../iodbc/herr.h>
24#include <../iodbc/henv.h>
25#include <../iodbc/hdbc.h>
26#include <../iodbc/hstmt.h>
27
28#include <../iodbc/itrace.h>
29#include <stdio.h>
30
e3e65dac
RR
31extern RETCODE _iodbcdm_driverunload();
32
7e616b10
RR
33RETCODE SQL_API SQLAllocConnect(
34 HENV henv,
35 HDBC FAR* phdbc )
1a6944fd 36{
7e616b10
RR
37 GENV_t FAR* genv = (GENV_t FAR*)henv;
38 DBC_t FAR* pdbc;
1a6944fd
RR
39
40#if (ODBCVER >= 0x0300)
7e616b10
RR
41 if( henv == SQL_NULL_HENV
42 || genv->type != SQL_HANDLE_ENV )
1a6944fd 43#else
7e616b10 44 if( henv == SQL_NULL_HENV )
1a6944fd 45#endif
7e616b10
RR
46 {
47 return SQL_INVALID_HANDLE;
48 }
1a6944fd 49
7e616b10
RR
50 if( phdbc == NULL )
51 {
52 PUSHSQLERR ( genv->herr, en_S1009 );
1a6944fd 53
7e616b10
RR
54 return SQL_ERROR;
55 }
1a6944fd 56
7e616b10 57 pdbc = (DBC_t FAR*)MEM_ALLOC (sizeof(DBC_t));
1a6944fd 58
7e616b10
RR
59 if( pdbc == NULL )
60 {
61 *phdbc = SQL_NULL_HDBC;
1a6944fd 62
7e616b10 63 PUSHSQLERR ( genv->herr, en_S1001 );
1a6944fd 64
7e616b10
RR
65 return SQL_ERROR;
66 }
1a6944fd
RR
67
68#if (ODBCVER >= 0x0300)
7e616b10 69 pdbc->type = SQL_HANDLE_DBC;
1a6944fd 70#endif
7e616b10
RR
71 /* insert this dbc entry into the link list */
72 pdbc->next = genv->hdbc;
73 genv->hdbc = pdbc;
74 pdbc->genv = henv;
75
76 pdbc->henv = SQL_NULL_HENV;
77 pdbc->hstmt= SQL_NULL_HSTMT;
78 pdbc->herr = SQL_NULL_HERR;
79 pdbc->dhdbc= SQL_NULL_HDBC;
80 pdbc->state= en_dbc_allocated;
81 pdbc->trace = 0;
82 pdbc->tstm = NULL;
83 pdbc->tfile = NULL;
84
85 /* set connect options to default values */
86 pdbc->access_mode = SQL_MODE_DEFAULT;
87 pdbc->autocommit = SQL_AUTOCOMMIT_DEFAULT;
88 pdbc->current_qualifier = NULL;
89 pdbc->login_timeout = 0UL;
90 pdbc->odbc_cursors = SQL_CUR_DEFAULT;
91 pdbc->packet_size = 0UL;
92 pdbc->quiet_mode = (UDWORD)NULL;
93 pdbc->txn_isolation = SQL_TXN_READ_UNCOMMITTED;
94 pdbc->cb_commit = (SWORD)SQL_CB_DELETE;
95 pdbc->cb_rollback = (SWORD)SQL_CB_DELETE;
96
97 *phdbc = (HDBC)pdbc;
98
99 return SQL_SUCCESS;
1a6944fd
RR
100}
101
7e616b10 102RETCODE SQL_API SQLFreeConnect( HDBC hdbc )
1a6944fd 103{
7e616b10
RR
104 GENV_t FAR* genv;
105 DBC_t FAR* pdbc = (DBC_t FAR*)hdbc;
106 DBC_t FAR* tpdbc;
107
108 if( hdbc == SQL_NULL_HDBC )
109 {
110 return SQL_INVALID_HANDLE;
111 }
112
113 /* check state */
114 if( pdbc->state != en_dbc_allocated )
115 {
116 PUSHSQLERR ( pdbc->herr, en_S1010 );
117
118 return SQL_ERROR;
119 }
120
121 genv = (GENV_t FAR*)pdbc->genv;
122
123 for( tpdbc = (DBC_t FAR*)genv->hdbc;
124 tpdbc != NULL;
125 tpdbc = tpdbc->next )
126 {
127 if( pdbc == tpdbc )
128 {
129 genv->hdbc = pdbc->next;
130 break;
131 }
132
133 if( pdbc == tpdbc->next )
134 {
135 tpdbc->next = pdbc->next;
136 break;
137 }
138 }
139
140 /* free this dbc */
141 _iodbcdm_driverunload(pdbc);
142 _iodbcdm_freesqlerrlist( pdbc->herr );
143
144 if( pdbc->tfile )
145 {
146 MEM_FREE( pdbc->tfile );
147 }
148
149 SQLSetConnectOption( pdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF);
150
151 MEM_FREE ( pdbc );
152
153 return SQL_SUCCESS;
1a6944fd
RR
154}
155
7e616b10
RR
156RETCODE SQL_API SQLSetConnectOption(
157 HDBC hdbc,
158 UWORD fOption,
159 UDWORD vParam )
1a6944fd 160{
7e616b10
RR
161 GENV_t FAR* genv;
162 DBC_t FAR* pdbc = (DBC_t FAR*)hdbc;
163 STMT_t FAR* pstmt;
164 HPROC hproc = SQL_NULL_HPROC;
165 int sqlstat = en_00000;
166 RETCODE retcode = SQL_SUCCESS;
167
168 if( hdbc == SQL_NULL_HDBC )
169 {
170 return SQL_INVALID_HANDLE;
171 }
172
173 /* check option */
174 if( fOption < SQL_CONN_OPT_MIN
175 || ( fOption > SQL_CONN_OPT_MAX
176 && fOption < SQL_CONNECT_OPT_DRVR_START ) )
177 {
178 PUSHSQLERR ( pdbc->herr, en_S1092 );
179
180 return SQL_ERROR;
181 }
182
183 /* check state of connection handle */
184 switch( pdbc->state )
185 {
186 case en_dbc_allocated:
187 if( fOption == SQL_TRANSLATE_DLL
188 || fOption == SQL_TRANSLATE_OPTION )
189 {
190 /* This two options are only meaningful
191 * for specified driver. So, has to be
192 * set after a dirver has been loaded.
193 */
194 sqlstat = en_08003;
195 break;
196 }
197
198 if( fOption >= SQL_CONNECT_OPT_DRVR_START
199 && pdbc->henv == SQL_NULL_HENV )
200 /* An option only meaningful for drivers
201 * is passed before loading a driver.
202 * We classify this as an invalid option error.
203 * This is not documented by MS SDK guide.
204 */
205 {
206 sqlstat = en_S1092;
207 break;
208 }
209 break;
210
211 case en_dbc_needdata:
212 sqlstat = en_S1010;
213 break;
214
215 case en_dbc_connected:
216 case en_dbc_hstmt:
217 if( fOption == SQL_ODBC_CURSORS )
218 {
219 sqlstat = en_08002;
220 }
221 break;
222
223 default:
224 break;
225 }
226
227 /* check state of statement handle(s) */
228 for( pstmt = (STMT_t FAR*)pdbc->hstmt;
229 pstmt != NULL && sqlstat == en_00000;
230 pstmt = (STMT_t FAR*)pstmt->next )
231 {
232 if( pstmt->state >= en_stmt_needdata
233 || pstmt->asyn_on != en_NullProc )
234 {
235 sqlstat = en_S1010;
236 }
237 }
238
239 if( sqlstat != en_00000 )
240 {
241 PUSHSQLERR ( pdbc->herr, sqlstat );
242
243 return SQL_ERROR;
244 }
245
246 if( fOption == SQL_OPT_TRACE )
247 /* tracing flag can be set before and after connect
248 * and only meaningful for driver manager(actually
249 * there is only one tracing file under one global
250 * environment).
251 */
252 {
253 switch( vParam )
254 {
255 case SQL_OPT_TRACE_ON:
256 if( pdbc->tfile == NULL )
257 {
258 pdbc->tfile = (char FAR*)MEM_ALLOC( 1 +
259 STRLEN(SQL_OPT_TRACE_FILE_DEFAULT) );
260
261 if( pdbc->tfile == NULL )
262 {
263 PUSHSQLERR( pdbc->herr, en_S1001 );
264
265 return SQL_ERROR;
266 }
267
268 STRCPY( pdbc->tfile, SQL_OPT_TRACE_FILE_DEFAULT );
269 }
270
271 if( pdbc->tstm == NULL )
272 {
273#if defined(stderr) && defined(stdout)
274 if(STREQ( pdbc->tfile, "stderr"))
275 {
276 pdbc->tstm = stderr;
277 }
278 else
279 if(STREQ(pdbc->tfile, "stdout"))
280 {
281 pdbc->tstm = stdout;
282 }
283 else
1a6944fd 284#endif
7e616b10
RR
285 {
286 pdbc->tstm
287 = fopen(pdbc->tfile, "a+");
288 }
289
290 if(pdbc->tstm )
291 {
292 pdbc->trace = 1;
293 }
294 else
295 {
296 pdbc->trace = 0;
297
298 sqlstat = en_IM013;
299 retcode = SQL_ERROR;
300 }
301 }
302 break;
303
304 case SQL_OPT_TRACE_OFF:
305 if( pdbc->trace && pdbc->tstm )
306 {
307#if defined(stderr) && defined(stdout)
308 if( stderr != (FILE FAR*)(pdbc->tstm)
309 && stdout != (FILE FAR*)(pdbc->tstm) )
310#endif
311 {
312 fclose(pdbc->tstm);
313 }
314 }
315 pdbc->tstm = NULL;
316 pdbc->trace = 0;
317 break;
318
319 default:
320 PUSHSQLERR (pdbc->herr, en_S1009);
321 retcode = SQL_ERROR;
322 }
323
324 if( sqlstat != en_00000 )
325 {
326 PUSHSQLERR ( pdbc->herr, sqlstat );
327 }
328
329 return retcode;
330 }
331
332 if( fOption == SQL_OPT_TRACEFILE )
333 /* Tracing file can be set before and after connect
334 * and only meaningful for driver manager.
335 */
336 {
337 if( vParam == 0UL
338 || ((char FAR*)vParam)[0] == 0 )
339 {
340 PUSHSQLERR ( pdbc->herr, en_S1009 );
341
342 return SQL_ERROR;
343 }
344
345 if( pdbc->tfile && STREQ (pdbc->tfile, vParam) )
346 {
347 return SQL_SUCCESS;
348 }
349
350 if( pdbc->trace )
351 {
352 PUSHSQLERR ( pdbc->herr, en_IM014 );
353
354 return SQL_ERROR;
355 }
356
357 if( pdbc->tfile )
358 {
359 MEM_FREE( pdbc->tfile );
360 }
361
362 pdbc->tfile = (char FAR*)MEM_ALLOC( 1 + STRLEN( vParam ) );
363
364 if( pdbc->tfile == NULL )
365 {
366 PUSHSQLERR( pdbc->herr, en_S1001 );
367
368 return SQL_ERROR;
369 }
370
371 STRCPY ( pdbc->tfile, vParam );
372
373 return SQL_SUCCESS;
374 }
375
376 if( pdbc->state != en_dbc_allocated )
377 {
378 /* If already connected, then, driver's odbc call
379 * will be invoked. Otherwise, we only save the options
380 * and delay the setting process until the connection
381 * been established.
382 */
383 hproc = _iodbcdm_getproc( hdbc, en_SetConnectOption );
384
385 if( hproc == SQL_NULL_HPROC )
386 {
387 PUSHSQLERR ( pdbc->herr, en_IM001 );
388
389 return SQL_ERROR;
390 }
391
392 CALL_DRIVER ( hdbc, retcode, hproc, en_SetConnectOption, (
393 pdbc->dhdbc, fOption, vParam ) )
1a6944fd
RR
394
395#if 0
7e616b10 396 retcode = hproc( pdbc->dhdbc, fOption, vParam);
1a6944fd
RR
397#endif
398
7e616b10
RR
399 if( retcode != SQL_SUCCESS
400 && retcode != SQL_SUCCESS_WITH_INFO )
401 {
402 return retcode;
403 }
404 }
405
406 /*
407 * Now, either driver's odbc call was successed or
408 * driver has not been loaded yet. In the first case, we
409 * need flip flag for(such as access_mode, autocommit, ...)
410 * for our finit state machine. While in the second case,
411 * we need save option values(such as current_qualifier, ...)
412 * for delaied setting. So, ...
413 */
414
415 /* No matter what state we are(i.e. allocated or connected, ..)
416 * we need to flip the flag.
417 */
418 switch( fOption )
419 {
420 case SQL_ACCESS_MODE:
421 pdbc->access_mode = vParam;
422 break;
423
424 case SQL_AUTOCOMMIT:
425 pdbc->autocommit = vParam;
426 break;
427 }
428
429 /* state transition */
430 if( pdbc->state != en_dbc_allocated )
431 {
432 return retcode;
433 }
434
435 /* Only 'allocated' state is possible here, and we need to
436 * save the options for delaied setting.
437 */
438 switch( fOption )
439 {
440 case SQL_CURRENT_QUALIFIER:
441 if( pdbc->current_qualifier != NULL )
442 {
443 MEM_FREE ( pdbc->current_qualifier );
444 }
445
446 if( vParam == 0UL )
447 {
448 pdbc->current_qualifier = NULL;
449
450 break;
451 }
452
453 pdbc->current_qualifier
454 = (char FAR*)MEM_ALLOC (
455 STRLEN (vParam) + 1 );
456
457 if( pdbc->current_qualifier == NULL )
458 {
459 PUSHSQLERR ( pdbc->herr, en_S1001 );
460 return SQL_ERROR;
461 }
462
463 STRCPY ( pdbc->current_qualifier, vParam );
464 break;
465
466 case SQL_LOGIN_TIMEOUT:
467 pdbc->login_timeout = vParam;
468 break;
469
470 case SQL_ODBC_CURSORS:
471 pdbc->odbc_cursors = vParam;
472 break;
473
474 case SQL_PACKET_SIZE:
475 pdbc->packet_size = vParam;
476 break;
477
478 case SQL_QUIET_MODE:
479 pdbc->quiet_mode = vParam;
480 break;
481
482 case SQL_TXN_ISOLATION:
483 pdbc->txn_isolation = vParam;
484 break;
485
486 default:
487 /* Since we didn't save the option value for delaied
488 * setting, we should raise an error here.
489 */
490 break;
491 }
492
493 return retcode;
1a6944fd
RR
494}
495
7e616b10
RR
496RETCODE SQL_API SQLGetConnectOption(
497 HDBC hdbc,
498 UWORD fOption,
499 PTR pvParam )
1a6944fd 500{
7e616b10
RR
501 GENV_t FAR* genv;
502 DBC_t FAR* pdbc = (DBC_t FAR*)hdbc;
503 int sqlstat = en_00000;
504 HPROC hproc = SQL_NULL_HPROC;
505 RETCODE retcode;
506
507 if( hdbc == SQL_NULL_HDBC )
508 {
509 return SQL_INVALID_HANDLE;
510 }
511
512 /* check option */
513 if( fOption < SQL_CONN_OPT_MIN
514 || ( fOption > SQL_CONN_OPT_MAX
515 && fOption < SQL_CONNECT_OPT_DRVR_START ) )
516 {
517 PUSHSQLERR ( pdbc->herr, en_S1092 );
518
519 return SQL_ERROR;
520 }
521
522 /* check state */
523 switch( pdbc->state )
524 {
525 case en_dbc_allocated:
526 if( fOption != SQL_ACCESS_MODE
527 && fOption != SQL_AUTOCOMMIT
528 && fOption != SQL_LOGIN_TIMEOUT
529 && fOption != SQL_OPT_TRACE
530 && fOption != SQL_OPT_TRACEFILE )
531 {
532 sqlstat = en_08003;
533 }
534 /* MS ODBC SDK document only
535 * allows SQL_ACCESS_MODE
536 * and SQL_AUTOCOMMIT in this
537 * dbc state. We allow another
538 * two options, because they
539 * are only meaningful for driver
540 * manager.
541 */
542 break;
543
544 case en_dbc_needdata:
545 sqlstat = en_S1010;
546 break;
547
548 default:
549 break;
550 }
551
552 if( sqlstat != en_00000 )
553 {
554 PUSHSQLERR ( pdbc->herr, sqlstat );
555
556 return SQL_ERROR;
557 }
558
559 /* Tracing and tracing file options are only
560 * meaningful for driver manager
561 */
562 if( fOption == SQL_OPT_TRACE )
563 {
564 if( pdbc->trace )
565 *((UDWORD*)pvParam) = (UDWORD)SQL_OPT_TRACE_ON;
566 else
567 *((UDWORD*)pvParam) = (UDWORD)SQL_OPT_TRACE_OFF;
568
569 return SQL_SUCCESS;
570 }
571
572 if( fOption == SQL_OPT_TRACEFILE )
573 {
574 STRCPY (pvParam, pdbc->tfile );
575
576 return SQL_ERROR;
577 }
578
579 if( pdbc->state != en_dbc_allocated )
580 /* if already connected, we will invoke driver's function */
581 {
582 hproc = _iodbcdm_getproc( hdbc, en_GetConnectOption );
583
584 if( hproc == SQL_NULL_HPROC )
585 {
586 PUSHSQLERR( pdbc->herr, en_IM001 );
587
588 return SQL_ERROR;
589 }
590
591 CALL_DRIVER ( hdbc, retcode, hproc, en_GetConnectOption, (
592 pdbc->dhdbc, fOption, pvParam ) )
1a6944fd
RR
593
594#if 0
7e616b10 595 retcode = hproc(pdbc->dhdbc, fOption, pvParam);
1a6944fd 596#endif
7e616b10
RR
597
598 return retcode;
599 }
600
601 /* We needn't to handle options which are not allowed
602 * to be *get* at a allocated dbc state(and two tracing
603 * options which has been handled and returned). Thus,
604 * there are only two possible cases.
605 */
606 switch( fOption )
607 {
608 case SQL_ACCESS_MODE:
609 *((UDWORD*)pvParam) = pdbc->access_mode;
610 break;
611
612 case SQL_AUTOCOMMIT:
613 *((UDWORD*)pvParam) = pdbc->autocommit;
614 break;
615
616 case SQL_LOGIN_TIMEOUT:
617 *((UDWORD*)pvParam) = pdbc->login_timeout;
618 break;
619
620 default:
621 break;
622 }
623
624 return SQL_SUCCESS;
1a6944fd
RR
625}
626
7e616b10
RR
627static RETCODE _iodbcdm_transact(
628 HDBC hdbc,
629 UWORD fType )
1a6944fd 630{
7e616b10
RR
631 DBC_t FAR* pdbc = (DBC_t FAR*)hdbc;
632 STMT_t FAR* pstmt;
633 HPROC hproc;
634 RETCODE retcode;
635
636 /* check state */
637 switch( pdbc->state )
638 {
639 case en_dbc_allocated:
640 case en_dbc_needdata:
641 PUSHSQLERR ( pdbc->herr, en_08003 );
642 return SQL_ERROR;
643
644 case en_dbc_connected:
645 return SQL_SUCCESS;
646
647 case en_dbc_hstmt:
648 default:
649 break;
650 }
651
652 for( pstmt = (STMT_t FAR*)(pdbc->hstmt);
653 pstmt != NULL;
654 pstmt = pstmt->next )
655 {
656 if( pstmt->state >= en_stmt_needdata
657 || pstmt->asyn_on != en_NullProc )
658 {
659 PUSHSQLERR ( pdbc->herr, en_S1010 );
660
661 return SQL_ERROR;
662 }
663 }
664
665 hproc = _iodbcdm_getproc( hdbc, en_Transact );
666
667 if( hproc == SQL_NULL_HPROC )
668 {
669 PUSHSQLERR ( pdbc->herr, en_IM001 );
670
671 return SQL_ERROR;
672 }
673
674 CALL_DRIVER ( hdbc, retcode, hproc, en_Transact, (
675 SQL_NULL_HENV, pdbc->dhdbc, fType ) )
1a6944fd
RR
676
677#if 0
7e616b10 678 retcode = hproc( SQL_NULL_HENV, pdbc->dhdbc, fType );
1a6944fd
RR
679#endif
680
7e616b10
RR
681 /* state transition */
682 if( retcode != SQL_SUCCESS
683 && retcode != SQL_SUCCESS_WITH_INFO )
684 {
685 return retcode;
686 }
687
688 pdbc->state = en_dbc_hstmt;
689
690 for( pstmt = (STMT_t FAR*)(pdbc->hstmt);
691 pstmt != NULL;
692 pstmt = pstmt->next )
693 {
694 switch( pstmt->state )
695 {
696 case en_stmt_prepared:
697 if( pdbc->cb_commit == SQL_CB_DELETE
698 || pdbc->cb_rollback == SQL_CB_DELETE )
699 {
700 pstmt->state = en_stmt_allocated;
701 pstmt->prep_state = 0;
702 break;
703 }
704 break;
705
706 case en_stmt_executed:
707 case en_stmt_cursoropen:
708 case en_stmt_fetched:
709 case en_stmt_xfetched:
710 if( ! pstmt->prep_state
711 && pdbc->cb_commit != SQL_CB_PRESERVE
712 && pdbc->cb_rollback != SQL_CB_PRESERVE )
713 {
714 pstmt->state = en_stmt_allocated;
715 pstmt->prep_state = 0;
716 pstmt->cursor_state = en_stmt_cursor_no;
717 break;
718 }
719
720 if( pstmt->prep_state )
721 {
722 if( pdbc->cb_commit == SQL_CB_DELETE
723 || pdbc->cb_rollback== SQL_CB_DELETE )
724 {
725 pstmt->state = en_stmt_allocated;
726 pstmt->prep_state = 0;
727 pstmt->cursor_state = en_stmt_cursor_no;
728 break;
729 }
730
731 if( pdbc->cb_commit == SQL_CB_CLOSE
732 || pdbc->cb_rollback== SQL_CB_CLOSE )
733 {
734 pstmt->state
735 = en_stmt_prepared;
736 pstmt->cursor_state
737 = en_stmt_cursor_no;
738 break;
739 }
740 break;
741 }
742 break;
743
744 default:
745 break;
746 }
747 }
748
749 return retcode;
1a6944fd
RR
750}
751
7e616b10
RR
752RETCODE SQL_API SQLTransact(
753 HENV henv,
754 HDBC hdbc,
755 UWORD fType )
1a6944fd 756{
7e616b10
RR
757 GENV_t FAR* genv = (GENV_t FAR*)henv;
758 DBC_t FAR* pdbc = (DBC_t FAR*)hdbc;
759 HERR herr;
760 RETCODE retcode;
761
762 if( hdbc != SQL_NULL_HDBC )
763 {
764 herr = pdbc->herr;
765 }
766 else if( henv != SQL_NULL_HENV )
767 {
768 herr = genv->herr;
769 }
770 else
771 {
772 return SQL_INVALID_HANDLE;
773 }
774
775 /* check argument */
776 if( fType != SQL_COMMIT
777 && fType != SQL_ROLLBACK )
778 {
779 PUSHSQLERR ( herr, en_S1012 );
780
781 return SQL_ERROR;
782 }
783
784 if( hdbc != SQL_NULL_HDBC )
785 {
786 retcode = _iodbcdm_transact( hdbc, fType );
787 }
788 else
789 {
790 for( pdbc = (DBC_t FAR*)(genv->hdbc);
791 pdbc != NULL;
792 pdbc = pdbc->next )
793 {
794 retcode |= _iodbcdm_transact( hdbc, fType );
795 }
796 }
797
798 if( retcode != SQL_SUCCESS
799 && retcode != SQL_SUCCESS_WITH_INFO )
800 {
801 /* fail on one of the connection */
802 return SQL_ERROR;
803 }
804
805 return retcode;
1a6944fd 806}