1/*********************************************************************
2 *
3 * This is based on code created by Peter Harvey,
4 * (pharvey@codebydesign.com).
5 *
6 * Modified and extended by Nick Gorham
7 * (nick@lurcher.org).
8 *
9 * Any bugs or problems should be considered the fault of Nick and not
10 * Peter.
11 *
12 * copyright (c) 1999 Nick Gorham
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 **********************************************************************
29 *
30 * $Id: SQLEndTran.c,v 1.11 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLEndTran.c,v $
33 * Revision 1.11 2009/02/18 17:59:08 lurcher
34 * Shift to using config.h, the compile lines were making it hard to spot warnings
35 *
36 * Revision 1.10 2009/02/17 09:47:44 lurcher
37 * Clear up a number of bugs
38 *
39 * Revision 1.9 2006/05/31 17:35:34 lurcher
40 * Add unicode ODBCINST entry points
41 *
42 * Revision 1.8 2004/06/16 14:42:03 lurcher
43 *
44 *
45 * Fix potential corruption with threaded use and SQLEndTran
46 *
47 * Revision 1.7 2003/10/30 18:20:45 lurcher
48 *
49 * Fix broken thread protection
50 * Remove SQLNumResultCols after execute, lease S4/S% to driver
51 * Fix string overrun in SQLDriverConnect
52 * Add initial support for Interix
53 *
54 * Revision 1.6 2002/12/05 17:44:30 lurcher
55 *
56 * Display unknown return values in return logging
57 *
58 * Revision 1.5 2002/09/18 14:49:32 lurcher
59 *
60 * DataManagerII additions and some more threading fixes
61 *
62 * Revision 1.3 2002/08/20 12:41:07 lurcher
63 *
64 * Fix incorrect return state from SQLEndTran/SQLTransact
65 *
66 * Revision 1.2 2002/08/12 16:20:44 lurcher
67 *
68 * Make it try and find a working iconv set of encodings
69 *
70 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
71 *
72 * First upload to SourceForge
73 *
74 * Revision 1.2 2001/04/12 17:43:36 nick
75 *
76 * Change logging and added autotest to odbctest
77 *
78 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
79 * Imported Sources
80 *
81 * Revision 1.9 2000/08/16 15:57:51 ngorham
82 *
83 * Fix bug where it falled if called in state C4
84 *
85 * Revision 1.8 1999/11/13 23:40:59 ngorham
86 *
87 * Alter the way DM logging works
88 * Upgrade the Postgres driver to 6.4.6
89 *
90 * Revision 1.7 1999/10/24 23:54:17 ngorham
91 *
92 * First part of the changes to the error reporting
93 *
94 * Revision 1.6 1999/09/21 22:34:24 ngorham
95 *
96 * Improve performance by removing unneeded logging calls when logging is
97 * disabled
98 *
99 * Revision 1.5 1999/07/10 21:10:16 ngorham
100 *
101 * Adjust error sqlstate from driver manager, depending on requested
102 * version (ODBC2/3)
103 *
104 * Revision 1.4 1999/07/04 21:05:07 ngorham
105 *
106 * Add LGPL Headers to code
107 *
108 * Revision 1.3 1999/06/30 23:56:54 ngorham
109 *
110 * Add initial thread safety code
111 *
112 * Revision 1.2 1999/06/19 17:51:40 ngorham
113 *
114 * Applied assorted minor bug fixes
115 *
116 * Revision 1.1.1.1 1999/05/29 13:41:06 sShandyb
117 * first go at it
118 *
119 * Revision 1.3 1999/06/02 20:12:10 ngorham
120 *
121 * Fixed botched log entry, and removed the dos \r from the sql header files.
122 *
123 * Revision 1.2 1999/06/02 19:57:20 ngorham
124 *
125 * Added code to check if a attempt is being made to compile with a C++
126 * Compiler, and issue a message.
127 * Start work on the ODBC2-3 conversions.
128 *
129 * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey
130 * Imported sources
131 *
132 * Revision 1.2 1999/05/09 23:27:11 nick
133 * All the API done now
134 *
135 * Revision 1.1 1999/04/25 23:06:11 nick
136 * Initial revision
137 *
138 *
139 **********************************************************************/
140
141#include <config.h>
142#include "drivermanager.h"
143
144static char const rcsid[]= "$RCSfile: SQLEndTran.c,v $ $Revision: 1.11 $";
145
146SQLRETURN SQLEndTran( SQLSMALLINT handle_type,
147 SQLHANDLE handle,
148 SQLSMALLINT completion_type )
149{
150 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
151
152 if ( handle_type != SQL_HANDLE_ENV && handle_type != SQL_HANDLE_DBC )
153 {
154 DMHSTMT statement;
155 DMHDESC descriptor;
156
157 if ( handle_type == SQL_HANDLE_STMT ) {
158 if ( !__validate_stmt(( DMHSTMT ) handle ))
159 {
160 dm_log_write( __FILE__,
161 __LINE__,
162 LOG_INFO,
163 LOG_INFO,
164 "Error: SQL_INVALID_HANDLE" );
165
166 return SQL_INVALID_HANDLE;
167 }
168 statement = (DMHSTMT) handle;
169
170 function_entry( statement );
171 thread_protect( SQL_HANDLE_STMT, statement );
172
173 dm_log_write( __FILE__,
174 __LINE__,
175 LOG_INFO,
176 LOG_INFO,
177 "Error: HY092" );
178
179 __post_internal_error( &statement -> error,
180 ERROR_HY092, NULL,
181 statement -> connection -> environment -> requested_version );
182
183 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
184 }
185 else if ( handle_type == SQL_HANDLE_DESC ) {
186 if ( !__validate_desc(( DMHDESC ) handle ))
187 {
188 dm_log_write( __FILE__,
189 __LINE__,
190 LOG_INFO,
191 LOG_INFO,
192 "Error: SQL_INVALID_HANDLE" );
193
194 return SQL_INVALID_HANDLE;
195 }
196 descriptor = (DMHDESC) handle;
197
198 function_entry( descriptor );
199 thread_protect( SQL_HANDLE_DESC, descriptor );
200
201 dm_log_write( __FILE__,
202 __LINE__,
203 LOG_INFO,
204 LOG_INFO,
205 "Error: HY092" );
206
207 __post_internal_error( &descriptor -> error,
208 ERROR_HY092, NULL,
209 descriptor -> connection -> environment -> requested_version );
210
211 return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
212 }
213 else {
214 dm_log_write( __FILE__,
215 __LINE__,
216 LOG_INFO,
217 LOG_INFO,
218 "Error: SQL_INVALID_HANDLE" );
219
220 return SQL_INVALID_HANDLE;
221 }
222 }
223
224 if ( handle_type == SQL_HANDLE_ENV )
225 {
226 DMHENV environment = (DMHENV) handle;
227 DMHDBC connection;
228 SQLRETURN ret;
229
230 if ( !__validate_env( environment ))
231 {
232 dm_log_write( __FILE__,
233 __LINE__,
234 LOG_INFO,
235 LOG_INFO,
236 "Error: SQL_INVALID_HANDLE" );
237
238 return SQL_INVALID_HANDLE;
239 }
240
241 function_entry( environment );
242
243 if ( log_info.log_flag )
244 {
245 sprintf( environment -> msg, "\n\t\tEntry:\
246\n\t\t\tEnvironment = %p\
247\n\t\t\tCompletion Type = %d",
248 (void*)environment,
249 (int)completion_type );
250
251 dm_log_write( __FILE__,
252 __LINE__,
253 LOG_INFO,
254 LOG_INFO,
255 environment -> msg );
256 }
257
258 thread_protect( SQL_HANDLE_ENV, environment );
259
260 if ( completion_type != SQL_COMMIT &&
261 completion_type != SQL_ROLLBACK )
262 {
263 dm_log_write( __FILE__,
264 __LINE__,
265 LOG_INFO,
266 LOG_INFO,
267 "Error: HY012" );
268
269 __post_internal_error( &environment -> error,
270 ERROR_HY012, NULL,
271 environment -> requested_version );
272
273 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
274 }
275
276 if ( environment -> state == STATE_E2 )
277 {
278 /*
279 * check that none of the connections are in a need data state
280 */
281
282 connection = __get_dbc_root();
283
284 while( connection )
285 {
286 if ( connection -> environment == environment &&
287 connection -> state > STATE_C4 )
288 {
289 if( __check_stmt_from_dbc_v( connection, 8, STATE_S8, STATE_S9, STATE_S10, STATE_S11, STATE_S12, STATE_S13, STATE_S14, STATE_S15 )) {
290
291 dm_log_write( __FILE__,
292 __LINE__,
293 LOG_INFO,
294 LOG_INFO,
295 "Error: HY010" );
296
297 __post_internal_error( &environment -> error,
298 ERROR_HY010, NULL,
299 environment -> requested_version );
300
301 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
302 }
303 }
304
305 connection = connection -> next_class_list;
306 }
307
308 /*
309 * for each connection on this env
310 */
311
312 connection = __get_dbc_root();
313
314 while( connection )
315 {
316 if ( connection -> environment == environment &&
317 connection -> state > STATE_C4 )
318 {
319 if ( CHECK_SQLENDTRAN( connection ))
320 {
321 ret = SQLENDTRAN( connection,
322 SQL_HANDLE_DBC,
323 connection -> driver_dbc,
324 completion_type );
325
326 if ( !SQL_SUCCEEDED( ret ))
327 {
328 dm_log_write( __FILE__,
329 __LINE__,
330 LOG_INFO,
331 LOG_INFO,
332 "Error: 25S01" );
333
334 __post_internal_error( &environment -> error,
335 ERROR_25S01, NULL,
336 environment -> requested_version );
337
338 return function_return( SQL_HANDLE_ENV, environment, SQL_ERROR );
339 }
340 }
341 else if ( CHECK_SQLTRANSACT( connection ))
342 {
343 ret = SQLTRANSACT( connection,
344 SQL_NULL_HENV,
345 connection -> driver_dbc,
346 completion_type );
347
348 if ( !SQL_SUCCEEDED( ret ))
349 {
350 dm_log_write( __FILE__,
351 __LINE__,
352 LOG_INFO,
353 LOG_INFO,
354 "Error: 25S01" );
355
356 __post_internal_error( &environment -> error,
357 ERROR_25S01, NULL,
358 environment -> requested_version );
359
360 return function_return( SQL_HANDLE_ENV, environment, SQL_ERROR );
361 }
362 }
363 else
364 {
365 dm_log_write( __FILE__,
366 __LINE__,
367 LOG_INFO,
368 LOG_INFO,
369 "Error: IM001" );
370
371 __post_internal_error( &connection -> error,
372 ERROR_IM001, NULL,
373 environment -> requested_version );
374
375 return function_return_nodrv( SQL_HANDLE_ENV, environment, SQL_ERROR );
376 }
377 }
378
379 connection = connection -> next_class_list;
380 }
381 }
382
383
384 sprintf( environment -> msg,
385 "\n\t\tExit:[%s]",
386 __get_return_status( SQL_SUCCESS, s1 ));
387
388 dm_log_write( __FILE__,
389 __LINE__,
390 LOG_INFO,
391 LOG_INFO,
392 environment -> msg );
393
394 return function_return( SQL_HANDLE_ENV, environment, SQL_SUCCESS );
395 }
396 else if ( handle_type == SQL_HANDLE_DBC )
397 {
398 DMHDBC connection = (DMHDBC) handle;
399 SQLRETURN ret;
400
401 if ( !__validate_dbc( connection ))
402 {
403 return SQL_INVALID_HANDLE;
404 }
405
406 function_entry( connection );
407
408 if ( log_info.log_flag )
409 {
410 sprintf( connection -> msg, "\n\t\tEntry:\
411 \n\t\t\tConnection = %p\
412 \n\t\t\tCompletion Type = %d",
413 (void*)connection,
414 (int)completion_type );
415
416 dm_log_write( __FILE__,
417 __LINE__,
418 LOG_INFO,
419 LOG_INFO,
420 connection -> msg );
421 }
422 thread_protect( SQL_HANDLE_DBC, connection );
423
424 if ( connection -> state == STATE_C1 ||
425 connection -> state == STATE_C2 ||
426 connection -> state == STATE_C3 )
427 {
428 dm_log_write( __FILE__,
429 __LINE__,
430 LOG_INFO,
431 LOG_INFO,
432 "Error: 08003" );
433
434 __post_internal_error( &connection -> error,
435 ERROR_08003, NULL,
436 connection -> environment -> requested_version );
437
438 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
439 }
440
441 /*
442 * check status of statements belonging to this connection
443 */
444
445 if( __check_stmt_from_dbc_v( connection, 8, STATE_S8, STATE_S9, STATE_S10, STATE_S11, STATE_S12, STATE_S13, STATE_S14, STATE_S15 )) {
446
447 dm_log_write( __FILE__,
448 __LINE__,
449 LOG_INFO,
450 LOG_INFO,
451 "Error: HY010" );
452
453 __post_internal_error( &connection -> error,
454 ERROR_HY010, NULL,
455 connection -> environment -> requested_version );
456
457 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
458 }
459
460 if ( completion_type != SQL_COMMIT &&
461 completion_type != SQL_ROLLBACK )
462 {
463 dm_log_write( __FILE__,
464 __LINE__,
465 LOG_INFO,
466 LOG_INFO,
467 "Error: HY012" );
468
469 __post_internal_error( &connection -> error,
470 ERROR_HY012, NULL,
471 connection -> environment -> requested_version );
472
473 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
474 }
475
476 if ( CHECK_SQLENDTRAN( connection ))
477 {
478 ret = SQLENDTRAN( connection,
479 handle_type,
480 connection -> driver_dbc,
481 completion_type );
482 }
483 else if ( CHECK_SQLTRANSACT( connection ))
484 {
485 ret = SQLTRANSACT( connection,
486 SQL_NULL_HENV,
487 connection -> driver_dbc,
488 completion_type );
489 }
490 else
491 {
492 dm_log_write( __FILE__,
493 __LINE__,
494 LOG_INFO,
495 LOG_INFO,
496 "Error: IM001" );
497
498 __post_internal_error( &connection -> error,
499 ERROR_IM001, NULL,
500 connection -> environment -> requested_version );
501
502 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
503 }
504
505 if( SQL_SUCCEEDED(ret) )
506 {
507 SQLSMALLINT cb_value;
508 SQLSMALLINT cb_value_length = sizeof(SQLSMALLINT);
509 SQLRETURN ret1;
510
511 /*
512 * for each statement belonging to this connection set its state
513 * relative to the commit or rollback behavior
514 */
515
516 if ( connection -> cbs_found == 0 )
517 {
518 /* release thread so we can get the info */
519 thread_release( SQL_HANDLE_DBC, connection );
520
521 ret1 = SQLGetInfo(connection,
522 SQL_CURSOR_COMMIT_BEHAVIOR,
523 &connection -> ccb_value,
524 sizeof( SQLSMALLINT ),
525 &cb_value_length);
526
527 if ( SQL_SUCCEEDED( ret1 ))
528 {
529 ret1 = SQLGetInfo(connection,
530 SQL_CURSOR_ROLLBACK_BEHAVIOR,
531 &connection -> crb_value,
532 sizeof( SQLSMALLINT ),
533 &cb_value_length);
534 }
535
536 /* protect thread again */
537 thread_protect( SQL_HANDLE_DBC, connection );
538 if ( SQL_SUCCEEDED( ret1 ))
539 {
540 connection -> cbs_found = 1;
541 }
542 }
543
544 if( completion_type == SQL_COMMIT )
545 {
546 cb_value = connection -> ccb_value;
547 }
548 else
549 {
550 cb_value = connection -> crb_value;
551 }
552
553 if( connection -> cbs_found )
554 {
555 __set_stmt_state( connection, cb_value );
556 }
557 }
558
559 if ( log_info.log_flag )
560 {
561 sprintf( connection -> msg,
562 "\n\t\tExit:[%s]",
563 __get_return_status( ret, s1 ));
564
565 dm_log_write( __FILE__,
566 __LINE__,
567 LOG_INFO,
568 LOG_INFO,
569 connection -> msg );
570 }
571
572 return function_return( SQL_HANDLE_DBC, connection, ret );
573 }
574 else
575 {
576 /*
577 * the book here indicates that we can return a HY092 error
578 * here, but on what handle ?
579 */
580
581 return SQL_INVALID_HANDLE;
582 }
583}
584