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: SQLDescribeColW.c,v 1.14 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLDescribeColW.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 2008/05/20 13:43:47 lurcher
40 * Vms fixes
41 *
42 * Revision 1.11 2007/04/02 10:50:18 lurcher
43 * Fix some 64bit problems (only when sizeof(SQLLEN) == 8 )
44 *
45 * Revision 1.10 2007/02/28 15:37:47 lurcher
46 * deal with drivers that call internal W functions and end up in the driver manager. controlled by the --enable-handlemap configure arg
47 *
48 * Revision 1.9 2007/01/02 10:27:50 lurcher
49 * Fix descriptor leak with unicode only driver
50 *
51 * Revision 1.8 2003/10/30 18:20:45 lurcher
52 *
53 * Fix broken thread protection
54 * Remove SQLNumResultCols after execute, lease S4/S% to driver
55 * Fix string overrun in SQLDriverConnect
56 * Add initial support for Interix
57 *
58 * Revision 1.7 2002/12/05 17:44:30 lurcher
59 *
60 * Display unknown return values in return logging
61 *
62 * Revision 1.6 2002/08/23 09:42:37 lurcher
63 *
64 * Fix some build warnings with casts, and a AIX linker mod, to include
65 * deplib's on the link line, but not the libtool generated ones
66 *
67 * Revision 1.5 2002/08/19 09:11:49 lurcher
68 *
69 * Fix Maxor ineffiecny in Postgres Drivers, and fix a return state
70 *
71 * Revision 1.4 2002/07/24 08:49:51 lurcher
72 *
73 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
74 *
75 * Revision 1.3 2002/05/21 14:19:44 lurcher
76 *
77 * * Update libtool to escape from AIX build problem
78 * * Add fix to avoid file handle limitations
79 * * Add more UNICODE changes, it looks like it is native 16 representation
80 * the old way can be reproduced by defining UCS16BE
81 * * Add iusql, its just the same as isql but uses the wide functions
82 *
83 * Revision 1.2 2001/12/13 13:00:32 lurcher
84 *
85 * Remove most if not all warnings on 64 bit platforms
86 * Add support for new MS 3.52 64 bit changes
87 * Add override to disable the stopping of tracing
88 * Add MAX_ROWS support in postgres driver
89 *
90 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
91 *
92 * First upload to SourceForge
93 *
94 * Revision 1.4 2001/07/03 09:30:41 nick
95 *
96 * Add ability to alter size of displayed message in the log
97 *
98 * Revision 1.3 2001/04/12 17:43:36 nick
99 *
100 * Change logging and added autotest to odbctest
101 *
102 * Revision 1.2 2001/03/21 12:26:27 nick
103 *
104 * Alter def for SQLDescribeColW
105 *
106 * Revision 1.1 2000/12/31 20:30:54 nick
107 *
108 * Add UNICODE support
109 *
110 *
111 **********************************************************************/
112
113#include <config.h>
114#include "drivermanager.h"
115
116static char const rcsid[]= "$RCSfile: SQLDescribeColW.c,v $";
117
118SQLRETURN SQLDescribeColW( SQLHSTMT statement_handle,
119 SQLUSMALLINT column_number,
120 SQLWCHAR *column_name,
121 SQLSMALLINT buffer_length,
122 SQLSMALLINT *name_length,
123 SQLSMALLINT *data_type,
124 SQLULEN *column_size,
125 SQLSMALLINT *decimal_digits,
126 SQLSMALLINT *nullable )
127{
128 DMHSTMT statement = (DMHSTMT) statement_handle;
129 SQLRETURN ret;
130 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ], s2[ 100 + LOG_MESSAGE_LEN ], s3[ 100 + LOG_MESSAGE_LEN ], s4[ 100 + LOG_MESSAGE_LEN ];
131 SQLCHAR s5[ 100 + LOG_MESSAGE_LEN ];
132 SQLCHAR s6[ 100 + LOG_MESSAGE_LEN ];
133
134 /*
135 * check statement
136 */
137
138 if ( !__validate_stmt( statement ))
139 {
140 dm_log_write( __FILE__,
141 __LINE__,
142 LOG_INFO,
143 LOG_INFO,
144 "Error: SQL_INVALID_HANDLE" );
145
146#ifdef WITH_HANDLE_REDIRECT
147 {
148 DMHSTMT parent_statement;
149
150 parent_statement = find_parent_handle( statement, SQL_HANDLE_STMT );
151
152 if ( parent_statement ) {
153 dm_log_write( __FILE__,
154 __LINE__,
155 LOG_INFO,
156 LOG_INFO,
157 "Info: found parent handle" );
158
159 if ( CHECK_SQLDESCRIBECOLW( parent_statement -> connection ))
160 {
161 dm_log_write( __FILE__,
162 __LINE__,
163 LOG_INFO,
164 LOG_INFO,
165 "Info: calling redirected driver function" );
166
167 return SQLDESCRIBECOLW( parent_statement -> connection,
168 statement_handle,
169 column_number,
170 column_name,
171 buffer_length,
172 name_length,
173 data_type,
174 column_size,
175 decimal_digits,
176 nullable );
177 }
178 }
179 }
180#endif
181 return SQL_INVALID_HANDLE;
182 }
183
184 function_entry( statement );
185
186 if ( log_info.log_flag )
187 {
188 sprintf( statement -> msg, "\n\t\tEntry:\
189\n\t\t\tStatement = %p\
190\n\t\t\tColumn Number = %d\
191\n\t\t\tColumn Name = %p\
192\n\t\t\tBuffer Length = %d\
193\n\t\t\tName Length = %p\
194\n\t\t\tData Type = %p\
195\n\t\t\tColumn Size = %p\
196\n\t\t\tDecimal Digits = %p\
197\n\t\t\tNullable = %p",
198 statement,
199 column_number,
200 column_name,
201 buffer_length,
202 name_length,
203 data_type,
204 column_size,
205 decimal_digits,
206 nullable );
207
208 dm_log_write( __FILE__,
209 __LINE__,
210 LOG_INFO,
211 LOG_INFO,
212 statement -> msg );
213 }
214
215 thread_protect( SQL_HANDLE_STMT, statement );
216
217 if ( column_number == 0 &&
218 statement -> bookmarks_on == SQL_UB_OFF && statement -> connection -> bookmarks_on == SQL_UB_OFF )
219 {
220 dm_log_write( __FILE__,
221 __LINE__,
222 LOG_INFO,
223 LOG_INFO,
224 "Error: 07009" );
225
226 __post_internal_error_api( &statement -> error,
227 ERROR_07009, NULL,
228 statement -> connection -> environment -> requested_version,
229 SQL_API_SQLDESCRIBECOL );
230
231 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
232 }
233
234 /*
235 * sadly we can't trust the numcols value
236 *
237 if ( statement -> numcols < column_number )
238 {
239 __post_internal_error( &statement -> error,
240 ERROR_07009, NULL,
241 statement -> connection -> environment -> requested_version );
242
243 return function_return( SQL_HANDLE_STMT, statement, SQL_ERROR );
244 }
245 */
246
247 if ( buffer_length < 0 )
248 {
249 dm_log_write( __FILE__,
250 __LINE__,
251 LOG_INFO,
252 LOG_INFO,
253 "Error: HY090" );
254
255 __post_internal_error( &statement -> error,
256 ERROR_HY090, NULL,
257 statement -> connection -> environment -> requested_version );
258
259 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
260 }
261
262 /*
263 * check states
264 */
265
266 if ( statement -> state == STATE_S1 ||
267 statement -> state == STATE_S8 ||
268 statement -> state == STATE_S9 ||
269 statement -> state == STATE_S10 ||
270 statement -> state == STATE_S13 ||
271 statement -> state == STATE_S14 ||
272 statement -> state == STATE_S15 )
273 {
274 dm_log_write( __FILE__,
275 __LINE__,
276 LOG_INFO,
277 LOG_INFO,
278 "Error: HY010" );
279
280 __post_internal_error( &statement -> error,
281 ERROR_HY010, NULL,
282 statement -> connection -> environment -> requested_version );
283
284 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
285 }
286 /*
287 * This seems to be down to the driver in the MS DM
288 *
289 else if ( statement -> state == STATE_S2 )
290 {
291 dm_log_write( __FILE__,
292 __LINE__,
293 LOG_INFO,
294 LOG_INFO,
295 "Error: 07005" );
296
297 __post_internal_error( &statement -> error,
298 ERROR_07005, NULL,
299 statement -> connection -> environment -> requested_version );
300
301 return function_return( SQL_HANDLE_STMT, statement, SQL_ERROR );
302 }
303 */
304 else if ( statement -> state == STATE_S4 )
305 {
306 dm_log_write( __FILE__,
307 __LINE__,
308 LOG_INFO,
309 LOG_INFO,
310 "Error: HY010" );
311
312 __post_internal_error( &statement -> error,
313 ERROR_HY010, NULL,
314 statement -> connection -> environment -> requested_version );
315
316 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
317 }
318 else if ( statement -> state == STATE_S8 ||
319 statement -> state == STATE_S9 ||
320 statement -> state == STATE_S10 )
321 {
322 dm_log_write( __FILE__,
323 __LINE__,
324 LOG_INFO,
325 LOG_INFO,
326 "Error: HY010" );
327
328 __post_internal_error( &statement -> error,
329 ERROR_HY010, NULL,
330 statement -> connection -> environment -> requested_version );
331
332 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
333 }
334
335 if ( statement -> state == STATE_S11 ||
336 statement -> state == STATE_S12 )
337 {
338 if ( statement -> interupted_func != SQL_API_SQLDESCRIBECOL )
339 {
340 dm_log_write( __FILE__,
341 __LINE__,
342 LOG_INFO,
343 LOG_INFO,
344 "Error: HY010" );
345
346 __post_internal_error( &statement -> error,
347 ERROR_HY010, NULL,
348 statement -> connection -> environment -> requested_version );
349
350 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
351 }
352 }
353
354 if ( statement -> connection -> unicode_driver ||
355 CHECK_SQLDESCRIBECOLW( statement -> connection ))
356 {
357 if ( !CHECK_SQLDESCRIBECOLW( statement -> connection ))
358 {
359 dm_log_write( __FILE__,
360 __LINE__,
361 LOG_INFO,
362 LOG_INFO,
363 "Error: IM001" );
364
365 __post_internal_error( &statement -> error,
366 ERROR_IM001, NULL,
367 statement -> connection -> environment -> requested_version );
368
369 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
370 }
371
372 ret = SQLDESCRIBECOLW( statement -> connection,
373 statement -> driver_stmt,
374 column_number,
375 column_name,
376 buffer_length,
377 name_length,
378 data_type,
379 column_size,
380 decimal_digits,
381 nullable );
382 }
383 else
384 {
385 SQLCHAR *as1 = NULL;
386
387 if ( !CHECK_SQLDESCRIBECOL( statement -> connection ))
388 {
389 dm_log_write( __FILE__,
390 __LINE__,
391 LOG_INFO,
392 LOG_INFO,
393 "Error: IM001" );
394
395 __post_internal_error( &statement -> error,
396 ERROR_IM001, NULL,
397 statement -> connection -> environment -> requested_version );
398
399 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
400 }
401
402 if ( buffer_length > 0 && column_name )
403 {
404 as1 = malloc( buffer_length + 1 );
405 }
406
407 ret = SQLDESCRIBECOL( statement -> connection,
408 statement -> driver_stmt,
409 column_number,
410 as1 ? as1 : (SQLCHAR*)column_name,
411 buffer_length,
412 name_length,
413 data_type,
414 column_size,
415 decimal_digits,
416 nullable );
417
418 if ( column_name && as1 )
419 {
420 ansi_to_unicode_copy( column_name, (char*) as1, SQL_NTS, statement -> connection, NULL );
421 }
422
423 if ( as1 )
424 {
425 free( as1 );
426 }
427 }
428
429 if ( (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) && data_type )
430 {
431 *data_type=__map_type(MAP_SQL_D2DM,statement->connection, *data_type);
432 }
433
434 if ( ret == SQL_STILL_EXECUTING )
435 {
436 statement -> interupted_func = SQL_API_SQLDESCRIBECOL;
437 if ( statement -> state != STATE_S11 &&
438 statement -> state != STATE_S12 )
439 statement -> state = STATE_S11;
440 }
441
442 if ( log_info.log_flag )
443 {
444 if ( !SQL_SUCCEEDED( ret )) {
445 sprintf( statement -> msg,
446 "\n\t\tExit:[%s]",
447 __get_return_status( ret, s6 ));
448 }
449 else {
450 sprintf( statement -> msg,
451 "\n\t\tExit:[%s]\
452 \n\t\t\tColumn Name = %s\
453 \n\t\t\tData Type = %s\
454 \n\t\t\tColumn Size = %s\
455 \n\t\t\tDecimal Digits = %s\
456 \n\t\t\tNullable = %s",
457 __get_return_status( ret, s6 ),
458 __sdata_as_string( s1, SQL_WCHAR,
459 name_length, column_name ),
460 __sptr_as_string( s2, data_type ),
461 __ptr_as_string( s3, (SQLLEN*)column_size ),
462 __sptr_as_string( s4, decimal_digits ),
463 __sptr_as_string( s5, nullable ));
464 }
465
466 dm_log_write( __FILE__,
467 __LINE__,
468 LOG_INFO,
469 LOG_INFO,
470 statement -> msg );
471 }
472
473 return function_return( SQL_HANDLE_STMT, statement, ret );
474}
475