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 | |
185 | static char const rcsid[]= "$RCSfile: SQLGetData.c,v $ $Revision: 1.15 $" ; |
186 | |
187 | SQLRETURN 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 | |