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: SQLGetDescField.c,v 1.10 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLGetDescField.c,v $
33 * Revision 1.10 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.9 2008/09/29 14:02:45 lurcher
37 * Fix missing dlfcn group option
38 *
39 * Revision 1.8 2006/03/08 09:18:41 lurcher
40 * fix silly typo that was using sizeof( SQL_WCHAR ) instead of SQLWCHAR
41 *
42 * Revision 1.7 2004/11/22 17:02:49 lurcher
43 * Fix unicode/ansi conversion in the SQLGet functions
44 *
45 * Revision 1.6 2003/10/30 18:20:46 lurcher
46 *
47 * Fix broken thread protection
48 * Remove SQLNumResultCols after execute, lease S4/S% to driver
49 * Fix string overrun in SQLDriverConnect
50 * Add initial support for Interix
51 *
52 * Revision 1.5 2003/02/27 12:19:39 lurcher
53 *
54 * Add the A functions as well as the W
55 *
56 * Revision 1.4 2002/12/05 17:44:30 lurcher
57 *
58 * Display unknown return values in return logging
59 *
60 * Revision 1.3 2002/07/24 08:49:52 lurcher
61 *
62 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
63 *
64 * Revision 1.2 2002/01/21 18:00:51 lurcher
65 *
66 * Assorted fixed and changes, mainly UNICODE/bug fixes
67 *
68 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
69 *
70 * First upload to SourceForge
71 *
72 * Revision 1.5 2001/07/03 09:30:41 nick
73 *
74 * Add ability to alter size of displayed message in the log
75 *
76 * Revision 1.4 2001/04/17 16:29:39 nick
77 *
78 * More checks and autotest fixes
79 *
80 * Revision 1.3 2001/04/12 17:43:36 nick
81 *
82 * Change logging and added autotest to odbctest
83 *
84 * Revision 1.2 2000/12/31 20:30:54 nick
85 *
86 * Add UNICODE support
87 *
88 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
89 * Imported Sources
90 *
91 * Revision 1.7 1999/11/13 23:40:59 ngorham
92 *
93 * Alter the way DM logging works
94 * Upgrade the Postgres driver to 6.4.6
95 *
96 * Revision 1.6 1999/10/24 23:54:18 ngorham
97 *
98 * First part of the changes to the error reporting
99 *
100 * Revision 1.5 1999/09/21 22:34:25 ngorham
101 *
102 * Improve performance by removing unneeded logging calls when logging is
103 * disabled
104 *
105 * Revision 1.4 1999/07/10 21:10:16 ngorham
106 *
107 * Adjust error sqlstate from driver manager, depending on requested
108 * version (ODBC2/3)
109 *
110 * Revision 1.3 1999/07/04 21:05:07 ngorham
111 *
112 * Add LGPL Headers to code
113 *
114 * Revision 1.2 1999/06/30 23:56:55 ngorham
115 *
116 * Add initial thread safety code
117 *
118 * Revision 1.1.1.1 1999/05/29 13:41:07 sShandyb
119 * first go at it
120 *
121 * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey
122 * Imported sources
123 *
124 * Revision 1.3 1999/05/04 22:41:12 nick
125 * and another night ends
126 *
127 * Revision 1.2 1999/05/03 19:50:43 nick
128 * Another check point
129 *
130 * Revision 1.1 1999/04/25 23:06:11 nick
131 * Initial revision
132 *
133 *
134 **********************************************************************/
135
136#include <config.h>
137#include "drivermanager.h"
138
139static char const rcsid[]= "$RCSfile: SQLGetDescField.c,v $ $Revision: 1.10 $";
140
141SQLRETURN SQLGetDescFieldA( SQLHDESC descriptor_handle,
142 SQLSMALLINT rec_number,
143 SQLSMALLINT field_identifier,
144 SQLPOINTER value,
145 SQLINTEGER buffer_length,
146 SQLINTEGER *string_length )
147{
148 return SQLGetDescField( descriptor_handle,
149 rec_number,
150 field_identifier,
151 value,
152 buffer_length,
153 string_length );
154}
155
156SQLRETURN SQLGetDescField( SQLHDESC descriptor_handle,
157 SQLSMALLINT rec_number,
158 SQLSMALLINT field_identifier,
159 SQLPOINTER value,
160 SQLINTEGER buffer_length,
161 SQLINTEGER *string_length )
162{
163 /*
164 * not quite sure how the descriptor can be
165 * allocated to a statement, all the documentation talks
166 * about state transitions on statement states, but the
167 * descriptor may be allocated with more than one statement
168 * at one time. Which one should I check ?
169 */
170 DMHDESC descriptor = (DMHDESC) descriptor_handle;
171 SQLRETURN ret;
172 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
173 int isStrField = 0;
174
175 /*
176 * check descriptor
177 */
178
179 if ( !__validate_desc( descriptor ))
180 {
181 dm_log_write( __FILE__,
182 __LINE__,
183 LOG_INFO,
184 LOG_INFO,
185 "Error: SQL_INVALID_HANDLE" );
186
187 return SQL_INVALID_HANDLE;
188 }
189
190 function_entry( descriptor );
191
192 if ( log_info.log_flag )
193 {
194 sprintf( descriptor -> msg, "\n\t\tEntry:\
195\n\t\t\tDescriptor = %p\
196\n\t\t\tRec Number = %d\
197\n\t\t\tField Attr = %s\
198\n\t\t\tValue = %p\
199\n\t\t\tBuffer Length = %d\
200\n\t\t\tStrLen = %p",
201 descriptor,
202 rec_number,
203 __desc_attr_as_string( s1, field_identifier ),
204 value,
205 (int)buffer_length,
206 (void*)string_length );
207
208 dm_log_write( __FILE__,
209 __LINE__,
210 LOG_INFO,
211 LOG_INFO,
212 descriptor -> msg );
213 }
214
215 thread_protect( SQL_HANDLE_DESC, descriptor );
216
217 if ( descriptor -> connection -> state < STATE_C4 )
218 {
219 dm_log_write( __FILE__,
220 __LINE__,
221 LOG_INFO,
222 LOG_INFO,
223 "Error: HY010" );
224
225 __post_internal_error( &descriptor -> error,
226 ERROR_HY010, NULL,
227 descriptor -> connection -> environment -> requested_version );
228
229 return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
230 }
231
232 /*
233 * check status of statements associated with this descriptor
234 */
235
236 if( __check_stmt_from_desc( descriptor, STATE_S8 ) ||
237 __check_stmt_from_desc( descriptor, STATE_S9 ) ||
238 __check_stmt_from_desc( descriptor, STATE_S10 ) ||
239 __check_stmt_from_desc( descriptor, STATE_S11 ) ||
240 __check_stmt_from_desc( descriptor, STATE_S12 ) ||
241 __check_stmt_from_desc( descriptor, STATE_S13 ) ||
242 __check_stmt_from_desc( descriptor, STATE_S14 ) ||
243 __check_stmt_from_desc( descriptor, STATE_S15 )) {
244
245 dm_log_write( __FILE__,
246 __LINE__,
247 LOG_INFO,
248 LOG_INFO,
249 "Error: HY010" );
250
251 __post_internal_error( &descriptor -> error,
252 ERROR_HY010, NULL,
253 descriptor -> connection -> environment -> requested_version );
254
255 return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
256 }
257
258 if( __check_stmt_from_desc_ird( descriptor, STATE_S1 )) {
259
260 dm_log_write( __FILE__,
261 __LINE__,
262 LOG_INFO,
263 LOG_INFO,
264 "Error: HY007" );
265
266 __post_internal_error( &descriptor -> error,
267 ERROR_HY007, NULL,
268 descriptor -> connection -> environment -> requested_version );
269
270 return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
271 }
272
273 if ( rec_number < 0 )
274 {
275 __post_internal_error( &descriptor -> error,
276 ERROR_07009, NULL,
277 descriptor -> connection -> environment -> requested_version );
278
279 return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
280 }
281
282 switch ( field_identifier )
283 {
284 /* Fixed-length fields: buffer_length is ignored */
285 case SQL_DESC_ALLOC_TYPE:
286 case SQL_DESC_ARRAY_SIZE:
287 case SQL_DESC_ARRAY_STATUS_PTR:
288 case SQL_DESC_BIND_OFFSET_PTR:
289 case SQL_DESC_BIND_TYPE:
290 case SQL_DESC_COUNT:
291 case SQL_DESC_ROWS_PROCESSED_PTR:
292 case SQL_DESC_AUTO_UNIQUE_VALUE:
293 case SQL_DESC_CASE_SENSITIVE:
294 case SQL_DESC_CONCISE_TYPE:
295 case SQL_DESC_DATA_PTR:
296 case SQL_DESC_DATETIME_INTERVAL_CODE:
297 case SQL_DESC_DATETIME_INTERVAL_PRECISION:
298 case SQL_DESC_DISPLAY_SIZE:
299 case SQL_DESC_FIXED_PREC_SCALE:
300 case SQL_DESC_INDICATOR_PTR:
301 case SQL_DESC_LENGTH:
302 case SQL_DESC_NULLABLE:
303 case SQL_DESC_NUM_PREC_RADIX:
304 case SQL_DESC_OCTET_LENGTH:
305 case SQL_DESC_OCTET_LENGTH_PTR:
306 case SQL_DESC_PARAMETER_TYPE:
307 case SQL_DESC_PRECISION:
308 case SQL_DESC_ROWVER:
309 case SQL_DESC_SCALE:
310 case SQL_DESC_SEARCHABLE:
311 case SQL_DESC_TYPE:
312 case SQL_DESC_UNNAMED:
313 case SQL_DESC_UNSIGNED:
314 case SQL_DESC_UPDATABLE:
315 isStrField = 0;
316 break;
317 /* Pointer to data: buffer_length must be valid */
318 case SQL_DESC_BASE_COLUMN_NAME:
319 case SQL_DESC_BASE_TABLE_NAME:
320 case SQL_DESC_CATALOG_NAME:
321 case SQL_DESC_LABEL:
322 case SQL_DESC_LITERAL_PREFIX:
323 case SQL_DESC_LITERAL_SUFFIX:
324 case SQL_DESC_LOCAL_TYPE_NAME:
325 case SQL_DESC_NAME:
326 case SQL_DESC_SCHEMA_NAME:
327 case SQL_DESC_TABLE_NAME:
328 case SQL_DESC_TYPE_NAME:
329 isStrField = 1;
330 break;
331 default:
332 isStrField = buffer_length != SQL_IS_POINTER && buffer_length != SQL_IS_INTEGER
333 && buffer_length != SQL_IS_UINTEGER && buffer_length != SQL_IS_SMALLINT &&
334 buffer_length != SQL_IS_USMALLINT;
335 }
336
337 if ( isStrField && buffer_length < 0 )
338 {
339 __post_internal_error( &descriptor -> error,
340 ERROR_HY090, NULL,
341 descriptor -> connection -> environment -> requested_version );
342
343 return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
344 }
345
346 if ( descriptor -> connection -> unicode_driver )
347 {
348 SQLWCHAR *s1 = NULL;
349
350 if ( !CHECK_SQLGETDESCFIELDW( descriptor -> connection ))
351 {
352 dm_log_write( __FILE__,
353 __LINE__,
354 LOG_INFO,
355 LOG_INFO,
356 "Error: IM001" );
357
358 __post_internal_error( &descriptor -> error,
359 ERROR_IM001, NULL,
360 descriptor -> connection -> environment -> requested_version );
361
362 return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
363 }
364
365 if ( isStrField && buffer_length > 0 && value )
366 {
367 s1 = malloc( sizeof( SQLWCHAR ) * ( buffer_length + 1 ));
368 }
369
370 ret = SQLGETDESCFIELDW( descriptor -> connection,
371 descriptor -> driver_desc,
372 rec_number,
373 field_identifier,
374 s1 ? s1 : value,
375 s1 ? (sizeof ( SQLWCHAR ) * (buffer_length + 1)) : buffer_length,
376 string_length );
377
378 if ( isStrField && SQL_SUCCEEDED( ret ) )
379 {
380 if ( value && s1 )
381 {
382 unicode_to_ansi_copy( value, buffer_length, s1, SQL_NTS, descriptor -> connection, NULL );
383 }
384 }
385
386 if ( s1 )
387 {
388 free( s1 );
389 }
390 }
391 else
392 {
393 if ( !CHECK_SQLGETDESCFIELD( descriptor -> connection ))
394 {
395 dm_log_write( __FILE__,
396 __LINE__,
397 LOG_INFO,
398 LOG_INFO,
399 "Error: IM001" );
400
401 __post_internal_error( &descriptor -> error,
402 ERROR_IM001, NULL,
403 descriptor -> connection -> environment -> requested_version );
404
405 return function_return_nodrv( SQL_HANDLE_DESC, descriptor, SQL_ERROR );
406 }
407
408 ret = SQLGETDESCFIELD( descriptor -> connection,
409 descriptor -> driver_desc,
410 rec_number,
411 field_identifier,
412 value,
413 buffer_length,
414 string_length );
415 }
416
417 if ( log_info.log_flag )
418 {
419 sprintf( descriptor -> msg,
420 "\n\t\tExit:[%s]",
421 __get_return_status( ret, s1 ));
422
423 dm_log_write( __FILE__,
424 __LINE__,
425 LOG_INFO,
426 LOG_INFO,
427 descriptor -> msg );
428 }
429
430 return function_return( SQL_HANDLE_DESC, descriptor, ret );
431}
432