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 
103 static char const rcsid[]= "$RCSfile: SQLCancel.c,v $ $Revision: 1.4 $";
104 
SQLCancel(SQLHSTMT statement_handle)105 SQLRETURN 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                 statement -> state = STATE_S6;
240                 statement -> eod = 0;
241             }
242             else if ( statement -> interupted_func ==
243                     SQL_API_SQLSETPOS )
244             {
245                 if ( statement -> interupted_state == STATE_S5 ||
246                         statement -> interupted_state == STATE_S6 )
247                 {
248                     statement -> state = STATE_S6;
249                     statement -> eod = 0;
250                 }
251                 else if ( statement -> interupted_state == STATE_S7 )
252                 {
253                     statement -> state = STATE_S7;
254                 }
255             }
256         }
257         else if ( statement -> state == STATE_S11 ||
258                 statement -> state == STATE_S12 )
259         {
260             statement -> state = STATE_S12;
261         }
262         else {  /* Same action as SQLFreeStmt( SQL_CLOSE ) */
263             if ( statement -> state == STATE_S4 )
264             {
265                 if ( statement -> prepared )
266                     statement -> state = STATE_S2;
267                 else
268                     statement -> state = STATE_S1;
269             }
270             else
271             {
272                 if ( statement -> prepared )
273                     statement -> state = STATE_S3;
274                 else
275                     statement -> state = STATE_S1;
276             }
277             statement -> hascols = 0;
278         }
279     }
280 
281     if ( log_info.log_flag )
282     {
283         sprintf( statement -> msg,
284                 "\n\t\tExit:[%s]",
285                     __get_return_status( ret, s1 ));
286 
287         dm_log_write( __FILE__,
288                 __LINE__,
289                 LOG_INFO,
290                 LOG_INFO,
291                 statement -> msg );
292     }
293 
294 #if defined( HAVE_LIBPTH ) || defined( HAVE_LIBPTHREAD ) || defined( HAVE_LIBTHREAD )
295     if ( statement -> connection -> protection_level == 3 )
296     {
297         return function_return( SQL_HANDLE_STMT, statement, SQL_ERROR, DEFER_R2 );
298     }
299     else
300     {
301         return function_return( IGNORE_THREAD, statement, ret, DEFER_R2 );
302     }
303 #else
304     return function_return( IGNORE_THREAD, statement, ret, DEFER_R2 );
305 #endif
306 }
307