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: SQLDriverConnect.c,v 1.28 2009/02/18 17:59:08 lurcher Exp $
31 *
32 * $Log: SQLDriverConnect.c,v $
33 * Revision 1.28 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.27 2009/02/17 09:47:44 lurcher
37 * Clear up a number of bugs
38 *
39 * Revision 1.26 2009/01/16 11:02:38 lurcher
40 * Interface to GUI for DSN selection
41 *
42 * Revision 1.25 2009/01/14 10:01:42 lurcher
43 * remove debug printf
44 *
45 * Revision 1.24 2009/01/12 15:18:15 lurcher
46 * Add interface into odbcinstQ to allow for a dialog if SQLDriverConnect is called without a DSN=
47 *
48 * Revision 1.23 2008/11/24 12:44:23 lurcher
49 * Try and tidu up the connection version checking
50 *
51 * Revision 1.22 2008/09/29 14:02:44 lurcher
52 * Fix missing dlfcn group option
53 *
54 * Revision 1.21 2008/08/29 08:01:38 lurcher
55 * Alter the way W functions are passed to the driver
56 *
57 * Revision 1.20 2007/03/05 09:49:23 lurcher
58 * Get it to build on VMS again
59 *
60 * Revision 1.19 2004/10/22 09:10:19 lurcher
61 * Fix a couple of problems with FILEDSN's
62 *
63 * Revision 1.18 2004/09/08 16:38:54 lurcher
64 *
65 * Get ready for a 2.2.10 release
66 *
67 * Revision 1.17 2004/07/27 13:04:41 lurcher
68 *
69 * Strip FILEDSN from connection string before passing to driver
70 *
71 * Revision 1.16 2004/02/18 15:47:44 lurcher
72 *
73 * Fix a leak in the iconv code
74 *
75 * Revision 1.15 2003/10/30 18:20:45 lurcher
76 *
77 * Fix broken thread protection
78 * Remove SQLNumResultCols after execute, lease S4/S% to driver
79 * Fix string overrun in SQLDriverConnect
80 * Add initial support for Interix
81 *
82 * Revision 1.14 2003/09/08 15:34:29 lurcher
83 *
84 * A couple of small but perfectly formed fixes
85 *
86 * Revision 1.13 2003/02/27 12:19:39 lurcher
87 *
88 * Add the A functions as well as the W
89 *
90 * Revision 1.12 2003/01/23 15:33:24 lurcher
91 *
92 * Fix problems with using putenv()
93 *
94 * Revision 1.11 2002/12/20 11:36:46 lurcher
95 *
96 * Update DMEnvAttr code to allow setting in the odbcinst.ini entry
97 *
98 * Revision 1.10 2002/12/05 17:44:30 lurcher
99 *
100 * Display unknown return values in return logging
101 *
102 * Revision 1.9 2002/10/14 09:46:10 lurcher
103 *
104 * Remove extra return
105 *
106 * Revision 1.8 2002/10/02 09:28:33 lurcher
107 *
108 * Fix uninitialised pointer in SQLDriverConnect.c
109 *
110 * Revision 1.7 2002/08/23 09:42:37 lurcher
111 *
112 * Fix some build warnings with casts, and a AIX linker mod, to include
113 * deplib's on the link line, but not the libtool generated ones
114 *
115 * Revision 1.6 2002/07/25 09:30:26 lurcher
116 *
117 * Additional unicode and iconv changes
118 *
119 * Revision 1.5 2002/07/24 08:49:51 lurcher
120 *
121 * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
122 *
123 * Revision 1.4 2002/05/24 12:42:50 lurcher
124 *
125 * Alter NEWS and ChangeLog to match their correct usage
126 * Additional UNICODE tweeks
127 *
128 * Revision 1.3 2002/01/21 18:00:51 lurcher
129 *
130 * Assorted fixed and changes, mainly UNICODE/bug fixes
131 *
132 * Revision 1.2 2001/12/13 13:00:32 lurcher
133 *
134 * Remove most if not all warnings on 64 bit platforms
135 * Add support for new MS 3.52 64 bit changes
136 * Add override to disable the stopping of tracing
137 * Add MAX_ROWS support in postgres driver
138 *
139 * Revision 1.1.1.1 2001/10/17 16:40:05 lurcher
140 *
141 * First upload to SourceForge
142 *
143 * Revision 1.22 2001/10/16 10:37:32 nick
144 *
145 * Getting ready for 2.0.10
146 *
147 * Revision 1.21 2001/10/09 13:23:30 nick
148 *
149 * Add filedsn support to ODBCConfig
150 *
151 * Revision 1.20 2001/10/08 13:38:35 nick
152 *
153 * Add support for FILEDSN's
154 *
155 * Revision 1.19 2001/08/08 17:05:17 nick
156 *
157 * Add support for attribute setting in the ini files
158 *
159 * Revision 1.18 2001/07/20 13:20:44 nick
160 * *** empty log message ***
161 *
162 * Revision 1.17 2001/07/20 12:35:09 nick
163 *
164 * Fix SQLBrowseConnect operation
165 *
166 * Revision 1.16 2001/05/15 10:57:44 nick
167 *
168 * Add initial support for VMS
169 *
170 * Revision 1.15 2001/04/18 15:03:37 nick
171 *
172 * Fix problem when going to DB2 unicode driver
173 *
174 * Revision 1.14 2001/04/16 22:35:10 nick
175 *
176 * More tweeks to the AutoTest code
177 *
178 * Revision 1.13 2001/04/16 15:41:24 nick
179 *
180 * Fix some problems calling non existing error funcs
181 *
182 * Revision 1.12 2001/04/12 17:43:36 nick
183 *
184 * Change logging and added autotest to odbctest
185 *
186 * Revision 1.11 2001/04/03 16:34:12 nick
187 *
188 * Add support for strangly broken unicode drivers
189 *
190 * Revision 1.10 2001/01/03 12:02:03 nick
191 *
192 * Add missing __
193 *
194 * Revision 1.9 2001/01/03 11:57:26 nick
195 *
196 * Fix some name collisions
197 *
198 * Revision 1.8 2000/12/31 20:30:54 nick
199 *
200 * Add UNICODE support
201 *
202 * Revision 1.7 2000/12/18 13:02:13 nick
203 *
204 * More buf fixes
205 *
206 * Revision 1.6 2000/12/18 12:53:29 nick
207 *
208 * More pooling tweeks
209 *
210 * Revision 1.5 2000/12/18 12:27:50 nick
211 *
212 * Fix missing check for SQL_NTS
213 *
214 * Revision 1.4 2000/12/14 18:10:19 nick
215 *
216 * Add connection pooling
217 *
218 * Revision 1.3 2000/10/13 15:18:49 nick
219 *
220 * Change string length parameter from SQLINTEGER to SQLSMALLINT
221 *
222 * Revision 1.2 2000/10/06 08:49:38 nick
223 *
224 * Fix duplicated error messages on connect
225 *
226 * Revision 1.1.1.1 2000/09/04 16:42:52 nick
227 * Imported Sources
228 *
229 * Revision 1.15 2000/08/11 12:11:27 ngorham
230 *
231 * Make SQLDriverConnect return all the stacked errors from the driver, not
232 * just one
233 *
234 * Revision 1.14 2000/07/13 13:27:24 ngorham
235 *
236 * remove _ from odbcinst_system_file_path()
237 *
238 * Revision 1.13 2000/06/21 08:58:26 ngorham
239 *
240 * Stop SQLDriverConnect dumping core when passed a null dsn string
241 *
242 * Revision 1.12 2000/02/20 10:18:47 ngorham
243 *
244 * Add support for ODBCINI environment override for Applix.
245 *
246 * Revision 1.11 1999/12/14 19:02:25 ngorham
247 *
248 * Mask out the password fields in the logging
249 *
250 * Revision 1.10 1999/11/13 23:40:59 ngorham
251 *
252 * Alter the way DM logging works
253 * Upgrade the Postgres driver to 6.4.6
254 *
255 * Revision 1.9 1999/10/24 23:54:17 ngorham
256 *
257 * First part of the changes to the error reporting
258 *
259 * Revision 1.8 1999/10/14 06:49:24 ngorham
260 *
261 * Remove @all_includes@ from Drivers/MiniSQL/Makefile.am
262 *
263 * Revision 1.7 1999/09/21 22:34:24 ngorham
264 *
265 * Improve performance by removing unneeded logging calls when logging is
266 * disabled
267 *
268 * Revision 1.6 1999/08/17 06:20:00 ngorham
269 *
270 * Remove posibility of returning without clearing the connection mutex.
271 *
272 * Revision 1.5 1999/08/03 21:47:39 shandyb
273 * Moving to automake: changed files in DriverManager
274 *
275 * Revision 1.4 1999/07/10 21:10:16 ngorham
276 *
277 * Adjust error sqlstate from driver manager, depending on requested
278 * version (ODBC2/3)
279 *
280 * Revision 1.3 1999/07/04 21:05:07 ngorham
281 *
282 * Add LGPL Headers to code
283 *
284 * Revision 1.2 1999/06/30 23:56:54 ngorham
285 *
286 * Add initial thread safety code
287 *
288 * Revision 1.1.1.1 1999/05/29 13:41:05 sShandyb
289 * first go at it
290 *
291 * Revision 1.1.1.1 1999/05/27 18:23:17 pharvey
292 * Imported sources
293 *
294 * Revision 1.4 1999/05/09 23:27:11 nick
295 * All the API done now
296 *
297 * Revision 1.3 1999/04/30 16:22:47 nick
298 * Another checkpoint
299 *
300 * Revision 1.2 1999/04/29 20:47:37 nick
301 * Another checkpoint
302 *
303 * Revision 1.1 1999/04/25 23:06:11 nick
304 * Initial revision
305 *
306 *
307 **********************************************************************/
308
309#include <config.h>
310#include <string.h>
311#include "drivermanager.h"
312
313static char const rcsid[]= "$RCSfile: SQLDriverConnect.c,v $ $Revision: 1.28 $";
314
315/*
316 * connection pooling stuff
317 */
318
319extern int pooling_enabled;
320
321void __generate_connection_string( struct con_struct *con_str, char *str, int str_len )
322{
323struct con_pair *cp;
324char *tmp;
325
326 str[ 0 ] = '\0';
327
328 if ( con_str -> count == 0 )
329 {
330 return;
331 }
332
333 cp = con_str -> list;
334 while( cp )
335 {
336 size_t attrlen = strlen( cp -> attribute );
337 int use_esc = isspace( *(cp -> attribute ) ) || attrlen && isspace( cp->attribute[attrlen - 1] );
338 for ( tmp = cp -> attribute; *tmp; tmp++ )
339 {
340 use_esc |= (*tmp == '{') || (*tmp == '}');
341 attrlen += (*tmp == '}');
342 }
343 tmp = malloc( strlen( cp -> keyword ) + attrlen + 10 );
344 if( use_esc )
345 {
346 char *tmp2 = tmp + sprintf( tmp, "%s={", cp -> keyword );
347 char *tmp3;
348 for( tmp3 = cp -> attribute; *tmp3 ; tmp3++ )
349 {
350 *tmp2++ = *tmp3;
351 if ( '}' == *tmp3++ )
352 {
353 *tmp2++ = '}';
354 }
355 }
356 *tmp2++ = '}';
357 *tmp2++ = 0;
358 }
359 else
360 {
361 sprintf( tmp, "%s=%s;", cp -> keyword, cp -> attribute );
362 }
363
364 if ( strlen( str ) + strlen( tmp ) > str_len )
365 {
366 break;
367 }
368 else
369 {
370 strcat( str, tmp );
371 }
372 free( tmp );
373
374 cp = cp -> next;
375 }
376}
377
378void __get_attr( char ** cp, char ** keyword, char ** value )
379{
380char * ptr;
381int len;
382
383 *keyword = *value = NULL;
384
385 while ( isspace( **cp ) || **cp == ';' )
386 {
387 (*cp)++;
388 }
389
390 if ( !**cp )
391 return;
392
393 ptr = *cp;
394
395 /*
396 * To handle the case attribute in which the attribute is of the form
397 * "ATTR;" instead of "ATTR=VALUE;"
398 */
399
400 while ( **cp && **cp != '=' )
401 {
402 (*cp)++;
403 }
404
405 if ( !**cp )
406 return;
407
408 len = *cp - ptr;
409 *keyword = malloc( len + 1 );
410 memcpy( *keyword, ptr, len );
411 (*keyword)[ len ] = '\0';
412
413 (*cp)++;
414
415 if ( **cp == '{' )
416 {
417 /* escaped with '{' - all characters until next '}' not followed by '}', or
418 end of string, are part of the value */
419 int i = 0;
420 ptr = ++*cp;
421 while ( **cp && (**cp != '}' || (*cp)[1] == '}') )
422 {
423 if ( **cp == '}' )
424 (*cp)++;
425 (*cp)++;
426 }
427 len = *cp - ptr;
428 *value = malloc( len + 1 );
429 while( ptr < *cp )
430 {
431 if ( ((*value)[i++] = *ptr++) == '}')
432 {
433 ptr++;
434 }
435 }
436 (*value)[i] = 0;
437 if ( **cp == '}' )
438 {
439 (*cp)++;
440 }
441 }
442 else
443 {
444 /* non-escaped: all characters until ';' or end of string are value */
445 ptr = *cp;
446 while ( **cp && **cp != ';' )
447 {
448 (*cp)++;
449 }
450 len = *cp - ptr;
451 *value = malloc( len + 1 );
452 memcpy( *value, ptr, len );
453 (*value)[ len ] = 0;
454 }
455}
456
457struct con_pair * __get_pair( char ** cp )
458{
459char *keyword, *value;
460struct con_pair * con_p;
461
462 __get_attr( cp, &keyword, &value );
463 if ( keyword )
464 {
465 con_p = malloc( sizeof( *con_p ));
466 con_p -> keyword = keyword;
467 con_p -> attribute = value;
468 return con_p;
469 }
470 else
471 {
472 return NULL;
473 }
474}
475
476int __append_pair( struct con_struct *con_str, char *kword, char *value )
477{
478struct con_pair *ptr, *end;
479
480 /* check that the keyword is not already in the list */
481
482 end = NULL;
483 if ( con_str -> count > 0 )
484 {
485 ptr = con_str -> list;
486 while( ptr )
487 {
488 if( strcasecmp( kword, ptr -> keyword ) == 0 )
489 {
490 free( ptr -> attribute );
491 ptr -> attribute = malloc( strlen( value ) + 1 );
492 strcpy( ptr -> attribute, value );
493 return 0;
494 }
495 end = ptr;
496 ptr = ptr -> next;
497 }
498 }
499
500 ptr = malloc( sizeof( *ptr ));
501
502 ptr -> keyword = malloc( strlen( kword ) + 1 );
503 strcpy( ptr -> keyword, kword );
504
505 ptr -> attribute = malloc( strlen( value ) + 1 );
506 strcpy( ptr -> attribute, value );
507
508 con_str -> count ++;
509
510 if ( con_str -> list )
511 {
512 end -> next = ptr;
513 ptr -> next = NULL;
514 }
515 else
516 {
517 ptr -> next = NULL;
518 con_str -> list = ptr;
519 }
520
521 return 0;
522}
523
524int __parse_connection_string_ex( struct con_struct *con_str,
525 char *str, int str_len, int exclude )
526{
527struct con_pair *cp;
528char *local_str, *ptr;
529int got_dsn = 0; /* if we have a DSN then ignore any DRIVER or FILEDSN */
530int got_driver = 0; /* if we have a DRIVER or FILEDSN then ignore any DSN */
531
532 con_str -> count = 0;
533 con_str -> list = NULL;
534
535 if ( str_len != SQL_NTS )
536 {
537 local_str = malloc( str_len + 1 );
538 memcpy( local_str, str, str_len );
539 local_str[ str_len ] = '\0';
540 }
541 else
542 {
543 local_str = str;
544 }
545
546 if ( !local_str || strlen( local_str ) == 0 ||
547 ( strlen( local_str ) == 1 && *local_str == ';' ))
548 {
549 /* connection-string ::= empty-string [;] */
550 if ( str_len != SQL_NTS )
551 free( local_str );
552 return 0;
553 }
554
555 ptr = local_str;
556
557 while(( cp = __get_pair( &ptr )) != NULL )
558 {
559 if ( strcasecmp( cp -> keyword, "DSN" ) == 0 )
560 {
561 if ( got_driver && exclude ) {
562 /* 11-29-2010 JM Modify to free the allocated memory before continuing. */
563 free( cp -> keyword );
564 free( cp -> attribute );
565 free( cp );
566 continue;
567 }
568
569 got_dsn = 1;
570 }
571 else if ( strcasecmp( cp -> keyword, "DRIVER" ) == 0 ||
572 strcasecmp( cp -> keyword, "FILEDSN" ) == 0 )
573 {
574 if ( got_dsn && exclude ) {
575 /* 11-29-2010 JM Modify to free the allocated memory before continuing. */
576 free( cp -> keyword );
577 free( cp -> attribute );
578 free( cp );
579 continue;
580 }
581
582 got_driver = 1;
583 }
584
585 __append_pair( con_str, cp -> keyword, cp -> attribute );
586 free( cp -> keyword );
587 free( cp -> attribute );
588 free( cp );
589 }
590
591 if ( str_len != SQL_NTS )
592 free( local_str );
593
594 return 0;
595}
596
597int __parse_connection_string( struct con_struct *con_str,
598 char *str, int str_len )
599{
600 return __parse_connection_string_ex( con_str, str, str_len, 1 );
601}
602
603char * __get_attribute_value( struct con_struct * con_str, char * keyword )
604{
605struct con_pair *cp;
606
607 if ( con_str -> count == 0 )
608 return NULL;
609
610 cp = con_str -> list;
611 while( cp )
612 {
613 if( strcasecmp( keyword, cp -> keyword ) == 0 )
614 {
615 if ( cp -> attribute )
616 return cp -> attribute;
617 else
618 return "";
619 }
620 cp = cp -> next;
621 }
622 return NULL;
623}
624
625void __release_conn( struct con_struct *con_str )
626{
627 struct con_pair *cp = con_str -> list;
628 struct con_pair *save;
629
630 while( cp )
631 {
632 free( cp -> attribute );
633 free( cp -> keyword );
634 save = cp;
635 cp = cp -> next;
636 free( save );
637 }
638
639 con_str -> count = 0;
640}
641
642void __handle_attr_extensions_cs( DMHDBC connection, struct con_struct *con_str )
643{
644 char *ptr;
645
646 if (( ptr = __get_attribute_value( con_str, "DMEnvAttr" )) != NULL ) {
647 __parse_attribute_string( &connection -> env_attribute, ptr, SQL_NTS );
648 }
649 if (( ptr = __get_attribute_value( con_str, "DMConnAttr" )) != NULL ) {
650 __parse_attribute_string( &connection -> dbc_attribute, ptr, SQL_NTS );
651 }
652 if (( ptr = __get_attribute_value( con_str, "DMStmtAttr" )) != NULL ) {
653 __parse_attribute_string( &connection -> stmt_attribute, ptr, SQL_NTS );
654 }
655}
656
657SQLRETURN SQLDriverConnectA(
658 SQLHDBC hdbc,
659 SQLHWND hwnd,
660 SQLCHAR *conn_str_in,
661 SQLSMALLINT len_conn_str_in,
662 SQLCHAR *conn_str_out,
663 SQLSMALLINT conn_str_out_max,
664 SQLSMALLINT *ptr_conn_str_out,
665 SQLUSMALLINT driver_completion )
666{
667 return SQLDriverConnect( hdbc,
668 hwnd,
669 conn_str_in,
670 len_conn_str_in,
671 conn_str_out,
672 conn_str_out_max,
673 ptr_conn_str_out,
674 driver_completion );
675}
676
677SQLRETURN SQLDriverConnect(
678 SQLHDBC hdbc,
679 SQLHWND hwnd,
680 SQLCHAR *conn_str_in,
681 SQLSMALLINT len_conn_str_in,
682 SQLCHAR *conn_str_out,
683 SQLSMALLINT conn_str_out_max,
684 SQLSMALLINT *ptr_conn_str_out,
685 SQLUSMALLINT driver_completion )
686{
687 DMHDBC connection = (DMHDBC)hdbc;
688 struct con_struct con_struct;
689 char *driver, *dsn = NULL, *filedsn, *tsavefile, savefile[ INI_MAX_PROPERTY_VALUE + 1 ];
690 char lib_name[ INI_MAX_PROPERTY_VALUE + 1 ];
691 char driver_name[ INI_MAX_PROPERTY_VALUE + 1 ];
692 SQLRETURN ret_from_connect;
693 SQLCHAR s1[ 2048 ];
694 SQLCHAR local_conn_str_in[ 2048 ];
695 SQLCHAR local_out_conection[ 2048 ];
696 char *save_filedsn;
697 int warnings = 0;
698
699 /*
700 * check connection
701 */
702
703 strcpy( driver_name, "" );
704
705 if ( !__validate_dbc( connection ))
706 {
707 dm_log_write( __FILE__,
708 __LINE__,
709 LOG_INFO,
710 LOG_INFO,
711 "Error: SQL_INVALID_HANDLE" );
712
713 return SQL_INVALID_HANDLE;
714 }
715
716 function_entry( connection );
717
718 /*
719 * replace this if not set for use by SAVEFILE
720 */
721
722 if ( !conn_str_out )
723 {
724 conn_str_out = local_out_conection;
725 conn_str_out_max = sizeof( local_out_conection );
726 }
727
728 if ( log_info.log_flag )
729 {
730 sprintf( connection -> msg, "\n\t\tEntry:\
731\n\t\t\tConnection = %p\
732\n\t\t\tWindow Hdl = %p\
733\n\t\t\tStr In = %s\
734\n\t\t\tStr Out = %p\
735\n\t\t\tStr Out Max = %d\
736\n\t\t\tStr Out Ptr = %p\
737\n\t\t\tCompletion = %d",
738 connection,
739 hwnd,
740 __string_with_length_hide_pwd( s1, conn_str_in,
741 len_conn_str_in ),
742 conn_str_out,
743 conn_str_out_max,
744 ptr_conn_str_out,
745 driver_completion );
746
747 dm_log_write( __FILE__,
748 __LINE__,
749 LOG_INFO,
750 LOG_INFO,
751 connection -> msg );
752 }
753
754 thread_protect( SQL_HANDLE_DBC, connection );
755
756 if ( len_conn_str_in < 0 && len_conn_str_in != SQL_NTS )
757 {
758 dm_log_write( __FILE__,
759 __LINE__,
760 LOG_INFO,
761 LOG_INFO,
762 "Error: HY090" );
763
764 __post_internal_error( &connection -> error,
765 ERROR_HY090, NULL,
766 connection -> environment -> requested_version );
767
768 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
769 }
770
771 if ( driver_completion == SQL_DRIVER_PROMPT &&
772 hwnd == NULL )
773 {
774 dm_log_write( __FILE__,
775 __LINE__,
776 LOG_INFO,
777 LOG_INFO,
778 "Error: HY092" );
779
780 __post_internal_error( &connection -> error,
781 ERROR_HY092, NULL,
782 connection -> environment -> requested_version );
783
784 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
785 }
786
787 if ( driver_completion != SQL_DRIVER_PROMPT &&
788 driver_completion != SQL_DRIVER_COMPLETE &&
789 driver_completion != SQL_DRIVER_COMPLETE_REQUIRED &&
790 driver_completion != SQL_DRIVER_NOPROMPT )
791 {
792 dm_log_write( __FILE__,
793 __LINE__,
794 LOG_INFO,
795 LOG_INFO,
796 "Error: HY110" );
797
798 __post_internal_error( &connection -> error,
799 ERROR_HY110, NULL,
800 connection -> environment -> requested_version );
801
802 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
803 }
804
805 /*
806 * check the state of the connection
807 */
808
809 if ( connection -> state != STATE_C2 )
810 {
811 dm_log_write( __FILE__,
812 __LINE__,
813 LOG_INFO,
814 LOG_INFO,
815 "Error: 08002" );
816
817 __post_internal_error( &connection -> error,
818 ERROR_08002, NULL,
819 connection -> environment -> requested_version );
820
821 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
822 }
823
824 /*
825 * parse the connection string, and call the GUI if needed
826 */
827
828 if ( driver_completion == SQL_DRIVER_NOPROMPT )
829 {
830 if ( !conn_str_in )
831 {
832 conn_str_in = (SQLCHAR*)"DSN=DEFAULT;";
833 len_conn_str_in = strlen((char*) conn_str_in );
834 }
835
836 __parse_connection_string( &con_struct,
837 (char*)conn_str_in, len_conn_str_in );
838 }
839 else {
840 if ( !conn_str_in )
841 {
842 conn_str_in = (SQLCHAR*)"";
843 len_conn_str_in = strlen((char*) conn_str_in );
844 }
845
846 __parse_connection_string( &con_struct,
847 (char*)conn_str_in, len_conn_str_in );
848
849 if ( !__get_attribute_value( &con_struct, "DSN" ) &&
850 !__get_attribute_value( &con_struct, "DRIVER" ) &&
851 !__get_attribute_value( &con_struct, "FILEDSN" ))
852 {
853 int ret;
854 SQLCHAR returned_dsn[ 1025 ], *prefix, *target;
855
856 /*
857 * try and call GUI to obtain a DSN
858 */
859
860 ret = _SQLDriverConnectPrompt( hwnd, returned_dsn, sizeof( returned_dsn ));
861 if ( !ret || returned_dsn[ 0 ] == '\0' )
862 {
863 __append_pair( &con_struct, "DSN", "DEFAULT" );
864 }
865 else
866 {
867 prefix = returned_dsn;
868 target = (SQLCHAR*)strchr( (char*)returned_dsn, '=' );
869 if ( target )
870 {
871 *target = '\0';
872 target ++;
873 __append_pair( &con_struct, (char*)prefix, (char*)target );
874 }
875 else {
876 __append_pair( &con_struct, "DSN", (char*)returned_dsn );
877 }
878 }
879
880 /*
881 * regenerate to pass to driver
882 */
883 __generate_connection_string( &con_struct, (char*)local_conn_str_in, sizeof( local_conn_str_in ));
884 conn_str_in = local_conn_str_in;
885 len_conn_str_in = strlen((char*) conn_str_in );
886 }
887 }
888
889 /*
890 * can we find a pooled connection to use here ?
891 */
892
893 connection -> pooled_connection = NULL;
894
895 if ( pooling_enabled && search_for_pool( connection,
896 NULL, 0,
897 NULL, 0,
898 NULL, 0,
899 conn_str_in, len_conn_str_in ))
900 {
901 /*
902 * copy the in string to the out string
903 */
904
905 ret_from_connect = SQL_SUCCESS;
906
907 if ( conn_str_out )
908 {
909 if ( len_conn_str_in < 0 )
910 {
911 len_conn_str_in = strlen((char*) conn_str_in );
912 }
913
914 if ( len_conn_str_in >= conn_str_out_max )
915 {
916 memcpy( conn_str_out, conn_str_in, conn_str_out_max - 1 );
917 conn_str_out[ conn_str_out_max - 1 ] = '\0';
918 if ( ptr_conn_str_out )
919 {
920 *ptr_conn_str_out = len_conn_str_in;
921 }
922
923 __post_internal_error( &connection -> error,
924 ERROR_01004, NULL,
925 connection -> environment -> requested_version );
926
927 ret_from_connect = SQL_SUCCESS_WITH_INFO;
928 }
929 else
930 {
931 memcpy( conn_str_out, conn_str_in, len_conn_str_in );
932 conn_str_out[ len_conn_str_in ] = '\0';
933 if ( ptr_conn_str_out )
934 {
935 *ptr_conn_str_out = len_conn_str_in;
936 }
937 }
938 }
939
940 if ( log_info.log_flag )
941 {
942 sprintf( connection -> msg,
943 "\n\t\tExit:[%s]",
944 __get_return_status( ret_from_connect, s1 ));
945
946 dm_log_write( __FILE__,
947 __LINE__,
948 LOG_INFO,
949 LOG_INFO,
950 connection -> msg );
951 }
952
953 connection -> state = STATE_C4;
954
955 __release_conn( &con_struct );
956
957 return function_return( SQL_HANDLE_DBC, connection, ret_from_connect );
958 }
959
960 /*
961 * else safe the info for later
962 */
963
964 if ( pooling_enabled )
965 {
966 connection -> dsn_length = 0;
967
968 strcpy( connection -> server, "" );
969 connection -> server_length = 0;
970 strcpy( connection -> user, "" );
971 connection -> user_length = 0;
972 strcpy( connection -> password, "" );
973 connection -> password_length = 0;
974
975 if ( len_conn_str_in == SQL_NTS )
976 {
977 strcpy( connection -> driver_connect_string, (char*)conn_str_in );
978 }
979 else
980 {
981 memcpy( connection -> driver_connect_string, conn_str_in, len_conn_str_in );
982 }
983 connection -> dsn_length = len_conn_str_in;
984 }
985
986
987 /*
988 * get for later
989 */
990
991 tsavefile = __get_attribute_value( &con_struct, "SAVEFILE" );
992 if ( tsavefile )
993 {
994 if ( strlen( tsavefile ) > INI_MAX_PROPERTY_VALUE ) {
995 memcpy( savefile, tsavefile, INI_MAX_PROPERTY_VALUE );
996 savefile[ INI_MAX_PROPERTY_VALUE ] = '\0';
997 }
998 else {
999 strcpy( savefile, tsavefile );
1000 }
1001 }
1002 else
1003 {
1004 savefile[ 0 ] = '\0';
1005 }
1006
1007 /*
1008 * open the file dsn, get each entry from it, if it's not in the connection
1009 * struct, add it
1010 */
1011
1012 filedsn = __get_attribute_value( &con_struct, "FILEDSN" );
1013 if ( filedsn )
1014 {
1015 char str[ 1024 * 16 ];
1016
1017 if ( SQLReadFileDSN( filedsn, "ODBC", NULL, str, sizeof( str ), NULL ))
1018 {
1019 struct con_struct con_struct1;
1020
1021 save_filedsn = strdup( filedsn );
1022
1023 if ( strlen( str ))
1024 {
1025 strcpy((char*)local_conn_str_in, (char*)conn_str_in );
1026 conn_str_in = local_conn_str_in;
1027
1028 __parse_connection_string( &con_struct1,
1029 str, strlen( str ));
1030
1031 /*
1032 * Get the attributes from the original string
1033 */
1034
1035 conn_str_in[ 0 ] = '\0';
1036
1037 if ( con_struct.count )
1038 {
1039 struct con_pair *cp;
1040
1041 cp = con_struct.list;
1042 while( cp )
1043 {
1044 char *str1;
1045
1046 /*
1047 * Don't pass FILEDSN down
1048 */
1049
1050 if ( strcasecmp( cp -> keyword, "FILEDSN" ) &&
1051 strcasecmp( cp -> keyword, "FILEDSN" ) )
1052 {
1053 str1 = malloc( strlen( cp -> keyword ) + strlen( cp -> attribute ) + 10 );
1054
1055 if ( !str1 ) {
1056 dm_log_write( __FILE__,
1057 __LINE__,
1058 LOG_INFO,
1059 LOG_INFO,
1060 "Error: HY001" );
1061
1062 __post_internal_error( &connection -> error,
1063 ERROR_HY001, NULL,
1064 connection -> environment -> requested_version );
1065
1066 if ( save_filedsn ) {
1067 free( save_filedsn );
1068 }
1069
1070 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1071 }
1072
1073 if ( strlen((char*) conn_str_in ) > 0 )
1074 {
1075 sprintf( str1, ";%s=%s", cp -> keyword, cp -> attribute );
1076 }
1077 else
1078 {
1079 sprintf( str1, "%s=%s", cp -> keyword, cp -> attribute );
1080 }
1081
1082 if ( strlen( (char*)conn_str_in ) + strlen( str1 ) < conn_str_out_max ) {
1083 strcat((char*) conn_str_in, str1 );
1084 }
1085 else {
1086 warnings = 1;
1087 __post_internal_error( &connection -> error,
1088 ERROR_01004, NULL,
1089 connection -> environment -> requested_version );
1090 }
1091
1092 free( str1 );
1093 }
1094
1095 cp = cp -> next;
1096 }
1097 }
1098
1099 if ( con_struct1.count )
1100 {
1101 struct con_pair *cp;
1102
1103 cp = con_struct1.list;
1104 while( cp )
1105 {
1106 if ( !__get_attribute_value( &con_struct, cp -> keyword ))
1107 {
1108 char *str1;
1109
1110 str1 = malloc( strlen( cp -> keyword ) + strlen( cp -> attribute ) + 10 );
1111 if ( !str1 ) {
1112 dm_log_write( __FILE__,
1113 __LINE__,
1114 LOG_INFO,
1115 LOG_INFO,
1116 "Error: HY001" );
1117
1118 __post_internal_error( &connection -> error,
1119 ERROR_HY001, NULL,
1120 connection -> environment -> requested_version );
1121
1122 if ( save_filedsn ) {
1123 free( save_filedsn );
1124 }
1125
1126 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1127 }
1128
1129 if ( strlen((char*) conn_str_in ) > 0 )
1130 {
1131 sprintf( str1, ";%s=%s", cp -> keyword, cp -> attribute );
1132 }
1133 else
1134 {
1135 sprintf( str1, "%s=%s", cp -> keyword, cp -> attribute );
1136 }
1137 if ( strlen( (char*)conn_str_in ) + strlen( str1 ) < conn_str_out_max ) {
1138 strcat((char*) conn_str_in, str1 );
1139 }
1140 else {
1141 warnings = 1;
1142 __post_internal_error( &connection -> error,
1143 ERROR_01004, NULL,
1144 connection -> environment -> requested_version );
1145 }
1146 free( str1 );
1147 }
1148 cp = cp -> next;
1149 }
1150 }
1151
1152 len_conn_str_in = strlen((char*) conn_str_in );
1153
1154 __release_conn( &con_struct1 );
1155 }
1156
1157 /*
1158 * reparse the string
1159 */
1160
1161 __release_conn( &con_struct );
1162
1163 __parse_connection_string( &con_struct,
1164 (char*)conn_str_in, len_conn_str_in );
1165 }
1166 else
1167 {
1168 save_filedsn = NULL;
1169 }
1170 }
1171 else
1172 {
1173 save_filedsn = NULL;
1174 }
1175
1176 /*
1177 * look for some keywords
1178 *
1179 * have we got a DRIVER= attribute
1180 */
1181 driver = __get_attribute_value( &con_struct, "DRIVER" );
1182 if ( driver )
1183 {
1184 /*
1185 * look up the driver in the ini file
1186 */
1187
1188 if ( strlen( driver ) >= sizeof( driver_name )) {
1189 dm_log_write( __FILE__,
1190 __LINE__,
1191 LOG_INFO,
1192 LOG_INFO,
1193 "Error: IM011" );
1194
1195 __post_internal_error( &connection -> error,
1196 ERROR_IM011, NULL,
1197 connection -> environment -> requested_version );
1198
1199 if ( save_filedsn ) {
1200 free( save_filedsn );
1201 }
1202
1203 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1204 }
1205
1206 strcpy( driver_name, driver );
1207
1208#ifdef PLATFORM64
1209 SQLGetPrivateProfileString( driver, "Driver64", "",
1210 lib_name, sizeof( lib_name ), "ODBCINST.INI" );
1211
1212 if ( lib_name[ 0 ] == '\0' )
1213 {
1214 SQLGetPrivateProfileString( driver, "Driver", "",
1215 lib_name, sizeof( lib_name ), "ODBCINST.INI" );
1216 }
1217#else
1218 SQLGetPrivateProfileString( driver, "Driver", "",
1219 lib_name, sizeof( lib_name ), "ODBCINST.INI" );
1220#endif
1221
1222 /*
1223 * Assume if it's not in a odbcinst.ini then it's a direct reference
1224 */
1225
1226 if ( lib_name[ 0 ] == '\0' ) {
1227 strcpy( lib_name, driver );
1228 }
1229
1230 strcpy( connection -> dsn, "" );
1231 __handle_attr_extensions( connection, NULL, driver_name );
1232 }
1233 else
1234 {
1235 dsn = __get_attribute_value( &con_struct, "DSN" );
1236 if ( !dsn )
1237 {
1238 dm_log_write( __FILE__,
1239 __LINE__,
1240 LOG_INFO,
1241 LOG_INFO,
1242 "Error: IM002" );
1243
1244 __post_internal_error( &connection -> error,
1245 ERROR_IM002, NULL,
1246 connection -> environment -> requested_version );
1247
1248 __release_conn( &con_struct );
1249
1250 if ( save_filedsn ) {
1251 free( save_filedsn );
1252 }
1253
1254 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1255 }
1256
1257 if ( strlen( dsn ) > SQL_MAX_DSN_LENGTH )
1258 {
1259 dm_log_write( __FILE__,
1260 __LINE__,
1261 LOG_INFO,
1262 LOG_INFO,
1263 "Error: IM012" );
1264
1265 __post_internal_error( &connection -> error,
1266 ERROR_IM012, NULL,
1267 connection -> environment -> requested_version );
1268
1269 __release_conn( &con_struct );
1270
1271 if ( save_filedsn ) {
1272 free( save_filedsn );
1273 }
1274
1275 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1276 }
1277
1278 /*
1279 * look up the dsn in the ini file
1280 */
1281
1282 if ( !__find_lib_name( dsn, lib_name, driver_name ))
1283 {
1284 dm_log_write( __FILE__,
1285 __LINE__,
1286 LOG_INFO,
1287 LOG_INFO,
1288 "Error: IM002" );
1289
1290 __post_internal_error( &connection -> error,
1291 ERROR_IM002, NULL,
1292 connection -> environment -> requested_version );
1293
1294 __release_conn( &con_struct );
1295
1296 if ( save_filedsn ) {
1297 free( save_filedsn );
1298 }
1299
1300 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1301 }
1302
1303 strcpy( connection -> dsn, dsn );
1304 __handle_attr_extensions( connection, dsn, driver_name );
1305 }
1306
1307
1308 if ( dsn )
1309 {
1310 /*
1311 * do we have any Environment, Connection, or Statement attributes set in the ini ?
1312 */
1313
1314 __handle_attr_extensions( connection, dsn, driver_name );
1315 }
1316 else {
1317 /*
1318 * the attributes may be in the connection string
1319 */
1320 __handle_attr_extensions_cs( connection, &con_struct );
1321 }
1322
1323 __release_conn( &con_struct );
1324
1325 /*
1326 * we have now got the name of a lib to load
1327 */
1328 if ( !__connect_part_one( connection, lib_name, driver_name, &warnings ))
1329 {
1330 if ( save_filedsn ) {
1331 free( save_filedsn );
1332 }
1333
1334 __disconnect_part_four( connection ); /* release unicode handles */
1335
1336 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1337 }
1338
1339 if ( !CHECK_SQLDRIVERCONNECT( connection ) &&
1340 !CHECK_SQLDRIVERCONNECTW( connection ))
1341 {
1342 dm_log_write( __FILE__,
1343 __LINE__,
1344 LOG_INFO,
1345 LOG_INFO,
1346 "Error: IM001" );
1347
1348 __disconnect_part_one( connection );
1349 __disconnect_part_four( connection ); /* release unicode handles */
1350 __post_internal_error( &connection -> error,
1351 ERROR_IM001, NULL,
1352 connection -> environment -> requested_version );
1353
1354 if ( save_filedsn ) {
1355 free( save_filedsn );
1356 }
1357
1358 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1359 }
1360
1361 if ( CHECK_SQLDRIVERCONNECT( connection ))
1362 {
1363 /*
1364 if ( CHECK_SQLSETCONNECTATTR( connection ))
1365 {
1366 int lret;
1367
1368 lret = SQLSETCONNECTATTR( connection,
1369 connection -> driver_dbc,
1370 SQL_ATTR_ANSI_APP,
1371 SQL_AA_TRUE,
1372 0 );
1373 }
1374 */
1375
1376 ret_from_connect = SQLDRIVERCONNECT( connection,
1377 connection -> driver_dbc,
1378 hwnd,
1379 conn_str_in,
1380 len_conn_str_in,
1381 conn_str_out,
1382 conn_str_out_max,
1383 ptr_conn_str_out,
1384 driver_completion );
1385
1386 if ( ret_from_connect != SQL_SUCCESS )
1387 {
1388 SQLCHAR sqlstate[ 6 ];
1389 SQLINTEGER native_error;
1390 SQLSMALLINT ind;
1391 SQLCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
1392 SQLRETURN ret;
1393
1394 /*
1395 * get the errors from the driver before
1396 * loseing the connection
1397 */
1398
1399 if ( CHECK_SQLERROR( connection ))
1400 {
1401 do
1402 {
1403 ret = SQLERROR( connection,
1404 SQL_NULL_HENV,
1405 connection -> driver_dbc,
1406 SQL_NULL_HSTMT,
1407 sqlstate,
1408 &native_error,
1409 message_text,
1410 sizeof( message_text ),
1411 &ind );
1412
1413 if ( SQL_SUCCEEDED( ret ))
1414 {
1415 __post_internal_error_ex_noprefix( &connection -> error,
1416 sqlstate,
1417 native_error,
1418 message_text,
1419 SUBCLASS_ODBC, SUBCLASS_ODBC );
1420
1421 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1422 sqlstate, message_text );
1423
1424 dm_log_write_diag( connection -> msg );
1425 }
1426 }
1427 while( SQL_SUCCEEDED( ret ));
1428 }
1429 else if ( CHECK_SQLGETDIAGREC( connection ))
1430 {
1431 int rec = 1;
1432
1433 do
1434 {
1435 ret = SQLGETDIAGREC( connection,
1436 SQL_HANDLE_DBC,
1437 connection -> driver_dbc,
1438 rec ++,
1439 sqlstate,
1440 &native_error,
1441 message_text,
1442 sizeof( message_text ),
1443 &ind );
1444
1445
1446 if ( SQL_SUCCEEDED( ret ))
1447 {
1448 __post_internal_error_ex_noprefix( &connection -> error,
1449 sqlstate,
1450 native_error,
1451 message_text,
1452 SUBCLASS_ODBC, SUBCLASS_ODBC );
1453
1454 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1455 sqlstate, message_text );
1456
1457 dm_log_write_diag( connection -> msg );
1458 }
1459 }
1460 while( SQL_SUCCEEDED( ret ));
1461 }
1462 }
1463
1464
1465 /*
1466 * if it was a error then return now
1467 */
1468
1469 if ( !SQL_SUCCEEDED( ret_from_connect ))
1470 {
1471 __disconnect_part_one( connection );
1472 __disconnect_part_four( connection );
1473
1474 sprintf( connection -> msg,
1475 "\n\t\tExit:[%s]",
1476 __get_return_status( ret_from_connect, s1 ));
1477
1478 dm_log_write( __FILE__,
1479 __LINE__,
1480 LOG_INFO,
1481 LOG_INFO,
1482 connection -> msg );
1483
1484 if ( save_filedsn ) {
1485 free( save_filedsn );
1486 }
1487
1488 return function_return( SQL_HANDLE_DBC, connection, ret_from_connect );
1489 }
1490 connection -> unicode_driver = 0;
1491 }
1492 else
1493 {
1494 SQLWCHAR *uc_conn_str_in, *s1 = NULL;
1495 SQLCHAR s2[ 128 ];
1496 int wlen;
1497
1498 uc_conn_str_in = ansi_to_unicode_alloc( conn_str_in, len_conn_str_in, connection, &wlen );
1499 len_conn_str_in = wlen;
1500
1501 if ( CHECK_SQLSETCONNECTATTR( connection ))
1502 {
1503 int lret;
1504
1505 lret = SQLSETCONNECTATTR( connection,
1506 connection -> driver_dbc,
1507 SQL_ATTR_ANSI_APP,
1508 SQL_AA_FALSE,
1509 0 );
1510 }
1511
1512 if ( conn_str_out && conn_str_out_max > 0 )
1513 {
1514 s1 = malloc( sizeof( SQLWCHAR ) * ( conn_str_out_max + 1 ));
1515 }
1516
1517 ret_from_connect = SQLDRIVERCONNECTW( connection,
1518 connection -> driver_dbc,
1519 hwnd,
1520 uc_conn_str_in,
1521 len_conn_str_in,
1522 s1 ? s1 : (SQLWCHAR*)conn_str_out,
1523 conn_str_out_max,
1524 ptr_conn_str_out,
1525 driver_completion );
1526
1527 if ( uc_conn_str_in )
1528 free( uc_conn_str_in );
1529
1530 if ( ret_from_connect != SQL_SUCCESS )
1531 {
1532 SQLWCHAR sqlstate[ 6 ];
1533 SQLINTEGER native_error;
1534 SQLSMALLINT ind;
1535 SQLWCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
1536 SQLRETURN ret;
1537
1538 /*
1539 * get the errors from the driver before
1540 * loseing the connection
1541 */
1542
1543 if ( CHECK_SQLERRORW( connection ))
1544 {
1545 do
1546 {
1547 ret = SQLERRORW( connection,
1548 SQL_NULL_HENV,
1549 connection -> driver_dbc,
1550 SQL_NULL_HSTMT,
1551 sqlstate,
1552 &native_error,
1553 message_text,
1554 sizeof( message_text ),
1555 &ind );
1556
1557
1558 if ( SQL_SUCCEEDED( ret ))
1559 {
1560 SQLCHAR *as1, *as2;
1561
1562 __post_internal_error_ex_w_noprefix( &connection -> error,
1563 sqlstate,
1564 native_error,
1565 message_text,
1566 SUBCLASS_ODBC, SUBCLASS_ODBC );
1567
1568 as1 = (SQLCHAR*) unicode_to_ansi_alloc( sqlstate, SQL_NTS, connection, NULL );
1569 as2 = (SQLCHAR*) unicode_to_ansi_alloc( message_text, SQL_NTS, connection, NULL );
1570
1571 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1572 as1, as2 );
1573
1574 if ( as1 ) free( as1 );
1575 if ( as2 ) free( as2 );
1576
1577 dm_log_write_diag( connection -> msg );
1578 }
1579 }
1580 while( SQL_SUCCEEDED( ret ));
1581 }
1582 else if ( CHECK_SQLGETDIAGRECW( connection ))
1583 {
1584 int rec = 1;
1585
1586 do
1587 {
1588 ret = SQLGETDIAGRECW( connection,
1589 SQL_HANDLE_DBC,
1590 connection -> driver_dbc,
1591 rec ++,
1592 sqlstate,
1593 &native_error,
1594 message_text,
1595 sizeof( message_text ),
1596 &ind );
1597
1598
1599 if ( SQL_SUCCEEDED( ret ))
1600 {
1601 SQLCHAR *as1, *as2;
1602
1603 __post_internal_error_ex_w_noprefix( &connection -> error,
1604 sqlstate,
1605 native_error,
1606 message_text,
1607 SUBCLASS_ODBC, SUBCLASS_ODBC );
1608
1609 as1 = (SQLCHAR*) unicode_to_ansi_alloc( sqlstate, SQL_NTS, connection, NULL );
1610 as2 = (SQLCHAR*) unicode_to_ansi_alloc( message_text, SQL_NTS, connection, NULL );
1611
1612 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1613 as1, as2 );
1614
1615 if ( as1 ) free( as1 );
1616 if ( as2 ) free( as2 );
1617
1618 dm_log_write_diag( connection -> msg );
1619 }
1620 }
1621 while( SQL_SUCCEEDED( ret ));
1622 }
1623 }
1624
1625 /*
1626 * if it was a error then return now
1627 */
1628
1629 if ( !SQL_SUCCEEDED( ret_from_connect ))
1630 {
1631 __disconnect_part_one( connection );
1632 __disconnect_part_four( connection );
1633
1634 sprintf( connection -> msg,
1635 "\n\t\tExit:[%s]",
1636 __get_return_status( ret_from_connect, s2 ));
1637
1638 dm_log_write( __FILE__,
1639 __LINE__,
1640 LOG_INFO,
1641 LOG_INFO,
1642 connection -> msg );
1643
1644 if ( save_filedsn ) {
1645 free( save_filedsn );
1646 }
1647
1648 if ( s1 )
1649 {
1650 free( s1 );
1651 }
1652
1653 return function_return( SQL_HANDLE_DBC, connection, ret_from_connect );
1654 }
1655 else
1656 {
1657 if ( conn_str_out && s1 )
1658 {
1659 unicode_to_ansi_copy((char*) conn_str_out, conn_str_out_max, s1, SQL_NTS, connection, NULL );
1660 }
1661 }
1662
1663 if ( s1 )
1664 {
1665 free( s1 );
1666 }
1667
1668 connection -> unicode_driver = 1;
1669 }
1670
1671 /*
1672 * we should be connected now
1673 */
1674
1675 connection -> state = STATE_C4;
1676
1677 /*
1678 * did we get the type we wanted
1679 */
1680
1681 if ( connection -> driver_version !=
1682 connection -> environment -> requested_version )
1683 {
1684 connection -> driver_version =
1685 connection -> environment -> requested_version;
1686
1687 __post_internal_error( &connection -> error,
1688 ERROR_01000, "Driver does not support the requested version",
1689 connection -> environment -> requested_version );
1690 ret_from_connect = SQL_SUCCESS_WITH_INFO;
1691 }
1692
1693 if ( !__connect_part_two( connection ))
1694 {
1695 __disconnect_part_two( connection );
1696 __disconnect_part_one( connection );
1697 __disconnect_part_four( connection );
1698
1699 if ( save_filedsn ) {
1700 free( save_filedsn );
1701 }
1702
1703 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
1704 }
1705
1706 if ( log_info.log_flag )
1707 {
1708 if ( conn_str_out && strlen((char*) conn_str_out ) > 64 )
1709 {
1710 sprintf( connection -> msg,
1711 "\n\t\tExit:[%s]\
1712\n\t\t\tConnection Out [%.64s...]",
1713 __get_return_status( ret_from_connect, s1 ),
1714 conn_str_out );
1715 }
1716 else
1717 {
1718 sprintf( connection -> msg,
1719 "\n\t\tExit:[%s]\
1720\n\t\t\tConnection Out [%s]",
1721 __get_return_status( ret_from_connect, s1 ),
1722 __string_with_length_hide_pwd( s1,
1723 conn_str_out ? conn_str_out : (SQLCHAR*)"NULL", SQL_NTS ));
1724 }
1725
1726 dm_log_write( __FILE__,
1727 __LINE__,
1728 LOG_INFO,
1729 LOG_INFO,
1730 connection -> msg );
1731 }
1732
1733 /*
1734 * If we specified FILEDSN or SAVEFILE these need adding to the
1735 * output string
1736 */
1737
1738 if ( strlen( savefile ))
1739 {
1740 char *str = strdup((char*) conn_str_out );
1741 strcpy((char*) conn_str_out, "SAVEFILE=" );
1742 strcat((char*) conn_str_out, savefile );
1743 strcat((char*) conn_str_out, ";" );
1744 strcat((char*) conn_str_out, str );
1745 free( str );
1746
1747 if ( ptr_conn_str_out )
1748 {
1749 *ptr_conn_str_out = strlen((char*) conn_str_out );
1750 }
1751 }
1752
1753 if ( save_filedsn && strlen( save_filedsn ))
1754 {
1755 char *str = strdup((char*) conn_str_out );
1756 strcpy((char*) conn_str_out, "FILEDSN=" );
1757 strcat((char*) conn_str_out, save_filedsn );
1758 strcat((char*) conn_str_out, ";" );
1759 strcat((char*) conn_str_out, str );
1760 free( str );
1761
1762 if ( ptr_conn_str_out )
1763 {
1764 *ptr_conn_str_out = strlen((char*) conn_str_out );
1765 }
1766 }
1767
1768 if ( save_filedsn ) {
1769 free( save_filedsn );
1770 }
1771
1772 /*
1773 * write the connection string out to a file
1774 */
1775
1776 if ( tsavefile )
1777 {
1778 if ( SQL_SUCCEEDED( ret_from_connect ))
1779 {
1780 __parse_connection_string_ex( &con_struct,
1781 (char*)conn_str_out, conn_str_out_max, 0 );
1782
1783 /*
1784 * remove them
1785 */
1786
1787 SQLWriteFileDSN( savefile, "ODBC", NULL, NULL );
1788
1789 if ( con_struct.count )
1790 {
1791 int has_driver = 0;
1792 struct con_pair *cp;
1793
1794 cp = con_struct.list;
1795 while( cp )
1796 {
1797 if ( strcasecmp( cp -> keyword, "PWD" ) == 0 )
1798 {
1799 /*
1800 * don't save this
1801 */
1802 cp = cp -> next;
1803 continue;
1804 }
1805 else if ( strcasecmp( cp -> keyword, "SAVEFILE" ) == 0 )
1806 {
1807 /*
1808 * or this
1809 */
1810 cp = cp -> next;
1811 continue;
1812 }
1813 else if ( strcasecmp( cp -> keyword, "DSN" ) == 0 )
1814 {
1815 /*
1816 * don't save this either, there should be enough with the added DRIVER=
1817 * to make it work
1818 */
1819 cp = cp -> next;
1820 continue;
1821 }
1822 else if ( strcasecmp( cp -> keyword, "DRIVER" ) == 0 )
1823 {
1824 has_driver = 1;
1825 }
1826 SQLWriteFileDSN( savefile, "ODBC", cp -> keyword, cp -> attribute );
1827 cp = cp -> next;
1828 }
1829
1830 if ( !has_driver )
1831 {
1832 SQLWriteFileDSN( savefile, "ODBC", "Driver", driver_name );
1833 }
1834 }
1835
1836 __release_conn( &con_struct );
1837 }
1838 }
1839
1840 if ( warnings && ret_from_connect == SQL_SUCCESS )
1841 {
1842 ret_from_connect = SQL_SUCCESS_WITH_INFO;
1843 }
1844
1845 return function_return_nodrv( SQL_HANDLE_DBC, connection, ret_from_connect );
1846}
1847