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: SQLColAttributeW.c,v 1.14 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLColAttributeW.c,v $
33 * Revision 1.14 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.13 2008/08/29 08:01:38 lurcher
37 * Alter the way W functions are passed to the driver
38 *
39 * Revision 1.12 2007/04/02 10:50:18 lurcher
40 * Fix some 64bit problems (only when sizeof(SQLLEN) == 8 )
41 *
42 * Revision 1.11 2004/11/22 17:02:48 lurcher
43 * Fix unicode/ansi conversion in the SQLGet functions
44 *
45 * Revision 1.10 2004/10/30 20:19:21 peteralexharvey
46 * ODBC spec says last arg for SQLColAttribute() is SQLPOINTER not (SQLEN*).
47 * So switched back to SQLPOINTER.
48 *
49 * Revision 1.9 2004/10/29 10:00:36 lurcher
50 * Fix SQLColAttribute protype
51 *
52 * Revision 1.8 2003/10/30 18:20:45 lurcher
53 *
54 * Fix broken thread protection
55 * Remove SQLNumResultCols after execute, lease S4/S% to driver
56 * Fix string overrun in SQLDriverConnect
57 * Add initial support for Interix
58 *
59 * Revision 1.7 2002/12/05 17:44:30 lurcher
60 *
61 * Display unknown return values in return logging
62 *
63 * Revision 1.6 2002/08/23 09:42:37 lurcher
64 *
65 * Fix some build warnings with casts, and a AIX linker mod, to include
66 * deplib's on the link line, but not the libtool generated ones
67 *
68 * Revision 1.5 2002/08/19 09:11:49 lurcher
69 *
70 * Fix Maxor ineffiecny in Postgres Drivers, and fix a return state
71 *
72 * Revision 1.4 2002/07/24 08:49:51 lurcher
73 *
74 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
75 *
76 * Revision 1.3 2002/04/25 15:16:46 lurcher
77 *
78 * Fix bug with SQLCOlAttribute(s)(W) where a column of zero could not be
79 * used to get the count value
80 *
81 * Revision 1.2 2001/11/16 11:39:17 lurcher
82 *
83 * Add mapping between ODBC 2 and ODBC 3 types for SQLColAttribute(s)(W)
84 *
85 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
86 *
87 * First upload to SourceForge
88 *
89 * Revision 1.3 2001/07/03 09:30:41 nick
90 *
91 * Add ability to alter size of displayed message in the log
92 *
93 * Revision 1.2 2001/04/12 17:43:35 nick
94 *
95 * Change logging and added autotest to odbctest
96 *
97 * Revision 1.1 2000/12/31 20:30:54 nick
98 *
99 * Add UNICODE support
100 *
101 *
102 **********************************************************************/
103
104#include <config.h>
105#include "drivermanager.h"
106
107static char const rcsid[]= "$RCSfile: SQLColAttributeW.c,v $";
108
109SQLRETURN SQLColAttributeW ( SQLHSTMT statement_handle,
110 SQLUSMALLINT column_number,
111 SQLUSMALLINT field_identifier,
112 SQLPOINTER character_attribute,
113 SQLSMALLINT buffer_length,
114 SQLSMALLINT *string_length,
115 SQLLEN *numeric_attribute )
116{
117 DMHSTMT statement = (DMHSTMT) statement_handle;
118 SQLRETURN ret;
119 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
120
121 /*
122 * check statement
123 */
124 if ( !__validate_stmt( statement ))
125 {
126 dm_log_write( __FILE__,
127 __LINE__,
128 LOG_INFO,
129 LOG_INFO,
130 "Error: SQL_INVALID_HANDLE" );
131
132 return SQL_INVALID_HANDLE;
133 }
134
135 function_entry( statement );
136
137 if ( log_info.log_flag )
138 {
139 sprintf( statement -> msg, "\n\t\tEntry:\
140\n\t\t\tStatement = %p\
141\n\t\t\tColumn Number = %d\
142\n\t\t\tField Identifier = %s\
143\n\t\t\tCharacter Attr = %p\
144\n\t\t\tBuffer Length = %d\
145\n\t\t\tString Length = %p\
146\n\t\t\tNumeric Attribute = %p",
147 statement,
148 column_number,
149 __col_attr_as_string( s1, field_identifier ),
150 character_attribute,
151 buffer_length,
152 string_length,
153 numeric_attribute );
154
155 dm_log_write( __FILE__,
156 __LINE__,
157 LOG_INFO,
158 LOG_INFO,
159 statement -> msg );
160 }
161
162 thread_protect( SQL_HANDLE_STMT, statement );
163
164 if ( column_number == 0 &&
165 statement -> bookmarks_on == SQL_UB_OFF && statement -> connection -> bookmarks_on == SQL_UB_OFF &&
166 field_identifier != SQL_DESC_COUNT )
167 {
168 dm_log_write( __FILE__,
169 __LINE__,
170 LOG_INFO,
171 LOG_INFO,
172 "Error: 07009" );
173
174 __post_internal_error_api( &statement -> error,
175 ERROR_07009, NULL,
176 statement -> connection -> environment -> requested_version,
177 SQL_API_SQLCOLATTRIBUTE );
178
179 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
180 }
181
182 /*
183 * Commented out for now because most drivers can not calc num cols
184 * before Execute (they have no parse). - PAH
185 *
186
187 if ( field_identifier != SQL_DESC_COUNT &&
188 statement -> numcols < column_number )
189 {
190 __post_internal_error( &statement -> error,
191 ERROR_07009, NULL,
192 statement -> connection -> environment -> requested_version );
193 return function_return( statement, SQL_ERROR );
194 }
195
196 */
197
198 /*
199 * check states
200 */
201 if ( statement -> state == STATE_S1 )
202 {
203 dm_log_write( __FILE__,
204 __LINE__,
205 LOG_INFO,
206 LOG_INFO,
207 "Error: HY010" );
208
209 __post_internal_error( &statement -> error,
210 ERROR_HY010, NULL,
211 statement -> connection -> environment -> requested_version );
212
213 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
214 }
215 /*
216 else if ( statement -> state == STATE_S2 &&
217 field_identifier != SQL_DESC_COUNT )
218 {
219 dm_log_write( __FILE__,
220 __LINE__,
221 LOG_INFO,
222 LOG_INFO,
223 "Error: 07005" );
224
225 __post_internal_error( &statement -> error,
226 ERROR_07005, NULL,
227 statement -> connection -> environment -> requested_version );
228
229 return function_return( SQL_HANDLE_STMT, statement, SQL_ERROR );
230 }
231 */
232 else if ( statement -> state == STATE_S4 )
233 {
234 dm_log_write( __FILE__,
235 __LINE__,
236 LOG_INFO,
237 LOG_INFO,
238 "Error: 24000" );
239
240 __post_internal_error( &statement -> error,
241 ERROR_24000, NULL,
242 statement -> connection -> environment -> requested_version );
243
244 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
245 }
246 else if ( statement -> state == STATE_S8 ||
247 statement -> state == STATE_S9 ||
248 statement -> state == STATE_S10 ||
249 statement -> state == STATE_S13 ||
250 statement -> state == STATE_S14 ||
251 statement -> state == STATE_S15 )
252 {
253 dm_log_write( __FILE__,
254 __LINE__,
255 LOG_INFO,
256 LOG_INFO,
257 "Error: HY010" );
258
259 __post_internal_error( &statement -> error,
260 ERROR_HY010, NULL,
261 statement -> connection -> environment -> requested_version );
262
263 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
264 }
265
266 if ( statement -> state == STATE_S11 ||
267 statement -> state == STATE_S12 )
268 {
269 if ( statement -> interupted_func != SQL_API_SQLCOLATTRIBUTE )
270 {
271 dm_log_write( __FILE__,
272 __LINE__,
273 LOG_INFO,
274 LOG_INFO,
275 "Error: HY010" );
276
277 __post_internal_error( &statement -> error,
278 ERROR_HY010, NULL,
279 statement -> connection -> environment -> requested_version );
280
281 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
282 }
283 }
284
285 switch ( field_identifier )
286 {
287 case SQL_COLUMN_QUALIFIER_NAME:
288 case SQL_COLUMN_NAME:
289 case SQL_COLUMN_LABEL:
290 case SQL_COLUMN_OWNER_NAME:
291 case SQL_COLUMN_TABLE_NAME:
292 case SQL_COLUMN_TYPE_NAME:
293 case SQL_DESC_BASE_COLUMN_NAME:
294 case SQL_DESC_BASE_TABLE_NAME:
295 case SQL_DESC_LITERAL_PREFIX:
296 case SQL_DESC_LITERAL_SUFFIX:
297 case SQL_DESC_LOCAL_TYPE_NAME:
298 case SQL_DESC_NAME:
299 if ( buffer_length < 0 && buffer_length != SQL_NTS )
300 {
301 __post_internal_error( &statement -> error,
302 ERROR_HY090, NULL,
303 statement -> connection -> environment -> requested_version );
304
305 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
306 }
307 }
308
309 if ( statement -> connection -> unicode_driver ||
310 CHECK_SQLCOLATTRIBUTEW( statement -> connection ) ||
311 CHECK_SQLCOLATTRIBUTESW( statement -> connection ))
312 {
313 if ( !CHECK_SQLCOLATTRIBUTEW( statement -> connection ))
314 {
315 if ( CHECK_SQLCOLATTRIBUTESW( statement -> connection ))
316 {
317 /*
318 * map to the ODBC2 function
319 */
320
321 field_identifier = map_ca_odbc3_to_2( field_identifier );
322
323 ret = SQLCOLATTRIBUTESW( statement -> connection,
324 statement -> driver_stmt,
325 column_number,
326 field_identifier,
327 character_attribute,
328 buffer_length,
329 string_length,
330 numeric_attribute );
331 }
332 else
333 {
334 dm_log_write( __FILE__,
335 __LINE__,
336 LOG_INFO,
337 LOG_INFO,
338 "Error: IM001" );
339
340 __post_internal_error( &statement -> error,
341 ERROR_IM001, NULL,
342 statement -> connection -> environment -> requested_version );
343
344 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
345 }
346 }
347 else
348 {
349 ret = SQLCOLATTRIBUTEW( statement -> connection,
350 statement -> driver_stmt,
351 column_number,
352 field_identifier,
353 character_attribute,
354 buffer_length,
355 string_length,
356 numeric_attribute );
357 }
358 }
359 else
360 {
361 if ( !CHECK_SQLCOLATTRIBUTE( statement -> connection ))
362 {
363 if ( CHECK_SQLCOLATTRIBUTES( statement -> connection ))
364 {
365 SQLCHAR *as1 = NULL;
366
367 /*
368 * map to the ODBC2 function
369 */
370
371 field_identifier = map_ca_odbc3_to_2( field_identifier );
372
373 switch( field_identifier )
374 {
375 case SQL_COLUMN_QUALIFIER_NAME:
376 case SQL_COLUMN_NAME:
377 case SQL_COLUMN_LABEL:
378 case SQL_COLUMN_OWNER_NAME:
379 case SQL_COLUMN_TABLE_NAME:
380 case SQL_COLUMN_TYPE_NAME:
381 case SQL_DESC_BASE_COLUMN_NAME:
382 case SQL_DESC_BASE_TABLE_NAME:
383 case SQL_DESC_LITERAL_PREFIX:
384 case SQL_DESC_LITERAL_SUFFIX:
385 case SQL_DESC_LOCAL_TYPE_NAME:
386 case SQL_DESC_NAME:
387 buffer_length = buffer_length / 2;
388 if ( buffer_length > 0 )
389 {
390 as1 = malloc( buffer_length + 1 );
391 }
392 break;
393 }
394
395 ret = SQLCOLATTRIBUTES( statement -> connection,
396 statement -> driver_stmt,
397 column_number,
398 field_identifier,
399 as1 ? as1 : character_attribute,
400 buffer_length,
401 string_length,
402 numeric_attribute );
403
404 switch( field_identifier )
405 {
406 case SQL_COLUMN_QUALIFIER_NAME:
407 case SQL_COLUMN_NAME:
408 case SQL_COLUMN_LABEL:
409 case SQL_COLUMN_OWNER_NAME:
410 case SQL_COLUMN_TABLE_NAME:
411 case SQL_COLUMN_TYPE_NAME:
412 case SQL_DESC_BASE_COLUMN_NAME:
413 case SQL_DESC_BASE_TABLE_NAME:
414 case SQL_DESC_LITERAL_PREFIX:
415 case SQL_DESC_LITERAL_SUFFIX:
416 case SQL_DESC_LOCAL_TYPE_NAME:
417 case SQL_DESC_NAME:
418 if ( SQL_SUCCEEDED( ret ) && character_attribute && as1 )
419 {
420 ansi_to_unicode_copy( character_attribute, (char*) as1, SQL_NTS, statement -> connection, NULL );
421 }
422 if ( SQL_SUCCEEDED( ret ) && string_length )
423 {
424 *string_length *= sizeof( SQLWCHAR );
425 }
426 if ( as1 )
427 {
428 free( as1 );
429 }
430 break;
431 }
432 }
433 else
434 {
435 dm_log_write( __FILE__,
436 __LINE__,
437 LOG_INFO,
438 LOG_INFO,
439 "Error: IM001" );
440
441 __post_internal_error( &statement -> error,
442 ERROR_IM001, NULL,
443 statement -> connection -> environment -> requested_version );
444
445 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
446 }
447 }
448 else
449 {
450 SQLCHAR *as1 = NULL;
451
452 switch( field_identifier )
453 {
454 case SQL_DESC_BASE_COLUMN_NAME:
455 case SQL_DESC_BASE_TABLE_NAME:
456 case SQL_DESC_CATALOG_NAME:
457 case SQL_DESC_LABEL:
458 case SQL_DESC_LITERAL_PREFIX:
459 case SQL_DESC_LITERAL_SUFFIX:
460 case SQL_DESC_LOCAL_TYPE_NAME:
461 case SQL_DESC_NAME:
462 case SQL_DESC_SCHEMA_NAME:
463 case SQL_DESC_TABLE_NAME:
464 case SQL_DESC_TYPE_NAME:
465 case SQL_COLUMN_NAME:
466 buffer_length = buffer_length / 2;
467 if ( buffer_length > 0 )
468 {
469 as1 = malloc( buffer_length + 1 );
470 }
471 break;
472 }
473
474 ret = SQLCOLATTRIBUTE( statement -> connection,
475 statement -> driver_stmt,
476 column_number,
477 field_identifier,
478 as1 ? as1 : character_attribute,
479 buffer_length,
480 string_length,
481 numeric_attribute );
482
483 switch( field_identifier )
484 {
485 case SQL_DESC_BASE_COLUMN_NAME:
486 case SQL_DESC_BASE_TABLE_NAME:
487 case SQL_DESC_CATALOG_NAME:
488 case SQL_DESC_LABEL:
489 case SQL_DESC_LITERAL_PREFIX:
490 case SQL_DESC_LITERAL_SUFFIX:
491 case SQL_DESC_LOCAL_TYPE_NAME:
492 case SQL_DESC_NAME:
493 case SQL_DESC_SCHEMA_NAME:
494 case SQL_DESC_TABLE_NAME:
495 case SQL_DESC_TYPE_NAME:
496 case SQL_COLUMN_NAME:
497 if ( SQL_SUCCEEDED( ret ) && character_attribute && as1 )
498 {
499 ansi_to_unicode_copy( character_attribute, (char*) as1, SQL_NTS, statement -> connection, NULL );
500 }
501 if ( SQL_SUCCEEDED( ret ) && string_length )
502 {
503 *string_length *= sizeof( SQLWCHAR );
504 }
505
506 if ( as1 )
507 {
508 free( as1 );
509 }
510 break;
511
512 default:
513 break;
514 }
515 }
516 }
517
518 if ( ret == SQL_STILL_EXECUTING )
519 {
520 statement -> interupted_func = SQL_API_SQLCOLATTRIBUTE;
521 if ( statement -> state != STATE_S11 &&
522 statement -> state != STATE_S12 )
523 statement -> state = STATE_S11;
524 }
525 else if ( SQL_SUCCEEDED( ret ))
526 {
527 /*
528 * map ODBC 3 datetime fields to ODBC2
529 */
530
531 if ( field_identifier == SQL_COLUMN_TYPE &&
532 numeric_attribute )
533 {
534 *(SQLINTEGER*)numeric_attribute=
535 __map_type(MAP_SQL_D2DM, statement->connection,
536 *(SQLINTEGER*)numeric_attribute);
537 }
538 }
539
540 if ( log_info.log_flag )
541 {
542 sprintf( statement -> msg,
543 "\n\t\tExit:[%s]",
544 __get_return_status( ret, s1 ));
545
546 dm_log_write( __FILE__,
547 __LINE__,
548 LOG_INFO,
549 LOG_INFO,
550 statement -> msg );
551 }
552
553 return function_return( SQL_HANDLE_STMT, statement, ret );
554}
555