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