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: SQLConnectW.c,v 1.15 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLConnectW.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 2008/09/29 14:02:44 lurcher
37 * Fix missing dlfcn group option
38 *
39 * Revision 1.13 2007/02/28 15:37:47 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.12 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.11 2002/12/20 11:36:46 lurcher
50 *
51 * Update DMEnvAttr code to allow setting in the odbcinst.ini entry
52 *
53 * Revision 1.10 2002/12/05 17:44:30 lurcher
54 *
55 * Display unknown return values in return logging
56 *
57 * Revision 1.9 2002/08/23 09:42:37 lurcher
58 *
59 * Fix some build warnings with casts, and a AIX linker mod, to include
60 * deplib's on the link line, but not the libtool generated ones
61 *
62 * Revision 1.8 2002/07/25 09:30:26 lurcher
63 *
64 * Additional unicode and iconv changes
65 *
66 * Revision 1.7 2002/07/24 08:49:51 lurcher
67 *
68 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
69 *
70 * Revision 1.6 2002/05/28 13:30:34 lurcher
71 *
72 * Tidy up for AIX
73 *
74 * Revision 1.5 2002/05/24 12:42:50 lurcher
75 *
76 * Alter NEWS and ChangeLog to match their correct usage
77 * Additional UNICODE tweeks
78 *
79 * Revision 1.4 2002/04/10 11:04:36 lurcher
80 *
81 * Fix endian issue with 4 byte unicode support
82 *
83 * Revision 1.3 2002/01/21 18:00:51 lurcher
84 *
85 * Assorted fixed and changes, mainly UNICODE/bug fixes
86 *
87 * Revision 1.2 2001/12/13 13:00:32 lurcher
88 *
89 * Remove most if not all warnings on 64 bit platforms
90 * Add support for new MS 3.52 64 bit changes
91 * Add override to disable the stopping of tracing
92 * Add MAX_ROWS support in postgres driver
93 *
94 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
95 *
96 * First upload to SourceForge
97 *
98 * Revision 1.4 2001/07/03 09:30:41 nick
99 *
100 * Add ability to alter size of displayed message in the log
101 *
102 * Revision 1.3 2001/04/12 17:43:36 nick
103 *
104 * Change logging and added autotest to odbctest
105 *
106 * Revision 1.2 2001/01/04 13:16:25 nick
107 *
108 * Add support for GNU portable threads and tidy up some UNICODE compile
109 * warnings
110 *
111 * Revision 1.1 2000/12/31 20:30:54 nick
112 *
113 * Add UNICODE support
114 *
115 *
116 **********************************************************************/
117
118#include <config.h>
119#include "drivermanager.h"
120
121static char const rcsid[]= "$RCSfile: SQLConnectW.c,v $";
122
123SQLRETURN SQLConnectW( SQLHDBC connection_handle,
124 SQLWCHAR *server_name,
125 SQLSMALLINT name_length1,
126 SQLWCHAR *user_name,
127 SQLSMALLINT name_length2,
128 SQLWCHAR *authentication,
129 SQLSMALLINT name_length3 )
130{
131 DMHDBC connection = (DMHDBC)connection_handle;
132 int len, ret_from_connect;
133 SQLWCHAR dsn[ SQL_MAX_DSN_LENGTH + 1 ];
134 char lib_name[ INI_MAX_PROPERTY_VALUE + 1 ];
135 char driver_name[ INI_MAX_PROPERTY_VALUE + 1 ];
136 SQLCHAR ansi_dsn[ SQL_MAX_DSN_LENGTH + 1 ];
137 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ], s2[ 100 + LOG_MESSAGE_LEN ], s3[ 100 + LOG_MESSAGE_LEN ], ansi_user[ SQL_MAX_DSN_LENGTH + 1 ], ansi_pwd[ SQL_MAX_DSN_LENGTH + 1 ];
138 int warnings;
139
140 /*
141 * check connection
142 */
143 if ( !__validate_dbc( connection ))
144 {
145 dm_log_write( __FILE__,
146 __LINE__,
147 LOG_INFO,
148 LOG_INFO,
149 "Error: SQL_INVALID_HANDLE" );
150
151#ifdef WITH_HANDLE_REDIRECT
152 {
153 DMHDBC parent_connection;
154
155 parent_connection = find_parent_handle( connection, SQL_HANDLE_DBC );
156
157 if ( parent_connection ) {
158 dm_log_write( __FILE__,
159 __LINE__,
160 LOG_INFO,
161 LOG_INFO,
162 "Info: found parent handle" );
163
164 if ( CHECK_SQLCONNECTW( parent_connection ))
165 {
166 dm_log_write( __FILE__,
167 __LINE__,
168 LOG_INFO,
169 LOG_INFO,
170 "Info: calling redirected driver function" );
171
172 return SQLCONNECTW( parent_connection,
173 connection_handle,
174 server_name,
175 name_length1,
176 user_name,
177 name_length2,
178 authentication,
179 name_length3 );
180 }
181 }
182 }
183#endif
184
185 return SQL_INVALID_HANDLE;
186 }
187
188 function_entry( connection );
189
190 if ( log_info.log_flag )
191 {
192 sprintf( connection -> msg, "\n\t\tEntry:\
193\n\t\t\tConnection = %p\
194\n\t\t\tServer Name = %s\
195\n\t\t\tUser Name = %s\
196\n\t\t\tAuthentication = %s",
197 connection,
198 __wstring_with_length( s1, server_name, name_length1 ),
199 __wstring_with_length( s2, user_name, name_length2 ),
200 __wstring_with_length_pass( s3, authentication, name_length3 ));
201
202 dm_log_write( __FILE__,
203 __LINE__,
204 LOG_INFO,
205 LOG_INFO,
206 connection -> msg );
207 }
208
209 thread_protect( SQL_HANDLE_DBC, connection );
210
211 if (( name_length1 < 0 && name_length1 != SQL_NTS ) ||
212 ( name_length2 < 0 && name_length2 != SQL_NTS ) ||
213 ( name_length3 < 0 && name_length3 != SQL_NTS ))
214
215 {
216 dm_log_write( __FILE__,
217 __LINE__,
218 LOG_INFO,
219 LOG_INFO,
220 "Error: HY090" );
221
222 __post_internal_error( &connection -> error,
223 ERROR_HY090, NULL,
224 connection -> environment -> requested_version );
225
226 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
227 }
228
229 /*
230 * check the state of the connection
231 */
232 if ( connection -> state != STATE_C2 )
233 {
234 dm_log_write( __FILE__,
235 __LINE__,
236 LOG_INFO,
237 LOG_INFO,
238 "Error: 08002" );
239
240 __post_internal_error( &connection -> error,
241 ERROR_08002, NULL,
242 connection -> environment -> requested_version );
243
244 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
245 }
246
247 if ( name_length1 && server_name )
248 {
249 if ( name_length1 == SQL_NTS )
250 {
251 len = wide_strlen( server_name );
252
253 if ( len > SQL_MAX_DSN_LENGTH )
254 {
255 dm_log_write( __FILE__,
256 __LINE__,
257 LOG_INFO,
258 LOG_INFO,
259 "Error: HY090" );
260
261 __post_internal_error( &connection -> error,
262 ERROR_HY090, NULL,
263 connection -> environment -> requested_version );
264
265 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
266 }
267 }
268 else
269 {
270 len = name_length1;
271
272 if ( len > SQL_MAX_DSN_LENGTH )
273 {
274 dm_log_write( __FILE__,
275 __LINE__,
276 LOG_INFO,
277 LOG_INFO,
278 "Error: HY090" );
279
280 __post_internal_error( &connection -> error,
281 ERROR_HY090, NULL,
282 connection -> environment -> requested_version );
283
284 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
285 }
286 }
287 memcpy( dsn, server_name, sizeof( dsn[ 0 ] ) * len );
288 dsn[ len ] = (SQLWCHAR) 0;
289 }
290 else if ( name_length1 > SQL_MAX_DSN_LENGTH )
291 {
292 dm_log_write( __FILE__,
293 __LINE__,
294 LOG_INFO,
295 LOG_INFO,
296 "Error: IM010" );
297
298 __post_internal_error( &connection -> error,
299 ERROR_IM010, NULL,
300 connection -> environment -> requested_version );
301
302 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
303 }
304 else
305 {
306 int i;
307
308 for ( i = 0; i < 8; i ++ )
309 dsn[ i ] = "DEFAULT"[i];
310 }
311
312 /*
313 * No pooling for UNICODE at the moment
314 */
315
316 connection -> pooled_connection = NULL;
317
318 unicode_to_ansi_copy((char*) ansi_dsn, sizeof( ansi_dsn ), dsn, sizeof( ansi_dsn ), NULL, NULL );
319
320 if ( !*ansi_dsn || !__find_lib_name((char*) ansi_dsn, lib_name, driver_name ))
321 {
322 /*
323 * if not found look for a default
324 */
325
326 if ( !__find_lib_name( "DEFAULT", lib_name, driver_name ))
327 {
328 dm_log_write( __FILE__,
329 __LINE__,
330 LOG_INFO,
331 LOG_INFO,
332 "Error: IM002" );
333
334 __post_internal_error( &connection -> error,
335 ERROR_IM002, NULL,
336 connection -> environment -> requested_version );
337
338 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
339 }
340 }
341
342 /*
343 * do we have any Environment, Connection, or Statement attributes set in the ini ?
344 */
345
346 __handle_attr_extensions( connection, (char*) ansi_dsn, driver_name );
347
348 /*
349 * if necessary change the threading level
350 */
351
352 warnings = 0;
353
354 if ( !__connect_part_one( connection, lib_name, driver_name, &warnings ))
355 {
356 __disconnect_part_four( connection ); /* release unicode handles */
357
358 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
359 }
360
361 if ( !CHECK_SQLCONNECTW( connection ) &&
362 !CHECK_SQLCONNECT( connection ))
363 {
364 dm_log_write( __FILE__,
365 __LINE__,
366 LOG_INFO,
367 LOG_INFO,
368 "Error: IM001" );
369
370 __disconnect_part_one( connection );
371 __disconnect_part_four( connection ); /* release unicode handles */
372 __post_internal_error( &connection -> error,
373 ERROR_IM001, NULL,
374 connection -> environment -> requested_version );
375
376 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
377 }
378
379 if ( CHECK_SQLCONNECTW( connection ))
380 {
381 if ( CHECK_SQLSETCONNECTATTR( connection ))
382 {
383 int lret;
384
385 lret = SQLSETCONNECTATTR( connection,
386 connection -> driver_dbc,
387 SQL_ATTR_ANSI_APP,
388 SQL_AA_FALSE,
389 0 );
390 }
391
392 ret_from_connect = SQLCONNECTW( connection,
393 connection -> driver_dbc,
394 dsn, SQL_NTS,
395 user_name, name_length2,
396 authentication, name_length3 );
397
398 connection -> unicode_driver = 1;
399 }
400 else
401 {
402 if ( user_name )
403 {
404 if ( name_length2 == SQL_NTS )
405 unicode_to_ansi_copy((char*) ansi_user, sizeof( ansi_user ),user_name, sizeof( ansi_user ), connection, NULL);
406 else
407 unicode_to_ansi_copy((char*) ansi_user, sizeof( ansi_user ),user_name, name_length2, connection, NULL );
408 }
409
410 if ( authentication )
411 {
412 if ( name_length3 == SQL_NTS )
413 unicode_to_ansi_copy((char*) ansi_pwd, sizeof( ansi_pwd ), authentication, sizeof( ansi_pwd ), connection, NULL);
414 else
415 unicode_to_ansi_copy((char*) ansi_pwd, sizeof( ansi_pwd ), authentication, name_length3, connection, NULL );
416 }
417
418 /*
419 if ( CHECK_SQLSETCONNECTATTR( connection ))
420 {
421 int lret;
422
423 lret = SQLSETCONNECTATTR( connection,
424 connection -> driver_dbc,
425 SQL_ATTR_ANSI_APP,
426 SQL_AA_TRUE,
427 0 );
428 }
429 */
430
431 ret_from_connect = SQLCONNECT( connection,
432 connection -> driver_dbc,
433 ansi_dsn, SQL_NTS,
434 user_name ? ansi_user : NULL, name_length2,
435 authentication ? ansi_pwd : NULL, name_length3 );
436
437 connection -> unicode_driver = 0;
438 }
439
440 if ( ret_from_connect != SQL_SUCCESS )
441 {
442 /*
443 * get the errors from the driver before
444 * loseing the connection
445 */
446
447 if ( connection -> unicode_driver )
448 {
449 SQLWCHAR sqlstate[ 6 ];
450 SQLINTEGER native_error;
451 SQLSMALLINT ind;
452 SQLWCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
453 SQLRETURN ret;
454
455 if ( CHECK_SQLERRORW( connection ))
456 {
457 do
458 {
459 ret = SQLERRORW( connection,
460 SQL_NULL_HENV,
461 connection -> driver_dbc,
462 SQL_NULL_HSTMT,
463 sqlstate,
464 &native_error,
465 message_text,
466 sizeof( message_text ),
467 &ind );
468
469
470 if ( SQL_SUCCEEDED( ret ))
471 {
472 __post_internal_error_ex_w( &connection -> error,
473 sqlstate,
474 native_error,
475 message_text,
476 SUBCLASS_ODBC, SUBCLASS_ODBC );
477 }
478
479 sprintf( connection -> msg,
480 "\n\t\tExit:[%s]",
481 __get_return_status( ret_from_connect, s1 ));
482
483 dm_log_write( __FILE__,
484 __LINE__,
485 LOG_INFO,
486 LOG_INFO,
487 connection -> msg );
488 }
489 while( SQL_SUCCEEDED( ret ));
490 }
491 else if ( CHECK_SQLGETDIAGRECW( connection ))
492 {
493 int rec = 1;
494
495 do
496 {
497 ret = SQLGETDIAGRECW( connection,
498 SQL_HANDLE_DBC,
499 connection -> driver_dbc,
500 rec ++,
501 sqlstate,
502 &native_error,
503 message_text,
504 sizeof( message_text ),
505 &ind );
506
507
508 if ( SQL_SUCCEEDED( ret ))
509 {
510 __post_internal_error_ex_w( &connection -> error,
511 sqlstate,
512 native_error,
513 message_text,
514 SUBCLASS_ODBC, SUBCLASS_ODBC );
515 }
516
517 sprintf( connection -> msg,
518 "\n\t\tExit:[%s]",
519 __get_return_status( ret_from_connect, s1 ));
520
521 dm_log_write( __FILE__,
522 __LINE__,
523 LOG_INFO,
524 LOG_INFO,
525 connection -> msg );
526 }
527 while( SQL_SUCCEEDED( ret ));
528 }
529 }
530 else
531 {
532 SQLCHAR sqlstate[ 6 ];
533 SQLINTEGER native_error;
534 SQLSMALLINT ind;
535 SQLCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
536 SQLRETURN ret;
537
538 if ( CHECK_SQLERROR( connection ))
539 {
540 do
541 {
542 ret = SQLERROR( connection,
543 SQL_NULL_HENV,
544 connection -> driver_dbc,
545 SQL_NULL_HSTMT,
546 sqlstate,
547 &native_error,
548 message_text,
549 sizeof( message_text ),
550 &ind );
551
552
553 if ( SQL_SUCCEEDED( ret ))
554 {
555 __post_internal_error_ex( &connection -> error,
556 sqlstate,
557 native_error,
558 message_text,
559 SUBCLASS_ODBC, SUBCLASS_ODBC );
560 }
561
562 sprintf( connection -> msg,
563 "\n\t\tExit:[%s]",
564 __get_return_status( ret_from_connect, s1 ));
565
566 dm_log_write( __FILE__,
567 __LINE__,
568 LOG_INFO,
569 LOG_INFO,
570 connection -> msg );
571 }
572 while( SQL_SUCCEEDED( ret ));
573 }
574 else if ( CHECK_SQLGETDIAGREC( connection ))
575 {
576 int rec = 1;
577
578 do
579 {
580 ret = SQLGETDIAGREC( connection,
581 SQL_HANDLE_DBC,
582 connection -> driver_dbc,
583 rec ++,
584 sqlstate,
585 &native_error,
586 message_text,
587 sizeof( message_text ),
588 &ind );
589
590
591 if ( SQL_SUCCEEDED( ret ))
592 {
593 __post_internal_error_ex( &connection -> error,
594 sqlstate,
595 native_error,
596 message_text,
597 SUBCLASS_ODBC, SUBCLASS_ODBC );
598 }
599
600 sprintf( connection -> msg,
601 "\n\t\tExit:[%s]",
602 __get_return_status( ret_from_connect, s1 ));
603
604 dm_log_write( __FILE__,
605 __LINE__,
606 LOG_INFO,
607 LOG_INFO,
608 connection -> msg );
609 }
610 while( SQL_SUCCEEDED( ret ));
611 }
612 }
613
614
615 /*
616 * if it was a error then return now
617 */
618
619 if ( !SQL_SUCCEEDED( ret_from_connect ))
620 {
621 __disconnect_part_one( connection );
622 __disconnect_part_four( connection ); /* release unicode handles */
623
624 return function_return( SQL_HANDLE_DBC, connection, ret_from_connect );
625 }
626 }
627
628 /*
629 * we should be connected now
630 */
631 connection -> state = STATE_C4;
632 strcpy( connection -> dsn, (char*)ansi_dsn );
633
634 /*
635 * did we get the type we wanted
636 */
637 if ( connection -> driver_version !=
638 connection -> environment -> requested_version )
639 {
640 connection -> driver_version =
641 connection -> environment -> requested_version;
642
643 __post_internal_error( &connection -> error,
644 ERROR_01000, "Driver does not support the requested version",
645 connection -> environment -> requested_version );
646 ret_from_connect = SQL_SUCCESS_WITH_INFO;
647 }
648
649 if ( !__connect_part_two( connection ))
650 {
651 /*
652 * the cursor lib can kill us here, so be careful
653 */
654
655 __disconnect_part_two( connection );
656 __disconnect_part_one( connection );
657 __disconnect_part_four( connection ); /* release unicode handles */
658
659 connection -> state = STATE_C3;
660
661 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
662 }
663
664 if ( log_info.log_flag )
665 {
666 sprintf( connection -> msg,
667 "\n\t\tExit:[%s]",
668 __get_return_status( ret_from_connect, s1 ));
669
670 dm_log_write( __FILE__,
671 __LINE__,
672 LOG_INFO,
673 LOG_INFO,
674 connection -> msg );
675 }
676
677 if ( warnings && ret_from_connect == SQL_SUCCESS )
678 {
679 ret_from_connect = SQL_SUCCESS_WITH_INFO;
680 }
681
682 return function_return_nodrv( SQL_HANDLE_DBC, connection, ret_from_connect );
683}
684