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: SQLDescribeCol.c,v 1.13 2009/02/18 17:59:08 lurcher Exp $ |
31 | * |
32 | * $Log: SQLDescribeCol.c,v $ |
33 | * Revision 1.13 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.12 2008/09/29 14:02:44 lurcher |
37 | * Fix missing dlfcn group option |
38 | * |
39 | * Revision 1.11 2008/05/20 13:43:46 lurcher |
40 | * Vms fixes |
41 | * |
42 | * Revision 1.10 2007/04/02 10:50:18 lurcher |
43 | * Fix some 64bit problems (only when sizeof(SQLLEN) == 8 ) |
44 | * |
45 | * Revision 1.9 2007/01/02 10:27:50 lurcher |
46 | * Fix descriptor leak with unicode only driver |
47 | * |
48 | * Revision 1.8 2003/10/30 18:20:45 lurcher |
49 | * |
50 | * Fix broken thread protection |
51 | * Remove SQLNumResultCols after execute, lease S4/S% to driver |
52 | * Fix string overrun in SQLDriverConnect |
53 | * Add initial support for Interix |
54 | * |
55 | * Revision 1.7 2003/02/27 12:19:39 lurcher |
56 | * |
57 | * Add the A functions as well as the W |
58 | * |
59 | * Revision 1.6 2002/12/05 17:44:30 lurcher |
60 | * |
61 | * Display unknown return values in return logging |
62 | * |
63 | * Revision 1.5 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.4 2002/08/19 09:11:49 lurcher |
69 | * |
70 | * Fix Maxor ineffiecny in Postgres Drivers, and fix a return state |
71 | * |
72 | * Revision 1.3 2002/07/24 08:49:51 lurcher |
73 | * |
74 | * Alter UNICODE support to use iconv for UNICODE-ANSI conversion |
75 | * |
76 | * Revision 1.2 2001/12/13 13:00:32 lurcher |
77 | * |
78 | * Remove most if not all warnings on 64 bit platforms |
79 | * Add support for new MS 3.52 64 bit changes |
80 | * Add override to disable the stopping of tracing |
81 | * Add MAX_ROWS support in postgres driver |
82 | * |
83 | * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher |
84 | * |
85 | * First upload to SourceForge |
86 | * |
87 | * Revision 1.5 2001/07/03 09:30:41 nick |
88 | * |
89 | * Add ability to alter size of displayed message in the log |
90 | * |
91 | * Revision 1.4 2001/04/12 17:43:36 nick |
92 | * |
93 | * Change logging and added autotest to odbctest |
94 | * |
95 | * Revision 1.3 2001/01/02 09:55:04 nick |
96 | * |
97 | * More unicode bits |
98 | * |
99 | * Revision 1.2 2000/12/31 20:30:54 nick |
100 | * |
101 | * Add UNICODE support |
102 | * |
103 | * Revision 1.1.1.1 2000/09/04 16:42:52 nick |
104 | * Imported Sources |
105 | * |
106 | * Revision 1.10 2000/06/20 13:30:09 ngorham |
107 | * |
108 | * Fix problems when using bookmarks |
109 | * |
110 | * Revision 1.9 1999/11/28 18:35:50 ngorham |
111 | * |
112 | * Add extra ODBC3/2 Date/Time mapping |
113 | * |
114 | * Revision 1.8 1999/11/13 23:40:59 ngorham |
115 | * |
116 | * Alter the way DM logging works |
117 | * Upgrade the Postgres driver to 6.4.6 |
118 | * |
119 | * Revision 1.7 1999/10/24 23:54:17 ngorham |
120 | * |
121 | * First part of the changes to the error reporting |
122 | * |
123 | * Revision 1.6 1999/10/09 00:56:16 ngorham |
124 | * |
125 | * Added Manush's patch to map ODBC 3-2 datetime values |
126 | * |
127 | * Revision 1.5 1999/09/21 22:34:24 ngorham |
128 | * |
129 | * Improve performance by removing unneeded logging calls when logging is |
130 | * disabled |
131 | * |
132 | * Revision 1.4 1999/07/10 21:10:16 ngorham |
133 | * |
134 | * Adjust error sqlstate from driver manager, depending on requested |
135 | * version (ODBC2/3) |
136 | * |
137 | * Revision 1.3 1999/07/04 21:05:07 ngorham |
138 | * |
139 | * Add LGPL Headers to code |
140 | * |
141 | * Revision 1.2 1999/06/30 23:56:54 ngorham |
142 | * |
143 | * Add initial thread safety code |
144 | * |
145 | * Revision 1.1.1.1 1999/05/29 13:41:05 sShandyb |
146 | * first go at it |
147 | * |
148 | * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey |
149 | * Imported sources |
150 | * |
151 | * Revision 1.4 1999/05/03 19:50:43 nick |
152 | * Another check point |
153 | * |
154 | * Revision 1.3 1999/04/30 16:22:47 nick |
155 | * Another checkpoint |
156 | * |
157 | * Revision 1.2 1999/04/29 21:40:58 nick |
158 | * End of another night :-) |
159 | * |
160 | * Revision 1.1 1999/04/25 23:06:11 nick |
161 | * Initial revision |
162 | * |
163 | * |
164 | **********************************************************************/ |
165 | |
166 | #include <config.h> |
167 | #include "drivermanager.h" |
168 | |
169 | static char const rcsid[]= "$RCSfile: SQLDescribeCol.c,v $ $Revision: 1.13 $" ; |
170 | |
171 | SQLRETURN SQLDescribeColA( SQLHSTMT statement_handle, |
172 | SQLUSMALLINT column_number, |
173 | SQLCHAR *column_name, |
174 | SQLSMALLINT buffer_length, |
175 | SQLSMALLINT *name_length, |
176 | SQLSMALLINT *data_type, |
177 | SQLULEN *column_size, |
178 | SQLSMALLINT *decimal_digits, |
179 | SQLSMALLINT *nullable ) |
180 | { |
181 | return SQLDescribeCol( statement_handle, |
182 | column_number, |
183 | column_name, |
184 | buffer_length, |
185 | name_length, |
186 | data_type, |
187 | column_size, |
188 | decimal_digits, |
189 | nullable ); |
190 | } |
191 | |
192 | SQLRETURN SQLDescribeCol( SQLHSTMT statement_handle, |
193 | SQLUSMALLINT column_number, |
194 | SQLCHAR *column_name, |
195 | SQLSMALLINT buffer_length, |
196 | SQLSMALLINT *name_length, |
197 | SQLSMALLINT *data_type, |
198 | SQLULEN *column_size, |
199 | SQLSMALLINT *decimal_digits, |
200 | SQLSMALLINT *nullable ) |
201 | { |
202 | DMHSTMT statement = (DMHSTMT) statement_handle; |
203 | SQLRETURN ret; |
204 | SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ], s2[ 100 + LOG_MESSAGE_LEN ], s3[ 100 + LOG_MESSAGE_LEN ], s4[ 100 + LOG_MESSAGE_LEN ]; |
205 | SQLCHAR s5[ 100 + LOG_MESSAGE_LEN ], s6[ 100 + LOG_MESSAGE_LEN ]; |
206 | |
207 | /* |
208 | * check statement |
209 | */ |
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 | return SQL_INVALID_HANDLE; |
220 | } |
221 | |
222 | function_entry( statement ); |
223 | |
224 | if ( log_info.log_flag ) |
225 | { |
226 | sprintf( statement -> msg, "\n\t\tEntry:\ |
227 | \n\t\t\tStatement = %p\ |
228 | \n\t\t\tColumn Number = %d\ |
229 | \n\t\t\tColumn Name = %p\ |
230 | \n\t\t\tBuffer Length = %d\ |
231 | \n\t\t\tName Length = %p\ |
232 | \n\t\t\tData Type = %p\ |
233 | \n\t\t\tColumn Size = %p\ |
234 | \n\t\t\tDecimal Digits = %p\ |
235 | \n\t\t\tNullable = %p" , |
236 | statement, |
237 | column_number, |
238 | column_name, |
239 | buffer_length, |
240 | name_length, |
241 | data_type, |
242 | column_size, |
243 | decimal_digits, |
244 | nullable ); |
245 | |
246 | dm_log_write( __FILE__, |
247 | __LINE__, |
248 | LOG_INFO, |
249 | LOG_INFO, |
250 | statement -> msg ); |
251 | } |
252 | |
253 | thread_protect( SQL_HANDLE_STMT, statement ); |
254 | |
255 | if ( column_number == 0 && |
256 | statement -> bookmarks_on == SQL_UB_OFF && statement -> connection -> bookmarks_on == SQL_UB_OFF ) |
257 | { |
258 | dm_log_write( __FILE__, |
259 | __LINE__, |
260 | LOG_INFO, |
261 | LOG_INFO, |
262 | "Error: 07009" ); |
263 | |
264 | __post_internal_error_api( &statement -> error, |
265 | ERROR_07009, NULL, |
266 | statement -> connection -> environment -> requested_version, |
267 | SQL_API_SQLDESCRIBECOL ); |
268 | |
269 | return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
270 | } |
271 | |
272 | /* |
273 | * sadly we can't truct the numcols value |
274 | * |
275 | if ( statement -> numcols < column_number ) |
276 | { |
277 | __post_internal_error( &statement -> error, |
278 | ERROR_07009, NULL, |
279 | statement -> connection -> environment -> requested_version ); |
280 | |
281 | return function_return( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
282 | } |
283 | */ |
284 | |
285 | if ( buffer_length < 0 ) |
286 | { |
287 | dm_log_write( __FILE__, |
288 | __LINE__, |
289 | LOG_INFO, |
290 | LOG_INFO, |
291 | "Error: HY090" ); |
292 | |
293 | __post_internal_error( &statement -> error, |
294 | ERROR_HY090, NULL, |
295 | statement -> connection -> environment -> requested_version ); |
296 | |
297 | return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
298 | } |
299 | |
300 | /* |
301 | * check states |
302 | */ |
303 | |
304 | if ( statement -> state == STATE_S1 || |
305 | statement -> state == STATE_S8 || |
306 | statement -> state == STATE_S9 || |
307 | statement -> state == STATE_S10 || |
308 | statement -> state == STATE_S13 || |
309 | statement -> state == STATE_S14 || |
310 | statement -> state == STATE_S15 ) |
311 | { |
312 | dm_log_write( __FILE__, |
313 | __LINE__, |
314 | LOG_INFO, |
315 | LOG_INFO, |
316 | "Error: HY010" ); |
317 | |
318 | __post_internal_error( &statement -> error, |
319 | ERROR_HY010, NULL, |
320 | statement -> connection -> environment -> requested_version ); |
321 | |
322 | return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
323 | } |
324 | /* |
325 | * This seems to be down to the driver in the MS DM |
326 | * |
327 | else if ( statement -> state == STATE_S2 ) |
328 | { |
329 | dm_log_write( __FILE__, |
330 | __LINE__, |
331 | LOG_INFO, |
332 | LOG_INFO, |
333 | "Error: 07005" ); |
334 | |
335 | __post_internal_error( &statement -> error, |
336 | ERROR_07005, NULL, |
337 | statement -> connection -> environment -> requested_version ); |
338 | |
339 | return function_return( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
340 | } |
341 | */ |
342 | else if ( statement -> state == STATE_S4 ) |
343 | { |
344 | dm_log_write( __FILE__, |
345 | __LINE__, |
346 | LOG_INFO, |
347 | LOG_INFO, |
348 | "Error: HY010" ); |
349 | |
350 | __post_internal_error( &statement -> error, |
351 | ERROR_HY010, NULL, |
352 | statement -> connection -> environment -> requested_version ); |
353 | |
354 | return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
355 | } |
356 | else if ( statement -> state == STATE_S8 || |
357 | statement -> state == STATE_S9 || |
358 | statement -> state == STATE_S10 ) |
359 | { |
360 | dm_log_write( __FILE__, |
361 | __LINE__, |
362 | LOG_INFO, |
363 | LOG_INFO, |
364 | "Error: HY010" ); |
365 | |
366 | __post_internal_error( &statement -> error, |
367 | ERROR_HY010, NULL, |
368 | statement -> connection -> environment -> requested_version ); |
369 | |
370 | return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
371 | } |
372 | |
373 | if ( statement -> state == STATE_S11 || |
374 | statement -> state == STATE_S12 ) |
375 | { |
376 | if ( statement -> interupted_func != SQL_API_SQLDESCRIBECOL ) |
377 | { |
378 | dm_log_write( __FILE__, |
379 | __LINE__, |
380 | LOG_INFO, |
381 | LOG_INFO, |
382 | "Error: HY010" ); |
383 | |
384 | __post_internal_error( &statement -> error, |
385 | ERROR_HY010, NULL, |
386 | statement -> connection -> environment -> requested_version ); |
387 | |
388 | return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
389 | } |
390 | } |
391 | |
392 | if ( statement -> connection -> unicode_driver ) |
393 | { |
394 | SQLWCHAR *s1 = NULL; |
395 | |
396 | if ( !CHECK_SQLDESCRIBECOLW( statement -> connection )) |
397 | { |
398 | dm_log_write( __FILE__, |
399 | __LINE__, |
400 | LOG_INFO, |
401 | LOG_INFO, |
402 | "Error: IM001" ); |
403 | |
404 | __post_internal_error( &statement -> error, |
405 | ERROR_IM001, NULL, |
406 | statement -> connection -> environment -> requested_version ); |
407 | |
408 | return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
409 | } |
410 | |
411 | if ( column_name && buffer_length > 0 ) |
412 | { |
413 | s1 = malloc( sizeof( SQLWCHAR ) * ( buffer_length + 1 )); |
414 | } |
415 | |
416 | ret = SQLDESCRIBECOLW( statement -> connection, |
417 | statement -> driver_stmt, |
418 | column_number, |
419 | s1 ? s1 : (SQLWCHAR*)column_name, |
420 | buffer_length, |
421 | name_length, |
422 | data_type, |
423 | column_size, |
424 | decimal_digits, |
425 | nullable ); |
426 | |
427 | if ( SQL_SUCCEEDED( ret ) && column_name && s1 ) |
428 | { |
429 | unicode_to_ansi_copy((char*) column_name, buffer_length, s1, SQL_NTS, statement -> connection, NULL ); |
430 | } |
431 | |
432 | if ( s1 ) |
433 | { |
434 | free( s1 ); |
435 | } |
436 | } |
437 | else |
438 | { |
439 | if ( !CHECK_SQLDESCRIBECOL( statement -> connection )) |
440 | { |
441 | dm_log_write( __FILE__, |
442 | __LINE__, |
443 | LOG_INFO, |
444 | LOG_INFO, |
445 | "Error: IM001" ); |
446 | |
447 | __post_internal_error( &statement -> error, |
448 | ERROR_IM001, NULL, |
449 | statement -> connection -> environment -> requested_version ); |
450 | |
451 | return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR ); |
452 | } |
453 | |
454 | ret = SQLDESCRIBECOL( statement -> connection, |
455 | statement -> driver_stmt, |
456 | column_number, |
457 | column_name, |
458 | buffer_length, |
459 | name_length, |
460 | data_type, |
461 | column_size, |
462 | decimal_digits, |
463 | nullable ); |
464 | } |
465 | |
466 | if ( (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) && data_type ) |
467 | { |
468 | *data_type=__map_type(MAP_SQL_D2DM,statement->connection, *data_type); |
469 | } |
470 | |
471 | if ( ret == SQL_STILL_EXECUTING ) |
472 | { |
473 | statement -> interupted_func = SQL_API_SQLDESCRIBECOL; |
474 | if ( statement -> state != STATE_S11 && |
475 | statement -> state != STATE_S12 ) |
476 | statement -> state = STATE_S11; |
477 | } |
478 | |
479 | if ( log_info.log_flag ) |
480 | { |
481 | if ( !SQL_SUCCEEDED( ret )) { |
482 | sprintf( statement -> msg, |
483 | "\n\t\tExit:[%s]" , |
484 | __get_return_status( ret, s6 )); |
485 | } |
486 | else { |
487 | sprintf( statement -> msg, |
488 | "\n\t\tExit:[%s]\ |
489 | \n\t\t\tColumn Name = %s\ |
490 | \n\t\t\tData Type = %s\ |
491 | \n\t\t\tColumn Size = %s\ |
492 | \n\t\t\tDecimal Digits = %s\ |
493 | \n\t\t\tNullable = %s" , |
494 | __get_return_status( ret, s6 ), |
495 | __sdata_as_string( s1, SQL_CHAR, |
496 | name_length, column_name ), |
497 | __sptr_as_string( s2, data_type ), |
498 | __ptr_as_string( s3, (SQLLEN*)column_size ), |
499 | __sptr_as_string( s4, decimal_digits ), |
500 | __sptr_as_string( s5, nullable )); |
501 | } |
502 | |
503 | dm_log_write( __FILE__, |
504 | __LINE__, |
505 | LOG_INFO, |
506 | LOG_INFO, |
507 | statement -> msg ); |
508 | } |
509 | |
510 | return function_return( SQL_HANDLE_STMT, statement, ret ); |
511 | } |
512 | |