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