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 
175 static char const rcsid[]= "$RCSfile: SQLExecDirect.c,v $ $Revision: 1.11 $";
176 
SQLExecDirectA(SQLHSTMT statement_handle,SQLCHAR * statement_text,SQLINTEGER text_length)177 SQLRETURN 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 
SQLExecDirect(SQLHSTMT statement_handle,SQLCHAR * statement_text,SQLINTEGER text_length)186 SQLRETURN 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, DEFER_R1 );
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, DEFER_R1 );
528 }
529