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: SQLNativeSqlW.c,v 1.9 2009/02/18 17:59:08 lurcher Exp $
31  *
32  * $Log: SQLNativeSqlW.c,v $
33  * Revision 1.9  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.8  2008/08/29 08:01:39  lurcher
37  * Alter the way W functions are passed to the driver
38  *
39  * Revision 1.7  2007/02/28 15:37:48  lurcher
40  * deal with drivers that call internal W functions and end up in the driver manager. controlled by the --enable-handlemap configure arg
41  *
42  * Revision 1.6  2003/10/30 18:20:46  lurcher
43  *
44  * Fix broken thread protection
45  * Remove SQLNumResultCols after execute, lease S4/S% to driver
46  * Fix string overrun in SQLDriverConnect
47  * Add initial support for Interix
48  *
49  * Revision 1.5  2002/12/05 17:44:31  lurcher
50  *
51  * Display unknown return values in return logging
52  *
53  * Revision 1.4  2002/08/23 09:42:37  lurcher
54  *
55  * Fix some build warnings with casts, and a AIX linker mod, to include
56  * deplib's on the link line, but not the libtool generated ones
57  *
58  * Revision 1.3  2002/07/24 08:49:52  lurcher
59  *
60  * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
61  *
62  * Revision 1.2  2001/12/13 13:00:32  lurcher
63  *
64  * Remove most if not all warnings on 64 bit platforms
65  * Add support for new MS 3.52 64 bit changes
66  * Add override to disable the stopping of tracing
67  * Add MAX_ROWS support in postgres driver
68  *
69  * Revision 1.1.1.1  2001/10/17 16:40:06  lurcher
70  *
71  * First upload to SourceForge
72  *
73  * Revision 1.3  2001/04/12 17:43:36  nick
74  *
75  * Change logging and added autotest to odbctest
76  *
77  * Revision 1.2  2001/01/02 09:55:04  nick
78  *
79  * More unicode bits
80  *
81  * Revision 1.1  2000/12/31 20:30:54  nick
82  *
83  * Add UNICODE support
84  *
85  *
86  **********************************************************************/
87 
88 #include <config.h>
89 #include "drivermanager.h"
90 
91 static char const rcsid[]= "$RCSfile: SQLNativeSqlW.c,v $";
92 
SQLNativeSqlW(SQLHDBC hdbc,SQLWCHAR * sz_sql_str_in,SQLINTEGER cb_sql_str_in,SQLWCHAR * sz_sql_str,SQLINTEGER cb_sql_str_max,SQLINTEGER * pcb_sql_str)93 SQLRETURN SQLNativeSqlW(
94     SQLHDBC            hdbc,
95     SQLWCHAR            *sz_sql_str_in,
96     SQLINTEGER         cb_sql_str_in,
97     SQLWCHAR            *sz_sql_str,
98     SQLINTEGER         cb_sql_str_max,
99     SQLINTEGER         *pcb_sql_str )
100 {
101     DMHDBC connection = (DMHDBC)hdbc;
102     SQLRETURN ret;
103     SQLCHAR *s1;
104     SQLCHAR s2[ 100 + LOG_MESSAGE_LEN ];
105 
106     /*
107      * check connection
108      */
109 
110     if ( !__validate_dbc( connection ))
111     {
112         dm_log_write( __FILE__,
113                     __LINE__,
114                     LOG_INFO,
115                     LOG_INFO,
116                     "Error: SQL_INVALID_HANDLE" );
117 
118 #ifdef WITH_HANDLE_REDIRECT
119 		{
120 			DMHDBC parent_connection;
121 
122 			parent_connection = find_parent_handle( connection, SQL_HANDLE_DBC );
123 
124 			if ( parent_connection ) {
125         		dm_log_write( __FILE__,
126                 	__LINE__,
127                     	LOG_INFO,
128                     	LOG_INFO,
129                     	"Info: found parent handle" );
130 
131 				if ( CHECK_SQLNATIVESQLW( parent_connection ))
132 				{
133         			dm_log_write( __FILE__,
134                 		__LINE__,
135                    		 	LOG_INFO,
136                    		 	LOG_INFO,
137                    		 	"Info: calling redirected driver function" );
138 
139 					return SQLNATIVESQLW( parent_connection,
140 							connection,
141 							sz_sql_str_in,
142 							cb_sql_str_in,
143 							sz_sql_str,
144 							cb_sql_str_max,
145 							pcb_sql_str );
146 				}
147 			}
148 		}
149 #endif
150         return SQL_INVALID_HANDLE;
151     }
152 
153     function_entry( connection );
154 
155     if ( log_info.log_flag )
156     {
157         /*
158          * allocate some space for the buffer
159          */
160 
161         if ( sz_sql_str_in && cb_sql_str_in == SQL_NTS )
162         {
163             s1 = malloc(( wide_strlen( sz_sql_str_in ) * 2 ) + 100 );
164         }
165         else if ( sz_sql_str_in )
166         {
167             s1 = malloc( cb_sql_str_in + 100 );
168         }
169         else
170         {
171             s1 = malloc( 101 );
172         }
173 
174         sprintf( connection -> msg, "\n\t\tEntry:\
175 \n\t\t\tConnection = %p\
176 \n\t\t\tSQL In = %s\
177 \n\t\t\tSQL Out = %p\
178 \n\t\t\tSQL Out Len = %d\
179 \n\t\t\tSQL Len Ptr = %p",
180                 connection,
181                 __wstring_with_length( s1, sz_sql_str_in, cb_sql_str_in ),
182                 sz_sql_str,
183                 (int)cb_sql_str_max,
184                 pcb_sql_str );
185 
186         free( s1 );
187 
188         dm_log_write( __FILE__,
189                 __LINE__,
190                 LOG_INFO,
191                 LOG_INFO,
192                 connection -> msg );
193     }
194 
195     thread_protect( SQL_HANDLE_DBC, connection );
196 
197     if ( !sz_sql_str_in )
198     {
199         __post_internal_error( &connection -> error,
200                 ERROR_HY009, NULL,
201                 connection -> environment -> requested_version );
202 
203         return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
204     }
205 
206     if ( cb_sql_str_in < 0 &&
207             cb_sql_str_in != SQL_NTS )
208     {
209         dm_log_write( __FILE__,
210                 __LINE__,
211                 LOG_INFO,
212                 LOG_INFO,
213                 "Error: HY090" );
214 
215         __post_internal_error( &connection -> error,
216                 ERROR_HY090, NULL,
217                 connection -> environment -> requested_version );
218 
219         return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
220     }
221 
222     if ( sz_sql_str &&
223             cb_sql_str_max < 0 )
224     {
225         dm_log_write( __FILE__,
226                 __LINE__,
227                 LOG_INFO,
228                 LOG_INFO,
229                 "Error: HY090" );
230 
231         __post_internal_error( &connection -> error,
232                 ERROR_HY090, NULL,
233                 connection -> environment -> requested_version );
234 
235         return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
236     }
237 
238     if ( connection -> state == STATE_C2 ||
239             connection -> state == STATE_C3 )
240     {
241         dm_log_write( __FILE__,
242                 __LINE__,
243                 LOG_INFO,
244                 LOG_INFO,
245                 "Error: 08003" );
246 
247         __post_internal_error( &connection -> error,
248                 ERROR_08003, NULL,
249                 connection -> environment -> requested_version );
250 
251         return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
252     }
253 
254     if ( connection -> unicode_driver ||
255 		    CHECK_SQLNATIVESQLW( connection ))
256     {
257         if ( !CHECK_SQLNATIVESQLW( connection ))
258         {
259             dm_log_write( __FILE__,
260                     __LINE__,
261                     LOG_INFO,
262                     LOG_INFO,
263                     "Error: IM001" );
264 
265             __post_internal_error( &connection -> error,
266                     ERROR_IM001, NULL,
267                     connection -> environment -> requested_version );
268 
269             return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
270         }
271 
272         ret = SQLNATIVESQLW( connection,
273                 connection -> driver_dbc,
274                 sz_sql_str_in,
275                 cb_sql_str_in,
276                 sz_sql_str,
277                 cb_sql_str_max,
278                 pcb_sql_str );
279     }
280     else
281     {
282         SQLCHAR *as1 = NULL, *as2 = NULL;
283         int clen;
284 
285         if ( !CHECK_SQLNATIVESQL( connection ))
286         {
287             dm_log_write( __FILE__,
288                     __LINE__,
289                     LOG_INFO,
290                     LOG_INFO,
291                     "Error: IM001" );
292 
293             __post_internal_error( &connection -> error,
294                     ERROR_IM001, NULL,
295                     connection -> environment -> requested_version );
296 
297             return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
298         }
299 
300         as1 = (SQLCHAR*) unicode_to_ansi_alloc( sz_sql_str_in, cb_sql_str_in, connection, &clen );
301 
302         cb_sql_str_in = clen;
303 
304         if ( cb_sql_str_max > 0 && sz_sql_str )
305         {
306             as2 = malloc( cb_sql_str_max + 1 );
307         }
308 
309         ret = SQLNATIVESQL( connection,
310                 connection -> driver_dbc,
311                 as1 ? as1 : (SQLCHAR*) sz_sql_str_in,
312                 cb_sql_str_in,
313                 as2 ? as2 : (SQLCHAR*) sz_sql_str,
314                 cb_sql_str_max,
315                 pcb_sql_str );
316 
317         if ( SQL_SUCCEEDED( ret ) && as2 && sz_sql_str )
318         {
319             ansi_to_unicode_copy( sz_sql_str, (char*) as2, SQL_NTS, connection, NULL );
320         }
321 
322         if ( as1 ) free( as1 );
323         if ( as2 ) free( as2 );
324     }
325 
326     if ( log_info.log_flag )
327     {
328         /*
329          * allocate some space for the buffer
330          */
331 
332         if ( sz_sql_str && pcb_sql_str && *pcb_sql_str == SQL_NTS )
333         {
334             s1 = malloc( wide_strlen( sz_sql_str ) * 2 + 100 );
335         }
336         else if ( sz_sql_str &&  pcb_sql_str )
337         {
338             s1 = malloc( *pcb_sql_str + 100 );
339         }
340         else if ( sz_sql_str )
341         {
342             s1 = malloc( wide_strlen( sz_sql_str ) * 2 + 100 );
343         }
344         else
345         {
346             s1 = malloc( 101 );
347         }
348 
349         sprintf( connection -> msg,
350                 "\n\t\tExit:[%s]\
351 \n\t\t\tSQL Out = %s",
352                     __get_return_status( ret, s2 ),
353                     __idata_as_string( s1, SQL_CHAR,
354                         pcb_sql_str, sz_sql_str ));
355 
356         free( s1 );
357 
358         dm_log_write( __FILE__,
359                 __LINE__,
360                 LOG_INFO,
361                 LOG_INFO,
362                 connection -> msg );
363     }
364 
365     return function_return( SQL_HANDLE_DBC, connection, ret, DEFER_R3 );
366 }
367