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: SQLCancel.c,v 1.4 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLCancel.c,v $
33 * Revision 1.4 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.3 2003/10/30 18:20:45 lurcher
37 *
38 * Fix broken thread protection
39 * Remove SQLNumResultCols after execute, lease S4/S% to driver
40 * Fix string overrun in SQLDriverConnect
41 * Add initial support for Interix
42 *
43 * Revision 1.2 2002/12/05 17:44:30 lurcher
44 *
45 * Display unknown return values in return logging
46 *
47 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
48 *
49 * First upload to SourceForge
50 *
51 * Revision 1.2 2001/04/12 17:43:35 nick
52 *
53 * Change logging and added autotest to odbctest
54 *
55 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
56 * Imported Sources
57 *
58 * Revision 1.7 1999/11/13 23:40:58 ngorham
59 *
60 * Alter the way DM logging works
61 * Upgrade the Postgres driver to 6.4.6
62 *
63 * Revision 1.6 1999/10/24 23:54:17 ngorham
64 *
65 * First part of the changes to the error reporting
66 *
67 * Revision 1.5 1999/09/21 22:34:24 ngorham
68 *
69 * Improve performance by removing unneeded logging calls when logging is
70 * disabled
71 *
72 * Revision 1.4 1999/07/10 21:10:15 ngorham
73 *
74 * Adjust error sqlstate from driver manager, depending on requested
75 * version (ODBC2/3)
76 *
77 * Revision 1.3 1999/07/04 21:05:06 ngorham
78 *
79 * Add LGPL Headers to code
80 *
81 * Revision 1.2 1999/06/30 23:56:54 ngorham
82 *
83 * Add initial thread safety code
84 *
85 * Revision 1.1.1.1 1999/05/29 13:41:05 sShandyb
86 * first go at it
87 *
88 * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey
89 * Imported sources
90 *
91 * Revision 1.2 1999/05/04 22:41:12 nick
92 * and another night ends
93 *
94 * Revision 1.1 1999/04/25 23:02:41 nick
95 * Initial revision
96 *
97 *
98 **********************************************************************/
99
100#include <config.h>
101#include "drivermanager.h"
102
103static char const rcsid[]= "$RCSfile: SQLCancel.c,v $ $Revision: 1.4 $";
104
105SQLRETURN SQLCancel( SQLHSTMT statement_handle )
106{
107 DMHSTMT statement = (DMHSTMT) statement_handle;
108 SQLRETURN ret;
109 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
110
111 /*
112 * check statement
113 */
114
115 if ( !__validate_stmt( statement ))
116 {
117 dm_log_write( __FILE__,
118 __LINE__,
119 LOG_INFO,
120 LOG_INFO,
121 "Error: SQL_INVALID_HANDLE" );
122
123 return SQL_INVALID_HANDLE;
124 }
125
126 function_entry( statement );
127
128 if ( log_info.log_flag )
129 {
130 sprintf( statement -> msg, "\n\t\tEntry:\
131\n\t\t\tStatement = %p",
132 statement );
133
134 dm_log_write( __FILE__,
135 __LINE__,
136 LOG_INFO,
137 LOG_INFO,
138 statement -> msg );
139 }
140
141#if defined( HAVE_LIBPTH ) || defined( HAVE_LIBPTHREAD ) || defined( HAVE_LIBTHREAD )
142 /*
143 * Allow this past the thread checks if the driver is at all thread safe, as SQLCancel can
144 * be called across threads
145 */
146 if ( statement -> connection -> protection_level == 3 )
147 {
148 thread_protect( SQL_HANDLE_STMT, statement );
149 }
150#endif
151
152 /*
153 * check states
154 */
155
156 if ( !CHECK_SQLCANCEL( statement -> connection ))
157 {
158 dm_log_write( __FILE__,
159 __LINE__,
160 LOG_INFO,
161 LOG_INFO,
162 "Error: IM001" );
163
164 __post_internal_error( &statement -> error,
165 ERROR_IM001, NULL,
166 statement -> connection -> environment -> requested_version );
167
168#if defined( HAVE_LIBPTH ) || defined( HAVE_LIBPTHREAD ) || defined( HAVE_LIBTHREAD )
169 if ( statement -> connection -> protection_level == 3 )
170 {
171 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
172 }
173 else
174 {
175 return function_return_nodrv( IGNORE_THREAD, statement, SQL_ERROR );
176 }
177#else
178 return function_return_nodrv( IGNORE_THREAD, statement, SQL_ERROR );
179#endif
180 }
181
182 ret = SQLCANCEL( statement -> connection,
183 statement -> driver_stmt );
184
185 if ( SQL_SUCCEEDED( ret ))
186 {
187 if (ret == SQL_SUCCESS_WITH_INFO )
188 {
189 SQLULEN nRecs = 0;
190 SQLSMALLINT len;
191 SQLRETURN ret2 = statement->connection->unicode_driver && CHECK_SQLGETDIAGFIELDW( statement->connection ) ?
192 SQLGETDIAGFIELDW ( statement -> connection, SQL_HANDLE_STMT, statement->driver_stmt, 0, SQL_DIAG_NUMBER, &nRecs, 0, &len ) :
193 SQLGETDIAGFIELD( statement -> connection, SQL_HANDLE_STMT, statement->driver_stmt, 0, SQL_DIAG_NUMBER, &nRecs, 0, &len);
194 if ( SQL_SUCCEEDED( ret2 ) && nRecs )
195 {
196 SQLSMALLINT recNo = 1;
197 while (nRecs--)
198 {
199 SQLCHAR state[12]; /* use the same buffer for both, length must be long enough to hold 5 SQLWCHARs + NULL */
200 ret2 = statement->connection->unicode_driver && CHECK_SQLGETDIAGRECW( statement->connection ) ?
201 SQLGETDIAGRECW( statement->connection, SQL_HANDLE_STMT, statement->driver_stmt, recNo, (SQLWCHAR*)state, NULL, NULL, 0, NULL ) :
202 SQLGETDIAGREC( statement->connection, SQL_HANDLE_STMT, statement->driver_stmt, recNo, state, NULL, NULL, 0, NULL ) ;
203 if ( SQL_SUCCEEDED( ret2 ) && (statement->connection->unicode_driver ?
204 !memcmp(state, "0\0001\000S\0000\0005\0", 10) : !memcmp(state, "01S05", 5)) )
205 {
206 ret = SQL_SUCCESS;
207 break;
208 }
209 recNo++;
210 }
211 }
212 }
213
214 if ( statement -> state == STATE_S8 ||
215 statement -> state == STATE_S9 ||
216 statement -> state == STATE_S10 ||
217 statement -> state == STATE_S13 ||
218 statement -> state == STATE_S14 ||
219 statement -> state == STATE_S15 )
220 {
221 if ( statement -> interupted_func == SQL_API_SQLEXECDIRECT )
222 {
223 statement -> state = STATE_S1;
224 }
225 else if ( statement -> interupted_func == SQL_API_SQLEXECUTE )
226 {
227 if ( statement -> hascols )
228 {
229 statement -> state = STATE_S3;
230 }
231 else
232 {
233 statement -> state = STATE_S2;
234 }
235 }
236 else if ( statement -> interupted_func ==
237 SQL_API_SQLBULKOPERATIONS )
238 {
239 if ( statement -> interupted_state == STATE_S5 ||
240 statement -> interupted_state == STATE_S6 ||
241 statement -> interupted_state == STATE_S7 )
242 {
243 statement -> state = STATE_S6;
244 statement -> eod = 0;
245 }
246 else
247 {
248 statement -> state = STATE_S6;
249 statement -> eod = 0;
250 }
251 }
252 else if ( statement -> interupted_func ==
253 SQL_API_SQLSETPOS )
254 {
255 if ( statement -> interupted_state == STATE_S5 ||
256 statement -> interupted_state == STATE_S6 )
257 {
258 statement -> state = STATE_S6;
259 statement -> eod = 0;
260 }
261 else if ( statement -> interupted_state == STATE_S7 )
262 {
263 statement -> state = STATE_S7;
264 }
265 }
266 }
267 else if ( statement -> state == STATE_S11 ||
268 statement -> state == STATE_S12 )
269 {
270 statement -> state = STATE_S12;
271 }
272 else { /* Same action as SQLFreeStmt( SQL_CLOSE ) */
273 if ( statement -> state == STATE_S4 )
274 {
275 if ( statement -> prepared )
276 statement -> state = STATE_S2;
277 else
278 statement -> state = STATE_S1;
279 }
280 else
281 {
282 if ( statement -> prepared )
283 statement -> state = STATE_S3;
284 else
285 statement -> state = STATE_S1;
286 }
287 statement -> hascols = 0;
288 }
289 }
290
291 if ( log_info.log_flag )
292 {
293 sprintf( statement -> msg,
294 "\n\t\tExit:[%s]",
295 __get_return_status( ret, s1 ));
296
297 dm_log_write( __FILE__,
298 __LINE__,
299 LOG_INFO,
300 LOG_INFO,
301 statement -> msg );
302 }
303
304#if defined( HAVE_LIBPTH ) || defined( HAVE_LIBPTHREAD ) || defined( HAVE_LIBTHREAD )
305 if ( statement -> connection -> protection_level == 3 )
306 {
307 return function_return( SQL_HANDLE_STMT, statement, SQL_ERROR );
308 }
309 else
310 {
311 return function_return( IGNORE_THREAD, statement, ret );
312 }
313#else
314 return function_return( IGNORE_THREAD, statement, ret );
315#endif
316}
317