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: SQLCopyDesc.c,v 1.8 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLCopyDesc.c,v $
33 * Revision 1.8 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.7 2009/02/17 09:47:44 lurcher
37 * Clear up a number of bugs
38 *
39 * Revision 1.6 2004/03/30 13:20:11 lurcher
40 *
41 *
42 * Fix problem with SQLCopyDesc
43 * Add additional target for iconv
44 *
45 * Revision 1.5 2003/10/30 18:20:45 lurcher
46 *
47 * Fix broken thread protection
48 * Remove SQLNumResultCols after execute, lease S4/S% to driver
49 * Fix string overrun in SQLDriverConnect
50 * Add initial support for Interix
51 *
52 * Revision 1.4 2002/12/05 17:44:30 lurcher
53 *
54 * Display unknown return values in return logging
55 *
56 * Revision 1.3 2002/09/18 14:49:32 lurcher
57 *
58 * DataManagerII additions and some more threading fixes
59 *
60 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
61 *
62 * First upload to SourceForge
63 *
64 * Revision 1.2 2001/04/12 17:43:36 nick
65 *
66 * Change logging and added autotest to odbctest
67 *
68 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
69 * Imported Sources
70 *
71 * Revision 1.8 2001/05/26 19:11:37 ngorham
72 *
73 * Add SQLCopyDesc functionality and fix bug that was stopping messages
74 * coming out of SQLConnect
75 *
76 * Revision 1.7 1999/11/13 23:40:58 ngorham
77 *
78 * Alter the way DM logging works
79 * Upgrade the Postgres driver to 6.4.6
80 *
81 * Revision 1.6 1999/10/24 23:54:17 ngorham
82 *
83 * First part of the changes to the error reporting
84 *
85 * Revision 1.5 1999/09/21 22:34:24 ngorham
86 *
87 * Improve performance by removing unneeded logging calls when logging is
88 * disabled
89 *
90 * Revision 1.4 1999/07/10 21:10:16 ngorham
91 *
92 * Adjust error sqlstate from driver manager, depending on requested
93 * version (ODBC2/3)
94 *
95 * Revision 1.3 1999/07/04 21:05:07 ngorham
96 *
97 * Add LGPL Headers to code
98 *
99 * Revision 1.2 1999/06/30 23:56:54 ngorham
100 *
101 * Add initial thread safety code
102 *
103 * Revision 1.1.1.1 1999/05/29 13:41:05 sShandyb
104 * first go at it
105 *
106 * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey
107 * Imported sources
108 *
109 * Revision 1.2 1999/05/09 23:27:11 nick
110 * All the API done now
111 *
112 * Revision 1.1 1999/04/25 23:06:11 nick
113 * Initial revision
114 *
115 *
116 **********************************************************************/
117
118#include <config.h>
119#include "drivermanager.h"
120
121static char const rcsid[]= "$RCSfile: SQLCopyDesc.c,v $ $Revision: 1.8 $";
122
123struct cdesc
124{
125 int field_identifier;
126 int field_type;
127};
128
129/*
130 * note that SQL_VARCHAR indicates a pointer type, not a string
131 */
132
133static struct cdesc header_fields[] =
134{
135 { SQL_DESC_ARRAY_SIZE, SQL_INTEGER },
136 { SQL_DESC_ARRAY_STATUS_PTR, SQL_VARCHAR },
137 { SQL_DESC_BIND_OFFSET_PTR, SQL_VARCHAR },
138 { SQL_DESC_BIND_TYPE, SQL_VARCHAR },
139 { SQL_DESC_COUNT, SQL_SMALLINT },
140 { SQL_DESC_ROWS_PROCESSED_PTR, SQL_VARCHAR }
141};
142
143static struct cdesc rec_fields[] =
144{
145 { SQL_DESC_CONCISE_TYPE, SQL_SMALLINT },
146 { SQL_DESC_LENGTH, SQL_INTEGER },
147 { SQL_DESC_OCTET_LENGTH, SQL_INTEGER },
148 { SQL_DESC_PARAMETER_TYPE, SQL_SMALLINT },
149 { SQL_DESC_NUM_PREC_RADIX, SQL_INTEGER },
150 { SQL_DESC_PRECISION, SQL_SMALLINT },
151 { SQL_DESC_SCALE, SQL_SMALLINT },
152 { SQL_DESC_DATETIME_INTERVAL_CODE, SQL_SMALLINT },
153 { SQL_DESC_DATETIME_INTERVAL_PRECISION, SQL_SMALLINT },
154 { SQL_DESC_DATA_PTR, SQL_VARCHAR },
155 { SQL_DESC_INDICATOR_PTR, SQL_VARCHAR },
156 { SQL_DESC_OCTET_LENGTH_PTR, SQL_VARCHAR }
157};
158
159SQLRETURN SQLCopyDesc( SQLHDESC source_desc_handle,
160 SQLHDESC target_desc_handle )
161{
162 DMHDESC src_descriptor = (DMHDESC)source_desc_handle;
163 DMHDESC target_descriptor = (DMHDESC)target_desc_handle;
164 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ];
165
166 /*
167 * check descriptor
168 */
169
170 if ( !__validate_desc( src_descriptor ))
171 {
172 dm_log_write( __FILE__,
173 __LINE__,
174 LOG_INFO,
175 LOG_INFO,
176 "Error: SQL_INVALID_HANDLE" );
177
178 return SQL_INVALID_HANDLE;
179 }
180 if ( !__validate_desc( target_descriptor ))
181 {
182 dm_log_write( __FILE__,
183 __LINE__,
184 LOG_INFO,
185 LOG_INFO,
186 "Error: SQL_INVALID_HANDLE" );
187
188 return SQL_INVALID_HANDLE;
189 }
190
191 function_entry( src_descriptor );
192 function_entry( target_descriptor );
193
194 if ( log_info.log_flag )
195 {
196 sprintf( src_descriptor -> msg, "\n\t\tEntry:\
197\n\t\t\tSource Descriptor = %p\
198\n\t\t\tTarget Descriptor = %p",
199 src_descriptor,
200 target_descriptor );
201
202 dm_log_write( __FILE__,
203 __LINE__,
204 LOG_INFO,
205 LOG_INFO,
206 src_descriptor -> msg );
207 }
208
209 if ( src_descriptor -> associated_with ) {
210 DMHSTMT statement = (DMHSTMT) src_descriptor -> associated_with;
211
212 if ( statement -> state == STATE_S8 ||
213 statement -> state == STATE_S9 ||
214 statement -> state == STATE_S10 ||
215 statement -> state == STATE_S11 ||
216 statement -> state == STATE_S12 ||
217 statement -> state == STATE_S13 ||
218 statement -> state == STATE_S14 ||
219 statement -> state == STATE_S15 )
220 {
221 dm_log_write( __FILE__,
222 __LINE__,
223 LOG_INFO,
224 LOG_INFO,
225 "Error: HY010" );
226
227 __post_internal_error( &src_descriptor -> error,
228 ERROR_HY010, NULL,
229 src_descriptor -> connection -> environment -> requested_version );
230
231 function_return_nodrv( SQL_HANDLE_DESC, target_descriptor, SQL_SUCCESS );
232 return function_return_nodrv( SQL_HANDLE_DESC, src_descriptor, SQL_ERROR );
233 }
234 }
235
236 if ( target_descriptor -> associated_with ) {
237 DMHSTMT statement = (DMHSTMT) target_descriptor -> associated_with;
238
239 if ( statement -> state == STATE_S8 ||
240 statement -> state == STATE_S9 ||
241 statement -> state == STATE_S10 ||
242 statement -> state == STATE_S11 ||
243 statement -> state == STATE_S12 )
244 {
245 dm_log_write( __FILE__,
246 __LINE__,
247 LOG_INFO,
248 LOG_INFO,
249 "Error: HY010" );
250
251 __post_internal_error( &target_descriptor -> error,
252 ERROR_HY010, NULL,
253 target_descriptor -> connection -> environment -> requested_version );
254
255 return function_return_nodrv( IGNORE_THREAD, src_descriptor, SQL_ERROR );
256 }
257 }
258
259 /*
260 * if both descriptors are from the same driver then we can just
261 * pass it on
262 */
263
264 if ( (src_descriptor -> connection == target_descriptor -> connection ||
265 !strcmp(src_descriptor -> connection -> dl_name,
266 target_descriptor -> connection -> dl_name) ) &&
267 CHECK_SQLCOPYDESC( src_descriptor -> connection ))
268 {
269 SQLRETURN ret;
270
271 /*
272 * protect the common connection
273 */
274
275 thread_protect( SQL_HANDLE_DBC, src_descriptor -> connection );
276
277 ret = SQLCOPYDESC( src_descriptor -> connection,
278 src_descriptor -> driver_desc,
279 target_descriptor -> driver_desc );
280
281 if ( log_info.log_flag )
282 {
283 sprintf( target_descriptor -> msg,
284 "\n\t\tExit:[%s]",
285 __get_return_status( ret, s1 ));
286
287 dm_log_write( __FILE__,
288 __LINE__,
289 LOG_INFO,
290 LOG_INFO,
291 target_descriptor -> msg );
292 }
293
294 return function_return( IGNORE_THREAD, target_descriptor, ret );
295 }
296 else
297 {
298 /*
299 * TODO copy from one to the other
300 * protect the common environment
301 */
302
303 SQLRETURN ret = SQL_SUCCESS;
304 SQLSMALLINT count;
305 SQLSMALLINT sval;
306 SQLINTEGER ival;
307 SQLPOINTER pval;
308
309 if ( src_descriptor -> connection == target_descriptor -> connection )
310 thread_protect( SQL_HANDLE_DBC, src_descriptor -> connection );
311 else
312 thread_protect( SQL_HANDLE_ENV, src_descriptor -> connection -> environment );
313
314 if ( !CHECK_SQLGETDESCFIELD( src_descriptor -> connection ) ||
315 !CHECK_SQLSETDESCFIELD( src_descriptor -> connection ))
316 {
317 dm_log_write( __FILE__,
318 __LINE__,
319 LOG_INFO,
320 LOG_INFO,
321 "Error: IM001" );
322
323 __post_internal_error( &target_descriptor -> error,
324 ERROR_IM001, NULL,
325 target_descriptor -> connection -> environment -> requested_version );
326
327 if ( src_descriptor -> connection == target_descriptor -> connection )
328 thread_release( SQL_HANDLE_DBC, src_descriptor -> connection );
329 else
330 thread_release( SQL_HANDLE_ENV, src_descriptor -> connection -> environment );
331
332 return function_return_nodrv( IGNORE_THREAD, target_descriptor, SQL_ERROR );
333 }
334
335 /*
336 * get the count from the source field
337 */
338
339 ret = SQLGETDESCFIELD( src_descriptor -> connection,
340 src_descriptor -> driver_desc,
341 0,
342 SQL_DESC_COUNT,
343 &count,
344 sizeof( count ),
345 NULL );
346
347 if ( SQL_SUCCEEDED( ret ))
348 {
349 /*
350 * copy the header fields
351 */
352 int i;
353
354 for ( i = 0; i < sizeof( header_fields ) / sizeof( header_fields[ 0 ] ); i ++ )
355 {
356 if ( header_fields[ i ].field_type == SQL_INTEGER )
357 {
358 ret = SQLGETDESCFIELD( src_descriptor -> connection,
359 src_descriptor -> driver_desc,
360 0,
361 header_fields[ i ].field_identifier,
362 &ival,
363 sizeof( ival ),
364 NULL );
365 }
366 else if ( header_fields[ i ].field_type == SQL_SMALLINT )
367 {
368 ret = SQLGETDESCFIELD( src_descriptor -> connection,
369 src_descriptor -> driver_desc,
370 0,
371 header_fields[ i ].field_identifier,
372 &sval,
373 sizeof( sval ),
374 NULL );
375 }
376 if ( header_fields[ i ].field_type == SQL_VARCHAR )
377 {
378 ret = SQLGETDESCFIELD( src_descriptor -> connection,
379 src_descriptor -> driver_desc,
380 0,
381 header_fields[ i ].field_identifier,
382 &pval,
383 sizeof( pval ),
384 NULL );
385 }
386
387 if ( SQL_SUCCEEDED( ret ))
388 {
389 if ( header_fields[ i ].field_type == SQL_INTEGER )
390 {
391 ret = SQLSETDESCFIELD( target_descriptor -> connection,
392 target_descriptor -> driver_desc,
393 0,
394 header_fields[ i ].field_identifier,
395 ival,
396 sizeof( ival ));
397 }
398 else if ( header_fields[ i ].field_type == SQL_SMALLINT )
399 {
400 ret = SQLSETDESCFIELD( target_descriptor -> connection,
401 target_descriptor -> driver_desc,
402 0,
403 header_fields[ i ].field_identifier,
404 sval,
405 sizeof( sval ));
406 }
407 else if ( header_fields[ i ].field_type == SQL_VARCHAR )
408 {
409 ret = SQLSETDESCFIELD( target_descriptor -> connection,
410 target_descriptor -> driver_desc,
411 0,
412 header_fields[ i ].field_identifier,
413 pval,
414 sizeof( pval ));
415 }
416 }
417
418 if ( !SQL_SUCCEEDED( ret ))
419 break;
420 }
421 }
422
423 if ( SQL_SUCCEEDED( ret ))
424 {
425 /*
426 * copy the records
427 */
428 int i, rec;
429
430 for ( rec = 0; rec <= count; rec ++ )
431 {
432 for ( i = 0; i < sizeof( rec_fields ) / sizeof( rec_fields[ 0 ] ); i ++ )
433 {
434 if ( rec_fields[ i ].field_type == SQL_INTEGER )
435 {
436 ret = SQLGETDESCFIELD( src_descriptor -> connection,
437 src_descriptor -> driver_desc,
438 rec,
439 rec_fields[ i ].field_identifier,
440 &ival,
441 sizeof( ival ),
442 NULL );
443 }
444 else if ( rec_fields[ i ].field_type == SQL_SMALLINT )
445 {
446 ret = SQLGETDESCFIELD( src_descriptor -> connection,
447 src_descriptor -> driver_desc,
448 rec,
449 rec_fields[ i ].field_identifier,
450 &sval,
451 sizeof( sval ),
452 NULL );
453 }
454 if ( rec_fields[ i ].field_type == SQL_VARCHAR )
455 {
456 ret = SQLGETDESCFIELD( src_descriptor -> connection,
457 src_descriptor -> driver_desc,
458 rec,
459 rec_fields[ i ].field_identifier,
460 &pval,
461 sizeof( pval ),
462 NULL );
463 }
464
465 if ( SQL_SUCCEEDED( ret ))
466 {
467 if ( rec_fields[ i ].field_type == SQL_INTEGER )
468 {
469 ret = SQLSETDESCFIELD( target_descriptor -> connection,
470 target_descriptor -> driver_desc,
471 rec,
472 rec_fields[ i ].field_identifier,
473 ival,
474 sizeof( ival ));
475 }
476 else if ( rec_fields[ i ].field_type == SQL_SMALLINT )
477 {
478 ret = SQLSETDESCFIELD( target_descriptor -> connection,
479 target_descriptor -> driver_desc,
480 rec,
481 rec_fields[ i ].field_identifier,
482 sval,
483 sizeof( sval ));
484 }
485 else if ( rec_fields[ i ].field_type == SQL_VARCHAR )
486 {
487 ret = SQLSETDESCFIELD( target_descriptor -> connection,
488 target_descriptor -> driver_desc,
489 rec,
490 rec_fields[ i ].field_identifier,
491 pval,
492 sizeof( pval ));
493 }
494 }
495
496 if ( !SQL_SUCCEEDED( ret ))
497 break;
498 }
499 if ( !SQL_SUCCEEDED( ret ))
500 break;
501 }
502 }
503
504 if ( log_info.log_flag )
505 {
506 sprintf( src_descriptor -> msg,
507 "\n\t\tExit:[%s]",
508 __get_return_status( ret, s1 ));
509
510 dm_log_write( __FILE__,
511 __LINE__,
512 LOG_INFO,
513 LOG_INFO,
514 src_descriptor -> msg );
515 }
516
517 if ( src_descriptor -> connection == target_descriptor -> connection )
518 thread_release( SQL_HANDLE_DBC, src_descriptor -> connection );
519 else
520 thread_release( SQL_HANDLE_ENV, src_descriptor -> connection -> environment );
521
522 return function_return( IGNORE_THREAD, target_descriptor, ret );
523 }
524}
525