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: SQLGetData.c,v 1.15 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLGetData.c,v $
33 * Revision 1.15 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.14 2007/04/02 10:50:19 lurcher
37 * Fix some 64bit problems (only when sizeof(SQLLEN) == 8 )
38 *
39 * Revision 1.13 2006/04/11 10:22:56 lurcher
40 * Fix a data type check
41 *
42 * Revision 1.12 2006/03/08 11:22:13 lurcher
43 * Add check for valid C_TYPE
44 *
45 * Revision 1.11 2004/02/02 10:10:45 lurcher
46 *
47 * Fix some connection pooling problems
48 * Include sqlucode in sqlext
49 *
50 * Revision 1.10 2003/10/30 18:20:46 lurcher
51 *
52 * Fix broken thread protection
53 * Remove SQLNumResultCols after execute, lease S4/S% to driver
54 * Fix string overrun in SQLDriverConnect
55 * Add initial support for Interix
56 *
57 * Revision 1.9 2002/12/05 17:44:30 lurcher
58 *
59 * Display unknown return values in return logging
60 *
61 * Revision 1.8 2002/08/23 09:42:37 lurcher
62 *
63 * Fix some build warnings with casts, and a AIX linker mod, to include
64 * deplib's on the link line, but not the libtool generated ones
65 *
66 * Revision 1.7 2002/08/19 09:11:49 lurcher
67 *
68 * Fix Maxor ineffiecny in Postgres Drivers, and fix a return state
69 *
70 * Revision 1.6 2002/07/24 08:49:52 lurcher
71 *
72 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
73 *
74 * Revision 1.5 2002/07/10 15:05:57 lurcher
75 *
76 * Alter the return code in the Postgres driver, for a warning, it should be
77 * 01000 it was 00000
78 * Fix a problem in DriverManagerII with the postgres driver as the driver
79 * doesn't return a propper list of schemas
80 * Allow the delimiter to be set in isql to a hex/octal char not just a
81 * printable one
82 *
83 * Revision 1.4 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.3 2001/12/04 10:16:59 lurcher
91 *
92 * Fix SQLSetScrollOption problem
93 *
94 * Revision 1.2 2001/11/22 14:27:02 lurcher
95 *
96 * Add UNICODE conversion fix
97 *
98 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
99 *
100 * First upload to SourceForge
101 *
102 * Revision 1.5 2001/09/27 17:05:48 nick
103 *
104 * Assorted fixes and tweeks
105 *
106 * Revision 1.4 2001/07/03 09:30:41 nick
107 *
108 * Add ability to alter size of displayed message in the log
109 *
110 * Revision 1.3 2001/04/12 17:43:36 nick
111 *
112 * Change logging and added autotest to odbctest
113 *
114 * Revision 1.2 2001/01/01 11:04:13 nick
115 *
116 * Add UNICODE conversion to SQLGetData
117 *
118 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
119 * Imported Sources
120 *
121 * Revision 1.10 2000/06/20 13:30:09 ngorham
122 *
123 * Fix problems when using bookmarks
124 *
125 * Revision 1.9 1999/11/13 23:40:59 ngorham
126 *
127 * Alter the way DM logging works
128 * Upgrade the Postgres driver to 6.4.6
129 *
130 * Revision 1.8 1999/10/24 23:54:18 ngorham
131 *
132 * First part of the changes to the error reporting
133 *
134 * Revision 1.7 1999/10/09 00:56:16 ngorham
135 *
136 * Added Manush's patch to map ODBC 3-2 datetime values
137 *
138 * Revision 1.6 1999/10/09 00:15:58 ngorham
139 *
140 * Add mapping from SQL_TYPE_X to SQL_X and SQL_C_TYPE_X to SQL_C_X
141 * when the driver is a ODBC 2 one
142 *
143 * Revision 1.5 1999/09/21 22:34:25 ngorham
144 *
145 * Improve performance by removing unneeded logging calls when logging is
146 * disabled
147 *
148 * Revision 1.4 1999/07/10 21:10:16 ngorham
149 *
150 * Adjust error sqlstate from driver manager, depending on requested
151 * version (ODBC2/3)
152 *
153 * Revision 1.3 1999/07/04 21:05:07 ngorham
154 *
155 * Add LGPL Headers to code
156 *
157 * Revision 1.2 1999/06/30 23:56:55 ngorham
158 *
159 * Add initial thread safety code
160 *
161 * Revision 1.1.1.1 1999/05/29 13:41:07 sShandyb
162 * first go at it
163 *
164 * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey
165 * Imported sources
166 *
167 * Revision 1.4 1999/05/03 19:50:43 nick
168 * Another check point
169 *
170 * Revision 1.3 1999/04/30 16:22:47 nick
171 * Another checkpoint
172 *
173 * Revision 1.2 1999/04/29 20:47:37 nick
174 * Another checkpoint
175 *
176 * Revision 1.1 1999/04/25 23:06:11 nick
177 * Initial revision
178 *
179 *
180 **********************************************************************/
181
182#include <config.h>
183#include "drivermanager.h"
184
185static char const rcsid[]= "$RCSfile: SQLGetData.c,v $ $Revision: 1.15 $";
186
187SQLRETURN SQLGetData( SQLHSTMT statement_handle,
188 SQLUSMALLINT column_number,
189 SQLSMALLINT target_type,
190 SQLPOINTER target_value,
191 SQLLEN buffer_length,
192 SQLLEN *strlen_or_ind )
193{
194 DMHSTMT statement = (DMHSTMT) statement_handle;
195 SQLRETURN ret;
196 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ], s2[ 100 + LOG_MESSAGE_LEN ];
197 int unicode_switch = 0;
198 SQLLEN ind_value;
199 SQLCHAR *as1 = NULL;
200 SQLCHAR s3[ 100 + LOG_MESSAGE_LEN ];
201
202 /*
203 * check statement
204 */
205
206 if ( !__validate_stmt( statement ))
207 {
208 dm_log_write( __FILE__,
209 __LINE__,
210 LOG_INFO,
211 LOG_INFO,
212 "Error: SQL_INVALID_HANDLE" );
213
214 return SQL_INVALID_HANDLE;
215 }
216
217 function_entry( statement );
218
219 if ( log_info.log_flag )
220 {
221 sprintf( statement -> msg, "\n\t\tEntry:\
222\n\t\t\tStatement = %p\
223\n\t\t\tColumn Number = %d\
224\n\t\t\tTarget Type = %d %s\
225\n\t\t\tBuffer Length = %d\
226\n\t\t\tTarget Value = %p\
227\n\t\t\tStrLen Or Ind = %p",
228 statement,
229 column_number,
230 target_type,
231 __sql_as_text( target_type ),
232 (int)buffer_length,
233 target_value,
234 (void*)strlen_or_ind );
235
236 dm_log_write( __FILE__,
237 __LINE__,
238 LOG_INFO,
239 LOG_INFO,
240 statement -> msg );
241 }
242
243 thread_protect( SQL_HANDLE_STMT, statement );
244
245 if ( column_number == 0 &&
246 statement -> bookmarks_on == SQL_UB_OFF && statement -> connection -> bookmarks_on == SQL_UB_OFF )
247 {
248 dm_log_write( __FILE__,
249 __LINE__,
250 LOG_INFO,
251 LOG_INFO,
252 "Error: 07009" );
253
254 __post_internal_error_api( &statement -> error,
255 ERROR_07009, NULL,
256 statement -> connection -> environment -> requested_version,
257 SQL_API_SQLGETDATA );
258
259 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
260 }
261
262 /*
263 * can't trust the numcols value
264 *
265 if ( statement -> numcols < column_number )
266 {
267 dm_log_write( __FILE__,
268 __LINE__,
269 LOG_INFO,
270 LOG_INFO,
271 "Error: 07009" );
272
273 __post_internal_error( &statement -> error,
274 ERROR_07009, NULL,
275 statement -> connection -> environment -> requested_version );
276
277 return function_return( SQL_HANDLE_STMT, statement, SQL_ERROR );
278 }
279 */
280
281 /*
282 * check states
283 */
284
285 if ( statement -> state == STATE_S1 ||
286 statement -> state == STATE_S2 ||
287 statement -> state == STATE_S3 )
288 {
289 dm_log_write( __FILE__,
290 __LINE__,
291 LOG_INFO,
292 LOG_INFO,
293 "Error: HY010" );
294
295 __post_internal_error( &statement -> error,
296 ERROR_HY010, NULL,
297 statement -> connection -> environment -> requested_version );
298
299 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
300 }
301 else if ( statement -> state == STATE_S4 ||
302 statement -> state == STATE_S5 ||
303 ( statement -> state == STATE_S6 || statement -> state == STATE_S7 )
304 && statement -> eod )
305 {
306 dm_log_write( __FILE__,
307 __LINE__,
308 LOG_INFO,
309 LOG_INFO,
310 "Error: 24000" );
311
312 __post_internal_error( &statement -> error,
313 ERROR_24000, 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 statement -> state == STATE_S13 )
322 {
323 dm_log_write( __FILE__,
324 __LINE__,
325 LOG_INFO,
326 LOG_INFO,
327 "Error: HY010" );
328
329 __post_internal_error( &statement -> error,
330 ERROR_HY010, NULL,
331 statement -> connection -> environment -> requested_version );
332
333 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
334 }
335
336 if ( statement -> state == STATE_S11 ||
337 statement -> state == STATE_S12 )
338 {
339 if ( statement -> interupted_func != SQL_API_SQLGETDATA )
340 {
341 dm_log_write( __FILE__,
342 __LINE__,
343 LOG_INFO,
344 LOG_INFO,
345 "Error: HY010" );
346
347 __post_internal_error( &statement -> error,
348 ERROR_HY010, NULL,
349 statement -> connection -> environment -> requested_version );
350
351 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
352 }
353 }
354
355 if ( target_value == NULL ) {
356 dm_log_write( __FILE__,
357 __LINE__,
358 LOG_INFO,
359 LOG_INFO,
360 "Error: HY009" );
361
362 __post_internal_error( &statement -> error,
363 ERROR_HY009, NULL,
364 statement -> connection -> environment -> requested_version );
365
366 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
367 }
368
369 if ( buffer_length < 0 ) {
370 dm_log_write( __FILE__,
371 __LINE__,
372 LOG_INFO,
373 LOG_INFO,
374 "Error: HY090" );
375
376 __post_internal_error( &statement -> error,
377 ERROR_HY090, NULL,
378 statement -> connection -> environment -> requested_version );
379
380 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
381 }
382
383 /*
384 * TO_DO assorted checks need adding here, relating to bound columns
385 * and what sort of SQLGetData extensions the driver supports
386 */
387
388 /*
389 * check valid C_TYPE
390 */
391
392 if ( !check_target_type( target_type, statement -> connection -> environment -> requested_version ))
393 {
394 dm_log_write( __FILE__,
395 __LINE__,
396 LOG_INFO,
397 LOG_INFO,
398 "Error: HY003" );
399
400 __post_internal_error( &statement -> error,
401 ERROR_HY003, NULL,
402 statement -> connection -> environment -> requested_version );
403
404 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
405 }
406
407 if ( !CHECK_SQLGETDATA( statement -> connection ))
408 {
409 dm_log_write( __FILE__,
410 __LINE__,
411 LOG_INFO,
412 LOG_INFO,
413 "Error: IM001" );
414
415 __post_internal_error( &statement -> error,
416 ERROR_IM001, NULL,
417 statement -> connection -> environment -> requested_version );
418
419 return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
420 }
421
422 if (statement -> connection -> driver_act_ver==SQL_OV_ODBC2)
423 {
424 switch( target_type )
425 {
426 case SQL_WCHAR:
427 target_type = SQL_CHAR;
428 unicode_switch = 1;
429 buffer_length = buffer_length / sizeof( SQLWCHAR );
430 break;
431
432 case SQL_WVARCHAR:
433 target_type = SQL_VARCHAR;
434 unicode_switch = 1;
435 buffer_length = buffer_length / sizeof( SQLWCHAR );
436 break;
437
438 case SQL_WLONGVARCHAR:
439 target_type = SQL_LONGVARCHAR;
440 unicode_switch = 1;
441 buffer_length = buffer_length / sizeof( SQLWCHAR );
442 break;
443 }
444 }
445
446 if ( unicode_switch )
447 {
448 if ( buffer_length > 0 && target_value )
449 {
450 as1 = malloc( buffer_length + 1 );
451
452 ret = SQLGETDATA( statement -> connection,
453 statement -> driver_stmt,
454 column_number,
455 __map_type(MAP_C_DM2D,statement->connection,target_type),
456 as1,
457 buffer_length,
458 &ind_value );
459 }
460 else
461 {
462 ret = SQLGETDATA( statement -> connection,
463 statement -> driver_stmt,
464 column_number,
465 __map_type(MAP_C_DM2D,statement->connection,target_type),
466 target_value,
467 buffer_length,
468 &ind_value );
469 }
470
471 }
472 else
473 {
474 ret = SQLGETDATA( statement -> connection,
475 statement -> driver_stmt,
476 column_number,
477 __map_type(MAP_C_DM2D,statement->connection,target_type),
478 target_value,
479 buffer_length,
480 strlen_or_ind );
481 }
482
483 if ( ret == SQL_STILL_EXECUTING )
484 {
485 statement -> interupted_func = SQL_API_SQLGETDATA;
486 if ( statement -> state != STATE_S11 &&
487 statement -> state != STATE_S12 )
488 {
489 statement -> interupted_state = statement -> state;
490 statement -> state = STATE_S11;
491 }
492 }
493 else if ( SQL_SUCCEEDED( ret ) && unicode_switch )
494 {
495 if ( target_value && ind_value >= 0 && as1 )
496 {
497 if ( ind_value > buffer_length )
498 {
499 ansi_to_unicode_copy( target_value, (char*) as1, buffer_length, statement -> connection, NULL );
500 }
501 else
502 {
503 ansi_to_unicode_copy( target_value, (char*) as1, ind_value + 1, statement -> connection, NULL );
504 }
505 }
506
507 if ( as1 )
508 {
509 free( as1 );
510 }
511
512 if ( ind_value > 0 )
513 {
514 ind_value *= sizeof( SQLWCHAR );
515 }
516
517 if ( strlen_or_ind )
518 {
519 *strlen_or_ind = ind_value;
520 }
521 }
522
523 if ( ret != SQL_STILL_EXECUTING
524 && (statement -> state == STATE_S11 || statement -> state == STATE_S12) )
525 {
526 statement -> state = statement -> interupted_state;
527 }
528
529 if ( statement -> state == STATE_S14 ) {
530 statement -> state = STATE_S15;
531 }
532
533 if ( log_info.log_flag )
534 {
535 sprintf( statement -> msg,
536 "\n\t\tExit:[%s]\
537 \n\t\t\tBuffer = %s\
538 \n\t\t\tStrlen Or Ind = %s",
539 __get_return_status( ret, s3 ),
540 __data_as_string( s1, target_type,
541 strlen_or_ind, target_value ),
542 __ptr_as_string( s2, strlen_or_ind ));
543
544 dm_log_write( __FILE__,
545 __LINE__,
546 LOG_INFO,
547 LOG_INFO,
548 statement -> msg );
549 }
550
551 return function_return( SQL_HANDLE_STMT, statement, ret );
552}
553