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