1/*********************************************************************
2 *
3 * (pharvey@codebydesign.com).
4 *
5 * Modified and extended by Nick Gorham
6 * (nick@lurcher.org).
7 *
8 * copyright (c) 1999 Nick Gorham
9 *
10 * Any bugs or problems should be considered the fault of Nick and not
11 * Peter.
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 *
27 **********************************************************************
28 *
29 * $Id: SQLExecDirect.c,v 1.11 2009/02/18 17:59:08 lurcher Exp $
30 *
31 * $Log: SQLExecDirect.c,v $
32 * Revision 1.11 2009/02/18 17:59:08 lurcher
33 * Shift to using config.h, the compile lines were making it hard to spot warnings
34 *
35 * Revision 1.10 2006/04/11 10:22:56 lurcher
36 * Fix a data type check
37 *
38 * Revision 1.9 2003/10/30 18:20:45 lurcher
39 *
40 * Fix broken thread protection
41 * Remove SQLNumResultCols after execute, lease S4/S% to driver
42 * Fix string overrun in SQLDriverConnect
43 * Add initial support for Interix
44 *
45 * Revision 1.8 2003/02/27 12:19:39 lurcher
46 *
47 * Add the A functions as well as the W
48 *
49 * Revision 1.7 2002/12/05 17:44:30 lurcher
50 *
51 * Display unknown return values in return logging
52 *
53 * Revision 1.6 2002/07/24 08:49:52 lurcher
54 *
55 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
56 *
57 * Revision 1.5 2002/07/18 15:21:56 lurcher
58 *
59 * Fix problem with SQLExecute/SQLExecDirect returning SQL_NO_DATA
60 *
61 * Revision 1.4 2002/01/21 18:00:51 lurcher
62 *
63 * Assorted fixed and changes, mainly UNICODE/bug fixes
64 *
65 * Revision 1.3 2002/01/15 14:47:44 lurcher
66 *
67 * Reset stmt->prepared flag after entering a SQLParamData state from
68 * SQLExecDirect
69 *
70 * Revision 1.2 2001/12/13 13:00:32 lurcher
71 *
72 * Remove most if not all warnings on 64 bit platforms
73 * Add support for new MS 3.52 64 bit changes
74 * Add override to disable the stopping of tracing
75 * Add MAX_ROWS support in postgres driver
76 *
77 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
78 *
79 * First upload to SourceForge
80 *
81 * Revision 1.5 2001/08/17 11:03:35 nick
82 *
83 * Fix final state from SQLExecute if error happens
84 *
85 * Revision 1.4 2001/04/18 15:03:37 nick
86 *
87 * Fix problem when going to DB2 unicode driver
88 *
89 * Revision 1.3 2001/04/12 17:43:36 nick
90 *
91 * Change logging and added autotest to odbctest
92 *
93 * Revision 1.2 2000/12/31 20:30:54 nick
94 *
95 * Add UNICODE support
96 *
97 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
98 * Imported Sources
99 *
100 * Revision 1.11 2000/06/20 12:43:58 ngorham
101 *
102 * Fix bug that caused a success with info message from SQLExecute or
103 * SQLExecDirect to be lost if used with a ODBC 3 driver and the application
104 * called SQLGetDiagRec
105 *
106 * Revision 1.10 2000/06/16 16:52:16 ngorham
107 *
108 * Stop info messages being lost when calling SQLExecute etc on ODBC 3
109 * drivers, the SQLNumResultCols were clearing the error before
110 * function return had a chance to get to them
111 *
112 * Revision 1.9 1999/11/18 22:42:09 ngorham
113 *
114 * Fix missing function_entry in SQLExecDirect()
115 *
116 * Revision 1.8 1999/11/13 23:40:59 ngorham
117 *
118 * Alter the way DM logging works
119 * Upgrade the Postgres driver to 6.4.6
120 *
121 * Revision 1.7 1999/11/10 03:51:33 ngorham
122 *
123 * Update the error reporting in the DM to enable ODBC 3 and 2 calls to
124 * work at the same time
125 *
126 * Revision 1.6 1999/10/24 23:54:18 ngorham
127 *
128 * First part of the changes to the error reporting
129 *
130 * Revision 1.5 1999/09/21 22:34:24 ngorham
131 *
132 * Improve performance by removing unneeded logging calls when logging is
133 * disabled
134 *
135 * Revision 1.4 1999/07/10 21:10:16 ngorham
136 *
137 * Adjust error sqlstate from driver manager, depending on requested
138 * version (ODBC2/3)
139 *
140 * Revision 1.3 1999/07/04 21:05:07 ngorham
141 *
142 * Add LGPL Headers to code
143 *
144 * Revision 1.2 1999/06/30 23:56:54 ngorham
145 *
146 * Add initial thread safety code
147 *
148 * Revision 1.1.1.1 1999/05/29 13:41:06 sShandyb
149 * first go at it
150 *
151 * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey
152 * Imported sources
153 *
154 * Revision 1.5 1999/05/04 22:41:12 nick
155 * and another night ends
156 *
157 * Revision 1.4 1999/05/03 19:50:43 nick
158 * Another check point
159 *
160 * Revision 1.3 1999/04/30 16:22:47 nick
161 * Another checkpoint
162 *
163 * Revision 1.2 1999/04/29 21:40:58 nick
164 * End of another night :-)
165 *
166 * Revision 1.1 1999/04/25 23:06:11 nick
167 * Initial revision
168 *
169 *
170 **********************************************************************/
171
172#include <config.h>
173#include "drivermanager.h"
174
175static char const rcsid[]= "$RCSfile: SQLExecDirect.c,v $ $Revision: 1.11 $";
176
177SQLRETURN SQLExecDirectA( SQLHSTMT statement_handle,
178 SQLCHAR *statement_text,
179 SQLINTEGER text_length )
180{
181 return SQLExecDirect( statement_handle,
182 statement_text,
183 text_length );
184}
185
186SQLRETURN SQLExecDirect( SQLHSTMT statement_handle,
187 SQLCHAR *statement_text,
188 SQLINTEGER text_length )
189{
190 DMHSTMT statement = (DMHSTMT) statement_handle;
191 SQLRETURN ret;
192 SQLCHAR *s1;
193 SQLCHAR s2[ 100 + LOG_MESSAGE_LEN ];
194
195 /*
196 * check statement
197 */
198
199 if ( !__validate_stmt( statement ))
200 {
201 dm_log_write( __FILE__,
202 __LINE__,
203 LOG_INFO,
204 LOG_INFO,
205 "Error: SQL_INVALID_HANDLE" );
206
207 return SQL_INVALID_HANDLE;
208 }
209
210 function_entry( statement );
211
212 if ( log_info.log_flag )
213 {
214 /*
215 * allocate some space for the buffer
216 */
217
218 if ( statement_text && text_length == SQL_NTS )
219 {
220 s1 = malloc( strlen((char*) statement_text ) + LOG_MESSAGE_LEN );
221 }
222 else if ( statement_text )
223 {
224 s1 = malloc( text_length + LOG_MESSAGE_LEN );
225 }
226 else
227 {
228 s1 = malloc( LOG_MESSAGE_LEN );
229 }
230
231 sprintf( statement -> msg, "\n\t\tEntry:\
232\n\t\t\tStatement = %p\
233\n\t\t\tSQL = %s",
234 statement,
235 __string_with_length( s1, statement_text, text_length ));
236
237 free( s1 );
238
239 dm_log_write( __FILE__,
240 __LINE__,
241 LOG_INFO,
242 LOG_INFO,
243 statement -> msg );
244 }
245
246 thread_protect( SQL_HANDLE_STMT, statement );
247
248 if ( !statement_text )
249 {
250 dm_log_write( __FILE__,
251 __LINE__,
252 LOG_INFO,
253 LOG_INFO,
254 "Error: HY009" );
255
256 __post_internal_error( &statement -> error,
257 ERROR_HY009, NULL,
258 statement -> connection -> environment -> requested_version );
259
260 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
261 }
262
263 if ( text_length <= 0 && text_length != SQL_NTS )
264 {
265 dm_log_write( __FILE__,
266 __LINE__,
267 LOG_INFO,
268 LOG_INFO,
269 "Error: HY090" );
270
271 __post_internal_error( &statement -> error,
272 ERROR_HY090, NULL,
273 statement -> connection -> environment -> requested_version );
274
275 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
276 }
277
278 /*
279 * check states
280 */
281
282#ifdef NR_PROBE
283 if ( statement -> state == STATE_S5 ||
284 statement -> state == STATE_S6 ||
285 statement -> state == STATE_S7 )
286#else
287 if (( statement -> state == STATE_S6 && statement -> eod == 0 ) ||
288 statement -> state == STATE_S7 )
289#endif
290 {
291 dm_log_write( __FILE__,
292 __LINE__,
293 LOG_INFO,
294 LOG_INFO,
295 "Error: 24000" );
296
297 __post_internal_error( &statement -> error,
298 ERROR_24000, NULL,
299 statement -> connection -> environment -> requested_version );
300
301 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
302 }
303 else if ( statement -> state == STATE_S8 ||
304 statement -> state == STATE_S9 ||
305 statement -> state == STATE_S10 ||
306 statement -> state == STATE_S13 ||
307 statement -> state == STATE_S14 ||
308 statement -> state == STATE_S15 )
309 {
310 dm_log_write( __FILE__,
311 __LINE__,
312 LOG_INFO,
313 LOG_INFO,
314 "Error: HY010" );
315
316 __post_internal_error( &statement -> error,
317 ERROR_HY010, NULL,
318 statement -> connection -> environment -> requested_version );
319
320 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
321 }
322
323 if ( statement -> state == STATE_S11 ||
324 statement -> state == STATE_S12 )
325 {
326 if ( statement -> interupted_func != SQL_API_SQLEXECDIRECT )
327 {
328 dm_log_write( __FILE__,
329 __LINE__,
330 LOG_INFO,
331 LOG_INFO,
332 "Error: HY010" );
333
334 __post_internal_error( &statement -> error,
335 ERROR_HY010, NULL,
336 statement -> connection -> environment -> requested_version );
337
338 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
339 }
340 }
341
342 if ( statement -> connection -> unicode_driver )
343 {
344 SQLWCHAR *s1;
345 int wlen;
346
347#ifdef NR_PROBE
348 if ( !CHECK_SQLEXECDIRECTW( statement -> connection ) ||
349 !CHECK_SQLNUMRESULTCOLS( statement -> connection ))
350 {
351 dm_log_write( __FILE__,
352 __LINE__,
353 LOG_INFO,
354 LOG_INFO,
355 "Error: IM001" );
356
357 __post_internal_error( &statement -> error,
358 ERROR_IM001, NULL,
359 statement -> connection -> environment -> requested_version );
360
361 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
362 }
363#else
364 if ( !CHECK_SQLEXECDIRECTW( statement -> connection ))
365 {
366 dm_log_write( __FILE__,
367 __LINE__,
368 LOG_INFO,
369 LOG_INFO,
370 "Error: IM001" );
371
372 __post_internal_error( &statement -> error,
373 ERROR_IM001, NULL,
374 statement -> connection -> environment -> requested_version );
375
376 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
377 }
378#endif
379
380 s1 = ansi_to_unicode_alloc( statement_text, text_length, statement -> connection, &wlen );
381
382 text_length = wlen;
383
384 ret = SQLEXECDIRECTW( statement -> connection,
385 statement -> driver_stmt,
386 s1,
387 text_length );
388
389 if ( s1 )
390 free( s1 );
391 }
392 else
393 {
394#ifdef NR_PROBE
395 if ( !CHECK_SQLEXECDIRECT( statement -> connection ) ||
396 !CHECK_SQLNUMRESULTCOLS( statement -> connection ))
397 {
398 dm_log_write( __FILE__,
399 __LINE__,
400 LOG_INFO,
401 LOG_INFO,
402 "Error: IM001" );
403
404 __post_internal_error( &statement -> error,
405 ERROR_IM001, NULL,
406 statement -> connection -> environment -> requested_version );
407
408 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
409 }
410#else
411 if ( !CHECK_SQLEXECDIRECT( statement -> connection ))
412 {
413 dm_log_write( __FILE__,
414 __LINE__,
415 LOG_INFO,
416 LOG_INFO,
417 "Error: IM001" );
418
419 __post_internal_error( &statement -> error,
420 ERROR_IM001, NULL,
421 statement -> connection -> environment -> requested_version );
422
423 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
424 }
425#endif
426
427 ret = SQLEXECDIRECT( statement -> connection,
428 statement -> driver_stmt,
429 statement_text,
430 text_length );
431 }
432
433 if ( SQL_SUCCEEDED( ret ))
434 {
435#ifdef NR_PROBE
436 SQLRETURN local_ret;
437
438 /*
439 * grab any errors
440 */
441
442 if ( ret == SQL_SUCCESS_WITH_INFO )
443 {
444 function_return_ex( IGNORE_THREAD, statement, ret, TRUE );
445 }
446
447 local_ret = SQLNUMRESULTCOLS( statement -> connection,
448 statement -> driver_stmt, &statement -> numcols );
449
450 if ( statement -> numcols > 0 )
451 {
452 statement -> state = STATE_S5;
453 }
454 else
455 {
456 statement -> state = STATE_S4;
457 }
458#else
459 /*
460 * We don't know for sure
461 */
462 statement -> hascols = 1;
463 statement -> state = STATE_S5;
464#endif
465
466 statement -> prepared = 0;
467
468 /*
469 * there is a issue here with transactions, but for the
470 * moment
471 *
472 statement -> connection -> state = STATE_C6;
473 */
474 }
475 else if ( ret == SQL_NO_DATA )
476 {
477 statement -> state = STATE_S4;
478 statement -> prepared = 0;
479 }
480 else if ( ret == SQL_NEED_DATA )
481 {
482 statement -> interupted_func = SQL_API_SQLEXECDIRECT;
483 statement -> interupted_state = statement -> state;
484 statement -> state = STATE_S8;
485
486 statement -> prepared = 0;
487 }
488 else if ( ret == SQL_PARAM_DATA_AVAILABLE )
489 {
490 statement -> interupted_func = SQL_API_SQLEXECDIRECT;
491 statement -> interupted_state = statement -> state;
492 statement -> state = STATE_S13;
493 }
494 else if ( ret == SQL_STILL_EXECUTING )
495 {
496 statement -> interupted_func = SQL_API_SQLEXECDIRECT;
497 if ( statement -> state != STATE_S11 &&
498 statement -> state != STATE_S12 )
499 statement -> state = STATE_S11;
500
501 statement -> prepared = 0;
502 }
503 else if ( statement -> state >= STATE_S2 && statement -> state <= STATE_S4 ||
504 statement -> state >= STATE_S11 && statement -> state <= STATE_S12 &&
505 statement -> interupted_state >= STATE_S2 && statement -> interupted_state <= STATE_S4)
506 {
507 statement -> state = STATE_S1;
508 }
509 else if ( statement -> state >= STATE_S11 && statement -> state <= STATE_S12 )
510 {
511 statement -> state = statement -> interupted_state;
512 }
513
514 if ( log_info.log_flag )
515 {
516 sprintf( statement -> msg,
517 "\n\t\tExit:[%s]",
518 __get_return_status( ret, s2 ));
519
520 dm_log_write( __FILE__,
521 __LINE__,
522 LOG_INFO,
523 LOG_INFO,
524 statement -> msg );
525 }
526
527 return function_return( SQL_HANDLE_STMT, statement, ret );
528}
529