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 Ke Jin <kejin@empress.com>
11 * Copyright (C) 1996-2021 OpenLink Software <iodbc@openlinksw.com>
12 * All Rights Reserved.
13 *
14 * This software is released under the terms of either of the following
15 * licenses:
16 *
17 * - GNU Library General Public License (see LICENSE.LGPL)
18 * - The BSD License (see LICENSE.BSD).
19 *
20 * Note that the only valid version of the LGPL license as far as this
21 * project is concerned is the original GNU Library General Public License
22 * Version 2, dated June 1991.
23 *
24 * While not mandated by the BSD license, any patches you make to the
25 * iODBC source code may be contributed back into the iODBC project
26 * at your discretion. Contributions will benefit the Open Source and
27 * Data Access community as a whole. Submissions may be made at:
28 *
29 * http://www.iodbc.org
30 *
31 *
32 * GNU Library Generic Public License Version 2
33 * ============================================
34 * This library is free software; you can redistribute it and/or
35 * modify it under the terms of the GNU Library General Public
36 * License as published by the Free Software Foundation; only
37 * Version 2 of the License dated June 1991.
38 *
39 * This library is distributed in the hope that it will be useful,
40 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42 * Library General Public License for more details.
43 *
44 * You should have received a copy of the GNU Library General Public
45 * License along with this library; if not, write to the Free
46 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
47 *
48 *
49 * The BSD License
50 * ===============
51 * Redistribution and use in source and binary forms, with or without
52 * modification, are permitted provided that the following conditions
53 * are met:
54 *
55 * 1. Redistributions of source code must retain the above copyright
56 * notice, this list of conditions and the following disclaimer.
57 * 2. Redistributions in binary form must reproduce the above copyright
58 * notice, this list of conditions and the following disclaimer in
59 * the documentation and/or other materials provided with the
60 * distribution.
61 * 3. Neither the name of OpenLink Software Inc. nor the names of its
62 * contributors may be used to endorse or promote products derived
63 * from this software without specific prior written permission.
64 *
65 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
66 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
67 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
68 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
69 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
70 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
71 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
72 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
73 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
74 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
75 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
76 */
77
78
79 #include <iodbc.h>
80
81 #include <sql.h>
82 #include <sqlext.h>
83 #include <sqlucode.h>
84 #include <iodbcext.h>
85
86 #include "unicode.h"
87
88 #include "dlproc.h"
89
90 #include "herr.h"
91 #include "henv.h"
92 #include "hdbc.h"
93 #include "hstmt.h"
94
95 #include "itrace.h"
96 #include <stdio.h>
97
98
99 extern SQLRETURN _iodbcdm_driverunload (HDBC hdbc, int ver);
100
101 static SQLRETURN
_iodbcdm_drvopt_store(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLULEN vParam,SQLCHAR waMode)102 _iodbcdm_drvopt_store (SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam,
103 SQLCHAR waMode)
104 {
105 CONN (pdbc, hdbc);
106 DRVOPT *popt;
107
108 /*
109 * Check if this option is already registered
110 */
111 for (popt = pdbc->drvopt; popt != NULL; popt = popt->next)
112 {
113 if (popt->Option == fOption)
114 break;
115 }
116
117 /*
118 * New option
119 */
120 if (popt == NULL)
121 {
122 if ((popt = (DRVOPT *) MEM_ALLOC (sizeof (DRVOPT))) == NULL)
123 return SQL_ERROR;
124
125 popt->Option = fOption;
126 popt->next = pdbc->drvopt;
127 pdbc->drvopt = popt;
128 }
129
130 /*
131 * Store the value
132 */
133 popt->Param = vParam;
134 popt->waMode = waMode;
135
136 return SQL_SUCCESS;
137 }
138
139
140 static SQLRETURN
_iodbcdm_drvopt_free(SQLHDBC hdbc)141 _iodbcdm_drvopt_free (SQLHDBC hdbc)
142 {
143 CONN (pdbc, hdbc);
144 DRVOPT *popt;
145
146 popt = pdbc->drvopt;
147 while (popt != NULL)
148 {
149 DRVOPT *tmp = popt->next;
150 free (popt);
151 popt = tmp;
152 }
153 pdbc->drvopt = NULL;
154
155 return SQL_SUCCESS;
156 }
157
158
159 SQLRETURN
SQLAllocConnect_Internal(SQLHENV henv,SQLHDBC * phdbc)160 SQLAllocConnect_Internal (
161 SQLHENV henv,
162 SQLHDBC * phdbc)
163 {
164 GENV (genv, henv);
165 CONN (pdbc, NULL);
166
167 if (phdbc == NULL)
168 {
169 PUSHSQLERR (genv->herr, en_S1009);
170 return SQL_ERROR;
171 }
172
173 pdbc = (DBC_t *) MEM_ALLOC (sizeof (DBC_t));
174
175 if (pdbc == NULL)
176 {
177 *phdbc = SQL_NULL_HDBC;
178
179 PUSHSQLERR (genv->herr, en_S1001);
180 return SQL_ERROR;
181 }
182 pdbc->rc = 0;
183
184 /*
185 * Initialize this handle
186 */
187 pdbc->type = SQL_HANDLE_DBC;
188
189 /* insert this dbc entry into the link list */
190 pdbc->next = (DBC_t *) genv->hdbc;
191 genv->hdbc = pdbc;
192 #if (ODBCVER >= 0x0300)
193 if (genv->odbc_ver == 0)
194 genv->odbc_ver = SQL_OV_ODBC2;
195 pdbc->hdesc = NULL;
196
197 pdbc->cp_pdbc = NULL;
198 pdbc->cp_in_use = FALSE;
199 pdbc->cp_timeout = 0;
200 pdbc->cp_expiry_time = 0;
201 pdbc->cp_retry_wait = 0;
202 pdbc->cp_probe = NULL;
203 pdbc->cp_dsn = NULL;
204 pdbc->cp_uid = NULL;
205 pdbc->cp_pwd = NULL;
206 pdbc->cp_connstr = NULL;
207 #endif
208 pdbc->genv = genv;
209 pdbc->conv = genv->conv;
210
211 pdbc->henv = SQL_NULL_HENV;
212 pdbc->hstmt = SQL_NULL_HSTMT;
213 pdbc->herr = SQL_NULL_HERR;
214 pdbc->dhdbc = SQL_NULL_HDBC;
215 pdbc->state = en_dbc_allocated;
216 pdbc->drvopt = NULL;
217 pdbc->dbc_cip = 0;
218 pdbc->err_rec = 0;
219
220 /* set connect options to default values */
221 pdbc->access_mode = SQL_MODE_DEFAULT;
222 pdbc->autocommit = SQL_AUTOCOMMIT_DEFAULT;
223 pdbc->current_qualifier = NULL;
224 pdbc->login_timeout = 0UL;
225 pdbc->odbc_cursors = SQL_CUR_DEFAULT;
226 pdbc->packet_size = 0UL;
227 pdbc->quiet_mode = (UDWORD) NULL;
228 pdbc->txn_isolation = SQL_TXN_READ_UNCOMMITTED;
229 pdbc->cb_commit = (SWORD) SQL_CB_DELETE;
230 pdbc->cb_rollback = (SWORD) SQL_CB_DELETE;
231
232 *phdbc = (SQLHDBC) pdbc;
233
234 return SQL_SUCCESS;
235 }
236
237
238 SQLRETURN SQL_API
SQLAllocConnect(SQLHENV henv,SQLHDBC * phdbc)239 SQLAllocConnect (SQLHENV henv, SQLHDBC * phdbc)
240 {
241 GENV (genv, henv);
242 SQLRETURN retcode = SQL_SUCCESS;
243
244 ODBC_LOCK ();
245 if (!IS_VALID_HENV (genv))
246 {
247 ODBC_UNLOCK ();
248 return SQL_INVALID_HANDLE;
249 }
250 CLEAR_ERRORS (genv);
251
252 TRACE (trace_SQLAllocConnect (TRACE_ENTER, henv, phdbc));
253
254 retcode = SQLAllocConnect_Internal (henv, phdbc);
255
256 TRACE (trace_SQLAllocConnect (TRACE_LEAVE, henv, phdbc));
257
258 ODBC_UNLOCK ();
259
260 return SQL_SUCCESS;
261 }
262
263
264 SQLRETURN
SQLFreeConnect_Internal(SQLHDBC hdbc,int ver)265 SQLFreeConnect_Internal (SQLHDBC hdbc, int ver)
266 {
267 CONN (pdbc, hdbc);
268 GENV (genv, pdbc->genv);
269 CONN (tpdbc, NULL);
270
271 /* check state */
272 if (pdbc->state != en_dbc_allocated)
273 {
274 PUSHSQLERR (pdbc->herr, en_S1010);
275 return SQL_ERROR;
276 }
277
278 for (tpdbc = (DBC_t *) genv->hdbc; tpdbc != NULL; tpdbc = tpdbc->next)
279 {
280 if (pdbc == tpdbc)
281 {
282 genv->hdbc = pdbc->next;
283 break;
284 }
285
286 if (pdbc == tpdbc->next)
287 {
288 tpdbc->next = pdbc->next;
289 break;
290 }
291 }
292
293 /* free this dbc */
294 _iodbcdm_driverunload (pdbc, 3);
295
296 /* free driver connect options */
297 _iodbcdm_drvopt_free (pdbc);
298
299 /* free probe */
300 if (pdbc->cp_probe)
301 MEM_FREE (pdbc->cp_probe);
302
303 /*
304 * Invalidate this handle
305 */
306 pdbc->type = 0;
307
308 return SQL_SUCCESS;
309 }
310
311
312 SQLRETURN SQL_API
SQLFreeConnect(SQLHDBC hdbc)313 SQLFreeConnect (SQLHDBC hdbc)
314 {
315 ENTER_HDBC (hdbc, 1,
316 trace_SQLFreeConnect (TRACE_ENTER, hdbc));
317
318 retcode = SQLFreeConnect_Internal (hdbc, 2);
319
320 LEAVE_HDBC (hdbc, 1,
321 trace_SQLFreeConnect (TRACE_LEAVE, hdbc);
322 MEM_FREE(hdbc);
323 );
324 }
325
326
327 SQLRETURN
_iodbcdm_SetConnectOption(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLULEN vParam,SQLCHAR waMode)328 _iodbcdm_SetConnectOption (
329 SQLHDBC hdbc,
330 SQLUSMALLINT fOption,
331 SQLULEN vParam,
332 SQLCHAR waMode)
333 {
334 CONN (pdbc, hdbc);
335 ENVR (penv, pdbc->henv);
336 STMT (pstmt, NULL);
337 HPROC hproc2 = SQL_NULL_HPROC;
338 HPROC hproc3 = SQL_NULL_HPROC;
339 sqlstcode_t sqlstat = en_00000;
340 SQLRETURN retcode = SQL_SUCCESS;
341 SQLUINTEGER odbc_ver;
342 SQLUINTEGER dodbc_ver;
343 CONV_DIRECT conv_direct = CD_NONE;
344 DM_CONV *conv = &pdbc->conv;
345
346 odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
347 dodbc_ver = (penv != SQL_NULL_HENV) ? penv->dodbc_ver : odbc_ver;
348
349 #if (ODBCVER < 0x0300)
350 /* check option */
351 if (fOption < SQL_CONN_OPT_MIN ||
352 (fOption > SQL_CONN_OPT_MAX && fOption < SQL_CONNECT_OPT_DRVR_START))
353 {
354 PUSHSQLERR (pdbc->herr, en_S1092);
355
356 return SQL_ERROR;
357 }
358 #endif
359
360 /* check state of connection handle */
361 switch (pdbc->state)
362 {
363 case en_dbc_allocated:
364 if (fOption == SQL_TRANSLATE_DLL || fOption == SQL_TRANSLATE_OPTION)
365 {
366 /* This two options are only meaningful
367 * for specified driver. So, has to be
368 * set after a driver has been loaded.
369 */
370 sqlstat = en_08003;
371 break;
372 }
373
374 /*
375 * An option only meaningful for the driver is passed before the
376 * driver was actually loaded. We save it here and pass it onto
377 * the driver at a later stage.
378 */
379 if (fOption >= SQL_CONNECT_OPT_DRVR_START && pdbc->henv == SQL_NULL_HENV)
380 _iodbcdm_drvopt_store (hdbc, fOption, vParam, waMode);
381
382 break;
383
384 case en_dbc_needdata:
385 sqlstat = en_S1010;
386 break;
387
388 case en_dbc_connected:
389 case en_dbc_hstmt:
390 if (fOption == SQL_ODBC_CURSORS)
391 {
392 sqlstat = en_08002;
393 }
394 break;
395
396 default:
397 break;
398 }
399
400 /* check state of statement handle(s) */
401 for (pstmt = (STMT_t *) pdbc->hstmt;
402 pstmt != NULL && sqlstat == en_00000;
403 pstmt = (STMT_t *) pstmt->next)
404 {
405 if (pstmt->state >= en_stmt_needdata || pstmt->asyn_on != en_NullProc)
406 {
407 sqlstat = en_S1010;
408 }
409 }
410
411 if (sqlstat != en_00000)
412 {
413 PUSHSQLERR (pdbc->herr, sqlstat);
414
415 return SQL_ERROR;
416 }
417
418 #if (ODBCVER >= 0x0300)
419 if (fOption == SQL_OPT_TRACE || fOption == SQL_ATTR_TRACE)
420 #else
421 if (fOption == SQL_OPT_TRACE)
422 #endif
423 /* tracing flag can be set before and after connect
424 * and only meaningful for driver manager(actually
425 * there is only one tracing file under one global
426 * environment).
427 */
428 {
429 switch ((SQLUINTEGER)vParam)
430 {
431 case SQL_OPT_TRACE_ON:
432 trace_start ();
433 break;
434
435 case SQL_OPT_TRACE_OFF:
436 trace_stop ();
437 break;
438
439 default:
440 PUSHSQLERR (pdbc->herr, en_HY024);
441 return SQL_ERROR;
442 }
443
444 if (sqlstat != en_00000)
445 {
446 PUSHSQLERR (pdbc->herr, sqlstat);
447 }
448
449 return retcode;
450 }
451
452 #if (ODBCVER >= 0x0300)
453 if (fOption == SQL_OPT_TRACEFILE || fOption == SQL_ATTR_TRACEFILE)
454 #else
455 if (fOption == SQL_OPT_TRACEFILE)
456 #endif
457 /* Tracing file can be set before and after connect
458 * and only meaningful for driver manager.
459 */
460 {
461 SQLCHAR *_vParam;
462 SQLCHAR *tmp = NULL;
463
464 if (((char *)vParam) == NULL
465 || (waMode != 'W' && ((char *) vParam)[0] == '\0')
466 || (waMode == 'W' && DM_GetWCharAt(conv, (void *)vParam, 0) == L'\0' ))
467 {
468 PUSHSQLERR (pdbc->herr, en_S1009);
469 return SQL_ERROR;
470 }
471
472 _vParam = (SQLCHAR *)vParam;
473 if (waMode == 'W')
474 {
475 if ((_vParam = tmp = DM_WtoU8(conv, (void *)vParam, SQL_NTS)) == NULL)
476 {
477 PUSHSQLERR (pdbc->herr, en_S1001);
478 return SQL_ERROR;
479 }
480 }
481
482 if (ODBCSharedTraceFlag)
483 {
484 PUSHSQLERR (pdbc->herr, en_IM013);
485 return SQL_ERROR;
486 }
487
488 trace_set_filename ((char *) _vParam);
489 MEM_FREE (tmp);
490 return SQL_SUCCESS;
491 }
492
493 if (pdbc->state != en_dbc_allocated)
494 {
495 /* If already connected, then, driver's odbc call
496 * will be invoked. Otherwise, we only save the options
497 * and delay the setting process until the connection
498 * been established.
499 */
500 void * _vParam = NULL;
501
502 if (penv->unicode_driver && waMode != 'W')
503 conv_direct = CD_A2W;
504 else if (!penv->unicode_driver && waMode == 'W')
505 conv_direct = CD_W2A;
506 else if (waMode == 'W' && conv->dm_cp!=conv->drv_cp)
507 conv_direct = CD_W2W;
508
509 switch (fOption)
510 {
511 case SQL_ATTR_TRACEFILE:
512 case SQL_CURRENT_QUALIFIER:
513 case SQL_TRANSLATE_DLL:
514 case SQL_APPLICATION_NAME:
515 case SQL_COPT_SS_ENLIST_IN_DTC:
516 case SQL_COPT_SS_PERF_QUERY_LOG:
517 case SQL_COPT_SS_PERF_DATA_LOG:
518 case SQL_CURRENT_SCHEMA:
519 if (conv_direct != CD_NONE)
520 {
521 _vParam = conv_text_m2d (conv, (void *)vParam, SQL_NTS, conv_direct);
522 vParam = (SQLULEN)_vParam;
523 }
524 break;
525 }
526
527 if (penv->unicode_driver)
528 {
529 /* SQL_XXX_W */
530 #if (ODBCVER >= 0x0300)
531 hproc3 = _iodbcdm_getproc (pdbc, en_SetConnectAttrW);
532 #endif
533 hproc2 = _iodbcdm_getproc (pdbc, en_SetConnectOptionW);
534 }
535 else
536 {
537 /* SQL_XXX */
538 /* SQL_XXX_A */
539 #if (ODBCVER >= 0x0300)
540 hproc3 = _iodbcdm_getproc (pdbc, en_SetConnectAttr);
541 if (hproc3 == SQL_NULL_HPROC)
542 hproc3 = _iodbcdm_getproc (pdbc, en_SetConnectAttrA);
543 #endif
544 hproc2 = _iodbcdm_getproc (pdbc, en_SetConnectOption);
545 if (hproc2 == SQL_NULL_HPROC)
546 hproc2 = _iodbcdm_getproc (pdbc, en_SetConnectOptionA);
547 }
548
549 if (odbc_ver == SQL_OV_ODBC2 && (dodbc_ver == SQL_OV_ODBC2
550 || (dodbc_ver == SQL_OV_ODBC3 && hproc2 != SQL_NULL_HPROC)))
551 hproc3 = SQL_NULL_HPROC;
552
553 #if (ODBCVER >= 0x0300)
554 if (hproc3 != SQL_NULL_HPROC)
555 {
556 switch (fOption)
557 {
558 /* integer attributes */
559 case SQL_ATTR_ACCESS_MODE:
560 case SQL_ATTR_AUTOCOMMIT:
561 case SQL_ATTR_LOGIN_TIMEOUT:
562 case SQL_ATTR_ODBC_CURSORS:
563 case SQL_ATTR_PACKET_SIZE:
564 case SQL_ATTR_QUIET_MODE:
565 case SQL_ATTR_TRANSLATE_OPTION:
566 case SQL_ATTR_TXN_ISOLATION:
567 CALL_DRIVER (hdbc, pdbc, retcode, hproc3,
568 (pdbc->dhdbc, fOption, vParam, 0));
569 break;
570
571 /* ODBC3 defined options */
572 case SQL_ATTR_ASYNC_ENABLE:
573 case SQL_ATTR_AUTO_IPD:
574 case SQL_ATTR_CONNECTION_DEAD:
575 case SQL_ATTR_CONNECTION_TIMEOUT:
576 case SQL_ATTR_METADATA_ID:
577 PUSHSQLERR (pdbc->herr, en_IM001);
578 MEM_FREE(_vParam);
579 return SQL_ERROR;
580
581 default: /* string & driver defined */
582
583 CALL_DRIVER (hdbc, pdbc, retcode, hproc3,
584 (pdbc->dhdbc, fOption, vParam, SQL_NTS));
585 }
586 }
587 else
588 #endif
589 {
590 if (hproc2 == SQL_NULL_HPROC)
591 {
592 PUSHSQLERR (pdbc->herr, en_IM001);
593 MEM_FREE(_vParam);
594 return SQL_ERROR;
595 }
596
597 CALL_DRIVER (hdbc, pdbc, retcode, hproc2,
598 (pdbc->dhdbc, fOption, vParam));
599 }
600
601 MEM_FREE(_vParam);
602 if (!SQL_SUCCEEDED (retcode))
603 {
604 return retcode;
605 }
606 }
607
608 /*
609 * Now, either driver's odbc call was successful or
610 * driver has not been loaded yet. In the first case, we
611 * need flip flag for(such as access_mode, autocommit, ...)
612 * for our finit state machine. While in the second case,
613 * we need save option values(such as current_qualifier, ...)
614 * for delayed setting. So, ...
615 */
616
617 /* No matter what state we are(i.e. allocated or connected, ..)
618 * we need to flip the flag.
619 */
620 switch (fOption)
621 {
622 case SQL_ACCESS_MODE:
623 pdbc->access_mode = vParam;
624 break;
625
626 case SQL_AUTOCOMMIT:
627 pdbc->autocommit = vParam;
628 break;
629 }
630
631 /* state transition */
632 if (pdbc->state != en_dbc_allocated)
633 {
634 return retcode;
635 }
636
637 /* Only 'allocated' state is possible here, and we need to
638 * save the options for delayed setting.
639 */
640 switch (fOption)
641 {
642 case SQL_CURRENT_QUALIFIER:
643 if (pdbc->current_qualifier != NULL)
644 {
645 MEM_FREE (pdbc->current_qualifier);
646 }
647
648 if (vParam == 0UL)
649 {
650 pdbc->current_qualifier = NULL;
651 break;
652 }
653
654 if (waMode != 'W')
655 pdbc->current_qualifier = (wchar_t *) MEM_ALLOC (STRLEN (vParam) + 1);
656 else
657 pdbc->current_qualifier = (wchar_t *) MEM_ALLOC((DM_WCSLEN (conv, (void *)vParam) + 1)
658 * DM_WCHARSIZE(conv));
659
660 if (pdbc->current_qualifier == NULL)
661 {
662 PUSHSQLERR (pdbc->herr, en_S1001);
663 return SQL_ERROR;
664 }
665
666 if (waMode != 'W')
667 STRCPY ((char *)pdbc->current_qualifier, vParam);
668 else
669 DM_WCSCPY (conv, pdbc->current_qualifier, (void *)vParam);
670
671 pdbc->current_qualifier_WA = waMode;
672 break;
673
674 case SQL_LOGIN_TIMEOUT:
675 pdbc->login_timeout = vParam;
676 break;
677
678 case SQL_ODBC_CURSORS:
679 pdbc->odbc_cursors = vParam;
680 break;
681
682 case SQL_PACKET_SIZE:
683 pdbc->packet_size = vParam;
684 break;
685
686 case SQL_QUIET_MODE:
687 pdbc->quiet_mode = vParam;
688 break;
689
690 case SQL_TXN_ISOLATION:
691 pdbc->txn_isolation = vParam;
692 break;
693
694 default:
695 /* Since we didn't save the option value for delayed
696 * setting, we should raise an error here.
697 */
698 break;
699 }
700
701 return retcode;
702 }
703
704
705 SQLRETURN SQL_API
SQLSetConnectOption(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLULEN vParam)706 SQLSetConnectOption (
707 SQLHDBC hdbc,
708 SQLUSMALLINT fOption,
709 SQLULEN vParam)
710 {
711 ENTER_HDBC (hdbc, 0,
712 trace_SQLSetConnectOption (TRACE_ENTER, hdbc, fOption, vParam));
713
714 retcode = _iodbcdm_SetConnectOption (hdbc, fOption, vParam, 'A');
715
716 LEAVE_HDBC (hdbc, 0,
717 trace_SQLSetConnectOption (TRACE_LEAVE, hdbc, fOption, vParam));
718 }
719
720
721 #if ODBCVER >= 0x0300
722 SQLRETURN SQL_API
SQLSetConnectOptionA(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLULEN vParam)723 SQLSetConnectOptionA (
724 SQLHDBC hdbc,
725 SQLUSMALLINT fOption,
726 SQLULEN vParam)
727 {
728 ENTER_HDBC (hdbc, 0,
729 trace_SQLSetConnectOption (TRACE_ENTER, hdbc, fOption, vParam));
730
731 retcode = _iodbcdm_SetConnectOption (hdbc, fOption, vParam, 'A');
732
733 LEAVE_HDBC (hdbc, 0,
734 trace_SQLSetConnectOption (TRACE_LEAVE, hdbc, fOption, vParam));
735 }
736
737
738 SQLRETURN SQL_API
SQLSetConnectOptionW(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLULEN vParam)739 SQLSetConnectOptionW (
740 SQLHDBC hdbc,
741 SQLUSMALLINT fOption,
742 SQLULEN vParam)
743 {
744 ENTER_HDBC (hdbc, 0,
745 trace_SQLSetConnectOptionW (TRACE_ENTER, hdbc, fOption, vParam));
746
747 retcode = _iodbcdm_SetConnectOption (hdbc, fOption, vParam, 'W');
748
749 LEAVE_HDBC (hdbc, 0,
750 trace_SQLSetConnectOptionW (TRACE_LEAVE, hdbc, fOption, vParam));
751 }
752 #endif
753
754
755 SQLRETURN SQL_API
_iodbcdm_GetConnectOption(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLPOINTER pvParam,SQLCHAR waMode)756 _iodbcdm_GetConnectOption (
757 SQLHDBC hdbc,
758 SQLUSMALLINT fOption,
759 SQLPOINTER pvParam,
760 SQLCHAR waMode)
761 {
762 CONN (pdbc, hdbc);
763 ENVR (penv, pdbc->henv);
764 HPROC hproc2 = SQL_NULL_HPROC;
765 HPROC hproc3 = SQL_NULL_HPROC;
766 sqlstcode_t sqlstat = en_00000;
767 SQLRETURN retcode = SQL_SUCCESS;
768 SQLUINTEGER odbc_ver;
769 SQLUINTEGER dodbc_ver;
770 CONV_DIRECT conv_direct = CD_NONE;
771 DM_CONV *conv = &pdbc->conv;
772
773 odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
774 dodbc_ver = (penv != SQL_NULL_HENV) ? penv->dodbc_ver : odbc_ver;
775
776 #if (ODBCVER < 0x0300)
777 /* check option */
778 if (fOption < SQL_CONN_OPT_MIN ||
779 (fOption > SQL_CONN_OPT_MAX && fOption < SQL_CONNECT_OPT_DRVR_START))
780 {
781 PUSHSQLERR (pdbc->herr, en_S1092);
782
783 return SQL_ERROR;
784 }
785 #endif
786
787 if (penv != SQL_NULL_HENV)
788 {
789 if (penv->unicode_driver && waMode != 'W')
790 conv_direct = CD_A2W;
791 else if (!penv->unicode_driver && waMode == 'W')
792 conv_direct = CD_W2A;
793 else if (waMode == 'W' && conv->dm_cp != conv->drv_cp)
794 conv_direct = CD_W2W;
795 }
796
797 /* check state */
798 switch (pdbc->state)
799 {
800 case en_dbc_allocated:
801 if (fOption != SQL_ACCESS_MODE
802 && fOption != SQL_AUTOCOMMIT
803 && fOption != SQL_LOGIN_TIMEOUT
804 && fOption != SQL_OPT_TRACE
805 && fOption != SQL_OPT_TRACEFILE)
806 {
807 sqlstat = en_08003;
808 }
809 /* MS ODBC SDK document only
810 * allows SQL_ACCESS_MODE
811 * and SQL_AUTOCOMMIT in this
812 * dbc state. We allow another
813 * two options, because they
814 * are only meaningful for driver
815 * manager.
816 */
817 break;
818
819 case en_dbc_needdata:
820 sqlstat = en_S1010;
821 break;
822
823 default:
824 break;
825 }
826
827 if (sqlstat != en_00000)
828 {
829 PUSHSQLERR (pdbc->herr, sqlstat);
830 return SQL_ERROR;
831 }
832
833 /* Tracing and tracing file options are only
834 * meaningful for driver manager
835 */
836 #if (ODBCVER >= 0x0300)
837 if (fOption == SQL_OPT_TRACE || fOption == SQL_ATTR_TRACE)
838 #else
839 if (fOption == SQL_OPT_TRACE)
840 #endif
841 {
842 if (ODBCSharedTraceFlag)
843 *((UDWORD *) pvParam) = (UDWORD) SQL_OPT_TRACE_ON;
844 else
845 *((UDWORD *) pvParam) = (UDWORD) SQL_OPT_TRACE_OFF;
846
847 return SQL_SUCCESS;
848 }
849
850 #if (ODBCVER >= 0x0300)
851 if (fOption == SQL_OPT_TRACEFILE || fOption == SQL_ATTR_TRACEFILE)
852 #else
853 if (fOption == SQL_OPT_TRACEFILE)
854 #endif
855 {
856 char *fname;
857
858 fname = trace_get_filename (); /* UTF8 format */
859
860 if (waMode != 'W')
861 {
862 STRCPY (pvParam, fname);
863 }
864 else
865 {
866 DM_strcpy_U8toW (conv, pvParam, (SQLCHAR *)fname);
867 }
868
869 free (fname);
870
871 return SQL_SUCCESS;
872 }
873
874 if (pdbc->state != en_dbc_allocated)
875 /* if already connected, we will invoke driver's function */
876 {
877
878 void * _Param = NULL;
879 void * paramOut = pvParam;
880
881 switch (fOption)
882 {
883 case SQL_CURRENT_QUALIFIER:
884 case SQL_TRANSLATE_DLL:
885
886 if (conv_direct != CD_NONE)
887 {
888 if ((_Param = malloc(SQL_MAX_OPTION_STRING_LENGTH * WCHAR_MAXSIZE)) == NULL)
889 {
890 PUSHSQLERR (pdbc->herr, en_HY001);
891 return SQL_ERROR;
892 }
893 paramOut = _Param;
894 }
895 break;
896 }
897
898
899 if (penv->unicode_driver)
900 {
901 /* SQL_XXX_W */
902 #if (ODBCVER >= 0x0300)
903 hproc3 = _iodbcdm_getproc (pdbc, en_GetConnectAttrW);
904 #endif
905 hproc2 = _iodbcdm_getproc (pdbc, en_GetConnectOptionW);
906 }
907 else
908 {
909 /* SQL_XXX */
910 /* SQL_XXX_A */
911 #if (ODBCVER >= 0x0300)
912 hproc3 = _iodbcdm_getproc (pdbc, en_GetConnectAttr);
913 if (hproc3 == SQL_NULL_HPROC)
914 hproc3 = _iodbcdm_getproc (pdbc, en_GetConnectAttrA);
915 #endif
916 hproc2 = _iodbcdm_getproc (pdbc, en_GetConnectOption);
917 if (hproc2 == SQL_NULL_HPROC)
918 hproc2 = _iodbcdm_getproc (pdbc, en_GetConnectOptionA);
919 }
920
921 if (odbc_ver == SQL_OV_ODBC2 && (dodbc_ver == SQL_OV_ODBC2
922 || (dodbc_ver == SQL_OV_ODBC3 && hproc2 != SQL_NULL_HPROC)))
923 hproc3 = SQL_NULL_HPROC;
924
925 #if (ODBCVER >= 0x0300)
926 if (hproc3 != SQL_NULL_HPROC)
927 {
928 switch (fOption)
929 {
930 /* integer attributes */
931 case SQL_ATTR_ACCESS_MODE:
932 case SQL_ATTR_AUTOCOMMIT:
933 case SQL_ATTR_LOGIN_TIMEOUT:
934 case SQL_ATTR_ODBC_CURSORS:
935 case SQL_ATTR_PACKET_SIZE:
936 case SQL_ATTR_QUIET_MODE:
937 case SQL_ATTR_TRANSLATE_OPTION:
938 case SQL_ATTR_TXN_ISOLATION:
939 CALL_DRIVER (hdbc, pdbc, retcode, hproc3,
940 (pdbc->dhdbc, fOption, paramOut, 0, NULL));
941 break;
942
943 /* ODBC3 defined options */
944 case SQL_ATTR_ASYNC_ENABLE:
945 case SQL_ATTR_AUTO_IPD:
946 case SQL_ATTR_CONNECTION_DEAD:
947 case SQL_ATTR_CONNECTION_TIMEOUT:
948 case SQL_ATTR_METADATA_ID:
949 PUSHSQLERR (pdbc->herr, en_IM001);
950 MEM_FREE(_Param);
951 return SQL_ERROR;
952
953 default: /* string & driver defined */
954
955 CALL_DRIVER (hdbc, pdbc, retcode, hproc3,
956 (pdbc->dhdbc, fOption, paramOut, SQL_MAX_OPTION_STRING_LENGTH, NULL));
957
958 }
959 }
960 else
961 #endif
962 {
963 if (hproc2 == SQL_NULL_HPROC)
964 {
965 PUSHSQLERR (pdbc->herr, en_IM001);
966 MEM_FREE(_Param);
967 return SQL_ERROR;
968 }
969
970 CALL_DRIVER (hdbc, pdbc, retcode, hproc2,
971 (pdbc->dhdbc, fOption, paramOut));
972 }
973
974
975 if (pvParam && conv_direct != CD_NONE && SQL_SUCCEEDED (retcode))
976 {
977 size_t sizeMax = SQL_MAX_OPTION_STRING_LENGTH;
978 if (conv->dm_cp != CP_UTF8)
979 sizeMax *= DM_WCHARSIZE(conv);
980
981 switch (fOption)
982 {
983 case SQL_ATTR_TRACEFILE:
984 case SQL_CURRENT_QUALIFIER:
985 case SQL_TRANSLATE_DLL:
986 if (conv_direct == CD_A2W)
987 {
988 /* ansi<=unicode*/
989 dm_StrCopyOut2_W2A_d2m (conv, paramOut, (SQLCHAR *)pvParam,
990 SQL_MAX_OPTION_STRING_LENGTH, NULL, NULL);
991 }
992 else if (conv_direct == CD_W2A)
993 {
994 /* unicode<=ansi*/
995 dm_StrCopyOut2_A2W_d2m (conv, (SQLCHAR *)paramOut, pvParam,
996 sizeMax, NULL, NULL);
997 }
998 else if (conv_direct == CD_W2W)
999 {
1000 /* unicode<=unicode*/
1001 dm_StrCopyOut2_W2W_d2m (conv, paramOut, pvParam,
1002 sizeMax, NULL, NULL);
1003 }
1004 break;
1005 }
1006 }
1007
1008 MEM_FREE(_Param);
1009 return retcode;
1010 }
1011
1012 /* We needn't to handle options which are not allowed
1013 * to be *get* at a allocated dbc state(and two tracing
1014 * options which has been handled and returned). Thus,
1015 * there are only two possible cases.
1016 */
1017 switch (fOption)
1018 {
1019 case SQL_ACCESS_MODE:
1020 *((UDWORD *) pvParam) = pdbc->access_mode;
1021 break;
1022
1023 case SQL_AUTOCOMMIT:
1024 *((UDWORD *) pvParam) = pdbc->autocommit;
1025 break;
1026
1027 case SQL_LOGIN_TIMEOUT:
1028 *((UDWORD *) pvParam) = pdbc->login_timeout;
1029 break;
1030
1031 default:
1032 break;
1033 }
1034
1035 return SQL_SUCCESS;
1036 }
1037
1038
1039 SQLRETURN SQL_API
SQLGetConnectOption(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLPOINTER pvParam)1040 SQLGetConnectOption (SQLHDBC hdbc,
1041 SQLUSMALLINT fOption,
1042 SQLPOINTER pvParam)
1043 {
1044 ENTER_HDBC (hdbc, 0,
1045 trace_SQLGetConnectOption (TRACE_ENTER, hdbc, fOption, pvParam));
1046
1047 retcode = _iodbcdm_GetConnectOption (hdbc, fOption, pvParam, 'A');
1048
1049 LEAVE_HDBC (hdbc, 0,
1050 trace_SQLGetConnectOption (TRACE_LEAVE, hdbc, fOption, pvParam));
1051 }
1052
1053
1054 #if ODBCVER >= 0x0300
1055 SQLRETURN SQL_API
SQLGetConnectOptionA(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLPOINTER pvParam)1056 SQLGetConnectOptionA (
1057 SQLHDBC hdbc,
1058 SQLUSMALLINT fOption,
1059 SQLPOINTER pvParam)
1060 {
1061 ENTER_HDBC (hdbc, 0,
1062 trace_SQLGetConnectOption (TRACE_ENTER, hdbc, fOption, pvParam));
1063
1064 retcode = _iodbcdm_GetConnectOption (hdbc, fOption, pvParam, 'A');
1065
1066 LEAVE_HDBC (hdbc, 0,
1067 trace_SQLGetConnectOption (TRACE_LEAVE, hdbc, fOption, pvParam));
1068 }
1069
1070
1071 SQLRETURN SQL_API
SQLGetConnectOptionW(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLPOINTER pvParam)1072 SQLGetConnectOptionW (
1073 SQLHDBC hdbc,
1074 SQLUSMALLINT fOption,
1075 SQLPOINTER pvParam)
1076 {
1077 ENTER_HDBC (hdbc, 0,
1078 trace_SQLGetConnectOptionW (TRACE_ENTER, hdbc, fOption, pvParam));
1079
1080 retcode = _iodbcdm_GetConnectOption (hdbc, fOption, pvParam, 'W');
1081
1082 LEAVE_HDBC (hdbc, 0,
1083 trace_SQLGetConnectOptionW (TRACE_LEAVE, hdbc, fOption, pvParam));
1084 }
1085 #endif
1086
1087
1088 static SQLRETURN
_iodbcdm_transact(HDBC hdbc,UWORD fType)1089 _iodbcdm_transact (
1090 HDBC hdbc,
1091 UWORD fType)
1092 {
1093 CONN (pdbc, hdbc);
1094 ENVR (penv, pdbc->henv);
1095 STMT (pstmt, NULL);
1096 HPROC hproc2 = SQL_NULL_HPROC;
1097 HPROC hproc3 = SQL_NULL_HPROC;
1098 SQLRETURN retcode;
1099 SQLUINTEGER odbc_ver;
1100 SQLUINTEGER dodbc_ver;
1101
1102 odbc_ver = ((GENV_t *) pdbc->genv)->odbc_ver;
1103 dodbc_ver = (penv != SQL_NULL_HENV) ? penv->dodbc_ver : odbc_ver;
1104
1105 /* check state */
1106 switch (pdbc->state)
1107 {
1108 case en_dbc_allocated:
1109 case en_dbc_needdata:
1110 PUSHSQLERR (pdbc->herr, en_08003);
1111 return SQL_ERROR;
1112
1113 case en_dbc_connected:
1114 return SQL_SUCCESS;
1115
1116 case en_dbc_hstmt:
1117 default:
1118 break;
1119 }
1120
1121 for (pstmt = (STMT_t *) (pdbc->hstmt); pstmt != NULL; pstmt = pstmt->next)
1122 {
1123 if (pstmt->state >= en_stmt_needdata || pstmt->asyn_on != en_NullProc)
1124 {
1125 PUSHSQLERR (pdbc->herr, en_S1010);
1126
1127 return SQL_ERROR;
1128 }
1129 }
1130
1131
1132 hproc2 = _iodbcdm_getproc (pdbc, en_Transact);
1133 #if (ODBCVER >= 0x300)
1134 hproc3 = _iodbcdm_getproc (pdbc, en_EndTran);
1135 #endif
1136
1137 if (odbc_ver == SQL_OV_ODBC2 &&
1138 (dodbc_ver == SQL_OV_ODBC2
1139 || (dodbc_ver == SQL_OV_ODBC3 && hproc2 != SQL_NULL_HPROC)))
1140 hproc3 = SQL_NULL_HPROC;
1141
1142
1143 #if (ODBCVER >= 0x300)
1144 if (hproc3 != SQL_NULL_HPROC)
1145 {
1146 CALL_DRIVER (hdbc, pdbc, retcode, hproc3,
1147 (SQL_HANDLE_DBC, pdbc->dhdbc, fType));
1148 }
1149 else
1150 #endif
1151 {
1152 if (hproc2 == SQL_NULL_HPROC)
1153 {
1154 PUSHSQLERR (pdbc->herr, en_IM001);
1155 return SQL_ERROR;
1156 }
1157 CALL_DRIVER (hdbc, pdbc, retcode, hproc2,
1158 (SQL_NULL_HENV, pdbc->dhdbc, fType));
1159 }
1160
1161
1162 /* state transition */
1163 if (!SQL_SUCCEEDED (retcode))
1164 {
1165 return retcode;
1166 }
1167
1168 pdbc->state = en_dbc_hstmt;
1169
1170 for (pstmt = (STMT_t *) (pdbc->hstmt); pstmt != NULL; pstmt = pstmt->next)
1171 {
1172 switch (pstmt->state)
1173 {
1174 case en_stmt_prepared:
1175 if (pdbc->cb_commit == SQL_CB_DELETE
1176 || pdbc->cb_rollback == SQL_CB_DELETE)
1177 {
1178 pstmt->state = en_stmt_allocated;
1179 pstmt->prep_state = 0;
1180 break;
1181 }
1182 break;
1183
1184 case en_stmt_executed_with_info:
1185 case en_stmt_executed:
1186 case en_stmt_cursoropen:
1187 case en_stmt_fetched:
1188 case en_stmt_xfetched:
1189 if (!pstmt->prep_state
1190 && pdbc->cb_commit != SQL_CB_PRESERVE
1191 && pdbc->cb_rollback != SQL_CB_PRESERVE)
1192 {
1193 pstmt->state = en_stmt_allocated;
1194 pstmt->prep_state = 0;
1195 pstmt->cursor_state = en_stmt_cursor_no;
1196 break;
1197 }
1198
1199 if (pstmt->prep_state)
1200 {
1201 if (pdbc->cb_commit == SQL_CB_DELETE
1202 || pdbc->cb_rollback == SQL_CB_DELETE)
1203 {
1204 pstmt->state = en_stmt_allocated;
1205 pstmt->prep_state = 0;
1206 pstmt->cursor_state = en_stmt_cursor_no;
1207 break;
1208 }
1209
1210 if (pdbc->cb_commit == SQL_CB_CLOSE
1211 || pdbc->cb_rollback == SQL_CB_CLOSE)
1212 {
1213 pstmt->state = en_stmt_prepared;
1214 pstmt->cursor_state = en_stmt_cursor_no;
1215 break;
1216 }
1217 break;
1218 }
1219 break;
1220
1221 default:
1222 break;
1223 }
1224 }
1225
1226 return retcode;
1227 }
1228
1229
1230 SQLRETURN
SQLTransact_Internal(SQLHENV henv,SQLHDBC hdbc,SQLUSMALLINT fType)1231 SQLTransact_Internal (
1232 SQLHENV henv,
1233 SQLHDBC hdbc,
1234 SQLUSMALLINT fType)
1235 {
1236 GENV (genv, henv);
1237 CONN (pdbc, hdbc);
1238 HERR herr;
1239 SQLRETURN retcode = SQL_SUCCESS;
1240
1241 if (IS_VALID_HDBC (pdbc))
1242 {
1243 CLEAR_ERRORS (pdbc);
1244 herr = pdbc->herr;
1245 }
1246 else if (IS_VALID_HENV (genv))
1247 {
1248 CLEAR_ERRORS (genv);
1249 herr = genv->herr;
1250 }
1251 else
1252 {
1253 return SQL_INVALID_HANDLE;
1254 }
1255
1256 /* check argument */
1257 if (fType != SQL_COMMIT && fType != SQL_ROLLBACK)
1258 {
1259 /* SQLHENV handle = IS_VALID_HDBC (pdbc) ? ((SQLHENV) pdbc) : genv;*/
1260 PUSHSQLERR (herr, en_S1012);
1261 return SQL_ERROR;
1262 }
1263
1264 if (hdbc != SQL_NULL_HDBC)
1265 {
1266 retcode = _iodbcdm_transact (pdbc, fType);
1267 }
1268 else
1269 {
1270 for (pdbc = (DBC_t *) (genv->hdbc); pdbc != NULL; pdbc = pdbc->next)
1271 {
1272 retcode |= _iodbcdm_transact (pdbc, fType);
1273 }
1274 }
1275
1276 if (!SQL_SUCCEEDED (retcode))
1277 {
1278 /* fail on one of the connection */
1279 return SQL_ERROR;
1280 }
1281
1282 return retcode;
1283 }
1284
1285
1286 SQLRETURN SQL_API
SQLTransact(SQLHENV henv,SQLHDBC hdbc,SQLUSMALLINT fType)1287 SQLTransact (
1288 SQLHENV henv,
1289 SQLHDBC hdbc,
1290 SQLUSMALLINT fType)
1291 {
1292 SQLRETURN retcode = SQL_SUCCESS;
1293
1294 ODBC_LOCK ();
1295 TRACE (trace_SQLTransact (TRACE_ENTER, henv, hdbc, fType));
1296
1297 retcode = SQLTransact_Internal (henv, hdbc, fType);
1298
1299 TRACE (trace_SQLTransact (TRACE_LEAVE, henv, hdbc, fType));
1300 ODBC_UNLOCK ();
1301
1302 return retcode;
1303 }
1304