]>
Commit | Line | Data |
---|---|---|
1a6944fd RR |
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 | } |