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: SQLBrowseConnectW.c,v 1.13 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLBrowseConnectW.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 2007/10/19 10:14:05 lurcher
37 * Pull errors from SQLBrowseConnect when it returns SQL_NEED_DATA
38 *
39 * Revision 1.11 2007/02/28 15:37:46 lurcher
40 * deal with drivers that call internal W functions and end up in the driver manager. controlled by the --enable-handlemap configure arg
41 *
42 * Revision 1.10 2003/10/30 18:20:45 lurcher
43 *
44 * Fix broken thread protection
45 * Remove SQLNumResultCols after execute, lease S4/S% to driver
46 * Fix string overrun in SQLDriverConnect
47 * Add initial support for Interix
48 *
49 * Revision 1.9 2002/12/05 17:44:30 lurcher
50 *
51 * Display unknown return values in return logging
52 *
53 * Revision 1.8 2002/08/23 09:42:37 lurcher
54 *
55 * Fix some build warnings with casts, and a AIX linker mod, to include
56 * deplib's on the link line, but not the libtool generated ones
57 *
58 * Revision 1.7 2002/08/15 08:10:33 lurcher
59 *
60 * Couple of small fixes from John L Miller
61 *
62 * Revision 1.6 2002/07/25 09:30:26 lurcher
63 *
64 * Additional unicode and iconv changes
65 *
66 * Revision 1.5 2002/07/24 08:49:51 lurcher
67 *
68 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
69 *
70 * Revision 1.4 2002/02/08 17:59:40 lurcher
71 *
72 * Fix threading problem in SQLBrowseConnect
73 *
74 * Revision 1.3 2002/01/21 18:00:51 lurcher
75 *
76 * Assorted fixed and changes, mainly UNICODE/bug fixes
77 *
78 * Revision 1.2 2001/12/13 13:00:32 lurcher
79 *
80 * Remove most if not all warnings on 64 bit platforms
81 * Add support for new MS 3.52 64 bit changes
82 * Add override to disable the stopping of tracing
83 * Add MAX_ROWS support in postgres driver
84 *
85 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
86 *
87 * First upload to SourceForge
88 *
89 * Revision 1.7 2001/07/20 12:35:09 nick
90 *
91 * Fix SQLBrowseConnect operation
92 *
93 * Revision 1.6 2001/07/03 09:30:41 nick
94 *
95 * Add ability to alter size of displayed message in the log
96 *
97 * Revision 1.5 2001/05/15 10:57:44 nick
98 *
99 * Add initial support for VMS
100 *
101 * Revision 1.4 2001/04/16 15:41:24 nick
102 *
103 * Fix some problems calling non existing error funcs
104 *
105 * Revision 1.3 2001/04/12 17:43:35 nick
106 *
107 * Change logging and added autotest to odbctest
108 *
109 * Revision 1.2 2001/01/02 09:55:04 nick
110 *
111 * More unicode bits
112 *
113 * Revision 1.1 2000/12/31 20:30:54 nick
114 *
115 * Add UNICODE support
116 *
117 *
118 **********************************************************************/
119
120#include <config.h>
121#include "drivermanager.h"
122
123static char const rcsid[]= "$RCSfile: SQLBrowseConnectW.c,v $";
124
125#define BUFFER_LEN 4095
126
127SQLRETURN SQLBrowseConnectW(
128 SQLHDBC hdbc,
129 SQLWCHAR *conn_str_in,
130 SQLSMALLINT len_conn_str_in,
131 SQLWCHAR *conn_str_out,
132 SQLSMALLINT conn_str_out_max,
133 SQLSMALLINT *ptr_conn_str_out )
134{
135 DMHDBC connection = (DMHDBC) hdbc;
136 struct con_struct con_struct;
137 char *driver, *dsn;
138 char lib_name[ INI_MAX_PROPERTY_VALUE + 1 ];
139 char driver_name[ INI_MAX_PROPERTY_VALUE + 1 ];
140 char in_str[ BUFFER_LEN ];
141 SQLRETURN ret;
142 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ], s2[ 100 + LOG_MESSAGE_LEN ];
143 SQLWCHAR *uc_in_str;
144 int warnings = 0;
145
146 /*
147 * check connection
148 */
149
150 if ( !__validate_dbc( connection ))
151 {
152 dm_log_write( __FILE__,
153 __LINE__,
154 LOG_INFO,
155 LOG_INFO,
156 "Error: SQL_INVALID_HANDLE" );
157
158#ifdef WITH_HANDLE_REDIRECT
159 {
160 DMHDBC parent_connection;
161
162 parent_connection = find_parent_handle( connection, SQL_HANDLE_DBC );
163
164 if ( parent_connection ) {
165 dm_log_write( __FILE__,
166 __LINE__,
167 LOG_INFO,
168 LOG_INFO,
169 "Info: found parent handle" );
170
171 if ( CHECK_SQLBROWSECONNECTW( parent_connection ))
172 {
173 dm_log_write( __FILE__,
174 __LINE__,
175 LOG_INFO,
176 LOG_INFO,
177 "Info: calling redirected driver function" );
178
179 return SQLBROWSECONNECTW( parent_connection,
180 connection,
181 conn_str_in,
182 len_conn_str_in,
183 conn_str_out,
184 conn_str_out_max,
185 ptr_conn_str_out );
186 }
187 }
188 }
189#endif
190
191 return SQL_INVALID_HANDLE;
192 }
193
194 function_entry( connection );
195
196 if ( log_info.log_flag )
197 {
198 sprintf( connection -> msg, "\n\t\tEntry:\
199\n\t\t\tConnection = %p\
200\n\t\t\tStr In = %s\
201\n\t\t\tStr Out = %s\
202\n\t\t\tPtr Conn Str Out = %p",
203 connection,
204 __wstring_with_length( s1, conn_str_in, len_conn_str_in ),
205 __wstring_with_length( s2, conn_str_out, conn_str_out_max ),
206 ptr_conn_str_out );
207
208 dm_log_write( __FILE__,
209 __LINE__,
210 LOG_INFO,
211 LOG_INFO,
212 connection -> msg );
213 }
214
215 /*
216 * check the state of the connection
217 */
218
219 if ( connection -> state == STATE_C4 ||
220 connection -> state == STATE_C5 ||
221 connection -> state == STATE_C6 )
222 {
223 dm_log_write( __FILE__,
224 __LINE__,
225 LOG_INFO,
226 LOG_INFO,
227 "Error: 08002" );
228
229 __post_internal_error( &connection -> error,
230 ERROR_08002, NULL,
231 connection -> environment -> requested_version );
232
233 return function_return_nodrv( IGNORE_THREAD, connection, SQL_ERROR );
234 }
235
236 /*
237 * are we at the start of a connection
238 */
239
240 thread_protect( SQL_HANDLE_DBC, connection );
241
242 if ( connection -> state == STATE_C2 )
243 {
244 /*
245 * parse the connection string
246 */
247
248 __parse_connection_string_w( &con_struct,
249 conn_str_in, len_conn_str_in );
250
251 /*
252 * look for some keywords
253 * have we got a DRIVER= attribute
254 */
255
256 driver = __get_attribute_value( &con_struct, "DRIVER" );
257 if ( driver )
258 {
259 /*
260 * look up the driver in the ini file
261 */
262 SQLGetPrivateProfileString( driver, "Driver", "",
263 lib_name, sizeof( lib_name ), "ODBCINST.INI" );
264
265 if ( lib_name[ 0 ] == '\0' )
266 {
267 dm_log_write( __FILE__,
268 __LINE__,
269 LOG_INFO,
270 LOG_INFO,
271 "Error: IM002" );
272
273 __post_internal_error( &connection -> error,
274 ERROR_IM002, NULL,
275 connection -> environment -> requested_version );
276 __release_conn( &con_struct );
277
278 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
279 }
280
281 __generate_connection_string( &con_struct, in_str, sizeof( in_str ));
282 strcpy( connection -> dsn, "" );
283 }
284 else
285 {
286 dsn = __get_attribute_value( &con_struct, "DSN" );
287 if ( !dsn )
288 {
289 __append_pair( &con_struct, "DSN", "DEFAULT" );
290 dsn = "DEFAULT";
291 }
292
293 if ( strlen( dsn ) > SQL_MAX_DSN_LENGTH )
294 {
295 dm_log_write( __FILE__,
296 __LINE__,
297 LOG_INFO,
298 LOG_INFO,
299 "Error: IM012" );
300
301 __post_internal_error( &connection -> error,
302 ERROR_IM012, NULL,
303 connection -> environment -> requested_version );
304
305 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
306 }
307
308 sprintf( in_str, "DSN=%s;", dsn );
309
310 /*
311 * look up the dsn in the ini file
312 */
313
314 if ( !__find_lib_name( dsn, lib_name, driver_name ))
315 {
316 dm_log_write( __FILE__,
317 __LINE__,
318 LOG_INFO,
319 LOG_INFO,
320 "Error: IM002" );
321
322 __post_internal_error( &connection -> error,
323 ERROR_IM002, NULL,
324 connection -> environment -> requested_version );
325 __release_conn( &con_struct );
326
327 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
328 }
329
330 __generate_connection_string( &con_struct, in_str, sizeof( in_str ));
331 strcpy( connection -> dsn, dsn );
332 }
333
334 __release_conn( &con_struct );
335
336 /*
337 * we now have a driver to connect to
338 */
339
340 if ( !__connect_part_one( connection, lib_name, driver_name, &warnings ))
341 {
342 __disconnect_part_four( connection ); /* release unicode handles */
343
344 dm_log_write( __FILE__,
345 __LINE__,
346 LOG_INFO,
347 LOG_INFO,
348 "Error: connect_part_one fails" );
349
350 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
351 }
352
353 if ( !CHECK_SQLBROWSECONNECTW( connection ) &&
354 !CHECK_SQLBROWSECONNECT( connection ))
355 {
356 dm_log_write( __FILE__,
357 __LINE__,
358 LOG_INFO,
359 LOG_INFO,
360 "Error: IM001" );
361
362 __disconnect_part_one( connection );
363 __disconnect_part_four( connection ); /* release unicode handles */
364 __post_internal_error( &connection -> error,
365 ERROR_IM001, NULL,
366 connection -> environment -> requested_version );
367
368 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
369 }
370 }
371 else
372 {
373 if ( len_conn_str_in == SQL_NTS )
374 {
375 int i;
376
377 for( i = 0; conn_str_in[ i ]; i ++ )
378 {
379 in_str[ i ] = (char) conn_str_in[ i ];
380 }
381 in_str[ i ] = '\0';
382 }
383 else
384 {
385 int i;
386
387 for( i = 0; i < len_conn_str_in; i ++ )
388 {
389 in_str[ i ] = (char) conn_str_in[ i ];
390 }
391 in_str[ i ] = '\0';
392 }
393 }
394
395 if ( CHECK_SQLBROWSECONNECTW( connection ))
396 {
397 uc_in_str = ansi_to_unicode_alloc((SQLCHAR*) in_str, SQL_NTS, connection, NULL );
398
399 ret = SQLBROWSECONNECTW( connection,
400 connection -> driver_dbc,
401 uc_in_str,
402 SQL_NTS,
403 conn_str_out,
404 conn_str_out_max,
405 ptr_conn_str_out );
406
407 if ( uc_in_str )
408 free( uc_in_str );
409
410 connection -> unicode_driver = 1;
411 }
412 else
413 {
414 if ( conn_str_out )
415 {
416 if ( conn_str_out_max > 0 )
417 {
418 SQLCHAR *ob = malloc( conn_str_out_max + 1 );
419 SQLINTEGER len;
420
421 ret = SQLBROWSECONNECT( connection,
422 connection -> driver_dbc,
423 in_str,
424 SQL_NTS,
425 ob,
426 conn_str_out_max,
427 &len );
428
429 if ( len > 0 )
430 {
431 ansi_to_unicode_copy( conn_str_out, (char*) ob, len, connection, NULL );
432 }
433
434 if ( ptr_conn_str_out )
435 {
436 *ptr_conn_str_out = len;
437 }
438 }
439 else
440 {
441 ret = SQLBROWSECONNECT( connection,
442 connection -> driver_dbc,
443 in_str,
444 SQL_NTS,
445 conn_str_out,
446 conn_str_out_max,
447 ptr_conn_str_out );
448 }
449 }
450 else
451 {
452 ret = SQLBROWSECONNECT( connection,
453 connection -> driver_dbc,
454 in_str,
455 SQL_NTS,
456 conn_str_out,
457 conn_str_out_max,
458 ptr_conn_str_out );
459 }
460
461 connection -> unicode_driver = 0;
462 }
463
464 if ( !SQL_SUCCEEDED( ret ) || ret == SQL_NEED_DATA )
465 {
466 if ( connection -> unicode_driver )
467 {
468 SQLWCHAR sqlstate[ 6 ];
469 SQLINTEGER native_error;
470 SQLSMALLINT ind;
471 SQLWCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
472 SQLRETURN eret;
473
474 /*
475 * get the error from the driver before
476 * loseing the connection
477 */
478
479 if ( CHECK_SQLERRORW( connection ))
480 {
481 do
482 {
483 eret = SQLERRORW( connection,
484 SQL_NULL_HENV,
485 connection -> driver_dbc,
486 SQL_NULL_HSTMT,
487 sqlstate,
488 &native_error,
489 message_text,
490 sizeof( message_text ),
491 &ind );
492
493
494 if ( SQL_SUCCEEDED( eret ))
495 {
496 __post_internal_error_ex_w( &connection -> error,
497 sqlstate,
498 native_error,
499 message_text,
500 SUBCLASS_ODBC, SUBCLASS_ODBC );
501 }
502 }
503 while( SQL_SUCCEEDED( eret ));
504 }
505 else if ( CHECK_SQLGETDIAGRECW( connection ))
506 {
507 int rec = 1;
508
509 do
510 {
511 eret = SQLGETDIAGRECW( connection,
512 SQL_HANDLE_DBC,
513 connection -> driver_dbc,
514 rec ++,
515 sqlstate,
516 &native_error,
517 message_text,
518 sizeof( message_text ),
519 &ind );
520
521 if ( SQL_SUCCEEDED( eret ))
522 {
523 __post_internal_error_ex_w( &connection -> error,
524 sqlstate,
525 native_error,
526 message_text,
527 SUBCLASS_ODBC, SUBCLASS_ODBC );
528 }
529 }
530 while( SQL_SUCCEEDED( eret ));
531 }
532
533 if ( ret != SQL_NEED_DATA )
534 {
535 __disconnect_part_one( connection );
536 __disconnect_part_four( connection ); /* release unicode handles */
537 connection -> state = STATE_C2;
538 }
539 else
540 {
541 connection -> state = STATE_C3;
542 }
543 }
544 else
545 {
546 SQLCHAR sqlstate[ 6 ];
547 SQLINTEGER native_error;
548 SQLSMALLINT ind;
549 SQLCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
550 SQLRETURN eret;
551
552 /*
553 * get the error from the driver before
554 * loseing the connection
555 */
556 if ( CHECK_SQLERROR( connection ))
557 {
558 do
559 {
560 eret = SQLERROR( connection,
561 SQL_NULL_HENV,
562 connection -> driver_dbc,
563 SQL_NULL_HSTMT,
564 sqlstate,
565 &native_error,
566 message_text,
567 sizeof( message_text ),
568 &ind );
569
570
571 if ( SQL_SUCCEEDED( eret ))
572 {
573 __post_internal_error_ex( &connection -> error,
574 sqlstate,
575 native_error,
576 message_text,
577 SUBCLASS_ODBC, SUBCLASS_ODBC );
578 }
579 }
580 while( SQL_SUCCEEDED( eret ));
581 }
582 else if ( CHECK_SQLGETDIAGREC( connection ))
583 {
584 int rec = 1;
585
586 do
587 {
588 eret = SQLGETDIAGRECW( connection,
589 SQL_HANDLE_DBC,
590 connection -> driver_dbc,
591 rec ++,
592 sqlstate,
593 &native_error,
594 message_text,
595 sizeof( message_text ),
596 &ind );
597
598 if ( SQL_SUCCEEDED( eret ))
599 {
600 __post_internal_error_ex( &connection -> error,
601 sqlstate,
602 native_error,
603 message_text,
604 SUBCLASS_ODBC, SUBCLASS_ODBC );
605 }
606 }
607 while( SQL_SUCCEEDED( eret ));
608 }
609
610 if ( ret != SQL_NEED_DATA )
611 {
612 __disconnect_part_one( connection );
613 __disconnect_part_four( connection ); /* release unicode handles */
614 connection -> state = STATE_C2;
615 }
616 else
617 {
618 connection -> state = STATE_C3;
619 }
620 }
621 }
622 else
623 {
624 /*
625 * we should be connected now
626 */
627
628 connection -> state = STATE_C4;
629
630 if( ret == SQL_SUCCESS_WITH_INFO )
631 {
632 function_return_ex( IGNORE_THREAD, connection, ret, TRUE );
633 }
634
635 if ( !__connect_part_two( connection ))
636 {
637 __disconnect_part_two( connection );
638 __disconnect_part_one( connection );
639 __disconnect_part_four( connection ); /* release unicode handles */
640
641 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
642 }
643 }
644
645 if ( log_info.log_flag )
646 {
647 sprintf( connection -> msg,
648 "\n\t\tExit:[%s]\
649 \n\t\t\tPtr Conn Str Out = %s",
650 __get_return_status( ret, s2 ),
651 __sptr_as_string( s1, ptr_conn_str_out ));
652
653 dm_log_write( __FILE__,
654 __LINE__,
655 LOG_INFO,
656 LOG_INFO,
657 connection -> msg );
658 }
659
660 if ( warnings && ret == SQL_SUCCESS )
661 {
662 ret = SQL_SUCCESS_WITH_INFO;
663 }
664
665 return function_return_nodrv( SQL_HANDLE_DBC, connection, ret );
666}
667