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: SQLErrorW.c,v 1.9 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLErrorW.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/05/20 13:43:47 lurcher
37 * Vms fixes
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 2002/12/05 17:44:30 lurcher
43 *
44 * Display unknown return values in return logging
45 *
46 * Revision 1.5 2002/07/25 09:30:26 lurcher
47 *
48 * Additional unicode and iconv changes
49 *
50 * Revision 1.4 2002/07/24 08:49:52 lurcher
51 *
52 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
53 *
54 * Revision 1.3 2002/05/21 14:19:44 lurcher
55 *
56 * * Update libtool to escape from AIX build problem
57 * * Add fix to avoid file handle limitations
58 * * Add more UNICODE changes, it looks like it is native 16 representation
59 * the old way can be reproduced by defining UCS16BE
60 * * Add iusql, its just the same as isql but uses the wide functions
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:05 lurcher
70 *
71 * First upload to SourceForge
72 *
73 * Revision 1.3 2001/07/03 09:30:41 nick
74 *
75 * Add ability to alter size of displayed message in the log
76 *
77 * Revision 1.2 2001/04/12 17:43:36 nick
78 *
79 * Change logging and added autotest to odbctest
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
91static char const rcsid[]= "$RCSfile: SQLErrorW.c,v $";
92
93/*
94 * unicode mapping function
95 */
96
97static SQLRETURN extract_sql_error_w( EHEAD *head,
98 SQLWCHAR *sqlstate,
99 SQLINTEGER *native_error,
100 SQLWCHAR *message_text,
101 SQLSMALLINT buffer_length,
102 SQLSMALLINT *text_length )
103{
104 ERROR *err;
105 SQLRETURN ret;
106
107 if ( sqlstate )
108 {
109 SQLWCHAR *tmp;
110
111 tmp = ansi_to_unicode_alloc((SQLCHAR*) "00000", SQL_NTS, __get_connection( head ), NULL );
112 wide_strcpy( sqlstate, tmp );
113 free( tmp );
114 }
115
116 if ( head -> sql_error_head.error_count < 1 )
117 {
118 return SQL_NO_DATA;
119 }
120
121 err = head -> sql_error_head.error_list_head;
122 head -> sql_error_head.error_list_head = err -> next;
123
124 /*
125 * is it the last
126 */
127 if ( head -> sql_error_head.error_list_tail == err )
128 head -> sql_error_head.error_list_tail = NULL;
129
130 /*
131 * not empty yet
132 */
133 if ( head -> sql_error_head.error_list_head )
134 {
135 head -> sql_error_head.error_list_head -> prev = NULL;
136 }
137
138 head -> sql_error_head.error_count --;
139
140 if ( sqlstate )
141 {
142 wide_strcpy( sqlstate, err -> sqlstate );
143 }
144 if ( message_text && buffer_length < wide_strlen( err -> msg ) + 1 )
145 {
146 ret = SQL_SUCCESS_WITH_INFO;
147 }
148 else
149 {
150 ret = SQL_SUCCESS;
151 }
152
153 if ( message_text )
154 {
155 if ( ret == SQL_SUCCESS )
156 {
157 wide_strcpy( message_text, err -> msg );
158 }
159 else
160 {
161 memcpy( message_text, err -> msg, buffer_length * 2 );
162 message_text[ buffer_length - 1 ] = 0;
163 }
164 }
165
166 if ( text_length )
167 {
168 *text_length = wide_strlen( err -> msg );
169 }
170
171 if ( native_error )
172 {
173 *native_error = err -> native_error;
174 }
175
176 /*
177 * clean up
178 */
179
180 free( err -> msg );
181 free( err );
182
183 /*
184 * map 3 to 2 if required
185 */
186
187 if ( SQL_SUCCEEDED( ret ) && sqlstate )
188 __map_error_state_w( sqlstate, __get_version( head ));
189
190 return ret;
191}
192
193SQLRETURN SQLErrorW( SQLHENV environment_handle,
194 SQLHDBC connection_handle,
195 SQLHSTMT statement_handle,
196 SQLWCHAR *sqlstate,
197 SQLINTEGER *native_error,
198 SQLWCHAR *message_text,
199 SQLSMALLINT buffer_length,
200 SQLSMALLINT *text_length )
201{
202 SQLRETURN ret;
203 SQLCHAR s0[ 32 ], s1[ 100 + LOG_MESSAGE_LEN ];
204 SQLCHAR s2[ 100 + LOG_MESSAGE_LEN ];
205 SQLCHAR s3[ 100 + LOG_MESSAGE_LEN ];
206
207 if ( statement_handle )
208 {
209 DMHSTMT statement = ( DMHSTMT ) statement_handle;
210
211 if ( !__validate_stmt( statement ))
212 {
213 dm_log_write( __FILE__,
214 __LINE__,
215 LOG_INFO,
216 LOG_INFO,
217 "Error: SQL_INVALID_HANDLE" );
218
219#ifdef WITH_HANDLE_REDIRECT
220 {
221 DMHSTMT parent_statement;
222
223 parent_statement = find_parent_handle( statement, SQL_HANDLE_STMT );
224
225 if ( parent_statement ) {
226 dm_log_write( __FILE__,
227 __LINE__,
228 LOG_INFO,
229 LOG_INFO,
230 "Info: found parent handle" );
231
232 if ( CHECK_SQLERRORW( parent_statement -> connection ))
233 {
234 dm_log_write( __FILE__,
235 __LINE__,
236 LOG_INFO,
237 LOG_INFO,
238 "Info: calling redirected driver function" );
239
240 return SQLERRORW( parent_statement -> connection,
241 environment_handle,
242 connection_handle,
243 statement_handle,
244 sqlstate,
245 native_error,
246 message_text,
247 buffer_length,
248 text_length );
249 }
250 }
251 }
252#endif
253 return SQL_INVALID_HANDLE;
254 }
255
256 thread_protect( SQL_HANDLE_STMT, statement );
257
258 if ( log_info.log_flag )
259 {
260 sprintf( statement -> msg,
261 "\n\t\tEntry:\
262\n\t\t\tStatement = %p\
263\n\t\t\tSQLState = %p\
264\n\t\t\tNative = %p\
265\n\t\t\tMessage Text = %p\
266\n\t\t\tBuffer Length = %d\
267\n\t\t\tText Len Ptr = %p",
268 statement,
269 sqlstate,
270 native_error,
271 message_text,
272 buffer_length,
273 text_length );
274
275 dm_log_write( __FILE__,
276 __LINE__,
277 LOG_INFO,
278 LOG_INFO,
279 statement -> msg );
280 }
281
282 ret = extract_sql_error_w( &statement -> error,
283 sqlstate,
284 native_error,
285 message_text,
286 buffer_length,
287 text_length );
288
289 if ( log_info.log_flag )
290 {
291 if ( SQL_SUCCEEDED( ret ))
292 {
293 char *ts1, *ts2;
294
295 sprintf( statement -> msg,
296 "\n\t\tExit:[%s]\
297\n\t\t\tSQLState = %s\
298\n\t\t\tNative = %s\
299\n\t\t\tMessage Text = %s",
300 __get_return_status( ret, s2 ),
301 __sdata_as_string( s3, SQL_CHAR,
302 NULL, ts1 = unicode_to_ansi_alloc( sqlstate, SQL_NTS, statement -> connection, NULL )),
303 __iptr_as_string( s0, native_error ),
304 __sdata_as_string( s1, SQL_CHAR,
305 text_length, ( ts2 = unicode_to_ansi_alloc( message_text, SQL_NTS, statement -> connection, NULL ))));
306
307 free( ts1 );
308 free( ts2 );
309 }
310 else
311 {
312 sprintf( statement -> msg,
313 "\n\t\tExit:[%s]",
314 __get_return_status( ret, s2 ));
315 }
316
317 dm_log_write( __FILE__,
318 __LINE__,
319 LOG_INFO,
320 LOG_INFO,
321 statement -> msg );
322 }
323
324 thread_release( SQL_HANDLE_STMT, statement );
325
326 return ret;
327 }
328 else if ( connection_handle )
329 {
330 DMHDBC connection = ( DMHDBC ) connection_handle;
331
332 if ( !__validate_dbc( connection ))
333 {
334 dm_log_write( __FILE__,
335 __LINE__,
336 LOG_INFO,
337 LOG_INFO,
338 "Error: SQL_INVALID_HANDLE" );
339
340#ifdef WITH_HANDLE_REDIRECT
341 {
342 DMHDBC parent_connection;
343
344 parent_connection = find_parent_handle( connection, SQL_HANDLE_DBC );
345
346 if ( parent_connection ) {
347 dm_log_write( __FILE__,
348 __LINE__,
349 LOG_INFO,
350 LOG_INFO,
351 "Info: found parent handle" );
352
353 if ( CHECK_SQLERRORW( parent_connection ))
354 {
355 dm_log_write( __FILE__,
356 __LINE__,
357 LOG_INFO,
358 LOG_INFO,
359 "Info: calling redirected driver function" );
360
361 return SQLERRORW( parent_connection,
362 environment_handle,
363 connection_handle,
364 statement_handle,
365 sqlstate,
366 native_error,
367 message_text,
368 buffer_length,
369 text_length );
370 }
371 }
372 }
373#endif
374 return SQL_INVALID_HANDLE;
375 }
376
377 thread_protect( SQL_HANDLE_DBC, connection );
378
379 if ( log_info.log_flag )
380 {
381 sprintf( connection -> msg,
382 "\n\t\tEntry:\
383\n\t\t\tConnection = %p\
384\n\t\t\tSQLState = %p\
385\n\t\t\tNative = %p\
386\n\t\t\tMessage Text = %p\
387\n\t\t\tBuffer Length = %d\
388\n\t\t\tText Len Ptr = %p",
389 connection,
390 sqlstate,
391 native_error,
392 message_text,
393 buffer_length,
394 text_length );
395
396 dm_log_write( __FILE__,
397 __LINE__,
398 LOG_INFO,
399 LOG_INFO,
400 connection -> msg );
401 }
402
403 ret = extract_sql_error_w( &connection -> error,
404 sqlstate,
405 native_error,
406 message_text,
407 buffer_length,
408 text_length );
409
410 if ( log_info.log_flag )
411 {
412 if ( SQL_SUCCEEDED( ret ))
413 {
414 char *ts1, *ts2;
415
416 sprintf( connection -> msg,
417 "\n\t\tExit:[%s]\
418\n\t\t\tSQLState = %s\
419\n\t\t\tNative = %s\
420\n\t\t\tMessage Text = %s",
421 __get_return_status( ret, s2 ),
422 __sdata_as_string( s3, SQL_CHAR,
423 NULL, ts1 = unicode_to_ansi_alloc( sqlstate, SQL_NTS, connection, NULL )),
424 __iptr_as_string( s0, native_error ),
425 __sdata_as_string( s1, SQL_CHAR,
426 text_length, ( ts2 = unicode_to_ansi_alloc( message_text, SQL_NTS, connection, NULL ))));
427
428 free( ts1 );
429 free( ts2 );
430 }
431 else
432 {
433 sprintf( connection -> msg,
434 "\n\t\tExit:[%s]",
435 __get_return_status( ret, s2 ));
436 }
437
438 dm_log_write( __FILE__,
439 __LINE__,
440 LOG_INFO,
441 LOG_INFO,
442 connection -> msg );
443 }
444
445 thread_release( SQL_HANDLE_DBC, connection );
446 }
447 else if ( environment_handle )
448 {
449 DMHENV environment = ( DMHENV ) environment_handle;
450
451 if ( !__validate_env( environment ))
452 {
453 dm_log_write( __FILE__,
454 __LINE__,
455 LOG_INFO,
456 LOG_INFO,
457 "Error: SQL_INVALID_HANDLE" );
458
459 return SQL_INVALID_HANDLE;
460 }
461
462 thread_protect( SQL_HANDLE_ENV, environment );
463
464 if ( log_info.log_flag )
465 {
466 sprintf( environment -> msg,
467 "\n\t\tEntry:\
468\n\t\t\tEnvironment = %p\
469\n\t\t\tSQLState = %p\
470\n\t\t\tNative = %p\
471\n\t\t\tMessage Text = %p\
472\n\t\t\tBuffer Length = %d\
473\n\t\t\tText Len Ptr = %p",
474 environment,
475 sqlstate,
476 native_error,
477 message_text,
478 buffer_length,
479 text_length );
480
481 dm_log_write( __FILE__,
482 __LINE__,
483 LOG_INFO,
484 LOG_INFO,
485 environment -> msg );
486 }
487
488 ret = extract_sql_error_w( &environment -> error,
489 sqlstate,
490 native_error,
491 message_text,
492 buffer_length,
493 text_length );
494
495 if ( log_info.log_flag )
496 {
497 if ( SQL_SUCCEEDED( ret ))
498 {
499 char *ts1, *ts2;
500
501 sprintf( environment -> msg,
502 "\n\t\tExit:[%s]\
503\n\t\t\tSQLState = %s\
504\n\t\t\tNative = %s\
505\n\t\t\tMessage Text = %s",
506 __get_return_status( ret, s2 ),
507 __sdata_as_string( s3, SQL_CHAR,
508 NULL, ts1 = unicode_to_ansi_alloc( sqlstate, SQL_NTS, NULL, NULL )),
509 __iptr_as_string( s0, native_error ),
510 __sdata_as_string( s1, SQL_CHAR,
511 text_length, ( ts2 = unicode_to_ansi_alloc( message_text, SQL_NTS, NULL, NULL ))));
512
513 free( ts1 );
514 free( ts2 );
515 }
516 else
517 {
518 sprintf( environment -> msg,
519 "\n\t\tExit:[%s]",
520 __get_return_status( ret, s2 ));
521 }
522
523 dm_log_write( __FILE__,
524 __LINE__,
525 LOG_INFO,
526 LOG_INFO,
527 environment -> msg );
528 }
529
530 thread_release( SQL_HANDLE_ENV, environment );
531 }
532 else
533 {
534 dm_log_write( __FILE__,
535 __LINE__,
536 LOG_INFO,
537 LOG_INFO,
538 "Error: SQL_INVALID_HANDLE" );
539
540 return SQL_INVALID_HANDLE;
541 }
542
543 return ret;
544}
545
546