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