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: SQLGetDiagField.c,v 1.17 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLGetDiagField.c,v $
33 * Revision 1.17 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.16 2009/02/17 09:47:44 lurcher
37 * Clear up a number of bugs
38 *
39 * Revision 1.15 2009/02/04 09:30:01 lurcher
40 * Fix some SQLINTEGER/SQLLEN conflicts
41 *
42 * Revision 1.14 2008/09/29 14:02:45 lurcher
43 * Fix missing dlfcn group option
44 *
45 * Revision 1.13 2007/03/05 09:49:24 lurcher
46 * Get it to build on VMS again
47 *
48 * Revision 1.12 2006/11/27 14:08:33 lurcher
49 * Sync up dirs
50 *
51 * Revision 1.11 2006/05/31 17:35:34 lurcher
52 * Add unicode ODBCINST entry points
53 *
54 * Revision 1.10 2006/03/08 09:18:41 lurcher
55 * fix silly typo that was using sizeof( SQL_WCHAR ) instead of SQLWCHAR
56 *
57 * Revision 1.9 2005/12/19 18:43:26 lurcher
58 * Add new parts to contrib and alter how the errors are returned from the driver
59 *
60 * Revision 1.8 2003/02/27 12:19:39 lurcher
61 *
62 * Add the A functions as well as the W
63 *
64 * Revision 1.7 2002/12/05 17:44:30 lurcher
65 *
66 * Display unknown return values in return logging
67 *
68 * Revision 1.6 2002/11/11 17:10:12 lurcher
69 *
70 * VMS changes
71 *
72 * Revision 1.5 2002/07/24 08:49:52 lurcher
73 *
74 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
75 *
76 * Revision 1.4 2002/01/30 12:20:02 lurcher
77 *
78 * Add MyODBC 3 driver source
79 *
80 * Revision 1.3 2002/01/21 18:00:51 lurcher
81 *
82 * Assorted fixed and changes, mainly UNICODE/bug fixes
83 *
84 * Revision 1.2 2001/12/13 13:00:32 lurcher
85 *
86 * Remove most if not all warnings on 64 bit platforms
87 * Add support for new MS 3.52 64 bit changes
88 * Add override to disable the stopping of tracing
89 * Add MAX_ROWS support in postgres driver
90 *
91 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
92 *
93 * First upload to SourceForge
94 *
95 * Revision 1.4 2001/07/03 09:30:41 nick
96 *
97 * Add ability to alter size of displayed message in the log
98 *
99 * Revision 1.3 2001/04/12 17:43:36 nick
100 *
101 * Change logging and added autotest to odbctest
102 *
103 * Revision 1.2 2000/12/31 20:30:54 nick
104 *
105 * Add UNICODE support
106 *
107 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
108 * Imported Sources
109 *
110 * Revision 1.15 2000/08/22 22:56:27 ngorham
111 *
112 * Add fix to SQLGetDiagField to return the server name on statements and
113 * descriptors
114 *
115 * Revision 1.14 2000/08/21 10:31:58 ngorham
116 *
117 * Add missing line continuation char
118 *
119 * Revision 1.13 2000/08/09 08:48:18 ngorham
120 *
121 * Fix for SQLGetDiagField(SQL_DIAG_SUBCLASS_ORIGIN) returning a null string
122 *
123 * Revision 1.12 2000/08/03 10:49:34 ngorham
124 *
125 * Fix buffer overrun problem in GetDiagField
126 *
127 * Revision 1.11 2000/07/31 20:48:01 ngorham
128 *
129 * Fix bugs in SQLGetDiagField and with SQLColAttributes
130 *
131 * Revision 1.10 2000/06/23 16:11:35 ngorham
132 *
133 * Map ODBC 2 SQLSTATE values to ODBC 3
134 *
135 * Revision 1.9 2000/05/21 21:49:19 ngorham
136 *
137 * Assorted fixes
138 *
139 * Revision 1.8 1999/11/17 21:08:58 ngorham
140 *
141 * Fix Bug with the ODBC 3 error handling
142 *
143 * Revision 1.7 1999/11/13 23:40:59 ngorham
144 *
145 * Alter the way DM logging works
146 * Upgrade the Postgres driver to 6.4.6
147 *
148 * Revision 1.6 1999/11/10 03:51:33 ngorham
149 *
150 * Update the error reporting in the DM to enable ODBC 3 and 2 calls to
151 * work at the same time
152 *
153 * Revision 1.5 1999/09/21 22:34:25 ngorham
154 *
155 * Improve performance by removing unneeded logging calls when logging is
156 * disabled
157 *
158 * Revision 1.4 1999/07/12 19:42:06 ngorham
159 *
160 * Finished off SQLGetDiagField.c and fixed a but that caused SQLError to
161 * fail with Perl and PHP, connect errors were not being returned because
162 * I was checking to the environment being set, they were setting the
163 * statement and the environment. The order of checking has been changed.
164 *
165 * Revision 1.3 1999/07/04 21:05:07 ngorham
166 *
167 * Add LGPL Headers to code
168 *
169 * Revision 1.2 1999/06/30 23:56:55 ngorham
170 *
171 * Add initial thread safety code
172 *
173 * Revision 1.1.1.1 1999/05/29 13:41:07 sShandyb
174 * first go at it
175 *
176 * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey
177 * Imported sources
178 *
179 * Revision 1.5 1999/05/09 23:27:11 nick
180 * All the API done now
181 *
182 * Revision 1.4 1999/05/04 22:41:12 nick
183 * and another night ends
184 *
185 * Revision 1.3 1999/05/03 19:50:43 nick
186 * Another check point
187 *
188 * Revision 1.2 1999/04/30 16:22:47 nick
189 * Another checkpoint
190 *
191 * Revision 1.1 1999/04/25 23:06:11 nick
192 * Initial revision
193 *
194 *
195 **********************************************************************/
196
197#include <config.h>
198#include "drivermanager.h"
199
200static char const rcsid[]= "$RCSfile: SQLGetDiagField.c,v $ $Revision: 1.17 $";
201
202#define ODBC30_SUBCLASS "01S00,01S01,01S02,01S06,01S07,07S01,08S01,21S01,\
20321S02,25S01,25S02,25S03,42S01,42S02,42S11,42S12,42S21,42S22,HY095,HY097,HY098,\
204HY099,HY100,HY101,HY105,HY107,HY109,HY110,HY111,HYT00,HYT01,IM001,IM002,IM003,\
205IM004,IM005,IM006,IM007,IM008,IM010,IM011,IM012"
206
207extern int __is_env( EHEAD * head );
208
209/*
210 * is it a diag identifier that we have to convert from unicode to ansi
211 */
212
213static int is_char_diag( int diag_identifier )
214{
215 switch( diag_identifier ) {
216 case SQL_DIAG_CLASS_ORIGIN:
217 case SQL_DIAG_CONNECTION_NAME:
218 case SQL_DIAG_DYNAMIC_FUNCTION:
219 case SQL_DIAG_MESSAGE_TEXT:
220 case SQL_DIAG_SERVER_NAME:
221 case SQL_DIAG_SQLSTATE:
222 case SQL_DIAG_SUBCLASS_ORIGIN:
223 return 1;
224
225 default:
226 return 0;
227 }
228}
229
230static SQLRETURN extract_sql_error_field( EHEAD *head,
231 SQLSMALLINT rec_number,
232 SQLSMALLINT diag_identifier,
233 SQLPOINTER diag_info_ptr,
234 SQLSMALLINT buffer_length,
235 SQLSMALLINT *string_length_ptr )
236{
237 ERROR *ptr;
238
239 if ( is_char_diag( diag_identifier ) && buffer_length < 0 )
240 {
241 return SQL_ERROR;
242 }
243
244 /*
245 * check the header fields first
246 */
247
248 switch( diag_identifier )
249 {
250 case SQL_DIAG_CURSOR_ROW_COUNT:
251 case SQL_DIAG_ROW_COUNT:
252 {
253 SQLLEN val;
254 SQLRETURN ret;
255
256 if ( rec_number > 0 || head -> handle_type != SQL_HANDLE_STMT )
257 {
258 return SQL_ERROR;
259 }
260 else if ( head -> header_set )
261 {
262 switch( diag_identifier )
263 {
264 case SQL_DIAG_CURSOR_ROW_COUNT:
265 if ( SQL_SUCCEEDED( head -> diag_cursor_row_count_ret ) && diag_info_ptr )
266 {
267 *((SQLLEN*)diag_info_ptr) = head -> diag_cursor_row_count;
268 }
269 return head -> diag_cursor_row_count_ret;
270
271 case SQL_DIAG_ROW_COUNT:
272 if ( SQL_SUCCEEDED( head -> diag_row_count_ret ) && diag_info_ptr )
273 {
274 *((SQLLEN*)diag_info_ptr) = head -> diag_row_count;
275 }
276 return head -> diag_row_count_ret;
277 }
278 }
279 else if ( __get_connection( head ) -> unicode_driver &&
280 CHECK_SQLGETDIAGFIELDW( __get_connection( head )))
281 {
282 ret = SQLGETDIAGFIELDW( __get_connection( head ),
283 SQL_HANDLE_STMT,
284 __get_driver_handle( head ),
285 0,
286 diag_identifier,
287 diag_info_ptr,
288 buffer_length,
289 string_length_ptr );
290
291 return ret;
292 }
293 else if ( !__get_connection( head ) -> unicode_driver &&
294 CHECK_SQLGETDIAGFIELD( __get_connection( head )))
295 {
296 ret = SQLGETDIAGFIELD( __get_connection( head ),
297 SQL_HANDLE_STMT,
298 __get_driver_handle( head ),
299 0,
300 diag_identifier,
301 diag_info_ptr,
302 buffer_length,
303 string_length_ptr );
304
305 return ret;
306 }
307 else if ( CHECK_SQLROWCOUNT( __get_connection( head )))
308 {
309 ret = DEF_SQLROWCOUNT( __get_connection( head ),
310 __get_driver_handle( head ),
311 &val );
312
313 if ( !SQL_SUCCEEDED( ret ))
314 {
315 return ret;
316 }
317 }
318 else
319 {
320 val = 0;
321 }
322
323 if ( diag_info_ptr )
324 {
325 memcpy( diag_info_ptr, &val, sizeof( val ));
326 }
327 }
328 return SQL_SUCCESS;
329
330 case SQL_DIAG_DYNAMIC_FUNCTION:
331 {
332 SQLRETURN ret;
333
334 if ( rec_number > 0 )
335 {
336 return SQL_ERROR;
337 }
338 else if ( head -> handle_type != SQL_HANDLE_STMT )
339 {
340 if ( diag_info_ptr )
341 {
342 strcpy( diag_info_ptr, "" );
343 }
344 if ( string_length_ptr )
345 {
346 *string_length_ptr = 0;
347 }
348 return SQL_SUCCESS;
349 }
350 else if ( head -> header_set )
351 {
352 if ( SQL_SUCCEEDED( head -> diag_dynamic_function_ret ) && diag_info_ptr )
353 {
354 unicode_to_ansi_copy( diag_info_ptr, buffer_length, head -> diag_dynamic_function, SQL_NTS, __get_connection( head ), NULL );
355 if ( string_length_ptr )
356 {
357 *string_length_ptr = wide_strlen( head -> diag_dynamic_function );
358 }
359 }
360 return head -> diag_dynamic_function_ret;
361 }
362 else if ( __get_connection( head ) -> unicode_driver &&
363 CHECK_SQLGETDIAGFIELDW( __get_connection( head )))
364 {
365 SQLWCHAR *s1 = NULL;
366
367 if ( buffer_length > 0 )
368 {
369 s1 = malloc( sizeof( SQLWCHAR ) * ( buffer_length + 1 ));
370 }
371
372 ret = SQLGETDIAGFIELDW( __get_connection( head ),
373 SQL_HANDLE_STMT,
374 __get_driver_handle( head ),
375 0,
376 diag_identifier,
377 s1 ? s1 : diag_info_ptr,
378 buffer_length * sizeof ( SQLWCHAR ),
379 string_length_ptr );
380
381 if ( SQL_SUCCEEDED( ret ) && diag_info_ptr && s1 )
382 {
383 unicode_to_ansi_copy( diag_info_ptr, buffer_length, s1, buffer_length, __get_connection( head ), NULL );
384 }
385
386 if ( string_length_ptr && *string_length_ptr > 0 )
387 {
388 *string_length_ptr /= sizeof ( SQLWCHAR );
389 }
390
391 if ( s1 )
392 {
393 free( s1 );
394 }
395
396 return ret;
397 }
398 else if ( !__get_connection( head ) -> unicode_driver &&
399 CHECK_SQLGETDIAGFIELD( __get_connection( head )))
400 {
401 ret = SQLGETDIAGFIELD( __get_connection( head ),
402 SQL_HANDLE_STMT,
403 __get_driver_handle( head ),
404 0,
405 diag_identifier,
406 diag_info_ptr,
407 buffer_length,
408 string_length_ptr );
409
410 return ret;
411 }
412 if ( diag_info_ptr )
413 {
414 strcpy( diag_info_ptr, "" );
415 }
416 }
417 return SQL_SUCCESS;
418
419 case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
420 {
421 SQLINTEGER val;
422 SQLRETURN ret;
423
424 if ( rec_number > 0 )
425 {
426 return SQL_ERROR;
427 }
428 else if ( head -> handle_type != SQL_HANDLE_STMT )
429 {
430 *((SQLINTEGER*)diag_info_ptr) = 0;
431 return SQL_SUCCESS;
432 }
433 else if ( head -> header_set )
434 {
435 if ( SQL_SUCCEEDED( head -> diag_dynamic_function_code_ret ) && diag_info_ptr )
436 {
437 *((SQLINTEGER*)diag_info_ptr) = head -> diag_dynamic_function_code;
438 }
439 return head -> diag_dynamic_function_code_ret;
440 }
441 else if ( __get_connection( head ) -> unicode_driver &&
442 CHECK_SQLGETDIAGFIELDW( __get_connection( head )))
443 {
444 ret = SQLGETDIAGFIELDW( __get_connection( head ),
445 SQL_HANDLE_STMT,
446 __get_driver_handle( head ),
447 0,
448 diag_identifier,
449 diag_info_ptr,
450 buffer_length,
451 string_length_ptr );
452
453 return ret;
454 }
455 else if ( !__get_connection( head ) -> unicode_driver &&
456 CHECK_SQLGETDIAGFIELD( __get_connection( head )))
457 {
458 ret = SQLGETDIAGFIELD( __get_connection( head ),
459 SQL_HANDLE_STMT,
460 __get_driver_handle( head ),
461 0,
462 diag_identifier,
463 diag_info_ptr,
464 buffer_length,
465 string_length_ptr );
466
467 return ret;
468 }
469 else
470 {
471 val = SQL_DIAG_UNKNOWN_STATEMENT;
472 }
473
474 if ( diag_info_ptr )
475 {
476 memcpy( diag_info_ptr, &val, sizeof( val ));
477 }
478 }
479 return SQL_SUCCESS;
480
481 case SQL_DIAG_NUMBER:
482 {
483 SQLINTEGER val;
484
485 if ( rec_number > 0 )
486 {
487 return SQL_ERROR;
488 }
489 val = head -> sql_diag_head.internal_count +
490 head -> sql_diag_head.error_count;
491
492 if ( diag_info_ptr )
493 {
494 memcpy( diag_info_ptr, &val, sizeof( val ));
495 }
496 }
497 return SQL_SUCCESS;
498
499 case SQL_DIAG_RETURNCODE:
500 {
501 if ( diag_info_ptr )
502 {
503 memcpy( diag_info_ptr, &head -> return_code,
504 sizeof( head -> return_code ));
505 }
506 }
507 return SQL_SUCCESS;
508 }
509
510 /*
511 * else check the records
512 */
513
514 if ( rec_number < 1 ||
515 ( diag_identifier == SQL_DIAG_COLUMN_NUMBER ||
516 diag_identifier == SQL_DIAG_ROW_NUMBER ) && head -> handle_type != SQL_HANDLE_STMT )
517 {
518 return SQL_ERROR;
519 }
520
521 if ( rec_number <= head -> sql_diag_head.internal_count )
522 {
523 /*
524 * local errors
525 */
526
527 ptr = head -> sql_diag_head.internal_list_head;
528 while( rec_number > 1 )
529 {
530 ptr = ptr -> next;
531 rec_number --;
532 }
533 if ( !ptr )
534 {
535 return SQL_NO_DATA;
536 }
537 }
538 else if ( !__is_env( head ) && __get_connection( head ) -> state != STATE_C2 )
539 {
540 rec_number -= head -> sql_diag_head.internal_count;
541
542 if ( __get_connection( head ) -> unicode_driver &&
543 CHECK_SQLGETDIAGFIELDW( __get_connection( head )))
544 {
545 SQLRETURN ret;
546 SQLWCHAR *s1 = NULL;
547
548 if ( diag_info_ptr && buffer_length > 0 )
549 {
550 s1 = malloc( ( buffer_length + 1 ) * sizeof( SQLWCHAR ));
551 }
552
553 ret = SQLGETDIAGFIELDW( __get_connection( head ),
554 head -> handle_type,
555 __get_driver_handle( head ),
556 rec_number,
557 diag_identifier,
558 s1 ? s1 : diag_info_ptr,
559 s1 ? ( buffer_length + 1 ) * sizeof( SQLWCHAR ) : buffer_length,
560 string_length_ptr );
561
562 if ( SQL_SUCCEEDED( ret ) && s1 && diag_info_ptr )
563 {
564 unicode_to_ansi_copy( diag_info_ptr, buffer_length, s1, SQL_NTS, __get_connection( head ), NULL );
565
566 if ( string_length_ptr && *string_length_ptr > 0 )
567 {
568 *string_length_ptr /= sizeof( SQLWCHAR );
569 }
570 }
571
572 if ( s1 )
573 {
574 free( s1 );
575 }
576
577 if ( SQL_SUCCEEDED( ret ) && diag_identifier == SQL_DIAG_SQLSTATE )
578 {
579 /*
580 * map 3 to 2 if required
581 */
582 if ( diag_info_ptr )
583 {
584 if ( diag_info_ptr )
585 __map_error_state( diag_info_ptr, __get_version( head ));
586 }
587 }
588
589 return ret;
590 }
591 else if ( !__get_connection( head ) -> unicode_driver &&
592 CHECK_SQLGETDIAGFIELD( __get_connection( head )))
593 {
594 SQLRETURN ret;
595
596 ret = SQLGETDIAGFIELD( __get_connection( head ),
597 head -> handle_type,
598 __get_driver_handle( head ),
599 rec_number,
600 diag_identifier,
601 diag_info_ptr,
602 buffer_length,
603 string_length_ptr );
604
605 if ( SQL_SUCCEEDED( ret ) && diag_identifier == SQL_DIAG_SQLSTATE )
606 {
607 /*
608 * map 3 to 2 if required
609 */
610 if ( diag_info_ptr )
611 {
612 if ( diag_info_ptr )
613 __map_error_state( diag_info_ptr, __get_version( head ));
614 }
615 }
616
617 return ret;
618 }
619 else
620 {
621 ptr = head -> sql_diag_head.error_list_head;
622 while( rec_number > 1 )
623 {
624 ptr = ptr -> next;
625 rec_number --;
626 }
627 if ( !ptr )
628 {
629 return SQL_NO_DATA;
630 }
631 }
632 }
633 else
634 {
635 return SQL_NO_DATA;
636 }
637
638 /*
639 * if we are here ptr should point to the local error
640 * record
641 */
642
643 switch( diag_identifier )
644 {
645 case SQL_DIAG_CLASS_ORIGIN:
646 {
647 if ( SQL_SUCCEEDED( ptr -> diag_class_origin_ret ))
648 {
649 unicode_to_ansi_copy( diag_info_ptr, buffer_length, ptr -> diag_class_origin, SQL_NTS, __get_connection( head ), NULL );
650 if ( string_length_ptr )
651 {
652 *string_length_ptr = wide_strlen( ptr -> diag_class_origin );
653 }
654 return ptr -> diag_class_origin_ret;
655 }
656 else
657 {
658 return ptr -> diag_class_origin_ret;
659 }
660 }
661 break;
662
663 case SQL_DIAG_COLUMN_NUMBER:
664 {
665 if ( diag_info_ptr )
666 {
667 memcpy( diag_info_ptr, &ptr -> diag_column_number, sizeof( SQLINTEGER ));
668 }
669 return SQL_SUCCESS;
670 }
671 break;
672
673 case SQL_DIAG_CONNECTION_NAME:
674 {
675 if ( SQL_SUCCEEDED( ptr -> diag_connection_name_ret ))
676 {
677 unicode_to_ansi_copy( diag_info_ptr, buffer_length, ptr -> diag_connection_name, SQL_NTS, __get_connection( head ), NULL );
678 if ( string_length_ptr )
679 {
680 *string_length_ptr = wide_strlen( ptr -> diag_connection_name );
681 }
682 return ptr -> diag_connection_name_ret;
683 }
684 else
685 {
686 return ptr -> diag_connection_name_ret;
687 }
688 }
689 break;
690
691 case SQL_DIAG_MESSAGE_TEXT:
692 {
693 char *str;
694 int ret = SQL_SUCCESS;
695
696 str = unicode_to_ansi_alloc( ptr -> msg, SQL_NTS, __get_connection( head ), NULL );
697
698 if ( diag_info_ptr )
699 {
700 if ( buffer_length >= strlen( str ) + 1 )
701 {
702 strcpy( diag_info_ptr, str );
703 }
704 else
705 {
706 ret = SQL_SUCCESS_WITH_INFO;
707 memcpy( diag_info_ptr, str, buffer_length - 1 );
708 (( char * ) diag_info_ptr )[ buffer_length - 1 ] = '\0';
709 }
710 }
711 if ( string_length_ptr )
712 {
713 *string_length_ptr = strlen( str );
714 }
715
716 if ( str )
717 {
718 free( str );
719 }
720
721 return ret;
722 }
723 break;
724
725 case SQL_DIAG_NATIVE:
726 {
727 if ( diag_info_ptr )
728 {
729 memcpy( diag_info_ptr, &ptr -> native_error, sizeof( SQLINTEGER ));
730 }
731 return SQL_SUCCESS;
732 }
733 break;
734
735 case SQL_DIAG_ROW_NUMBER:
736 {
737 if ( diag_info_ptr )
738 {
739 memcpy( diag_info_ptr, &ptr -> diag_row_number, sizeof( SQLLEN ));
740 }
741 return SQL_SUCCESS;
742 }
743 break;
744
745 case SQL_DIAG_SERVER_NAME:
746 {
747 if ( SQL_SUCCEEDED( ptr -> diag_server_name_ret ))
748 {
749 unicode_to_ansi_copy( diag_info_ptr, buffer_length, ptr -> diag_server_name, SQL_NTS, __get_connection( head ), NULL );
750 if ( string_length_ptr )
751 {
752 *string_length_ptr = wide_strlen( ptr -> diag_server_name );
753 }
754 return ptr -> diag_server_name_ret;
755 }
756 else
757 {
758 return ptr -> diag_server_name_ret;
759 }
760 }
761 break;
762
763 case SQL_DIAG_SQLSTATE:
764 {
765 char *str;
766 int ret = SQL_SUCCESS;
767
768 str = unicode_to_ansi_alloc( ptr -> sqlstate, SQL_NTS, __get_connection( head ), NULL );
769
770 if ( diag_info_ptr )
771 {
772 if ( buffer_length >= strlen( str ) + 1 )
773 {
774 strcpy( diag_info_ptr, str );
775 }
776 else
777 {
778 ret = SQL_SUCCESS_WITH_INFO;
779 memcpy( diag_info_ptr, str, buffer_length - 1 );
780 (( char * ) diag_info_ptr )[ buffer_length - 1 ] = '\0';
781 }
782
783 /*
784 * map 3 to 2 if required
785 */
786
787 if ( diag_info_ptr )
788 __map_error_state( diag_info_ptr, __get_version( head ));
789 }
790 if ( string_length_ptr )
791 {
792 *string_length_ptr = strlen( str );
793 }
794
795 if ( str )
796 {
797 free( str );
798 }
799
800 return ret;
801 }
802 break;
803
804 case SQL_DIAG_SUBCLASS_ORIGIN:
805 {
806 if ( SQL_SUCCEEDED( ptr -> diag_subclass_origin_ret ))
807 {
808 unicode_to_ansi_copy( diag_info_ptr, buffer_length, ptr -> diag_subclass_origin, SQL_NTS, __get_connection( head ), NULL );
809 if ( string_length_ptr )
810 {
811 *string_length_ptr = wide_strlen( ptr -> diag_subclass_origin );
812 }
813 return ptr -> diag_subclass_origin_ret;
814 }
815 else
816 {
817 return ptr -> diag_subclass_origin_ret;
818 }
819 }
820 break;
821 }
822
823 return SQL_SUCCESS;
824}
825
826SQLRETURN SQLGetDiagFieldA( SQLSMALLINT handle_type,
827 SQLHANDLE handle,
828 SQLSMALLINT rec_number,
829 SQLSMALLINT diag_identifier,
830 SQLPOINTER diag_info_ptr,
831 SQLSMALLINT buffer_length,
832 SQLSMALLINT *string_length_ptr )
833{
834 return SQLGetDiagField( handle_type,
835 handle,
836 rec_number,
837 diag_identifier,
838 diag_info_ptr,
839 buffer_length,
840 string_length_ptr );
841}
842
843SQLRETURN SQLGetDiagField( SQLSMALLINT handle_type,
844 SQLHANDLE handle,
845 SQLSMALLINT rec_number,
846 SQLSMALLINT diag_identifier,
847 SQLPOINTER diag_info_ptr,
848 SQLSMALLINT buffer_length,
849 SQLSMALLINT *string_length_ptr )
850{
851 SQLRETURN ret;
852 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
853
854 if ( handle_type == SQL_HANDLE_ENV )
855 {
856 DMHENV environment = ( DMHENV ) handle;
857
858 if ( !__validate_env( environment ))
859 {
860 dm_log_write( __FILE__,
861 __LINE__,
862 LOG_INFO,
863 LOG_INFO,
864 "Error: SQL_INVALID_HANDLE" );
865
866 return SQL_INVALID_HANDLE;
867 }
868
869 thread_protect( SQL_HANDLE_ENV, environment );
870
871 if ( log_info.log_flag )
872 {
873 sprintf( environment -> msg,
874 "\n\t\tEntry:\
875\n\t\t\tEnvironment = %p\
876\n\t\t\tRec Number = %d\
877\n\t\t\tDiag Ident = %d\
878\n\t\t\tDiag Info Ptr = %p\
879\n\t\t\tBuffer Length = %d\
880\n\t\t\tString Len Ptr = %p",
881 environment,
882 rec_number,
883 diag_identifier,
884 diag_info_ptr,
885 buffer_length,
886 string_length_ptr );
887
888 dm_log_write( __FILE__,
889 __LINE__,
890 LOG_INFO,
891 LOG_INFO,
892 environment -> msg );
893 }
894
895 ret = extract_sql_error_field( &environment -> error,
896 rec_number,
897 diag_identifier,
898 diag_info_ptr,
899 buffer_length,
900 string_length_ptr );
901
902 if ( log_info.log_flag )
903 {
904 sprintf( environment -> msg,
905 "\n\t\tExit:[%s]",
906 __get_return_status( ret, s1 ));
907
908 dm_log_write( __FILE__,
909 __LINE__,
910 LOG_INFO,
911 LOG_INFO,
912 environment -> msg );
913 }
914
915 thread_release( SQL_HANDLE_ENV, environment );
916
917 return ret;
918 }
919 else if ( handle_type == SQL_HANDLE_DBC )
920 {
921 DMHDBC connection = ( DMHDBC ) handle;
922
923 if ( !__validate_dbc( connection ))
924 {
925 return SQL_INVALID_HANDLE;
926 }
927
928 thread_protect( SQL_HANDLE_DBC, connection );
929
930 if ( log_info.log_flag )
931 {
932 sprintf( connection -> msg,
933 "\n\t\tEntry:\
934\n\t\t\tConnection = %p\
935\n\t\t\tRec Number = %d\
936\n\t\t\tDiag Ident = %d\
937\n\t\t\tDiag Info Ptr = %p\
938\n\t\t\tBuffer Length = %d\
939\n\t\t\tString Len Ptr = %p",
940 connection,
941 rec_number,
942 diag_identifier,
943 diag_info_ptr,
944 buffer_length,
945 string_length_ptr );
946
947 dm_log_write( __FILE__,
948 __LINE__,
949 LOG_INFO,
950 LOG_INFO,
951 connection -> msg );
952 }
953
954 ret = extract_sql_error_field( &connection -> error,
955 rec_number,
956 diag_identifier,
957 diag_info_ptr,
958 buffer_length,
959 string_length_ptr );
960
961 if ( log_info.log_flag )
962 {
963 sprintf( connection -> msg,
964 "\n\t\tExit:[%s]",
965 __get_return_status( ret, s1 ));
966
967 dm_log_write( __FILE__,
968 __LINE__,
969 LOG_INFO,
970 LOG_INFO,
971 connection -> msg );
972 }
973
974 thread_release( SQL_HANDLE_DBC, connection );
975
976 return ret;
977 }
978 else if ( handle_type == SQL_HANDLE_STMT )
979 {
980 DMHSTMT statement = ( DMHSTMT ) handle;
981
982 if ( !__validate_stmt( statement ))
983 {
984 return SQL_INVALID_HANDLE;
985 }
986
987 thread_protect( SQL_HANDLE_STMT, statement );
988
989 if ( log_info.log_flag )
990 {
991 sprintf( statement -> msg,
992 "\n\t\tEntry:\
993\n\t\t\tStatement = %p\
994\n\t\t\tRec Number = %d\
995\n\t\t\tDiag Ident = %d\
996\n\t\t\tDiag Info Ptr = %p\
997\n\t\t\tBuffer Length = %d\
998\n\t\t\tString Len Ptr = %p",
999 statement,
1000 rec_number,
1001 diag_identifier,
1002 diag_info_ptr,
1003 buffer_length,
1004 string_length_ptr );
1005
1006 dm_log_write( __FILE__,
1007 __LINE__,
1008 LOG_INFO,
1009 LOG_INFO,
1010 statement -> msg );
1011 }
1012
1013 ret = extract_sql_error_field( &statement -> error,
1014 rec_number,
1015 diag_identifier,
1016 diag_info_ptr,
1017 buffer_length,
1018 string_length_ptr );
1019
1020 if ( log_info.log_flag )
1021 {
1022 sprintf( statement -> msg,
1023 "\n\t\tExit:[%s]",
1024 __get_return_status( ret, s1 ));
1025
1026 dm_log_write( __FILE__,
1027 __LINE__,
1028 LOG_INFO,
1029 LOG_INFO,
1030 statement -> msg );
1031 }
1032
1033 thread_release( SQL_HANDLE_STMT, statement );
1034
1035 return ret;
1036 }
1037 else if ( handle_type == SQL_HANDLE_DESC )
1038 {
1039 DMHDESC descriptor = ( DMHDESC ) handle;
1040
1041 if ( !__validate_desc( descriptor ))
1042 {
1043 return SQL_INVALID_HANDLE;
1044 }
1045
1046 thread_protect( SQL_HANDLE_DESC, descriptor );
1047
1048 if ( log_info.log_flag )
1049 {
1050 sprintf( descriptor -> msg,
1051 "\n\t\tEntry:\
1052\n\t\t\tDescriptor = %p\
1053\n\t\t\tRec Number = %d\
1054\n\t\t\tDiag Ident = %d\
1055\n\t\t\tDiag Info Ptr = %p\
1056\n\t\t\tBuffer Length = %d\
1057\n\t\t\tString Len Ptr = %p",
1058 descriptor,
1059 rec_number,
1060 diag_identifier,
1061 diag_info_ptr,
1062 buffer_length,
1063 string_length_ptr );
1064
1065 dm_log_write( __FILE__,
1066 __LINE__,
1067 LOG_INFO,
1068 LOG_INFO,
1069 descriptor -> msg );
1070 }
1071
1072 ret = extract_sql_error_field( &descriptor -> error,
1073 rec_number,
1074 diag_identifier,
1075 diag_info_ptr,
1076 buffer_length,
1077 string_length_ptr );
1078
1079 if ( log_info.log_flag )
1080 {
1081 sprintf( descriptor -> msg,
1082 "\n\t\tExit:[%s]",
1083 __get_return_status( ret, s1 ));
1084
1085 dm_log_write( __FILE__,
1086 __LINE__,
1087 LOG_INFO,
1088 LOG_INFO,
1089 descriptor -> msg );
1090 }
1091
1092 thread_release( SQL_HANDLE_DESC, descriptor );
1093
1094 return ret;
1095 }
1096 return SQL_NO_DATA;
1097}
1098
1099