1/* 2 * hdbc.c 3 * 4 * $Id: hdbc.c 2613 1999-06-01 15:32:12Z VZ $ 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 42extern RETCODE _iodbcdm_driverunload(); 43 44 45RETCODE SQL_API 46SQLAllocConnect ( 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 117RETCODE SQL_API 118SQLFreeConnect (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 173RETCODE SQL_API 174SQLSetConnectOption ( 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 507RETCODE SQL_API 508SQLGetConnectOption ( 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 634static 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 756RETCODE SQL_API 757SQLTransact ( 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} 812