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: SQLGetDiagRecW.c,v 1.11 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLGetDiagRecW.c,v $
33 * Revision 1.11 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.10 2009/02/04 09:30:02 lurcher
37 * Fix some SQLINTEGER/SQLLEN conflicts
38 *
39 * Revision 1.9 2007/11/26 11:37:23 lurcher
40 * Sync up before tag
41 *
42 * Revision 1.8 2007/02/28 15:37:48 lurcher
43 * deal with drivers that call internal W functions and end up in the driver manager. controlled by the --enable-handlemap configure arg
44 *
45 * Revision 1.7 2002/12/05 17:44:31 lurcher
46 *
47 * Display unknown return values in return logging
48 *
49 * Revision 1.6 2002/11/11 17:10:17 lurcher
50 *
51 * VMS changes
52 *
53 * Revision 1.5 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.4 2002/07/24 08:49:52 lurcher
59 *
60 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
61 *
62 * Revision 1.3 2002/05/21 14:19:44 lurcher
63 *
64 * * Update libtool to escape from AIX build problem
65 * * Add fix to avoid file handle limitations
66 * * Add more UNICODE changes, it looks like it is native 16 representation
67 * the old way can be reproduced by defining UCS16BE
68 * * Add iusql, its just the same as isql but uses the wide functions
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.3 2001/07/03 09:30:41 nick
82 *
83 * Add ability to alter size of displayed message in the log
84 *
85 * Revision 1.2 2001/04/12 17:43:36 nick
86 *
87 * Change logging and added autotest to odbctest
88 *
89 * Revision 1.1 2000/12/31 20:30:54 nick
90 *
91 * Add UNICODE support
92 *
93 *
94 **********************************************************************/
95
96#include <config.h>
97#include "drivermanager.h"
98
99static char const rcsid[]= "$RCSfile: SQLGetDiagRecW.c,v $";
100
101extern int __is_env( EHEAD * head ); /* in SQLGetDiagRec.c */
102
103static SQLRETURN extract_sql_error_rec_w( EHEAD *head,
104 SQLWCHAR *sqlstate,
105 SQLINTEGER rec_number,
106 SQLINTEGER *native_error,
107 SQLWCHAR *message_text,
108 SQLSMALLINT buffer_length,
109 SQLSMALLINT *text_length )
110{
111 SQLRETURN ret;
112
113 if ( sqlstate )
114 {
115 SQLWCHAR *tmp;
116
117 tmp = ansi_to_unicode_alloc((SQLCHAR*) "00000", SQL_NTS, __get_connection( head ), NULL );
118 wide_strcpy( sqlstate, tmp );
119 free( tmp );
120 }
121
122 if ( rec_number <= head -> sql_diag_head.internal_count )
123 {
124 ERROR *ptr;
125
126 ptr = head -> sql_diag_head.internal_list_head;
127 while( rec_number > 1 )
128 {
129 ptr = ptr -> next;
130 rec_number --;
131 }
132
133 if ( !ptr )
134 {
135 return SQL_NO_DATA;
136 }
137
138 if ( sqlstate )
139 {
140 wide_strcpy( sqlstate, ptr -> sqlstate );
141 }
142 if ( buffer_length < wide_strlen( ptr -> msg ) + 1 )
143 {
144 ret = SQL_SUCCESS_WITH_INFO;
145 }
146 else
147 {
148 ret = SQL_SUCCESS;
149 }
150
151 if ( message_text )
152 {
153 if ( ret == SQL_SUCCESS )
154 {
155 wide_strcpy( message_text, ptr -> msg );
156 }
157 else
158 {
159 memcpy( message_text, ptr -> msg, buffer_length * 2 );
160 message_text[ buffer_length - 1 ] = '\0';
161 }
162 }
163
164 if ( text_length )
165 {
166 *text_length = wide_strlen( ptr -> msg );
167 }
168
169 if ( native_error )
170 {
171 *native_error = ptr -> native_error;
172 }
173
174 /*
175 * map 3 to 2 if required
176 */
177
178 if ( SQL_SUCCEEDED( ret ) && sqlstate )
179 __map_error_state_w(sqlstate, __get_version( head ));
180
181 return ret;
182 }
183 else if ( !__is_env( head ) && __get_connection( head ) -> state != STATE_C2
184 && head->sql_diag_head.error_count )
185 {
186 ERROR *ptr;
187 rec_number -= head -> sql_diag_head.internal_count;
188
189 if ( __get_connection( head ) -> unicode_driver &&
190 CHECK_SQLGETDIAGRECW( __get_connection( head )))
191 {
192 ret = SQLGETDIAGRECW( __get_connection( head ),
193 head -> handle_type,
194 __get_driver_handle( head ),
195 rec_number,
196 sqlstate,
197 native_error,
198 message_text,
199 buffer_length,
200 text_length );
201
202 /*
203 * map 3 to 2 if required
204 */
205
206 if ( SQL_SUCCEEDED( ret ) && sqlstate )
207 {
208 __map_error_state_w( sqlstate, __get_version( head ));
209 }
210
211 return ret;
212 }
213 else if ( !__get_connection( head ) -> unicode_driver &&
214 CHECK_SQLGETDIAGREC( __get_connection( head )))
215 {
216 SQLCHAR *as1 = NULL, *as2 = NULL;
217
218 if ( sqlstate )
219 {
220 as1 = malloc( 7 );
221 }
222
223 if ( message_text && buffer_length > 0 )
224 {
225 as2 = malloc( buffer_length + 1 );
226 }
227
228 ret = SQLGETDIAGREC( __get_connection( head ),
229 head -> handle_type,
230 __get_driver_handle( head ),
231 rec_number,
232 as1 ? as1 : (SQLCHAR *)sqlstate,
233 native_error,
234 as2 ? as2 : (SQLCHAR *)message_text,
235 buffer_length,
236 text_length );
237
238 /*
239 * map 3 to 2 if required
240 */
241
242 if ( SQL_SUCCEEDED( ret ) && sqlstate )
243 {
244 if ( sqlstate )
245 {
246 if ( as1 )
247 {
248 ansi_to_unicode_copy( sqlstate,(char*) as1, SQL_NTS, __get_connection( head ), NULL );
249 __map_error_state_w( sqlstate, __get_version( head ));
250 }
251 }
252 if ( message_text )
253 {
254 if ( as2 )
255 {
256 ansi_to_unicode_copy( message_text,(char*) as2, SQL_NTS, __get_connection( head ), NULL );
257 }
258 }
259 }
260
261 if ( as1 ) free( as1 );
262 if ( as2 ) free( as2 );
263
264 return ret;
265 }
266 else
267 {
268 ptr = head -> sql_diag_head.error_list_head;
269 while( rec_number > 1 )
270 {
271 ptr = ptr -> next;
272 rec_number --;
273 }
274
275 if ( !ptr )
276 {
277 return SQL_NO_DATA;
278 }
279
280 if ( sqlstate )
281 {
282 wide_strcpy( sqlstate, ptr -> sqlstate );
283 }
284 if ( buffer_length < wide_strlen( ptr -> msg ) + 1 )
285 {
286 ret = SQL_SUCCESS_WITH_INFO;
287 }
288 else
289 {
290 ret = SQL_SUCCESS;
291 }
292
293 if ( message_text )
294 {
295 if ( ret == SQL_SUCCESS )
296 {
297 wide_strcpy( message_text, ptr -> msg );
298 }
299 else
300 {
301 memcpy( message_text, ptr -> msg, buffer_length * 2 );
302 message_text[ buffer_length - 1 ] = '\0';
303 }
304 }
305
306 if ( text_length )
307 {
308 *text_length = wide_strlen( ptr -> msg );
309 }
310
311 if ( native_error )
312 {
313 *native_error = ptr -> native_error;
314 }
315
316 /*
317 * map 3 to 2 if required
318 */
319
320 if ( SQL_SUCCEEDED( ret ) && sqlstate )
321 __map_error_state_w( sqlstate, __get_version( head ));
322
323 return ret;
324 }
325 }
326 else
327 {
328 return SQL_NO_DATA;
329 }
330}
331
332SQLRETURN SQLGetDiagRecW( SQLSMALLINT handle_type,
333 SQLHANDLE handle,
334 SQLSMALLINT rec_number,
335 SQLWCHAR *sqlstate,
336 SQLINTEGER *native,
337 SQLWCHAR *message_text,
338 SQLSMALLINT buffer_length,
339 SQLSMALLINT *text_length_ptr )
340{
341 SQLRETURN ret;
342 SQLCHAR s0[ 32 ], s1[ 100 + LOG_MESSAGE_LEN ];
343 SQLCHAR s2[ 100 + LOG_MESSAGE_LEN ];
344 SQLCHAR s3[ 100 + LOG_MESSAGE_LEN ];
345
346 if ( rec_number < 1 )
347 {
348 return SQL_ERROR;
349 }
350
351 if ( handle_type == SQL_HANDLE_ENV )
352 {
353 DMHENV environment = ( DMHENV ) handle;
354
355 if ( !__validate_env( environment ))
356 {
357 dm_log_write( __FILE__,
358 __LINE__,
359 LOG_INFO,
360 LOG_INFO,
361 "Error: SQL_INVALID_HANDLE" );
362
363 return SQL_INVALID_HANDLE;
364 }
365
366 thread_protect( SQL_HANDLE_ENV, environment );
367
368 if ( log_info.log_flag )
369 {
370 sprintf( environment -> msg,
371 "\n\t\tEntry:\
372\n\t\t\tEnvironment = %p\
373\n\t\t\tRec Number = %d\
374\n\t\t\tSQLState = %p\
375\n\t\t\tNative = %p\
376\n\t\t\tMessage Text = %p\
377\n\t\t\tBuffer Length = %d\
378\n\t\t\tText Len Ptr = %p",
379 environment,
380 rec_number,
381 sqlstate,
382 native,
383 message_text,
384 buffer_length,
385 text_length_ptr );
386
387 dm_log_write( __FILE__,
388 __LINE__,
389 LOG_INFO,
390 LOG_INFO,
391 environment -> msg );
392 }
393
394 ret = extract_sql_error_rec_w( &environment -> error,
395 sqlstate,
396 rec_number,
397 native,
398 message_text,
399 buffer_length,
400 text_length_ptr );
401
402 if ( log_info.log_flag )
403 {
404 if ( SQL_SUCCEEDED( ret ))
405 {
406 char *ts1, *ts2;
407
408 sprintf( environment -> msg,
409 "\n\t\tExit:[%s]\
410\n\t\t\tSQLState = %s\
411\n\t\t\tNative = %s\
412\n\t\t\tMessage Text = %s",
413 __get_return_status( ret, s2 ),
414 __sdata_as_string( s3, SQL_CHAR,
415 NULL, ts1 = unicode_to_ansi_alloc( sqlstate, SQL_NTS, NULL, NULL )),
416 __iptr_as_string( s0, native ),
417 __sdata_as_string( s1, SQL_CHAR,
418 text_length_ptr, ts2 = unicode_to_ansi_alloc( message_text, SQL_NTS, NULL, NULL )));
419
420 if ( ts1 ) {
421 free( ts1 );
422 }
423 if ( ts2 ) {
424 free( ts2 );
425 }
426 }
427 else
428 {
429 sprintf( environment -> msg,
430 "\n\t\tExit:[%s]",
431 __get_return_status( ret, s2 ));
432 }
433
434 dm_log_write( __FILE__,
435 __LINE__,
436 LOG_INFO,
437 LOG_INFO,
438 environment -> msg );
439 }
440
441 thread_release( SQL_HANDLE_ENV, environment );
442
443 return ret;
444 }
445 else if ( handle_type == SQL_HANDLE_DBC )
446 {
447 DMHDBC connection = ( DMHDBC ) handle;
448
449 if ( !__validate_dbc( connection ))
450 {
451 dm_log_write( __FILE__,
452 __LINE__,
453 LOG_INFO,
454 LOG_INFO,
455 "Error: SQL_INVALID_HANDLE" );
456
457#ifdef WITH_HANDLE_REDIRECT
458 {
459 DMHDBC parent_connection;
460
461 parent_connection = find_parent_handle( connection, SQL_HANDLE_DBC );
462
463 if ( parent_connection ) {
464 dm_log_write( __FILE__,
465 __LINE__,
466 LOG_INFO,
467 LOG_INFO,
468 "Info: found parent handle" );
469
470 if ( CHECK_SQLGETDIAGRECW( parent_connection ))
471 {
472 dm_log_write( __FILE__,
473 __LINE__,
474 LOG_INFO,
475 LOG_INFO,
476 "Info: calling redirected driver function" );
477
478 return SQLGETDIAGRECW( parent_connection,
479 handle_type,
480 connection,
481 rec_number,
482 sqlstate,
483 native,
484 message_text,
485 buffer_length,
486 text_length_ptr );
487 }
488 }
489 }
490#endif
491 return SQL_INVALID_HANDLE;
492 }
493
494 thread_protect( SQL_HANDLE_DBC, connection );
495
496 if ( log_info.log_flag )
497 {
498 sprintf( connection -> msg,
499 "\n\t\tEntry:\
500\n\t\t\tConnection = %p\
501\n\t\t\tRec Number = %d\
502\n\t\t\tSQLState = %p\
503\n\t\t\tNative = %p\
504\n\t\t\tMessage Text = %p\
505\n\t\t\tBuffer Length = %d\
506\n\t\t\tText Len Ptr = %p",
507 connection,
508 rec_number,
509 sqlstate,
510 native,
511 message_text,
512 buffer_length,
513 text_length_ptr );
514
515 dm_log_write( __FILE__,
516 __LINE__,
517 LOG_INFO,
518 LOG_INFO,
519 connection -> msg );
520 }
521
522 ret = extract_sql_error_rec_w( &connection -> error,
523 sqlstate,
524 rec_number,
525 native,
526 message_text,
527 buffer_length,
528 text_length_ptr );
529
530 if ( log_info.log_flag )
531 {
532 if ( SQL_SUCCEEDED( ret ))
533 {
534 char *ts1, *ts2;
535
536 sprintf( connection -> msg,
537 "\n\t\tExit:[%s]\
538\n\t\t\tSQLState = %s\
539\n\t\t\tNative = %s\
540\n\t\t\tMessage Text = %s",
541 __get_return_status( ret, s2 ),
542 __sdata_as_string( s3, SQL_CHAR,
543 NULL, ts1 = unicode_to_ansi_alloc( sqlstate, SQL_NTS, connection, NULL )),
544 __iptr_as_string( s0, native ),
545 __sdata_as_string( s1, SQL_CHAR,
546 text_length_ptr, ts2 = unicode_to_ansi_alloc( message_text, SQL_NTS, connection, NULL )));
547
548 if ( ts1 ) {
549 free( ts1 );
550 }
551 if ( ts2 ) {
552 free( ts2 );
553 }
554 }
555 else
556 {
557 sprintf( connection -> msg,
558 "\n\t\tExit:[%s]",
559 __get_return_status( ret, s2 ));
560 }
561
562 dm_log_write( __FILE__,
563 __LINE__,
564 LOG_INFO,
565 LOG_INFO,
566 connection -> msg );
567 }
568
569 thread_release( SQL_HANDLE_DBC, connection );
570
571 return ret;
572 }
573 else if ( handle_type == SQL_HANDLE_STMT )
574 {
575 DMHSTMT statement = ( DMHSTMT ) handle;
576
577 if ( !__validate_stmt( statement ))
578 {
579 dm_log_write( __FILE__,
580 __LINE__,
581 LOG_INFO,
582 LOG_INFO,
583 "Error: SQL_INVALID_HANDLE" );
584
585#ifdef WITH_HANDLE_REDIRECT
586 {
587 DMHSTMT parent_statement;
588
589 parent_statement = find_parent_handle( statement, SQL_HANDLE_STMT );
590
591 if ( parent_statement ) {
592 dm_log_write( __FILE__,
593 __LINE__,
594 LOG_INFO,
595 LOG_INFO,
596 "Info: found parent handle" );
597
598 if ( CHECK_SQLGETDIAGRECW( parent_statement -> connection ))
599 {
600 dm_log_write( __FILE__,
601 __LINE__,
602 LOG_INFO,
603 LOG_INFO,
604 "Info: calling redirected driver function" );
605
606 return SQLGETDIAGRECW( parent_statement -> connection,
607 handle_type,
608 statement,
609 rec_number,
610 sqlstate,
611 native,
612 message_text,
613 buffer_length,
614 text_length_ptr );
615 }
616 }
617 }
618#endif
619 return SQL_INVALID_HANDLE;
620 }
621
622 thread_protect( SQL_HANDLE_STMT, statement );
623
624 if ( log_info.log_flag )
625 {
626 sprintf( statement -> msg,
627 "\n\t\tEntry:\
628\n\t\t\tStatement = %p\
629\n\t\t\tRec Number = %d\
630\n\t\t\tSQLState = %p\
631\n\t\t\tNative = %p\
632\n\t\t\tMessage Text = %p\
633\n\t\t\tBuffer Length = %d\
634\n\t\t\tText Len Ptr = %p",
635 statement,
636 rec_number,
637 sqlstate,
638 native,
639 message_text,
640 buffer_length,
641 text_length_ptr );
642
643 dm_log_write( __FILE__,
644 __LINE__,
645 LOG_INFO,
646 LOG_INFO,
647 statement -> msg );
648 }
649
650 ret = extract_sql_error_rec_w( &statement -> error,
651 sqlstate,
652 rec_number,
653 native,
654 message_text,
655 buffer_length,
656 text_length_ptr );
657
658 if ( log_info.log_flag )
659 {
660 if ( SQL_SUCCEEDED( ret ))
661 {
662 char *ts1, *ts2;
663
664 sprintf( statement -> msg,
665 "\n\t\tExit:[%s]\
666\n\t\t\tSQLState = %s\
667\n\t\t\tNative = %s\
668\n\t\t\tMessage Text = %s",
669 __get_return_status( ret, s2 ),
670 __sdata_as_string( s3, SQL_CHAR,
671 NULL, ts1 = unicode_to_ansi_alloc( sqlstate, SQL_NTS, statement -> connection, NULL )),
672 __iptr_as_string( s0, native ),
673 __sdata_as_string( s1, SQL_CHAR,
674 text_length_ptr, ts2 = unicode_to_ansi_alloc( message_text, SQL_NTS, statement -> connection, NULL )));
675
676 if ( ts1 ) {
677 free( ts1 );
678 }
679 if ( ts2 ) {
680 free( ts2 );
681 }
682 }
683 else
684 {
685 sprintf( statement -> msg,
686 "\n\t\tExit:[%s]",
687 __get_return_status( ret, s2 ));
688 }
689
690 dm_log_write( __FILE__,
691 __LINE__,
692 LOG_INFO,
693 LOG_INFO,
694 statement -> msg );
695 }
696
697 thread_release( SQL_HANDLE_STMT, statement );
698
699 return ret;
700 }
701 else if ( handle_type == SQL_HANDLE_DESC )
702 {
703 DMHDESC descriptor = ( DMHDESC ) handle;
704
705 if ( !__validate_desc( descriptor ))
706 {
707 dm_log_write( __FILE__,
708 __LINE__,
709 LOG_INFO,
710 LOG_INFO,
711 "Error: SQL_INVALID_HANDLE" );
712
713#ifdef WITH_HANDLE_REDIRECT
714 {
715 DMHDESC parent_desc;
716
717 parent_desc = find_parent_handle( descriptor, SQL_HANDLE_DESC );
718
719 if ( parent_desc ) {
720 dm_log_write( __FILE__,
721 __LINE__,
722 LOG_INFO,
723 LOG_INFO,
724 "Info: found parent handle" );
725
726 if ( CHECK_SQLGETDIAGRECW( parent_desc -> connection ))
727 {
728 dm_log_write( __FILE__,
729 __LINE__,
730 LOG_INFO,
731 LOG_INFO,
732 "Info: calling redirected driver function" );
733
734 return SQLGETDIAGRECW( parent_desc -> connection,
735 handle_type,
736 descriptor,
737 rec_number,
738 sqlstate,
739 native,
740 message_text,
741 buffer_length,
742 text_length_ptr );
743 }
744 }
745 }
746#endif
747 return SQL_INVALID_HANDLE;
748 }
749
750 thread_protect( SQL_HANDLE_DESC, descriptor );
751
752 if ( log_info.log_flag )
753 {
754 sprintf( descriptor -> msg,
755 "\n\t\tEntry:\
756\n\t\t\tDescriptor = %p\
757\n\t\t\tRec Number = %d\
758\n\t\t\tSQLState = %p\
759\n\t\t\tNative = %p\
760\n\t\t\tMessage Text = %p\
761\n\t\t\tBuffer Length = %d\
762\n\t\t\tText Len Ptr = %p",
763 descriptor,
764 rec_number,
765 sqlstate,
766 native,
767 message_text,
768 buffer_length,
769 text_length_ptr );
770
771 dm_log_write( __FILE__,
772 __LINE__,
773 LOG_INFO,
774 LOG_INFO,
775 descriptor -> msg );
776 }
777
778 ret = extract_sql_error_rec_w( &descriptor -> error,
779 sqlstate,
780 rec_number,
781 native,
782 message_text,
783 buffer_length,
784 text_length_ptr );
785
786 if ( log_info.log_flag )
787 {
788 if ( SQL_SUCCEEDED( ret ))
789 {
790 char *ts1, *ts2;
791
792 sprintf( descriptor -> msg,
793 "\n\t\tExit:[%s]\
794\n\t\t\tSQLState = %s\
795\n\t\t\tNative = %s\
796\n\t\t\tMessage Text = %s",
797 __get_return_status( ret, s2 ),
798 __sdata_as_string( s3, SQL_CHAR,
799 NULL, ts1 = unicode_to_ansi_alloc( sqlstate, SQL_NTS, descriptor -> connection, NULL )),
800 __iptr_as_string( s0, native ),
801 __sdata_as_string( s1, SQL_CHAR,
802 text_length_ptr, ts2 = unicode_to_ansi_alloc( message_text, SQL_NTS, descriptor -> connection, NULL )));
803
804 if ( ts1 ) {
805 free( ts1 );
806 }
807 if ( ts2 ) {
808 free( ts2 );
809 }
810 }
811 else
812 {
813 sprintf( descriptor -> msg,
814 "\n\t\tExit:[%s]",
815 __get_return_status( ret, s2 ));
816 }
817
818 dm_log_write( __FILE__,
819 __LINE__,
820 LOG_INFO,
821 LOG_INFO,
822 descriptor -> msg );
823 }
824
825 thread_release( SQL_HANDLE_DESC, descriptor );
826
827 return ret;
828 }
829 return SQL_NO_DATA;
830}
831
832