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: SQLConnect.c,v 1.66 2009/05/15 15:23:56 lurcher Exp $
31  *
32  * $Log: SQLConnect.c,v $
33  * Revision 1.66  2009/05/15 15:23:56  lurcher
34  * Fix pooled connection thread problems
35  *
36  * Revision 1.65  2009/03/26 14:39:21  lurcher
37  * Fix typo in isql
38  *
39  * Revision 1.64  2009/02/18 17:59:08  lurcher
40  * Shift to using config.h, the compile lines were making it hard to spot warnings
41  *
42  * Revision 1.63  2009/02/17 09:47:44  lurcher
43  * Clear up a number of bugs
44  *
45  * Revision 1.62  2009/01/13 10:54:13  lurcher
46  * Allow setting of default Threading level
47  *
48  * Revision 1.61  2008/11/24 12:44:23  lurcher
49  * Try and tidu up the connection version checking
50  *
51  * Revision 1.60  2008/09/29 14:02:43  lurcher
52  * Fix missing dlfcn group option
53  *
54  * Revision 1.59  2008/08/29 08:01:38  lurcher
55  * Alter the way W functions are passed to the driver
56  *
57  * Revision 1.58  2008/06/17 16:14:13  lurcher
58  * Fix for iconv memory leak and some fixes for CYGWIN
59  *
60  * Revision 1.57  2008/05/30 12:04:55  lurcher
61  * Fix a couple of build problems and get ready for the next release
62  *
63  * Revision 1.56  2007/07/13 14:01:18  lurcher
64  * Fix problem when not using iconv
65  *
66  * Revision 1.55  2007/03/13 10:35:38  lurcher
67  * clear the iconv handles after use
68  *
69  * Revision 1.54  2007/03/07 22:53:29  lurcher
70  * Fix pooling iconv leak, and try and allow the W entry point in a setup lib to be used
71  *
72  * Revision 1.53  2007/01/02 10:27:50  lurcher
73  * Fix descriptor leak with unicode only driver
74  *
75  * Revision 1.52  2006/10/13 08:43:10  lurcher
76  *
77  *
78  * Remove debug printf
79  *
80  * Revision 1.51  2006/06/28 08:08:41  lurcher
81  * Add timestamp with timezone to Postgres7.1 driver
82  *
83  * Revision 1.50  2006/04/11 10:22:56  lurcher
84  * Fix a data type check
85  *
86  * Revision 1.49  2005/11/08 09:37:10  lurcher
87  * Allow the driver and application to have different length handles
88  *
89  * Revision 1.48  2005/10/06 08:50:58  lurcher
90  * Fix problem with SQLDrivers not returning first entry
91  *
92  * Revision 1.47  2005/07/08 12:11:23  lurcher
93  *
94  * Fix a cursor lib problem (it was broken if you did metadata calls)
95  * Alter the params to SQLParamOptions to use SQLULEN
96  *
97  * Revision 1.46  2005/05/24 16:51:57  lurcher
98  * Fix potential for the driver to no have its handle closed
99  *
100  * Revision 1.45  2005/03/01 14:24:40  lurcher
101  * Change DontDLClose default
102  *
103  * Revision 1.44  2005/02/01 10:24:23  lurcher
104  * Cope if SHLIBEXT is not set
105  *
106  * Revision 1.43  2004/12/20 18:06:13  lurcher
107  * Fix small typo in SQLConnect
108  *
109  * Revision 1.42  2004/09/22 09:13:38  lurcher
110  * Replaced crypt auth in postgres with md5 for 7.1 Postgres driver
111  *
112  * Revision 1.41  2004/09/08 16:38:53  lurcher
113  *
114  * Get ready for a 2.2.10 release
115  *
116  * Revision 1.40  2004/07/25 00:42:02  peteralexharvey
117  * for OS2 port
118  *
119  * Revision 1.39  2004/07/24 17:55:37  lurcher
120  * Sync up CVS
121  *
122  * Revision 1.38  2004/06/16 14:42:03  lurcher
123  *
124  *
125  * Fix potential corruption with threaded use and SQLEndTran
126  *
127  * Revision 1.37  2004/05/10 15:58:52  lurcher
128  *
129  * Stop the driver manager calling free handle twice
130  *
131  * Revision 1.36  2004/04/01 12:34:26  lurcher
132  *
133  * Fix minor memory leak
134  * Add support for 64bit HPUX
135  *
136  * Revision 1.35  2004/02/26 15:52:03  lurcher
137  *
138  * Fix potential to call SQLFreeEnv in driver twice
139  * Set default value if call to SQLGetPrivateProfileString fails because
140  * the odbcinst.ini file is not found, and can't be created
141  *
142  * Revision 1.34  2004/02/18 15:47:44  lurcher
143  *
144  * Fix a leak in the iconv code
145  *
146  * Revision 1.33  2004/02/17 11:05:35  lurcher
147  *
148  * 2.2.8 release
149  *
150  * Revision 1.32  2004/02/02 10:10:45  lurcher
151  *
152  * Fix some connection pooling problems
153  * Include sqlucode in sqlext
154  *
155  * Revision 1.31  2003/12/01 16:37:17  lurcher
156  *
157  * Fix a bug in SQLWritePrivateProfileString
158  *
159  * Revision 1.30  2003/10/30 18:20:45  lurcher
160  *
161  * Fix broken thread protection
162  * Remove SQLNumResultCols after execute, lease S4/S% to driver
163  * Fix string overrun in SQLDriverConnect
164  * Add initial support for Interix
165  *
166  * Revision 1.29  2003/10/06 15:43:46  lurcher
167  *
168  * Fix cursor lib to work with SQLFetch as well as the other fetch calls
169  * Update README.OSX to detail building the cursor lib
170  *
171  * Revision 1.28  2003/09/08 15:34:29  lurcher
172  *
173  * A couple of small but perfectly formed fixes
174  *
175  * Revision 1.27  2003/08/15 17:34:43  lurcher
176  *
177  * Remove some unneeded ODBC2->3 attribute conversions
178  *
179  * Revision 1.26  2003/08/08 11:14:21  lurcher
180  *
181  * Fix UNICODE problem in SQLDriverConnectW
182  *
183  * Revision 1.25  2003/02/27 12:19:39  lurcher
184  *
185  * Add the A functions as well as the W
186  *
187  * Revision 1.24  2003/02/26 13:05:42  lurcher
188  *
189  * Update for new autoconf
190  *
191  * Revision 1.23  2003/02/25 13:28:28  lurcher
192  *
193  * Allow errors on the drivers AllocHandle to be reported
194  * Fix a problem that caused errors to not be reported in the log
195  * Remove a redundant line from the spec file
196  *
197  * Revision 1.22  2003/02/06 18:13:01  lurcher
198  *
199  * Another HP_UX twiddle
200  *
201  * Revision 1.21  2003/02/06 12:58:25  lurcher
202  *
203  * Fix a speeling problem :-)
204  *
205  * Revision 1.20  2002/12/20 11:36:46  lurcher
206  *
207  * Update DMEnvAttr code to allow setting in the odbcinst.ini entry
208  *
209  * Revision 1.19  2002/12/05 17:44:30  lurcher
210  *
211  * Display unknown return values in return logging
212  *
213  * Revision 1.18  2002/11/19 18:52:27  lurcher
214  *
215  * Alter the cursor lib to not require linking to the driver manager.
216  *
217  * Revision 1.17  2002/11/13 15:59:20  lurcher
218  *
219  * More VMS changes
220  *
221  * Revision 1.16  2002/08/27 08:49:02  lurcher
222  *
223  * New version number and fix for cursor lib loading
224  *
225  * Revision 1.15  2002/08/23 09:42:37  lurcher
226  *
227  * Fix some build warnings with casts, and a AIX linker mod, to include
228  * deplib's on the link line, but not the libtool generated ones
229  *
230  * Revision 1.14  2002/08/12 13:17:52  lurcher
231  *
232  * Replicate the way the MS DM handles loading of driver libs, and allocating
233  * handles in the driver. usage counting in the driver means that dlopen is
234  * only called for the first use, and dlclose for the last. AllocHandle for
235  * the driver environment is only called for the first time per driver
236  * per application environment.
237  *
238  * Revision 1.13  2002/07/25 09:30:26  lurcher
239  *
240  * Additional unicode and iconv changes
241  *
242  * Revision 1.12  2002/07/24 08:49:51  lurcher
243  *
244  * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
245  *
246  * Revision 1.11  2002/07/12 09:01:37  lurcher
247  *
248  * Fix problem, with SAPDB where if the connection specifies ODBC 2, the
249  * don't make use of the ODBC 3 method of SQLGetFunctions
250  *
251  * Revision 1.10  2002/07/04 17:27:56  lurcher
252  *
253  * Small bug fixes
254  *
255  * Revision 1.8  2002/05/24 12:42:49  lurcher
256  *
257  * Alter NEWS and ChangeLog to match their correct usage
258  * Additional UNICODE tweeks
259  *
260  * Revision 1.7  2002/03/26 09:35:46  lurcher
261  *
262  * Extend naming of cursor lib to work on non linux platforms
263  * (it expected a .so)
264  *
265  * Revision 1.6  2002/02/21 18:44:09  lurcher
266  *
267  * Fix bug on 32 bit platforms without long long support
268  * Add option to set environment variables from the ini file
269  *
270  * Revision 1.5  2002/01/21 18:00:51  lurcher
271  *
272  * Assorted fixed and changes, mainly UNICODE/bug fixes
273  *
274  * Revision 1.4  2001/12/19 15:55:53  lurcher
275  *
276  * Add option to disable calling of SQLGetFunctions in driver
277  *
278  * Revision 1.3  2001/12/13 13:00:32  lurcher
279  *
280  * Remove most if not all warnings on 64 bit platforms
281  * Add support for new MS 3.52 64 bit changes
282  * Add override to disable the stopping of tracing
283  * Add MAX_ROWS support in postgres driver
284  *
285  * Revision 1.2  2001/11/21 16:58:25  lurcher
286  *
287  * Assorted fixes to make the MAX OSX build work nicer
288  *
289  * Revision 1.1.1.1  2001/10/17 16:40:05  lurcher
290  *
291  * First upload to SourceForge
292  *
293  * Revision 1.31  2001/09/27 17:05:48  nick
294  *
295  * Assorted fixes and tweeks
296  *
297  * Revision 1.30  2001/08/08 17:05:17  nick
298  *
299  * Add support for attribute setting in the ini files
300  *
301  * Revision 1.29  2001/08/03 15:19:00  nick
302  *
303  * Add changes to set values before connect
304  *
305  * Revision 1.28  2001/07/31 12:03:46  nick
306  *
307  * Fix how the DM gets the CLI year for SQLGetInfo
308  * Fix small bug in strncasecmp
309  *
310  * Revision 1.27  2001/07/03 09:30:41  nick
311  *
312  * Add ability to alter size of displayed message in the log
313  *
314  * Revision 1.26  2001/06/25 12:55:15  nick
315  *
316  * Fix threading problem with multiple ENV's
317  *
318  * Revision 1.25  2001/06/13 11:23:11  nick
319  *
320  * Fix a couple of portability problems
321  *
322  * Revision 1.24  2001/05/31 16:05:55  nick
323  *
324  * Fix problems with postgres closing local sockets
325  * Make odbctest build with QT 3 (it doesn't work due to what I think are bugs
326  * in QT 3)
327  * Fix a couple of problems in the cursor lib
328  *
329  * Revision 1.23  2001/05/23 11:44:44  nick
330  *
331  * Fix typo
332  *
333  * Revision 1.22  2001/05/09 11:56:47  nick
334  *
335  * Add support for libtool 1.4
336  *
337  * Revision 1.21  2001/04/18 15:03:37  nick
338  *
339  * Fix problem when going to DB2 unicode driver
340  *
341  * Revision 1.20  2001/04/16 22:35:10  nick
342  *
343  * More tweeks to the AutoTest code
344  *
345  * Revision 1.19  2001/04/16 15:41:24  nick
346  *
347  * Fix some problems calling non existing error funcs
348  *
349  * Revision 1.18  2001/04/12 17:43:36  nick
350  *
351  * Change logging and added autotest to odbctest
352  *
353  * Revision 1.17  2001/04/04 11:30:38  nick
354  *
355  * Fix a memory leak in Postgre7.1
356  * Fix a problem with timed out pooled connections
357  * Add time to live option for pooled connections
358  *
359  * Revision 1.16  2001/04/03 16:34:12  nick
360  *
361  * Add support for strangly broken unicode drivers
362  *
363  * Revision 1.15  2001/03/30 08:35:39  nick
364  *
365  * Fix a couple of pooling problems
366  *
367  * Revision 1.14  2001/03/02 14:24:23  nick
368  *
369  * Fix thread detection for Solaris
370  *
371  * Revision 1.13  2001/02/12 11:20:22  nick
372  *
373  * Add supoort for calling SQLDriverLoad and SQLDriverUnload
374  *
375  * Revision 1.12  2000/12/31 20:30:54  nick
376  *
377  * Add UNICODE support
378  *
379  * Revision 1.11  2000/12/18 13:02:13  nick
380  *
381  * More buf fixes
382  *
383  * Revision 1.10  2000/12/17 11:02:37  nick
384  *
385  * Fix extra '*'
386  *
387  * Revision 1.9  2000/12/17 11:00:32  nick
388  *
389  * Add thread safe bits to pooling
390  *
391  * Revision 1.8  2000/12/14 18:10:19  nick
392  *
393  * Add connection pooling
394  *
395  * Revision 1.7  2000/11/29 11:26:18  nick
396  *
397  * Add unicode bits
398  *
399  * Revision 1.6  2000/11/22 18:35:43  nick
400  *
401  * Check input handle before touching output handle
402  *
403  * Revision 1.5  2000/11/22 17:19:32  nick
404  *
405  * Fix tracing problem in SQLConnect
406  *
407  * Revision 1.4  2000/11/14 10:15:27  nick
408  *
409  * Add test for localtime_r
410  *
411  * Revision 1.3  2000/10/25 08:58:55  nick
412  *
413  * Fix crash when null server and SQL_NTS is passed in
414  *
415  * Revision 1.2  2000/10/13 15:18:49  nick
416  *
417  * Change string length parameter from SQLINTEGER to SQLSMALLINT
418  *
419  * Revision 1.1.1.1  2000/09/04 16:42:52  nick
420  * Imported Sources
421  *
422  * Revision 1.30  2000/07/28 14:57:29  ngorham
423  *
424  * Don't copy the function pointers for ColAttribute, ColAttributes just
425  * set can_supply
426  *
427  * Revision 1.29  2000/06/27 17:34:09  ngorham
428  *
429  * Fix a problem when the second part of the connect failed a seg fault
430  * was generated in the error reporting
431  *
432  * Revision 1.28  2001/05/26 19:11:37  ngorham
433  *
434  * Add SQLCopyDesc functionality and fix bug that was stopping messages
435  * coming out of SQLConnect
436  *
437  * Revision 1.27  2000/05/21 21:49:19  ngorham
438  *
439  * Assorted fixes
440  *
441  * Revision 1.26  2000/04/27 20:49:03  ngorham
442  *
443  * Fixes to work with Star Office 5.2
444  *
445  * Revision 1.25  2000/04/19 22:00:57  ngorham
446  *
447  * We can always supply SQLGetFunctions
448  *
449  * Revision 1.24  2000/03/11 15:55:47  ngorham
450  *
451  * A few more changes and bug fixes (see NEWS)
452  *
453  * Revision 1.23  2000/02/25 00:02:00  ngorham
454  *
455  * Add a patch to support IBM DB2, and Solaris threads
456  *
457  * Revision 1.22  2000/02/02 07:55:20  ngorham
458  *
459  * Add flag to disable SQLFetch -> SQLExtendedFetch mapping
460  *
461  * Revision 1.21  1999/12/28 15:05:00  ngorham
462  *
463  * Fix bug that caused StarOffice to fail. A SQLConnect, SQLDisconnect,
464  * followed by another SQLConnect on the same DBC would fail.
465  *
466  * Revision 1.20  1999/12/17 09:40:30  ngorham
467  *
468  * Change a error return from HY004 to IM004
469  *
470  * Revision 1.19  1999/12/14 19:02:25  ngorham
471  *
472  * Mask out the password fields in the logging
473  *
474  * Revision 1.18  1999/11/13 23:40:58  ngorham
475  *
476  * Alter the way DM logging works
477  * Upgrade the Postgres driver to 6.4.6
478  *
479  * Revision 1.17  1999/11/10 03:51:33  ngorham
480  *
481  * Update the error reporting in the DM to enable ODBC 3 and 2 calls to
482  * work at the same time
483  *
484  * Revision 1.16  1999/10/24 23:54:17  ngorham
485  *
486  * First part of the changes to the error reporting
487  *
488  * Revision 1.15  1999/10/14 06:49:24  ngorham
489  *
490  * Remove @all_includes@ from Drivers/MiniSQL/Makefile.am
491  *
492  * Revision 1.14  1999/10/09 00:15:58  ngorham
493  *
494  * Add mapping from SQL_TYPE_X to SQL_X and SQL_C_TYPE_X to SQL_C_X
495  * when the driver is a ODBC 2 one
496  *
497  * Revision 1.13  1999/10/07 20:39:25  ngorham
498  *
499  * Added .cvsignore files and fixed a couple of bugs in the DM
500  *
501  * Revision 1.12  1999/10/06 07:10:46  ngorham
502  *
503  * As the book says check dlerror after a dl func
504  *
505  * Revision 1.11  1999/10/06 07:01:25  ngorham
506  *
507  * Added more support for non linux platforms
508  *
509  * Revision 1.10  1999/09/26 18:55:03  ngorham
510  *
511  * Fixed a problem where the cursor lib was being used by default
512  *
513  * Revision 1.9  1999/09/24 22:54:52  ngorham
514  *
515  * Fixed some unchanged dlopen,dlsym,dlclose functions
516  *
517  * Revision 1.8  1999/09/21 22:34:24  ngorham
518  *
519  * Improve performance by removing unneeded logging calls when logging is
520  * disabled
521  *
522  * Revision 1.7  1999/09/20 21:46:49  ngorham
523  *
524  * Added support for libtld dlopen replace
525  *
526  * Revision 1.6  1999/09/19 22:24:33  ngorham
527  *
528  * Added support for the cursor library
529  *
530  * Revision 1.5  1999/08/03 21:47:39  shandyb
531  * Moving to automake: changed files in DriverManager
532  *
533  * Revision 1.4  1999/07/10 21:10:15  ngorham
534  *
535  * Adjust error sqlstate from driver manager, depending on requested
536  * version (ODBC2/3)
537  *
538  * Revision 1.3  1999/07/04 21:05:07  ngorham
539  *
540  * Add LGPL Headers to code
541  *
542  * Revision 1.2  1999/06/30 23:56:54  ngorham
543  *
544  * Add initial thread safety code
545  *
546  * Revision 1.1.1.1  1999/05/29 13:41:05  sShandyb
547  * first go at it
548  *
549  * Revision 1.4  1999/06/07 01:29:30  pharvey
550  * *** empty log message ***
551  *
552  * Revision 1.3  1999/06/02 20:12:10  ngorham
553  *
554  * Fixed botched log entry, and removed the dos \r from the sql header files.
555  *
556  * Revision 1.2  1999/06/02 19:57:20  ngorham
557  *
558  * Added code to check if a attempt is being made to compile with a C++
559  * Compiler, and issue a message.
560  * Start work on the ODBC2-3 conversions.
561  *
562  * Revision 1.1.1.1  1999/05/27 18:23:17  pharvey
563  * Imported sources
564  *
565  * Revision 1.7  1999/05/09 23:27:11  nick
566  * All the API done now
567  *
568  * Revision 1.6  1999/05/04 22:41:12  nick
569  * and another night ends
570  *
571  * Revision 1.5  1999/05/03 19:50:43  nick
572  * Another check point
573  *
574  * Revision 1.4  1999/04/30 16:22:47  nick
575  * Another checkpoint
576  *
577  * Revision 1.3  1999/04/29 21:40:58  nick
578  * End of another night :-)
579  *
580  * Revision 1.2  1999/04/29 20:47:37  nick
581  * Another checkpoint
582  *
583  * Revision 1.1  1999/04/25 23:06:11  nick
584  * Initial revision
585  *
586  *
587  **********************************************************************/
588 
589 #include <config.h>
590 #ifdef HAVE_SYS_TIME_H
591 #include <sys/time.h>
592 #elif defined(HAVE_TIME_H)
593 #include <time.h>
594 #endif
595 #include "drivermanager.h"
596 
597 static char const rcsid[]= "$RCSfile: SQLConnect.c,v $ $Revision: 1.66 $";
598 
599 #ifdef __OS2__
600 #define CURSOR_LIB	"ODBCCR"
601 #else
602 #define CURSOR_LIB      "libodbccr"
603 #endif
604 
605 #ifndef CURSOR_LIB_VER
606 #ifdef  DEFINE_CURSOR_LIB_VER
607 #define CURSOR_LIB_VER  "2"
608 #endif
609 #endif
610 
611 /*
612  * structure to contain the loaded lib entry points
613  */
614 
615 static struct driver_func  template_func[] =
616 {
617     /* 00 */ { SQL_API_SQLALLOCCONNECT,      "SQLAllocConnect", (void*)SQLAllocConnect },
618     /* 01 */ { SQL_API_SQLALLOCENV,          "SQLAllocEnv", (void*)SQLAllocEnv  },
619     /* 02 */ { SQL_API_SQLALLOCHANDLE,       "SQLAllocHandle", (void*)SQLAllocHandle },
620     /* 03 */ { SQL_API_SQLALLOCSTMT,         "SQLAllocStmt", (void*)SQLAllocStmt },
621     /* 04 */ { SQL_API_SQLALLOCHANDLESTD,    "SQLAllocHandleStd", (void*)SQLAllocHandleStd },
622     /* 05 */ { SQL_API_SQLBINDCOL,           "SQLBindCol", (void*)SQLBindCol },
623     /* 06 */ { SQL_API_SQLBINDPARAM,         "SQLBindParam", (void*)SQLBindParam },
624     /* 07 */ { SQL_API_SQLBINDPARAMETER,     "SQLBindParameter", (void*)SQLBindParameter },
625     /* 08 */ { SQL_API_SQLBROWSECONNECT,     "SQLBrowseConnect",
626                 (void*)SQLBrowseConnect, (void*)SQLBrowseConnectW },
627     /* 09 */ { SQL_API_SQLBULKOPERATIONS,    "SQLBulkOperations", (void*)SQLBulkOperations },
628     /* 10 */ { SQL_API_SQLCANCEL,            "SQLCancel", (void*)SQLCancel },
629     /* 11 */ { SQL_API_SQLCLOSECURSOR,       "SQLCloseCursor", (void*)SQLCloseCursor },
630     /* 12 */ { SQL_API_SQLCOLATTRIBUTE,      "SQLColAttribute",
631                 (void*)SQLColAttribute, (void*)SQLColAttributeW },
632     /* 13 */ { SQL_API_SQLCOLATTRIBUTES,     "SQLColAttributes",
633                 (void*)SQLColAttributes, (void*)SQLColAttributesW },
634     /* 14 */ { SQL_API_SQLCOLUMNPRIVILEGES,  "SQLColumnPrivileges",
635                 (void*)SQLColumnPrivileges, (void*)SQLColumnPrivilegesW },
636     /* 15 */ { SQL_API_SQLCOLUMNS,           "SQLColumns",
637                 (void*)SQLColumns, (void*)SQLColumnsW },
638     /* 16 */ { SQL_API_SQLCONNECT,           "SQLConnect",
639                 (void*)SQLConnect, (void*)SQLConnectW },
640     /* 17 */ { SQL_API_SQLCOPYDESC,          "SQLCopyDesc", (void*)SQLCopyDesc },
641     /* 18 */ { SQL_API_SQLDATASOURCES,       "SQLDataSources",
642                 (void*)SQLDataSources, (void*)SQLDataSourcesW },
643     /* 19 */ { SQL_API_SQLDESCRIBECOL,       "SQLDescribeCol",
644                 (void*)SQLDescribeCol, (void*)SQLDescribeColW },
645     /* 20 */ { SQL_API_SQLDESCRIBEPARAM,     "SQLDescribeParam", (void*)SQLDescribeParam },
646     /* 21 */ { SQL_API_SQLDISCONNECT,        "SQLDisconnect", (void*)SQLDisconnect },
647     /* 22 */ { SQL_API_SQLDRIVERCONNECT,     "SQLDriverConnect",
648                 (void*)SQLDriverConnect, (void*)SQLDriverConnectW },
649     /* 23 */ { SQL_API_SQLDRIVERS,           "SQLDrivers",
650                 (void*)SQLDrivers, (void*)SQLDriversW },
651     /* 24 */ { SQL_API_SQLENDTRAN,           "SQLEndTran", (void*)SQLEndTran },
652     /* 25 */ { SQL_API_SQLERROR,             "SQLError",
653                 (void*)SQLError, (void*)SQLErrorW },
654     /* 26 */ { SQL_API_SQLEXECDIRECT,        "SQLExecDirect",
655                 (void*)SQLExecDirect, (void*)SQLExecDirectW },
656     /* 27 */ { SQL_API_SQLEXECUTE,           "SQLExecute", (void*)SQLExecute },
657     /* 28 */ { SQL_API_SQLEXTENDEDFETCH,     "SQLExtendedFetch", (void*)SQLExtendedFetch },
658     /* 29 */ { SQL_API_SQLFETCH,             "SQLFetch", (void*)SQLFetch },
659     /* 30 */ { SQL_API_SQLFETCHSCROLL,       "SQLFetchScroll", (void*)SQLFetchScroll },
660     /* 31 */ { SQL_API_SQLFOREIGNKEYS,       "SQLForeignKeys",
661                 (void*)SQLForeignKeys, (void*)SQLForeignKeysW },
662     /* 32 */ { SQL_API_SQLFREEENV,           "SQLFreeEnv", (void*)SQLFreeEnv },
663     /* 33 */ { SQL_API_SQLFREEHANDLE,        "SQLFreeHandle", (void*)SQLFreeHandle },
664     /* 34 */ { SQL_API_SQLFREESTMT,          "SQLFreeStmt", (void*)SQLFreeStmt },
665     /* 35 */ { SQL_API_SQLFREECONNECT,       "SQLFreeConnect", (void*)SQLFreeConnect },
666     /* 36 */ { SQL_API_SQLGETCONNECTATTR,    "SQLGetConnectAttr",
667                 (void*)SQLGetConnectAttr, (void*)SQLGetConnectAttrW },
668     /* 37 */ { SQL_API_SQLGETCONNECTOPTION,  "SQLGetConnectOption",
669                 (void*)SQLGetConnectOption, (void*)SQLGetConnectOptionW },
670     /* 38 */ { SQL_API_SQLGETCURSORNAME,     "SQLGetCursorName",
671                 (void*)SQLGetCursorName, (void*)SQLGetCursorNameW },
672     /* 39 */ { SQL_API_SQLGETDATA,           "SQLGetData", (void*)SQLGetData },
673     /* 40 */ { SQL_API_SQLGETDESCFIELD,      "SQLGetDescField",
674                 (void*)SQLGetDescField, (void*)SQLGetDescFieldW },
675     /* 41 */ { SQL_API_SQLGETDESCREC,        "SQLGetDescRec",
676                 (void*)SQLGetDescRec, (void*)SQLGetDescRecW },
677     /* 42 */ { SQL_API_SQLGETDIAGFIELD,      "SQLGetDiagField",
678                 (void*)SQLGetDiagField, (void*)SQLGetDiagFieldW },
679     /* 43 */ { SQL_API_SQLGETENVATTR,        "SQLGetEnvAttr", (void*)SQLGetEnvAttr },
680     /* 44 */ { SQL_API_SQLGETFUNCTIONS,      "SQLGetFunctions", (void*)SQLGetFunctions },
681     /* 45 */ { SQL_API_SQLGETINFO,           "SQLGetInfo",
682                 (void*)SQLGetInfo, (void*)SQLGetInfoW },
683     /* 46 */ { SQL_API_SQLGETSTMTATTR,       "SQLGetStmtAttr",
684                 (void*)SQLGetStmtAttr, (void*)SQLGetStmtAttrW },
685     /* 47 */ { SQL_API_SQLGETSTMTOPTION,     "SQLGetStmtOption", (void*)SQLGetStmtOption },
686     /* 48 */ { SQL_API_SQLGETTYPEINFO,       "SQLGetTypeInfo",
687                 (void*)SQLGetTypeInfo, (void*)SQLGetTypeInfoW },
688     /* 49 */ { SQL_API_SQLMORERESULTS,       "SQLMoreResults", (void*)SQLMoreResults },
689     /* 50 */ { SQL_API_SQLNATIVESQL,         "SQLNativeSql",
690                 (void*)SQLNativeSql, (void*)SQLNativeSqlW },
691     /* 51 */ { SQL_API_SQLNUMPARAMS,         "SQLNumParams", (void*)SQLNumParams },
692     /* 52 */ { SQL_API_SQLNUMRESULTCOLS,     "SQLNumResultCols", (void*)SQLNumResultCols },
693     /* 53 */ { SQL_API_SQLPARAMDATA,         "SQLParamData", (void*)SQLParamData },
694     /* 54 */ { SQL_API_SQLPARAMOPTIONS,      "SQLParamOptions", (void*)SQLParamOptions },
695     /* 55 */ { SQL_API_SQLPREPARE,           "SQLPrepare",
696                 (void*)SQLPrepare, (void*)SQLPrepareW },
697     /* 56 */ { SQL_API_SQLPRIMARYKEYS,       "SQLPrimaryKeys",
698                 (void*)SQLPrimaryKeys, (void*)SQLPrimaryKeysW },
699     /* 57 */ { SQL_API_SQLPROCEDURECOLUMNS,  "SQLProcedureColumns",
700                 (void*)SQLProcedureColumns, (void*)SQLProcedureColumnsW },
701     /* 58 */ { SQL_API_SQLPROCEDURES,        "SQLProcedures",
702                 (void*)SQLProcedures, (void*)SQLProceduresW },
703     /* 59 */ { SQL_API_SQLPUTDATA,           "SQLPutData", (void*)SQLPutData },
704     /* 60 */ { SQL_API_SQLROWCOUNT,          "SQLRowCount", (void*)SQLRowCount },
705     /* 61 */ { SQL_API_SQLSETCONNECTATTR,    "SQLSetConnectAttr",
706                 (void*)SQLSetConnectAttr, (void*)SQLSetConnectAttrW },
707     /* 62 */ { SQL_API_SQLSETCONNECTOPTION,  "SQLSetConnectOption",
708                 (void*)SQLSetConnectOption, (void*)SQLSetConnectOptionW },
709     /* 63 */ { SQL_API_SQLSETCURSORNAME,     "SQLSetCursorName",
710                 (void*)SQLSetCursorName, (void*)SQLSetCursorNameW },
711     /* 64 */ { SQL_API_SQLSETDESCFIELD,      "SQLSetDescField",
712                 (void*)SQLSetDescField, (void*)SQLSetDescFieldW },
713     /* 65 */ { SQL_API_SQLSETDESCREC,        "SQLSetDescRec", (void*)SQLSetDescRec },
714     /* 66 */ { SQL_API_SQLSETENVATTR,        "SQLSetEnvAttr", (void*)SQLSetEnvAttr },
715     /* 67 */ { SQL_API_SQLSETPARAM,          "SQLSetParam", (void*)SQLSetParam },
716     /* 68 */ { SQL_API_SQLSETPOS,            "SQLSetPos", (void*)SQLSetPos },
717     /* 69 */ { SQL_API_SQLSETSCROLLOPTIONS,  "SQLSetScrollOptions", (void*)SQLSetScrollOptions },
718     /* 70 */ { SQL_API_SQLSETSTMTATTR,       "SQLSetStmtAttr",
719                 (void*)SQLSetStmtAttr, (void*)SQLSetStmtAttrW },
720     /* 71 */ { SQL_API_SQLSETSTMTOPTION,     "SQLSetStmtOption", (void*)SQLSetStmtOption },
721     /* 72 */ { SQL_API_SQLSPECIALCOLUMNS,    "SQLSpecialColumns",
722                 (void*)SQLSpecialColumns, (void*)SQLSpecialColumnsW },
723     /* 73 */ { SQL_API_SQLSTATISTICS,        "SQLStatistics",
724                 (void*)SQLStatistics, (void*)SQLStatisticsW },
725     /* 74 */ { SQL_API_SQLTABLEPRIVILEGES,   "SQLTablePrivileges",
726                 (void*)SQLTablePrivileges, (void*)SQLTablePrivilegesW },
727     /* 75 */ { SQL_API_SQLTABLES,            "SQLTables",
728                 (void*)SQLTables, (void*)SQLTablesW },
729     /* 76 */ { SQL_API_SQLTRANSACT,          "SQLTransact", (void*)SQLTransact },
730     /* 77 */ { SQL_API_SQLGETDIAGREC,        "SQLGetDiagRec",
731                 (void*)SQLGetDiagRec, (void*)SQLGetDiagRecW },
732     /* 78 */ { SQL_API_SQLCANCELHANDLE,      "SQLCancelHandle", (void*)SQLCancelHandle },
733 };
734 
735 /*
736  * connection pooling stuff
737  */
738 
739 CPOOL *pool_head = NULL;
740 int pooling_enabled = 0;
741 
742 /*
743  * helper function and macro to make setting any values set before connection
744  * simplier
745  */
746 
747 #define DO_ATTR( connection, value, attr3, attr2 )    \
748         do_attr( connection, connection -> value, connection -> value##_set, attr3, \
749                 attr2 )
750 
do_attr(DMHDBC connection,int value,int value_set,int attr3,int attr2)751 static void do_attr( DMHDBC connection, int value,
752         int value_set, int attr3, int attr2  )
753 {
754     if ( value_set )
755     {
756         if (CHECK_SQLSETCONNECTATTR( connection ))
757         {
758             SQLSETCONNECTATTR(connection,
759                         connection -> driver_dbc,
760                         attr3,
761                         value,
762                         sizeof( value ));
763         }
764         else if (CHECK_SQLSETCONNECTOPTION(connection) && attr2 )
765         {
766             SQLSETCONNECTOPTION(connection,
767                         connection -> driver_dbc,
768                         attr2,
769                         value );
770         }
771         else if (CHECK_SQLSETCONNECTATTRW( connection ))     /* they are int values, so this should be safe */
772         {
773             SQLSETCONNECTATTRW(connection,
774                         connection -> driver_dbc,
775                         attr3,
776                         value,
777                         sizeof( value ));
778         }
779         else if (CHECK_SQLSETCONNECTOPTIONW(connection) && attr2 )
780         {
781             SQLSETCONNECTOPTIONW(connection,
782                         connection -> driver_dbc,
783                         attr2,
784                         value );
785         }
786     }
787 }
788 
789 /*
790  * implement reference counting for driver libs
791  */
792 
793 struct lib_count
794 {
795     char                *lib_name;
796     int                 count;
797     void                *handle;
798     struct lib_count    *next;
799 };
800 
801 /*
802  * I hate statics, but there is little option here, there can be multiple envs
803  * so I can't save it in them, I do use a single static instance, this avoid
804  * a potential leak if libodbc.so is dynamically loaded
805  */
806 
807 static struct lib_count *lib_list = NULL;
808 static struct lib_count single_lib_count;
809 static char single_lib_name[ INI_MAX_PROPERTY_VALUE + 1 ];
810 
odbc_dlopen(char * libname,char ** err)811 static void *odbc_dlopen( char *libname, char **err )
812 {
813     void *hand;
814     struct lib_count *list;
815 
816     mutex_lib_entry();
817 
818     /*
819      * have we already got it ?
820      */
821 
822     list = lib_list;
823     while( list )
824     {
825         if ( strcmp( list -> lib_name, libname ) == 0 )
826         {
827             break;
828         }
829 
830         list = list -> next;
831     }
832 
833     if ( list )
834     {
835         list -> count ++;
836         hand = list -> handle;
837     }
838     else
839     {
840         hand = lt_dlopen( libname );
841 
842         if ( hand )
843         {
844 	        /*
845 	        * If only one, then use the static space
846 	        */
847 
848 	        if ( lib_list == NULL )
849 	        {
850 		        list = &single_lib_count;
851 		        list -> next = lib_list;
852 		        lib_list = list;
853 		        list -> count = 1;
854 		        list -> lib_name = single_lib_name;
855 		        strcpy( single_lib_name, libname );
856 		        list -> handle = hand;
857 	        }
858 	        else
859 	        {
860 		        list = malloc( sizeof( struct lib_count ));
861 		        list -> next = lib_list;
862 		        lib_list = list;
863 		        list -> count = 1;
864 		        list -> lib_name = strdup( libname );
865 		        list -> handle = hand;
866 	        }
867         }
868         else {
869             if ( err ) {
870                 *err = (char*) lt_dlerror();
871             }
872         }
873     }
874 
875     mutex_lib_exit();
876 
877     return hand;
878 }
879 
odbc_dlclose(void * handle)880 static void odbc_dlclose( void *handle )
881 {
882     struct lib_count *list, *prev;
883 
884     mutex_lib_entry();
885 
886     /*
887      * look for list entry
888      */
889 
890     list = lib_list;
891     prev = NULL;
892     while( list )
893     {
894         if ( list -> handle == handle )
895         {
896             break;
897         }
898 
899         prev = list;
900         list = list -> next;
901     }
902 
903     /*
904      * it should always be found, but you never know...
905      */
906 
907     if ( list )
908     {
909         list -> count --;
910 
911         if ( list -> count < 1 )
912         {
913 		if ( list == &single_lib_count )
914 		{
915             if ( prev )
916             {
917                 prev -> next = list -> next;
918             }
919             else
920             {
921 			    lib_list = list -> next;
922             }
923 			lt_dlclose( list -> handle );
924 		}
925 		else
926 		{
927             free( list -> lib_name );
928             lt_dlclose( list -> handle );
929             if ( prev )
930             {
931                 prev -> next = list -> next;
932             }
933             else
934             {
935                 lib_list = list -> next;
936             }
937             free( list );
938 		}
939         }
940     }
941     else
942     {
943         lt_dlclose( handle );
944     }
945 
946     mutex_lib_exit();
947 }
948 
949 /*
950  * open the library, extract the names, and do setup
951  * before the actual connect.
952  */
953 
__connect_part_one(DMHDBC connection,char * driver_lib,char * driver_name,int * warnings)954 int __connect_part_one( DMHDBC connection, char *driver_lib, char *driver_name, int *warnings )
955 {
956     int i;
957     int ret;
958     int threading_level;
959     char threading_string[ 50 ];
960     char mapping_string[ 50 ];
961     char disable_gf[ 50 ];
962     char fake_string[ 50 ];
963     int fake_unicode;
964     char *err;
965     struct env_lib_struct *env_lib_list, *env_lib_prev;
966 
967     /*
968      * check to see if we want to alter the default threading level
969      * before opening the lib
970      */
971 
972     /*
973      * if the driver comes from odbc.ini not via odbcinst.ini the driver name will be empty
974      * so only look for the entry if it's set
975      */
976 
977     if ( driver_name[ 0 ] != '\0' )
978 	{
979     	SQLGetPrivateProfileString( driver_name, "Threading", "99",
980 					threading_string, sizeof( threading_string ),
981                 	"ODBCINST.INI" );
982     	threading_level = atoi( threading_string );
983     }
984     else
985 	{
986 	    threading_level = 99;
987     }
988 
989 	/*
990 	 * look for default in [ODBC] section
991 	 */
992 
993 	if ( threading_level == 99 )
994 	{
995     	SQLGetPrivateProfileString( "ODBC", "Threading", "0",
996 				threading_string, sizeof( threading_string ),
997                 		"ODBCINST.INI" );
998 
999     	threading_level = atoi( threading_string );
1000 	}
1001 
1002     if ( threading_level >= 0 && threading_level <= 3 )
1003     {
1004         dbc_change_thread_support( connection, threading_level );
1005     }
1006 
1007 	connection -> threading_level = threading_level;
1008 
1009     /*
1010      * do we want to disable the SQLFetch -> SQLExtendedFetch
1011      * mapping ?
1012      */
1013 
1014     SQLGetPrivateProfileString( driver_name, "ExFetchMapping", "1",
1015 				mapping_string, sizeof( mapping_string ),
1016                 "ODBCINST.INI" );
1017 
1018     connection -> ex_fetch_mapping = atoi( mapping_string );
1019 
1020     /*
1021      * Does the driver have support for SQLGetFunctions ?
1022      */
1023 
1024     SQLGetPrivateProfileString( driver_name, "DisableGetFunctions", "0",
1025 				disable_gf, sizeof( disable_gf ),
1026                 "ODBCINST.INI" );
1027 
1028     connection -> disable_gf = atoi( disable_gf );
1029 
1030     /*
1031      * do we want to keep hold of the lib handle, DB2 fails if we close
1032      */
1033 
1034     SQLGetPrivateProfileString( driver_name, "DontDLClose", "1",
1035 				mapping_string, sizeof( mapping_string ),
1036                 "ODBCINST.INI" );
1037 
1038     connection -> dont_dlclose = atoi( mapping_string ) != 0;
1039 
1040     /*
1041      * can we pool this one
1042      */
1043 
1044     SQLGetPrivateProfileString( driver_name, "CPTimeout", "0",
1045 				mapping_string, sizeof( mapping_string ),
1046                 "ODBCINST.INI" );
1047 
1048     connection -> pooling_timeout = atoi( mapping_string );
1049 
1050     /*
1051      * have we got a time-to-live value for the pooling
1052      */
1053 
1054     SQLGetPrivateProfileString( driver_name, "CPTimeToLive", "0",
1055 				mapping_string, sizeof( mapping_string ),
1056                 "ODBCINST.INI" );
1057 
1058     connection -> ttl = atoi( mapping_string );
1059 
1060     /*
1061      * Is there a check SQL statement
1062      */
1063 
1064     SQLGetPrivateProfileString( driver_name, "CPProbe", "",
1065 				connection -> probe_sql, sizeof( connection -> probe_sql ),
1066                 "ODBCINST.INI" );
1067 
1068     /*
1069      * if pooling then leave the dlopen
1070      */
1071 
1072     if ( connection -> pooling_timeout > 0 )
1073     {
1074         connection -> dont_dlclose = 1;
1075     }
1076 
1077     SQLGetPrivateProfileString( driver_name, "FakeUnicode", "0",
1078 				fake_string, sizeof( fake_string ),
1079                 "ODBCINST.INI" );
1080 
1081     fake_unicode = atoi( fake_string );
1082 
1083 #ifdef ENABLE_DRIVER_ICONV
1084 #ifdef HAVE_ICONV
1085     SQLGetPrivateProfileString( driver_name, "IconvEncoding", DEFAULT_ICONV_ENCODING,
1086 				connection->unicode_string, sizeof( connection->unicode_string ),
1087                 "ODBCINST.INI" );
1088 #endif
1089 
1090     /*
1091      * initialize unicode
1092      */
1093 
1094     if ( !unicode_setup( connection ))
1095     {
1096         char txt[ 256 ];
1097 
1098         sprintf( txt, "Can't initiate unicode conversion" );
1099 
1100         dm_log_write( __FILE__,
1101                 __LINE__,
1102                 LOG_INFO,
1103                 LOG_INFO,
1104                 txt );
1105 
1106         __post_internal_error( &connection -> error,
1107                 ERROR_IM003, txt,
1108                 connection -> environment -> requested_version );
1109 
1110         *warnings = TRUE;
1111     }
1112 #endif
1113 
1114     /*
1115      * initialize libtool
1116      */
1117 
1118     mutex_lib_entry();      /* warning, this doesn't protect from other libs in the application */
1119                             /* in their own threads calling dlinit(); */
1120     lt_dlinit();
1121     mutex_lib_exit();
1122 
1123     /*
1124      * open the lib
1125      */
1126 
1127     connection -> driver_env = (DRV_SQLHANDLE)NULL;
1128     connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
1129     connection -> functions = NULL;
1130     connection -> dl_handle = NULL;
1131 
1132     if ( !(connection -> dl_handle = odbc_dlopen( driver_lib, &err )))
1133     {
1134         char txt[ 2048 ];
1135 
1136         sprintf( txt, "Can't open lib '%s' : %s",
1137                 driver_lib, err ? err : "NULL ERROR RETURN" );
1138 
1139         dm_log_write( __FILE__,
1140                 __LINE__,
1141                 LOG_INFO,
1142                 LOG_INFO,
1143                 txt );
1144 
1145         __post_internal_error( &connection -> error,
1146                 ERROR_01000, txt,
1147                 connection -> environment -> requested_version );
1148 
1149         return 0;
1150     }
1151 
1152     /*
1153      * try and extract the ini and fini functions, and call ini if it's
1154      * found
1155      */
1156 
1157     connection -> ini_func.func =
1158             (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle,
1159                     ODBC_INI_FUNCTION );
1160 
1161     connection -> fini_func.func =
1162             (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle,
1163                     ODBC_FINI_FUNCTION );
1164 
1165     if ( connection -> ini_func.func )
1166     {
1167         connection -> ini_func.func();
1168     }
1169 
1170     /*
1171      * extract all the function entry points
1172      */
1173     if ( !(connection -> functions = malloc( sizeof( template_func ))))
1174     {
1175         dm_log_write( __FILE__,
1176                 __LINE__,
1177                 LOG_INFO,
1178                 LOG_INFO,
1179                 "Error: IM001" );
1180 
1181         __post_internal_error( &connection -> error,
1182                 ERROR_HY001, NULL,
1183                 connection -> environment -> requested_version );
1184         return 0;
1185     }
1186 
1187     memcpy( connection -> functions, template_func,
1188             sizeof( template_func ));
1189 
1190     for ( i = 0;
1191             i < sizeof( template_func ) / sizeof( template_func[ 0 ] );
1192             i ++ )
1193     {
1194         char name[ 128 ];
1195 
1196         connection -> functions[ i ].func =
1197             (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle,
1198                     connection -> functions[ i ].name );
1199 
1200         if ( connection -> functions[ i ].dm_funcW )
1201         {
1202             /*
1203              * get ANSI version from driver
1204              */
1205 
1206             if ( fake_unicode )
1207             {
1208                 sprintf( name, "%sW", connection -> functions[ i ].name );
1209             }
1210             else
1211             {
1212                 sprintf( name, "%sA", connection -> functions[ i ].name );
1213             }
1214             connection -> functions[ i ].funcA =
1215                 (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle, name );
1216 
1217             if ( connection -> functions[ i ].funcA &&
1218                     !connection -> functions[ i ].func )
1219             {
1220                 connection -> functions[ i ].func =
1221                     connection -> functions[ i ].funcA;
1222             }
1223             else if ( connection -> functions[ i ].func &&
1224                 !connection -> functions[ i ].funcA )
1225             {
1226                 connection -> functions[ i ].funcA =
1227                     connection -> functions[ i ].func;
1228             }
1229 
1230             /*
1231              * get UNICODE version from driver
1232              */
1233 
1234             sprintf( name, "%sW", connection -> functions[ i ].name );
1235             connection -> functions[ i ].funcW =
1236                 (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle, name );
1237         }
1238         else
1239         {
1240             connection -> functions[ i ].funcA =
1241                 connection -> functions[ i ].funcW = NULL;
1242         }
1243 
1244         /*
1245          * blank out ones that are in the DM to fix a big
1246          * with glib 2.0.6
1247          */
1248 
1249 		if ( connection -> functions[ i ].func &&
1250 			(void*)connection -> functions[ i ].func ==
1251             (void*)connection -> functions[ i ].dm_func )
1252 		{
1253 			connection -> functions[ i ].func = NULL;
1254 		}
1255 
1256 		if ( connection -> functions[ i ].funcW &&
1257 			(void*)connection -> functions[ i ].funcW ==
1258             (void*)connection -> functions[ i ].dm_funcW )
1259 		{
1260 			connection -> functions[ i ].funcW = NULL;
1261 		}
1262 
1263         connection -> functions[ i ].can_supply =
1264             ( connection -> functions[ i ].func != NULL ) ||
1265               ( connection -> functions[ i ].funcW != NULL );
1266     }
1267 
1268     /*
1269      * check if this is the first time this driver has been loaded under this
1270      * lib, if not then reuse the env, else get the env from the driver
1271      */
1272 
1273     mutex_lib_entry();
1274 
1275     env_lib_list = connection -> environment -> env_lib_list;
1276     env_lib_prev = NULL;
1277 
1278     while( env_lib_list )
1279     {
1280         if ( strcmp( driver_lib, env_lib_list -> lib_name ) == 0 )
1281         {
1282             break;
1283         }
1284         env_lib_prev = env_lib_list;
1285         env_lib_list = env_lib_list -> next;
1286     }
1287 
1288     connection -> driver_act_ver = 0;
1289     if ( env_lib_list )
1290     {
1291         /*
1292          * Fix by qcai@starquest.com
1293          */
1294         SQLUINTEGER actual_version = 0;
1295         int ret;
1296 
1297         env_lib_list -> count ++;
1298         connection -> driver_env = env_lib_list -> env_handle;
1299         connection -> env_list_ent = env_lib_list;
1300 
1301         /*
1302          * Fix by qcai@starquest.com, Feb 5, 2003
1303          *
1304          * Since the driver was already loaded before, the version number
1305          * has been properly figured out.  This connection just need to get
1306          * it from priviously set value.  Without it, the version number is
1307          * at initial value of 0 which causes this and subsequence connection
1308          * to return a warning message "Driver does not support the requested
1309          * version".
1310          */
1311 
1312         /*
1313          * Change from Rafie Einstein to check SQLGETENVATTR is valid
1314          */
1315         if ((CHECK_SQLGETENVATTR( connection )))
1316         {
1317             ret = SQLGETENVATTR( connection,
1318                  connection -> driver_env,
1319                  SQL_ATTR_ODBC_VERSION,
1320                  &actual_version,
1321                  0,
1322                  NULL );
1323         }
1324         else
1325         {
1326             ret = SQL_SUCCESS;
1327             actual_version = SQL_OV_ODBC2;
1328         }
1329 
1330         if ( !ret )
1331         {
1332             connection -> driver_version = actual_version;
1333         }
1334         else
1335         {
1336             connection -> driver_version =
1337             connection -> environment -> requested_version;
1338         }
1339         /* end of fix */
1340 
1341         /*
1342          * get value that has been pushed up by the initial connection to this driver
1343          */
1344 
1345         connection -> driver_act_ver = connection -> environment -> driver_act_ver;
1346     }
1347     else
1348     {
1349         env_lib_list = calloc( 1, sizeof( struct env_lib_struct ));
1350 
1351         env_lib_list -> count = 1;
1352         env_lib_list -> next = connection -> environment -> env_lib_list;
1353         env_lib_list -> lib_name = strdup( driver_lib );
1354         connection -> env_list_ent = env_lib_list;
1355 
1356         connection -> environment -> env_lib_list = env_lib_list;
1357 
1358         __set_local_attributes( connection, SQL_HANDLE_ENV );
1359 
1360         /*
1361          * allocate a env handle
1362          */
1363 
1364         if ( CHECK_SQLALLOCHANDLE( connection ))
1365         {
1366             ret = SQLALLOCHANDLE( connection,
1367                     SQL_HANDLE_ENV,
1368                     SQL_NULL_HENV,
1369                     &connection -> driver_env,
1370                     connection );
1371 			connection -> driver_act_ver = SQL_OV_ODBC3;
1372         }
1373         else if ( CHECK_SQLALLOCENV( connection ))
1374         {
1375             ret = SQLALLOCENV( connection,
1376                     &connection -> driver_env );
1377 			connection -> driver_act_ver = SQL_OV_ODBC2;
1378         }
1379         else
1380         {
1381             dm_log_write( __FILE__,
1382                     __LINE__,
1383                     LOG_INFO,
1384                     LOG_INFO,
1385                     "Error: IM004" );
1386 
1387             __post_internal_error( &connection -> error,
1388                     ERROR_IM004, NULL,
1389                     connection -> environment -> requested_version );
1390 
1391             if ( env_lib_list -> count == 1 )
1392             {
1393                 if ( env_lib_prev )
1394                 {
1395                     env_lib_prev -> next = env_lib_list -> next;
1396                 }
1397                 else
1398                 {
1399                     connection -> environment -> env_lib_list = env_lib_list -> next;
1400                 }
1401 
1402                 free( env_lib_list -> lib_name );
1403                 free( env_lib_list );
1404             }
1405             else
1406             {
1407                 env_lib_list -> count --;
1408             }
1409 
1410     		mutex_lib_exit();
1411             return 0;
1412         }
1413 
1414         /*
1415          * push up to environment to be reused
1416          */
1417 
1418         connection -> environment -> driver_act_ver = connection -> driver_act_ver;
1419 
1420         env_lib_list -> env_handle = connection -> driver_env;
1421 
1422         if ( ret )
1423         {
1424             dm_log_write( __FILE__,
1425                     __LINE__,
1426                     LOG_INFO,
1427                     LOG_INFO,
1428                     "Error: IM004" );
1429 
1430             __post_internal_error( &connection -> error,
1431                     ERROR_IM004, NULL,
1432                     connection -> environment -> requested_version );
1433 
1434             if ( env_lib_list -> count == 1 )
1435             {
1436                 if ( env_lib_prev )
1437                 {
1438                     env_lib_prev -> next = env_lib_list -> next;
1439                 }
1440                 else
1441                 {
1442                     connection -> environment -> env_lib_list = env_lib_list -> next;
1443                 }
1444 
1445                 free( env_lib_list -> lib_name );
1446                 free( env_lib_list );
1447             }
1448             else
1449             {
1450                 env_lib_list -> count --;
1451             }
1452 
1453     		mutex_lib_exit();
1454             return 0;
1455         }
1456 
1457         /*
1458          * if it looks like a 3.x driver, try setting the interface type
1459          * to 3.x
1460          */
1461 		if ( connection -> driver_act_ver >= SQL_OV_ODBC3 && CHECK_SQLSETENVATTR( connection ))
1462 		{
1463             ret = SQLSETENVATTR( connection,
1464                     connection -> driver_env,
1465                     SQL_ATTR_ODBC_VERSION,
1466                     connection -> environment -> requested_version,
1467                     0 );
1468 
1469             /*
1470              * if it don't set then assume a 2.x driver
1471              */
1472 
1473             if ( ret )
1474             {
1475                 connection -> driver_version = SQL_OV_ODBC2;
1476             }
1477             else
1478             {
1479                 if ( CHECK_SQLGETENVATTR( connection ))
1480                 {
1481                     SQLINTEGER actual_version;
1482 
1483                     ret = SQLGETENVATTR( connection,
1484                         connection -> driver_env,
1485                         SQL_ATTR_ODBC_VERSION,
1486                         &actual_version,
1487                         0,
1488                         NULL );
1489 
1490                     if ( !ret )
1491                     {
1492                         connection -> driver_version = actual_version;
1493                     }
1494                     else
1495                     {
1496                         connection -> driver_version =
1497                             connection -> environment -> requested_version;
1498                     }
1499                 }
1500                 else
1501                 {
1502                     connection -> driver_version =
1503                         connection -> environment -> requested_version;
1504                 }
1505             }
1506         }
1507         else
1508         {
1509             connection -> driver_version = SQL_OV_ODBC2;
1510         }
1511 
1512         /*
1513          * set any env attributes
1514          */
1515         __set_attributes( connection, SQL_HANDLE_ENV );
1516     }
1517 
1518     mutex_lib_exit();
1519 
1520     /*
1521      * allocate a connection handle
1522      */
1523 
1524     if ( connection -> driver_version >= SQL_OV_ODBC3 )
1525     {
1526         ret = SQL_SUCCESS;
1527 
1528         if ( CHECK_SQLALLOCHANDLE( connection ))
1529         {
1530             ret = SQLALLOCHANDLE( connection,
1531                     SQL_HANDLE_DBC,
1532                     connection -> driver_env,
1533                     &connection -> driver_dbc,
1534                     connection );
1535 
1536             if ( ret )
1537             {
1538                 dm_log_write( __FILE__,
1539                         __LINE__,
1540                         LOG_INFO,
1541                         LOG_INFO,
1542                         "Error: IM005" );
1543 
1544                 __post_internal_error( &connection -> error,
1545                         ERROR_IM005, NULL,
1546                         connection -> environment -> requested_version );
1547             }
1548         }
1549         else if ( CHECK_SQLALLOCCONNECT( connection ))
1550         {
1551             ret = SQLALLOCCONNECT( connection,
1552                     connection -> driver_env,
1553                     &connection -> driver_dbc );
1554 
1555             if ( ret )
1556             {
1557                 dm_log_write( __FILE__,
1558                         __LINE__,
1559                         LOG_INFO,
1560                         LOG_INFO,
1561                         "Error: IM005" );
1562 
1563                 __post_internal_error( &connection -> error,
1564                         ERROR_IM005, NULL,
1565                         connection -> environment -> requested_version );
1566             }
1567         }
1568         else
1569         {
1570             dm_log_write( __FILE__,
1571                     __LINE__,
1572                     LOG_INFO,
1573                     LOG_INFO,
1574                     "Error: IM005" );
1575 
1576             __post_internal_error( &connection -> error,
1577                     ERROR_IM005, NULL,
1578                     connection -> environment -> requested_version );
1579             return 0;
1580         }
1581 
1582         if ( ret )
1583         {
1584             SQLCHAR sqlstate[ 6 ];
1585             SQLINTEGER native_error;
1586             SQLSMALLINT ind;
1587             SQLCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
1588             SQLRETURN ret;
1589 
1590             /*
1591              * get the errors from the driver before
1592              * loseing the connection
1593              */
1594 
1595             if ( CHECK_SQLGETDIAGREC( connection ))
1596             {
1597                 int rec = 1;
1598 
1599                 do
1600                 {
1601                     ret = SQLGETDIAGREC( connection,
1602                             SQL_HANDLE_ENV,
1603                             connection -> driver_env,
1604                             rec ++,
1605                             sqlstate,
1606                             &native_error,
1607                             message_text,
1608                             sizeof( message_text ),
1609                             &ind );
1610 
1611 
1612                     if ( SQL_SUCCEEDED( ret ))
1613                     {
1614                         __post_internal_error_ex( &connection -> error,
1615                                 sqlstate,
1616                                 native_error,
1617                                 message_text,
1618                                 SUBCLASS_ODBC, SUBCLASS_ODBC );
1619 
1620                         sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1621                             sqlstate, message_text );
1622 
1623                         dm_log_write_diag( connection -> msg );
1624                     }
1625                 }
1626                 while( SQL_SUCCEEDED( ret ));
1627             }
1628             else if ( CHECK_SQLERROR( connection ))
1629             {
1630                 do
1631                 {
1632                     ret = SQLERROR( connection,
1633                             connection -> driver_env,
1634                             SQL_NULL_HDBC,
1635                             SQL_NULL_HSTMT,
1636                             sqlstate,
1637                             &native_error,
1638                             message_text,
1639                             sizeof( message_text ),
1640                             &ind );
1641 
1642 
1643                     if ( SQL_SUCCEEDED( ret ))
1644                     {
1645                         __post_internal_error_ex( &connection -> error,
1646                                 sqlstate,
1647                                 native_error,
1648                                 message_text,
1649                                 SUBCLASS_ODBC, SUBCLASS_ODBC );
1650 
1651                         sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1652                                 sqlstate, message_text );
1653 
1654                         dm_log_write_diag( connection -> msg );
1655                     }
1656                 }
1657                 while( SQL_SUCCEEDED( ret ));
1658             }
1659             return 0;
1660         }
1661     }
1662     else
1663     {
1664         ret = SQL_SUCCESS;
1665 
1666         if ( CHECK_SQLALLOCCONNECT( connection ))
1667         {
1668             ret = SQLALLOCCONNECT( connection,
1669                     connection -> driver_env,
1670                     &connection -> driver_dbc );
1671 
1672             if ( ret )
1673             {
1674                 dm_log_write( __FILE__,
1675                         __LINE__,
1676                         LOG_INFO,
1677                         LOG_INFO,
1678                         "Error: IM005" );
1679 
1680                 __post_internal_error( &connection -> error,
1681                         ERROR_IM005, NULL,
1682                         connection -> environment -> requested_version );
1683             }
1684         }
1685         else if ( CHECK_SQLALLOCHANDLE( connection ))
1686         {
1687             ret = SQLALLOCHANDLE( connection,
1688                     SQL_HANDLE_DBC,
1689                     connection -> driver_env,
1690                     &connection -> driver_dbc,
1691                     connection );
1692 
1693             if ( ret )
1694             {
1695                 dm_log_write( __FILE__,
1696                         __LINE__,
1697                         LOG_INFO,
1698                         LOG_INFO,
1699                         "Error: IM005" );
1700 
1701                 __post_internal_error( &connection -> error,
1702                         ERROR_IM005, NULL,
1703                         connection -> environment -> requested_version );
1704             }
1705         }
1706         else
1707         {
1708             dm_log_write( __FILE__,
1709                     __LINE__,
1710                     LOG_INFO,
1711                     LOG_INFO,
1712                     "Error: IM005" );
1713 
1714             __post_internal_error( &connection -> error,
1715                     ERROR_IM005, NULL,
1716                     connection -> environment -> requested_version );
1717             return 0;
1718         }
1719 
1720         if ( ret )
1721         {
1722             SQLCHAR sqlstate[ 6 ];
1723             SQLINTEGER native_error;
1724             SQLSMALLINT ind;
1725             SQLCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
1726             SQLRETURN ret;
1727 
1728             /*
1729              * get the errors from the driver before
1730              * loseing the connection
1731              */
1732 
1733             if ( CHECK_SQLERROR( connection ))
1734             {
1735                 do
1736                 {
1737                     ret = SQLERROR( connection,
1738                             connection -> driver_env,
1739                             SQL_NULL_HDBC,
1740                             SQL_NULL_HSTMT,
1741                             sqlstate,
1742                             &native_error,
1743                             message_text,
1744                             sizeof( message_text ),
1745                             &ind );
1746 
1747 
1748                     if ( SQL_SUCCEEDED( ret ))
1749                     {
1750                         __post_internal_error_ex( &connection -> error,
1751                                 sqlstate,
1752                                 native_error,
1753                                 message_text,
1754                                 SUBCLASS_ODBC, SUBCLASS_ODBC );
1755 
1756                         sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1757                                 sqlstate, message_text );
1758 
1759                         dm_log_write_diag( connection -> msg );
1760                     }
1761                 }
1762                 while( SQL_SUCCEEDED( ret ));
1763             }
1764             else if ( CHECK_SQLGETDIAGREC( connection ))
1765             {
1766                 int rec = 1;
1767 
1768                 do
1769                 {
1770                     ret = SQLGETDIAGREC( connection,
1771                             SQL_HANDLE_ENV,
1772                             connection -> driver_env,
1773                             rec ++,
1774                             sqlstate,
1775                             &native_error,
1776                             message_text,
1777                             sizeof( message_text ),
1778                             &ind );
1779 
1780 
1781                     if ( SQL_SUCCEEDED( ret ))
1782                     {
1783                         __post_internal_error_ex( &connection -> error,
1784                                 sqlstate,
1785                                 native_error,
1786                                 message_text,
1787                                 SUBCLASS_ODBC, SUBCLASS_ODBC );
1788 
1789                         sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1790                             sqlstate, message_text );
1791 
1792                         dm_log_write_diag( connection -> msg );
1793                     }
1794                 }
1795                 while( SQL_SUCCEEDED( ret ));
1796             }
1797             return 0;
1798         }
1799     }
1800 
1801     /*
1802      * set any connection atributes
1803      */
1804 
1805     DO_ATTR( connection, access_mode, SQL_ATTR_ACCESS_MODE, SQL_ACCESS_MODE );
1806     DO_ATTR( connection, login_timeout, SQL_ATTR_LOGIN_TIMEOUT, SQL_LOGIN_TIMEOUT );
1807     DO_ATTR( connection, auto_commit, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT );
1808     DO_ATTR( connection, async_enable, SQL_ATTR_ASYNC_ENABLE, SQL_ASYNC_ENABLE );
1809     DO_ATTR( connection, auto_ipd, SQL_ATTR_AUTO_IPD, 0 );
1810     DO_ATTR( connection, connection_timeout, SQL_ATTR_CONNECTION_TIMEOUT, 0 );
1811     DO_ATTR( connection, metadata_id, SQL_ATTR_METADATA_ID, 0 );
1812     DO_ATTR( connection, packet_size, SQL_ATTR_PACKET_SIZE, SQL_PACKET_SIZE );
1813     DO_ATTR( connection, quite_mode, SQL_ATTR_QUIET_MODE, SQL_QUIET_MODE );
1814     DO_ATTR( connection, txn_isolation, SQL_ATTR_TXN_ISOLATION, SQL_TXN_ISOLATION );
1815 
1816     while ( connection -> save_attr )
1817     {
1818         struct save_attr *sa;
1819 
1820         sa = connection -> save_attr;
1821 
1822         if ( sa -> str_attr )
1823         {
1824             if (CHECK_SQLSETCONNECTATTR( connection ))
1825             {
1826                 SQLSETCONNECTATTR(connection,
1827                             connection -> driver_dbc,
1828                             sa -> attr_type,
1829                             sa -> str_attr,
1830                             sa -> str_len );
1831             }
1832             else if (CHECK_SQLSETCONNECTOPTION(connection))
1833             {
1834                 SQLSETCONNECTOPTION(connection,
1835                             connection -> driver_dbc,
1836                             sa -> attr_type,
1837                             sa -> str_attr );
1838             }
1839             else if (CHECK_SQLSETCONNECTATTRW( connection ))
1840             {
1841                 SQLSETCONNECTATTRW(connection,
1842                             connection -> driver_dbc,
1843                             sa -> attr_type,
1844                             sa -> str_attr,
1845                             sa -> str_len );
1846             }
1847             else if (CHECK_SQLSETCONNECTOPTIONW(connection))
1848             {
1849                 SQLSETCONNECTOPTIONW(connection,
1850                             connection -> driver_dbc,
1851                             sa -> attr_type,
1852                             sa -> str_attr );
1853             }
1854 
1855             free( sa -> str_attr );
1856         }
1857         else
1858         {
1859             if (CHECK_SQLSETCONNECTATTR( connection ))
1860             {
1861                 SQLSETCONNECTATTR(connection,
1862                             connection -> driver_dbc,
1863                             sa -> attr_type,
1864                             sa -> intptr_attr,
1865                             sa -> str_len );
1866             }
1867             else if (CHECK_SQLSETCONNECTOPTION(connection))
1868             {
1869                 SQLSETCONNECTOPTION(connection,
1870                             connection -> driver_dbc,
1871                             sa -> attr_type,
1872                             sa -> intptr_attr );
1873             }
1874             else if (CHECK_SQLSETCONNECTATTRW( connection ))
1875             {
1876                 SQLSETCONNECTATTRW(connection,
1877                             connection -> driver_dbc,
1878                             sa -> attr_type,
1879                             sa -> intptr_attr,
1880                             sa -> str_len );
1881             }
1882             else if (CHECK_SQLSETCONNECTOPTIONW(connection))
1883             {
1884                 SQLSETCONNECTOPTIONW(connection,
1885                             connection -> driver_dbc,
1886                             sa -> attr_type,
1887                             sa -> intptr_attr );
1888             }
1889         }
1890 
1891         connection -> save_attr = sa -> next;
1892         free( sa );
1893     }
1894 
1895     /*
1896      * set any preset connection attributes
1897      */
1898 
1899     __set_attributes( connection, SQL_HANDLE_DBC );
1900 
1901     return 1;
1902 }
1903 
1904 /*
1905  * extract the available functions and call SQLSetConnectAttr
1906  */
1907 
__connect_part_two(DMHDBC connection)1908 int __connect_part_two( DMHDBC connection )
1909 {
1910     int i, use_cursor;
1911 
1912     /*
1913      * Call SQLFunctions to get the supported list and
1914      * mask out those that are exported but not supported
1915      */
1916 
1917     if ( CHECK_SQLGETFUNCTIONS( connection ) && !connection -> disable_gf )
1918     {
1919         SQLRETURN ret;
1920         SQLUSMALLINT supported_funcs[ SQL_API_ODBC3_ALL_FUNCTIONS_SIZE ];
1921 		SQLUSMALLINT supported_array[ 100 ];
1922 
1923         /*
1924          * try using fast version, but only if the driver is set to ODBC 3,
1925          * some drivers (SAPDB) fail to return the correct values in this situation
1926          */
1927 
1928         if ( connection -> driver_act_ver >= SQL_OV_ODBC3 )
1929         {
1930             ret = SQLGETFUNCTIONS( connection,
1931                 connection -> driver_dbc,
1932                 SQL_API_ODBC3_ALL_FUNCTIONS,
1933                 supported_funcs );
1934         }
1935         else
1936         {
1937 			ret = SQLGETFUNCTIONS( connection,
1938 				connection -> driver_dbc,
1939 				SQL_API_ALL_FUNCTIONS,
1940 				supported_array );
1941         }
1942 
1943         if ( ret == SQL_SUCCESS )
1944         {
1945             for ( i = 0;
1946                 i < sizeof( template_func ) / sizeof( template_func[ 0 ] );
1947                 i ++ )
1948             {
1949                 if ( connection -> functions[ i ].func )
1950                 {
1951                     SQLRETURN ret;
1952                     SQLUSMALLINT supported;
1953 
1954 					if ( connection -> driver_act_ver >= SQL_OV_ODBC3 )
1955 					{
1956                         supported = SQL_FUNC_EXISTS( supported_funcs, connection -> functions[ i ].ordinal );
1957 
1958                     	if ( supported == SQL_FALSE )
1959                     	{
1960                         	connection -> functions[ i ].func = NULL;
1961                         	connection -> functions[ i ].can_supply = 0;
1962                     	}
1963 					}
1964 					else
1965 					{
1966                         if ( connection -> functions[ i ].ordinal >= 100 )
1967 						{
1968 							ret = SQLGETFUNCTIONS( connection,
1969 								connection -> driver_dbc,
1970 								connection -> functions[ i ].ordinal,
1971 								&supported );
1972 						}
1973 						else
1974 						{
1975 							supported = supported_array[ connection -> functions[ i ].ordinal ];
1976 							ret = SQL_SUCCESS;
1977 						}
1978 
1979                     	if ( supported == SQL_FALSE || ret != SQL_SUCCESS )
1980                     	{
1981                         	connection -> functions[ i ].func = NULL;
1982                         	connection -> functions[ i ].can_supply = 0;
1983                     	}
1984 					}
1985                 }
1986             }
1987         }
1988         else
1989         {
1990             for ( i = 0;
1991                 i < sizeof( template_func ) / sizeof( template_func[ 0 ] );
1992                 i ++ )
1993             {
1994                 if ( connection -> functions[ i ].func )
1995                 {
1996                     SQLRETURN ret;
1997                     SQLUSMALLINT supported;
1998 
1999 					ret = SQLGETFUNCTIONS( connection,
2000 							connection -> driver_dbc,
2001 							connection -> functions[ i ].ordinal,
2002 							&supported );
2003 
2004                     if ( supported == SQL_FALSE || ret != SQL_SUCCESS )
2005                     {
2006                         connection -> functions[ i ].func = NULL;
2007                         connection -> functions[ i ].can_supply = 0;
2008                     }
2009                 }
2010             }
2011         }
2012     }
2013 
2014     /*
2015      * CoLAttributes is the same as ColAttribute
2016      */
2017 
2018     if ( connection -> functions[ DM_SQLCOLATTRIBUTE ].func &&
2019         !connection -> functions[ DM_SQLCOLATTRIBUTES ].func )
2020     {
2021         connection -> functions[ DM_SQLCOLATTRIBUTES ].can_supply = 1;
2022     }
2023     if ( connection -> functions[ DM_SQLCOLATTRIBUTES ].func &&
2024         !connection -> functions[ DM_SQLCOLATTRIBUTE ].func )
2025     {
2026         connection -> functions[ DM_SQLCOLATTRIBUTE ].can_supply = 1;
2027     }
2028 
2029     /*
2030      * mark the functions that the driver manager does
2031      */
2032 
2033     /*
2034      * SQLDatasources
2035      */
2036     connection -> functions[ DM_SQLDATASOURCES ].can_supply = 1;
2037 
2038     /*
2039      * SQLDrivers
2040      */
2041     connection -> functions[ DM_SQLDRIVERS ].can_supply = 1;
2042 
2043     /*
2044      * SQLAllocHandleStd
2045      */
2046     connection -> functions[ DM_SQLALLOCHANDLESTD ].can_supply = 1;
2047 
2048     /*
2049      * add all the functions that are supported via ODBC 2<->3
2050      * issues
2051      */
2052     if ( !connection -> functions[ DM_SQLALLOCENV ].func &&
2053             connection -> functions[ DM_SQLALLOCHANDLE ].func )
2054     {
2055         connection -> functions[ DM_SQLALLOCENV ].can_supply = 1;
2056     }
2057     if ( !connection -> functions[ DM_SQLALLOCCONNECT ].func &&
2058             connection -> functions[ DM_SQLALLOCHANDLE ].func )
2059     {
2060         connection -> functions[ DM_SQLALLOCCONNECT ].can_supply = 1;
2061     }
2062     if ( !connection -> functions[ DM_SQLALLOCSTMT ].func &&
2063             connection -> functions[ DM_SQLALLOCHANDLE ].func )
2064     {
2065         connection -> functions[ DM_SQLALLOCSTMT ].can_supply = 1;
2066     }
2067     if ( !connection -> functions[ DM_SQLFREEENV ].func &&
2068             connection -> functions[ DM_SQLFREEHANDLE ].func )
2069     {
2070         connection -> functions[ DM_SQLFREEENV ].can_supply = 1;
2071     }
2072     if ( !connection -> functions[ DM_SQLFREECONNECT ].func &&
2073             connection -> functions[ DM_SQLFREEHANDLE ].func )
2074     {
2075         connection -> functions[ DM_SQLFREECONNECT ].can_supply = 1;
2076     }
2077     if ( !connection -> functions[ DM_SQLGETDIAGREC ].func &&
2078             connection -> functions[ DM_SQLERROR ].func )
2079     {
2080         connection -> functions[ DM_SQLGETDIAGREC ].can_supply = 1;
2081     }
2082     if ( !connection -> functions[ DM_SQLGETDIAGFIELD ].func &&
2083             connection -> functions[ DM_SQLERROR ].func )
2084     {
2085         connection -> functions[ DM_SQLGETDIAGFIELD ].can_supply = 1;
2086     }
2087     if ( !connection -> functions[ DM_SQLERROR ].func &&
2088             connection -> functions[ DM_SQLGETDIAGREC ].func )
2089     {
2090         connection -> functions[ DM_SQLERROR ].can_supply = 1;
2091     }
2092 
2093     /*
2094      * ODBC 3 still needs SQLFreeStmt
2095      */
2096 
2097     /*
2098      * this is only partial, as we can't support a descriptor alloc
2099      */
2100     if ( !connection -> functions[ DM_SQLALLOCHANDLE ].func &&
2101             connection -> functions[ DM_SQLALLOCENV ].func &&
2102             connection -> functions[ DM_SQLALLOCCONNECT ].func &&
2103             connection -> functions[ DM_SQLALLOCHANDLE ].func )
2104     {
2105         connection -> functions[ DM_SQLALLOCHANDLE ].can_supply = 1;
2106     }
2107     if ( !connection -> functions[ DM_SQLFREEHANDLE ].func &&
2108             connection -> functions[ DM_SQLFREEENV ].func &&
2109             connection -> functions[ DM_SQLFREECONNECT ].func &&
2110             connection -> functions[ DM_SQLFREEHANDLE ].func )
2111     {
2112         connection -> functions[ DM_SQLFREEHANDLE ].can_supply = 1;
2113     }
2114 
2115     if ( !connection -> functions[ DM_SQLBINDPARAM ].func &&
2116                         connection -> functions[ DM_SQLBINDPARAMETER ].func )
2117     {
2118         connection -> functions[ DM_SQLBINDPARAM ].can_supply = 1;
2119     }
2120     else if ( !connection -> functions[ DM_SQLBINDPARAMETER ].func &&
2121                         connection -> functions[ DM_SQLBINDPARAM ].func )
2122     {
2123         connection -> functions[ DM_SQLBINDPARAMETER ].can_supply = 1;
2124     }
2125 
2126     if ( !connection -> functions[ DM_SQLGETCONNECTOPTION ].func &&
2127                         connection -> functions[ DM_SQLGETCONNECTATTR ].func )
2128     {
2129         connection -> functions[ DM_SQLGETCONNECTOPTION ].can_supply = 1;
2130     }
2131     else if ( !connection -> functions[ DM_SQLGETCONNECTATTR ].func &&
2132                         connection -> functions[ DM_SQLGETCONNECTOPTION ].func )
2133     {
2134         connection -> functions[ DM_SQLGETCONNECTATTR ].can_supply = 1;
2135     }
2136 
2137     if ( !connection -> functions[ DM_SQLGETSTMTOPTION ].func &&
2138                         connection -> functions[ DM_SQLGETSTMTATTR ].func )
2139     {
2140         connection -> functions[ DM_SQLGETSTMTOPTION ].can_supply = 1;
2141     }
2142     else if ( !connection -> functions[ DM_SQLGETSTMTATTR ].func &&
2143                         connection -> functions[ DM_SQLGETSTMTOPTION ].func )
2144     {
2145         connection -> functions[ DM_SQLGETSTMTATTR ].can_supply = 1;
2146     }
2147 
2148     if ( !connection -> functions[ DM_SQLPARAMOPTIONS ].func &&
2149                         connection -> functions[ DM_SQLSETSTMTATTR ].func )
2150     {
2151         connection -> functions[ DM_SQLPARAMOPTIONS ].can_supply = 1;
2152     }
2153 
2154     if ( !connection -> functions[ DM_SQLSETCONNECTOPTION ].func &&
2155                         connection -> functions[ DM_SQLSETCONNECTATTR ].func )
2156     {
2157         connection -> functions[ DM_SQLSETCONNECTOPTION ].can_supply = 1;
2158     }
2159     else if ( !connection -> functions[ DM_SQLSETCONNECTATTR ].func &&
2160                         connection -> functions[ DM_SQLSETCONNECTOPTION ].func )
2161     {
2162         connection -> functions[ DM_SQLSETCONNECTATTR ].can_supply = 1;
2163     }
2164 
2165     if ( !connection -> functions[ DM_SQLSETPARAM ].func &&
2166                         connection -> functions[ DM_SQLBINDPARAMETER ].func )
2167     {
2168         connection -> functions[ DM_SQLSETPARAM ].can_supply = 1;
2169     }
2170 
2171     if ( !connection -> functions[ DM_SQLSETSCROLLOPTIONS ].func &&
2172                         connection -> functions[ DM_SQLSETSTMTATTR ].func )
2173     {
2174         connection -> functions[ DM_SQLSETSCROLLOPTIONS ].can_supply = 1;
2175     }
2176 
2177     if ( !connection -> functions[ DM_SQLSETSTMTOPTION ].func &&
2178                         connection -> functions[ DM_SQLSETSTMTATTR ].func )
2179     {
2180         connection -> functions[ DM_SQLSETSTMTOPTION ].can_supply = 1;
2181     }
2182     else if ( !connection -> functions[ DM_SQLSETSTMTATTR ].func &&
2183                         connection -> functions[ DM_SQLSETSTMTOPTION ].func )
2184     {
2185         connection -> functions[ DM_SQLSETSTMTATTR ].can_supply = 1;
2186     }
2187 
2188     if ( !connection -> functions[ DM_SQLTRANSACT ].func &&
2189                         connection -> functions[ DM_SQLENDTRAN ].func )
2190     {
2191         connection -> functions[ DM_SQLTRANSACT ].can_supply = 1;
2192     }
2193     else if ( !connection -> functions[ DM_SQLENDTRAN ].func &&
2194                         connection -> functions[ DM_SQLTRANSACT ].func )
2195     {
2196         connection -> functions[ DM_SQLENDTRAN ].can_supply = 1;
2197     }
2198 
2199     /*
2200      * we can always do this
2201      */
2202 
2203     if ( !connection -> functions[ DM_SQLGETFUNCTIONS ].func )
2204     {
2205         connection -> functions[ DM_SQLGETFUNCTIONS ].can_supply = 1;
2206     }
2207 
2208     /*
2209      * TO_DO get some driver settings, such as the GETDATA_EXTENSTION
2210      * it supports
2211      */
2212 
2213     if ( CHECK_SQLGETINFO( connection ) || CHECK_SQLGETINFOW( connection ))
2214     {
2215         char txt[ 20 ];
2216         SQLRETURN ret;
2217 
2218         if ( connection -> driver_act_ver >= SQL_OV_ODBC3 )
2219         {
2220             ret = __SQLGetInfo( connection,
2221                     SQL_XOPEN_CLI_YEAR,
2222                     txt,
2223                     sizeof( connection -> cli_year ),
2224                     NULL );
2225 
2226             if ( SQL_SUCCEEDED( ret ))
2227             {
2228                 strcpy( connection -> cli_year, txt );
2229             }
2230         }
2231     }
2232 
2233     /*
2234      * TO_DO now we should pass any SQLSetEnvAttr settings
2235      */
2236 
2237     /*
2238      * now we have a connection handle, and we can check to see if
2239      * we need to use the cursor library
2240      */
2241 
2242     if ( connection -> cursors == SQL_CUR_USE_ODBC )
2243     {
2244         use_cursor = 1;
2245     }
2246     else if ( connection -> cursors == SQL_CUR_USE_IF_NEEDED )
2247     {
2248         /*
2249          * get scrollable info
2250          */
2251 
2252         if ( !CHECK_SQLGETINFO( connection ) && !CHECK_SQLGETINFOW( connection ))
2253         {
2254             /*
2255              * bit of a retarded driver, better give up
2256              */
2257             use_cursor = 0;
2258         }
2259         else
2260         {
2261             SQLRETURN ret;
2262             SQLUINTEGER val;
2263 
2264             /*
2265              * check if static cursors support scrolling
2266              */
2267 
2268             if ( connection -> driver_act_ver >=
2269                     SQL_OV_ODBC3 )
2270             {
2271                 ret = __SQLGetInfo( connection,
2272                         SQL_STATIC_CURSOR_ATTRIBUTES1,
2273                         &val,
2274                         sizeof( val ),
2275                         NULL );
2276 
2277                 if ( ret != SQL_SUCCESS )
2278                 {
2279                     use_cursor = 1;
2280                 }
2281                 else
2282                 {
2283                     /*
2284                      * do we need it ?
2285                      */
2286                     if ( !( val & SQL_CA1_ABSOLUTE ))
2287                     {
2288                         use_cursor = 1;
2289                     }
2290                     else
2291                     {
2292                         use_cursor = 0;
2293                     }
2294                 }
2295             }
2296             else
2297             {
2298                 ret = __SQLGetInfo( connection,
2299                         SQL_FETCH_DIRECTION,
2300                         &val,
2301                         sizeof( val ),
2302                         NULL );
2303 
2304                 if ( ret != SQL_SUCCESS )
2305                 {
2306                     use_cursor = 1;
2307                 }
2308                 else
2309                 {
2310                     /*
2311                      * are we needed
2312                      */
2313 
2314                     if ( !( val & SQL_FD_FETCH_PRIOR ))
2315                     {
2316                         use_cursor = 1;
2317                     }
2318                     else
2319                     {
2320                         use_cursor = 0;
2321                     }
2322                 }
2323             }
2324         }
2325     }
2326     else
2327     {
2328         use_cursor = 0;
2329     }
2330 
2331     /*
2332      * if required connect to the cursor lib
2333      */
2334 
2335     if ( use_cursor )
2336     {
2337 		char ext[ 32 ];
2338 		char name[ ODBC_FILENAME_MAX * 2 + 1 ];
2339         int (*cl_connect)(void*, struct driver_helper_funcs*);
2340         char *err;
2341         struct driver_helper_funcs dh;
2342 
2343 		/*
2344 		 * SHLIBEXT can end up unset on some distributions (suze)
2345 		 */
2346 
2347 		if ( strlen( SHLIBEXT ) == 0 )
2348 		{
2349 			strcpy( ext, ".so" );
2350 		}
2351 		else
2352 		{
2353             if ( strlen( SHLIBEXT ) + 1 > sizeof( ext )) {
2354                 fprintf( stderr, "internal error, unexpected SHLIBEXT value ('%s') may indicate a problem with configure\n", SHLIBEXT );
2355                 abort();
2356             }
2357 			strcpy( ext, SHLIBEXT );
2358 		}
2359 
2360 #ifdef CURSOR_LIB_VER
2361             sprintf( name, "%s%s.%s", CURSOR_LIB, ext, CURSOR_LIB_VER );
2362 #else
2363             sprintf( name, "%s%s", CURSOR_LIB, ext );
2364 #endif
2365 
2366         if ( !(connection -> cl_handle = odbc_dlopen( name, &err )))
2367         {
2368             char b1[ ODBC_FILENAME_MAX + 1 ];
2369             /*
2370              * try again
2371              */
2372 
2373 #ifdef CURSOR_LIB_VER
2374 #ifdef __VMS
2375                 sprintf( name, "%s:%s%s.%s", odbcinst_system_file_path( b1 ), CURSOR_LIB, ext, CURSOR_LIB_VER );
2376 #else
2377 #ifdef __OS2__
2378 	            /* OS/2 does not use the system_lib_path or version defines to construct a name */
2379                 sprintf( name, "%s.%s", CURSOR_LIB, ext );
2380 #else
2381                 sprintf( name, "%s/%s%s.%s", odbcinst_system_file_path( b1 ), CURSOR_LIB, ext, CURSOR_LIB_VER );
2382 #endif
2383 #endif
2384 #else
2385 #ifdef __VMS
2386                 sprintf( name, "%s:%s%s", odbcinst_system_file_path( b1 ), CURSOR_LIB, ext );
2387 #else
2388 #ifdef __OS2__
2389 	            /* OS/2 does not use the system_lib_path or version defines to construct a name */
2390                 sprintf( name, "%s%s", CURSOR_LIB, ext );
2391 #else
2392                 sprintf( name, "%s/%s%s", odbcinst_system_file_path( b1 ), CURSOR_LIB, ext );
2393 #endif
2394 #endif
2395 #endif
2396             if ( !(connection -> cl_handle = odbc_dlopen( name, &err )))
2397             {
2398                 char txt[ 256 ];
2399 
2400                 sprintf( txt, "Can't open cursor lib '%s' : %s",
2401                     name, err ? err : "NULL ERROR RETURN" );
2402 
2403                 dm_log_write( __FILE__,
2404                         __LINE__,
2405                         LOG_INFO,
2406                         LOG_INFO,
2407                         txt  );
2408 
2409                 __post_internal_error( &connection -> error,
2410                         ERROR_01000, txt,
2411                         connection -> environment -> requested_version );
2412 
2413                 return 0;
2414             }
2415         }
2416 
2417         if ( !( cl_connect = (int(*)(void*, struct driver_helper_funcs* ))lt_dlsym( connection -> cl_handle,
2418                         "CLConnect" )))
2419         {
2420             dm_log_write( __FILE__,
2421                     __LINE__,
2422                     LOG_INFO,
2423                     LOG_INFO,
2424                     "Error: 01000 Unable to load Cursor Lib" );
2425 
2426             __post_internal_error( &connection -> error,
2427                     ERROR_01000, "Unable to load cursor library",
2428                     connection -> environment -> requested_version );
2429 
2430             odbc_dlclose( connection -> cl_handle );
2431             connection -> cl_handle = NULL;
2432 
2433             return 0;
2434         }
2435 
2436         /*
2437          * setup helper functions
2438          */
2439 
2440         dh.__post_internal_error_ex = __post_internal_error_ex;
2441         dh.__post_internal_error = __post_internal_error;
2442         dh.dm_log_write = dm_log_write;
2443 
2444         if ( cl_connect( connection, &dh ) != SQL_SUCCESS )
2445         {
2446             odbc_dlclose( connection -> cl_handle );
2447             connection -> cl_handle = NULL;
2448             return 0;
2449         }
2450     }
2451     else
2452     {
2453         connection -> cl_handle = NULL;
2454     }
2455 
2456     return 1;
2457 }
2458 
release_env(DMHDBC connection)2459 static void release_env( DMHDBC connection )
2460 {
2461     struct env_lib_struct *env_lib_list, *env_lib_prev;
2462     int ret;
2463 
2464     if ( connection -> driver_env )
2465     {
2466         env_lib_prev = env_lib_list = NULL;
2467 
2468         mutex_lib_entry();
2469 
2470         if ( connection -> env_list_ent && connection -> environment )
2471         {
2472             env_lib_list = connection -> environment -> env_lib_list;
2473             while( env_lib_list )
2474             {
2475                 if ( env_lib_list == connection -> env_list_ent )
2476                 {
2477                     break;
2478                 }
2479                 env_lib_prev = env_lib_list;
2480                 env_lib_list = env_lib_list -> next;
2481             }
2482         }
2483 
2484         if ( env_lib_list && env_lib_list -> count > 1 )
2485         {
2486             env_lib_list -> count --;
2487         }
2488         else
2489         {
2490             if ( connection -> driver_version >= SQL_OV_ODBC3 )
2491             {
2492 				ret = SQL_ERROR;
2493                 if ( CHECK_SQLFREEHANDLE( connection ))
2494                 {
2495                     ret = SQLFREEHANDLE( connection,
2496                             SQL_HANDLE_ENV,
2497                             connection -> driver_env );
2498                 }
2499 				else if ( CHECK_SQLFREEENV( connection ))
2500                 {
2501                     ret = SQLFREEENV( connection,
2502                             connection -> driver_env );
2503 				}
2504 				if ( !ret )
2505 					connection -> driver_env = (DRV_SQLHANDLE)NULL;
2506             }
2507             else
2508             {
2509 				ret = SQL_ERROR;
2510                 if ( CHECK_SQLFREEENV( connection ))
2511                 {
2512                     ret = SQLFREEENV( connection,
2513                             connection -> driver_env );
2514                 }
2515                 else if ( CHECK_SQLFREEHANDLE( connection ))
2516                 {
2517                     ret = SQLFREEHANDLE( connection,
2518                             SQL_HANDLE_ENV,
2519                             connection -> driver_env );
2520                 }
2521 
2522                 if ( !ret )
2523                     connection -> driver_env = (DRV_SQLHANDLE)NULL;
2524             }
2525 
2526             /*
2527              * remove the entry
2528              */
2529 
2530             if ( env_lib_prev && env_lib_list )
2531             {
2532                 env_lib_prev -> next = env_lib_list -> next;
2533             }
2534             else
2535             {
2536 				if ( env_lib_list )
2537 				{
2538                 	connection -> environment -> env_lib_list = env_lib_list -> next;
2539 				}
2540             }
2541 
2542 	    	if ( env_lib_list )
2543 	    	{
2544             	free( env_lib_list -> lib_name );
2545             	free( env_lib_list );
2546 			}
2547         }
2548 
2549         mutex_lib_exit();
2550     }
2551 }
2552 
2553 /*
2554  * clean up after the first part of the connect
2555  */
2556 
__disconnect_part_one(DMHDBC connection)2557 void __disconnect_part_one( DMHDBC connection )
2558 {
2559     int ret = SQL_ERROR;
2560 
2561     /*
2562      * try a version 3 disconnect first on the connection
2563      */
2564     if ( connection -> driver_dbc )
2565     {
2566         if ( connection -> driver_version >= SQL_OV_ODBC3 )
2567         {
2568             if ( CHECK_SQLFREEHANDLE( connection ))
2569             {
2570                 ret = SQLFREEHANDLE( connection,
2571                         SQL_HANDLE_DBC,
2572                         connection -> driver_dbc );
2573 			}
2574 			else if ( CHECK_SQLFREECONNECT( connection ))
2575 			{
2576 				ret = SQLFREECONNECT( connection,
2577 						connection -> driver_dbc );
2578 			}
2579 
2580 			if ( !ret )
2581 			{
2582 				connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
2583             }
2584         }
2585 		else
2586 		{
2587 			if ( CHECK_SQLFREECONNECT( connection ))
2588 			{
2589 				ret = SQLFREECONNECT( connection,
2590 						connection -> driver_dbc );
2591 			}
2592 			else if ( CHECK_SQLFREEHANDLE( connection ))
2593             {
2594                 ret = SQLFREEHANDLE( connection,
2595                         SQL_HANDLE_DBC,
2596                         connection -> driver_dbc );
2597 			}
2598 
2599 			if ( !ret )
2600 			{
2601 				connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
2602             }
2603 		}
2604     	connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
2605     }
2606 
2607     /*
2608      * now disconnect the environment, if it's the last usage on the connection
2609      */
2610 
2611     if ( connection -> driver_env )
2612     {
2613         release_env( connection );
2614     }
2615 
2616     connection -> driver_env = (DRV_SQLHANDLE)NULL;
2617 
2618     /*
2619      * unload the lib
2620      */
2621     if ( connection -> cl_handle )
2622     {
2623         odbc_dlclose( connection -> cl_handle );
2624         connection -> cl_handle = NULL;
2625     }
2626 
2627     if ( connection -> dl_handle )
2628     {
2629         if ( !connection -> dont_dlclose )
2630         {
2631             /*
2632              * call fini function if found
2633              */
2634 
2635             if ( connection -> fini_func.func )
2636             {
2637                 connection -> fini_func.func();
2638             }
2639 
2640             odbc_dlclose( connection -> dl_handle );
2641         }
2642         connection -> dl_handle = NULL;
2643     }
2644 
2645     /*
2646      * free some memory
2647      */
2648 
2649     if ( connection -> functions )
2650     {
2651         free( connection -> functions );
2652         connection -> functions = NULL;
2653     }
2654 }
2655 
__disconnect_part_two(DMHDBC connection)2656 void __disconnect_part_two( DMHDBC connection )
2657 {
2658     if ( CHECK_SQLDISCONNECT( connection ))
2659     {
2660         SQLDISCONNECT( connection,
2661                 connection -> driver_dbc );
2662     }
2663 }
2664 
2665 /*
2666  * final clean up
2667  */
2668 
__disconnect_part_four(DMHDBC connection)2669 void __disconnect_part_four( DMHDBC connection )
2670 {
2671     /*
2672      * now disconnect the environment, if it's the last usage on the connection
2673      */
2674 
2675     release_env( connection );
2676 
2677     connection -> driver_env = (DRV_SQLHANDLE)NULL;
2678 
2679     /*
2680      * unload the lib
2681      */
2682 
2683     if ( connection -> cl_handle )
2684     {
2685         odbc_dlclose( connection -> cl_handle );
2686         connection -> cl_handle = NULL;
2687     }
2688 
2689     if ( connection -> dl_handle )
2690     {
2691         /*
2692          * this is safe, because the dlopen function will reuse the handle if we
2693          * open the same lib again
2694          */
2695         if ( !connection -> dont_dlclose )
2696         {
2697             if ( connection -> fini_func.func )
2698             {
2699                 connection -> fini_func.func();
2700             }
2701 
2702             odbc_dlclose( connection -> dl_handle );
2703         }
2704         connection -> dl_handle = NULL;
2705     }
2706 
2707     /*
2708      * free some memory
2709      */
2710 
2711     if ( connection -> functions )
2712     {
2713         free( connection -> functions );
2714         connection -> functions = NULL;
2715     }
2716     connection -> state = STATE_C2;
2717 
2718     /*
2719      * now clean up any statements that are left about
2720      */
2721 
2722     __clean_stmt_from_dbc( connection );
2723     __clean_desc_from_dbc( connection );
2724 }
2725 
2726 /*
2727  * normal disconnect
2728  */
2729 
__disconnect_part_three(DMHDBC connection)2730 void __disconnect_part_three( DMHDBC connection )
2731 {
2732     if ( connection -> driver_version >= SQL_OV_ODBC3 )
2733     {
2734         if ( CHECK_SQLFREEHANDLE( connection ))
2735         {
2736             SQLFREEHANDLE( connection,
2737                     SQL_HANDLE_DBC,
2738                     connection -> driver_dbc );
2739         }
2740         else if ( CHECK_SQLFREECONNECT( connection ))
2741         {
2742             SQLFREECONNECT( connection,
2743                     connection -> driver_dbc );
2744         }
2745     }
2746     else
2747     {
2748         if ( CHECK_SQLFREECONNECT( connection ))
2749         {
2750             SQLFREECONNECT( connection,
2751                     connection -> driver_dbc );
2752         }
2753         else if ( CHECK_SQLFREEHANDLE( connection ))
2754         {
2755             SQLFREEHANDLE( connection,
2756                     SQL_HANDLE_DBC,
2757                     connection -> driver_dbc );
2758         }
2759     }
2760 
2761     connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
2762 
2763     __disconnect_part_four( connection );
2764 }
2765 
2766 /*
2767  * interface for SQLGetFunctions
2768  */
2769 
__check_for_function(DMHDBC connection,SQLUSMALLINT function_id,SQLUSMALLINT * supported)2770 void  __check_for_function( DMHDBC connection,
2771         SQLUSMALLINT function_id,
2772         SQLUSMALLINT *supported )
2773 {
2774     int i;
2775 
2776     if ( !supported )
2777     {
2778         return;
2779     }
2780 
2781     if ( function_id == SQL_API_ODBC3_ALL_FUNCTIONS )
2782     {
2783         for ( i = 0; i < SQL_API_ODBC3_ALL_FUNCTIONS_SIZE; i ++ )
2784         {
2785             supported[ i ] = 0x0000;
2786         }
2787         for ( i = 0; i < sizeof( template_func ) / sizeof( template_func[ 0 ] ); i ++ )
2788         {
2789         int id = connection -> functions[ i ].ordinal;
2790 
2791             if ( connection -> functions[ i ].can_supply )
2792                 supported[ id >> 4 ] |= ( 1 << ( id & 0x000F ));
2793         }
2794     }
2795     else if ( function_id == SQL_API_ALL_FUNCTIONS )
2796     {
2797         for ( i = 0; i < 100; i ++ )
2798         {
2799             supported[ i ] = SQL_FALSE;
2800         }
2801         for ( i = 0; i < sizeof( template_func ) / sizeof( template_func[ 0 ] ); i ++ )
2802         {
2803             if ( connection -> functions[ i ].ordinal < 100 )
2804             {
2805                 if ( connection -> functions[ i ].can_supply )
2806                     supported[ connection -> functions[ i ].ordinal ] =
2807                         SQL_TRUE;
2808             }
2809         }
2810     }
2811     else
2812     {
2813         *supported = SQL_FALSE;
2814         for ( i = 0; i < sizeof( template_func ) / sizeof( template_func[ 0 ] ); i ++ )
2815         {
2816             if ( connection->functions[ i ].ordinal == function_id )
2817             {
2818                 if ( connection -> functions[ i ].can_supply )
2819                     *supported = SQL_TRUE;
2820                 break;
2821             }
2822         }
2823     }
2824 }
2825 
sql_strcmp(SQLCHAR * s1,SQLCHAR * s2,SQLSMALLINT l1,SQLSMALLINT l2)2826 static int sql_strcmp( SQLCHAR *s1, SQLCHAR *s2, SQLSMALLINT l1, SQLSMALLINT l2 )
2827 {
2828     if ( l1 != l2 )
2829     {
2830         return 1;
2831     }
2832 
2833     if ( l1 == SQL_NTS )
2834     {
2835         return strcmp((char*) s1, (char*)s2 );
2836     }
2837     else
2838     {
2839         return memcmp( s1, s2, l1 );
2840     }
2841 }
2842 
close_pooled_connection(CPOOL * ptr)2843 static void close_pooled_connection( CPOOL *ptr )
2844 {
2845     SQLRETURN ret;
2846 
2847     /*
2848      * disconnect from the driver
2849      */
2850 
2851     if ( !CHECK_SQLDISCONNECT(( &ptr->connection )))
2852     {
2853         return;
2854     }
2855 
2856     ret = SQLDISCONNECT(( &ptr -> connection ),
2857             ptr -> connection.driver_dbc );
2858 
2859     if ( SQL_SUCCEEDED( ret ))
2860     {
2861         /*
2862          * complete disconnection from driver
2863          */
2864 
2865         if ( ptr -> connection.driver_version >= SQL_OV_ODBC3 )
2866         {
2867             if ( CHECK_SQLFREEHANDLE(( &ptr -> connection )))
2868             {
2869                 SQLFREEHANDLE(( &ptr -> connection ),
2870                         SQL_HANDLE_DBC,
2871                         ptr -> connection.driver_dbc );
2872             }
2873             else if ( CHECK_SQLFREECONNECT(( &ptr -> connection )))
2874             {
2875                 SQLFREECONNECT(( &ptr -> connection ),
2876                         ptr -> connection.driver_dbc );
2877             }
2878         }
2879         else
2880         {
2881             if ( CHECK_SQLFREECONNECT(( &ptr -> connection )))
2882             {
2883                 SQLFREECONNECT(( &ptr -> connection ),
2884                         ptr -> connection.driver_dbc );
2885             }
2886             else if ( CHECK_SQLFREEHANDLE(( &ptr -> connection )))
2887             {
2888                 SQLFREEHANDLE(( &ptr -> connection ),
2889                         SQL_HANDLE_DBC,
2890                         ptr -> connection.driver_dbc );
2891             }
2892         }
2893 
2894         ptr -> connection.driver_dbc = (DRV_SQLHANDLE)NULL;
2895 
2896         /*
2897          * Only call freeenv if it's the last connection to the driver
2898          */
2899 
2900         release_env( &ptr -> connection );
2901 
2902         ptr -> connection.driver_env = (DRV_SQLHANDLE)NULL;
2903 
2904         /*
2905          * unload the lib
2906          */
2907 
2908         if ( ptr -> connection.cl_handle )
2909         {
2910             odbc_dlclose( ptr -> connection.cl_handle );
2911             ptr -> connection.cl_handle = NULL;
2912         }
2913 
2914         if ( ptr -> connection.dl_handle )
2915         {
2916             /*
2917              * this is safe, because the dlopen function will reuse the handle if we
2918              * open the same lib again
2919              */
2920             if ( !ptr -> connection.dont_dlclose )
2921             {
2922                 /*
2923                  * call fini function if found
2924                  */
2925 
2926                 if ( ptr -> connection.fini_func.func )
2927                 {
2928                     ptr -> connection.fini_func.func();
2929                 }
2930 
2931                 odbc_dlclose( ptr -> connection.dl_handle );
2932             }
2933             ptr -> connection.dl_handle = NULL;
2934         }
2935 
2936         /*
2937          * free some memory
2938          */
2939 
2940         if ( ptr -> connection.functions )
2941         {
2942             free( ptr -> connection.functions );
2943             ptr -> connection.functions = NULL;
2944         }
2945     }
2946     else
2947     {
2948         /*
2949          * All we can do is tidy up
2950          */
2951 
2952         ptr -> connection.driver_dbc = (DRV_SQLHANDLE)NULL;
2953         ptr -> connection.driver_env = (DRV_SQLHANDLE)NULL;
2954 
2955         /*
2956          * unload the lib
2957          */
2958 
2959         if ( ptr -> connection.cl_handle )
2960         {
2961             odbc_dlclose( ptr -> connection.cl_handle );
2962             ptr -> connection.cl_handle = NULL;
2963         }
2964 
2965         if ( ptr -> connection.dl_handle )
2966         {
2967             /*
2968              * this is safe, because the dlopen function will reuse the handle if we
2969              * open the same lib again
2970              */
2971             if ( !ptr -> connection.dont_dlclose )
2972             {
2973                 /*
2974                  * call fini function if found
2975                  */
2976 
2977                 if ( ptr -> connection.fini_func.func )
2978                 {
2979                     ptr -> connection.fini_func.func();
2980                 }
2981 
2982                 odbc_dlclose( ptr -> connection.dl_handle );
2983             }
2984             ptr -> connection.dl_handle = NULL;
2985         }
2986 
2987         /*
2988          * free some memory
2989          */
2990 
2991         if ( ptr -> connection.functions )
2992         {
2993             free( ptr -> connection.functions );
2994             ptr -> connection.functions = NULL;
2995         }
2996     }
2997 
2998     /*
2999      * now clean up any statements that are left about
3000      */
3001 
3002     __clean_stmt_from_dbc( &ptr -> connection );
3003     __clean_desc_from_dbc( &ptr -> connection );
3004 }
3005 
3006 /*
3007  * if a environment gets released from the application, we need to remove any referenvce to that environment
3008  * in pooled connections that belong to that environment
3009  */
3010 
__strip_from_pool(DMHENV env)3011 void __strip_from_pool( DMHENV env )
3012 {
3013     CPOOL *ptr;
3014 
3015     mutex_pool_entry();
3016 
3017     /*
3018      * look in the list of connections for one that matches
3019      */
3020 
3021     for( ptr = pool_head; ptr; ptr = ptr -> next )
3022     {
3023         if ( ptr -> connection.environment == env ) {
3024 
3025             ptr -> connection.environment = NULL;
3026         }
3027     }
3028 
3029     mutex_pool_exit();
3030 }
3031 
3032 
search_for_pool(DMHDBC connection,SQLCHAR * server_name,SQLSMALLINT name_length1,SQLCHAR * user_name,SQLSMALLINT name_length2,SQLCHAR * authentication,SQLSMALLINT name_length3,SQLCHAR * connect_string,SQLSMALLINT connect_string_length)3033 int search_for_pool( DMHDBC connection,
3034            SQLCHAR *server_name,
3035            SQLSMALLINT name_length1,
3036            SQLCHAR *user_name,
3037            SQLSMALLINT name_length2,
3038            SQLCHAR *authentication,
3039            SQLSMALLINT name_length3,
3040            SQLCHAR *connect_string,
3041            SQLSMALLINT connect_string_length )
3042 {
3043     time_t current_time;
3044     SQLUINTEGER dead;
3045     CPOOL *ptr, *prev;
3046     int has_checked = 0;
3047 
3048     mutex_pool_entry();
3049 
3050     current_time = time( NULL );
3051 
3052     /*
3053      * look in the list of connections for one that matches
3054      */
3055 
3056 restart:;
3057 
3058     for( ptr = pool_head, prev = NULL; ptr; prev = ptr, ptr = ptr -> next )
3059     {
3060         SQLRETURN ret;
3061 	    has_checked = 0;
3062 
3063         if ( ptr -> in_use )
3064         {
3065             continue;
3066         }
3067 
3068         /*
3069          * has it expired ? Do some cleaning up first
3070          */
3071 
3072         if ( ptr -> expiry_time < current_time )
3073         {
3074             /*
3075              * disconnect and remove
3076              */
3077 
3078             close_pooled_connection( ptr );
3079 
3080             if ( prev )
3081             {
3082                 prev -> next = ptr -> next;
3083                 free( ptr );
3084             }
3085             else
3086             {
3087                 pool_head = ptr -> next;
3088                 free( ptr );
3089             }
3090 
3091             goto restart;
3092         }
3093 
3094         /*
3095          * has the time-to-live got to one ?
3096          */
3097 
3098         if ( ptr -> ttl == 1 )
3099         {
3100             /*
3101              * disconnect and remove
3102              */
3103 
3104             close_pooled_connection( ptr );
3105 
3106             if ( prev )
3107             {
3108                 prev -> next = ptr -> next;
3109                 free( ptr );
3110             }
3111             else
3112             {
3113                 pool_head = ptr -> next;
3114                 free( ptr );
3115             }
3116 
3117             goto restart;
3118         }
3119         else if (  ptr -> ttl > 1 )
3120         {
3121             ptr -> ttl --;
3122         }
3123 
3124         if ( server_name )
3125         {
3126             if ( ptr -> server_length == 0 )
3127             {
3128                 continue;
3129             }
3130             if ( ptr -> server_length != name_length1 ||
3131                     sql_strcmp( server_name, (SQLCHAR*)ptr -> server,
3132                         name_length1, ptr -> server_length ))
3133             {
3134                 continue;
3135             }
3136             if ( ptr -> user_length != name_length2 ||
3137                     sql_strcmp( user_name, (SQLCHAR*)ptr -> user,
3138                         name_length2, ptr -> user_length ))
3139             {
3140                 continue;
3141             }
3142             if ( ptr -> password_length != name_length3 ||
3143                     sql_strcmp( authentication, (SQLCHAR*)ptr -> password,
3144                         name_length3, ptr -> password_length ))
3145             {
3146                 continue;
3147             }
3148         }
3149         else
3150         {
3151             if ( ptr -> dsn_length == 0 )
3152             {
3153                 continue;
3154             }
3155             if ( ptr -> dsn_length != connect_string_length ||
3156                     sql_strcmp( connect_string, (SQLCHAR*)ptr -> driver_connect_string,
3157                         connect_string_length, ptr -> dsn_length ))
3158             {
3159                 continue;
3160             }
3161         }
3162 
3163         /*
3164          * is it the same cursor usage ?
3165          */
3166 
3167         if ( ptr -> cursors != connection -> cursors )
3168         {
3169             continue;
3170         }
3171 
3172         /*
3173          * ok so far, is it still alive ?
3174          */
3175 
3176         if ((CHECK_SQLGETCONNECTATTR(( &ptr -> connection )) &&
3177                  SQL_SUCCEEDED( ret = SQLGETCONNECTATTR(( &ptr -> connection ),
3178                      ptr -> connection.driver_dbc,
3179                      SQL_ATTR_CONNECTION_DEAD,
3180                      &dead,
3181                      0,
3182                      0 ))) ||
3183             (CHECK_SQLGETCONNECTATTRW(( &ptr -> connection )) &&
3184                  SQL_SUCCEEDED( ret = SQLGETCONNECTATTRW(( &ptr -> connection ),
3185                      ptr -> connection.driver_dbc,
3186                      SQL_ATTR_CONNECTION_DEAD,
3187                      &dead,
3188                      0,
3189                      0 ))) ||
3190             (CHECK_SQLGETCONNECTOPTION(( &ptr -> connection )) &&
3191                  SQL_SUCCEEDED( ret = SQLGETCONNECTOPTION(( &ptr->connection ),
3192                      ptr -> connection.driver_dbc,
3193                      SQL_ATTR_CONNECTION_DEAD,
3194                      &dead ))) ||
3195             (CHECK_SQLGETCONNECTOPTIONW(( &ptr -> connection )) &&
3196                  SQL_SUCCEEDED( ret = SQLGETCONNECTOPTIONW(( &ptr->connection ),
3197                      ptr -> connection.driver_dbc,
3198                      SQL_ATTR_CONNECTION_DEAD,
3199                      &dead )))
3200            )
3201         {
3202             /*
3203              * if it failed assume that it's because it doesn't support
3204              * it, but it's ok
3205              */
3206             if ( dead == SQL_CD_TRUE )
3207             {
3208                 /*
3209                  * disconnect and remove
3210                  */
3211 
3212                 close_pooled_connection( ptr );
3213 
3214                 if ( prev )
3215                 {
3216                     prev -> next = ptr -> next;
3217                     free( ptr );
3218                     goto restart;
3219                 }
3220                 else
3221                 {
3222                     pool_head = ptr -> next;
3223                     free( ptr );
3224                     goto restart;
3225                 }
3226             }
3227             has_checked = 1;
3228         }
3229 
3230         /*
3231          * Need some other way of checking, This isn't safe to pool...
3232          * But it needs to be something thats not slower than connecting...
3233          * I have put this off, so its after the check that the server_name and all
3234          * the rest is ok to avoid waiting time, as the check could take time
3235          */
3236 
3237         if ( !has_checked )
3238         {
3239             if ( strlen( connection -> probe_sql ) > 0 )
3240             {
3241                 /*
3242                  * Execute the query, check we have all we need
3243                  */
3244 
3245                 if ( CHECK_SQLEXECDIRECT(( &ptr -> connection )) &&
3246                         (  CHECK_SQLALLOCHANDLE(( &ptr -> connection )) || CHECK_SQLALLOCSTMT(( &ptr -> connection ))) &&
3247                         CHECK_SQLNUMRESULTCOLS(( &ptr -> connection )) &&
3248                         CHECK_SQLFETCH(( &ptr -> connection )) &&
3249                         CHECK_SQLFREESTMT(( &ptr -> connection )))
3250                 {
3251                     DMHSTMT statement;
3252                     int ret;
3253                     int check_failed = 0;
3254 
3255                     statement = __alloc_stmt();
3256 
3257                     if ( CHECK_SQLALLOCHANDLE(( &ptr -> connection )))
3258                     {
3259                         ret = SQLALLOCHANDLE(( &ptr -> connection ),
3260                             SQL_HANDLE_STMT,
3261                             ptr -> connection.driver_dbc,
3262                             ( &statement -> driver_stmt ),
3263                             statement );
3264 
3265                     }
3266                     else
3267                     {
3268                         ret = SQLALLOCSTMT(( &ptr -> connection ),
3269                                 ptr -> connection.driver_dbc,
3270                                 ( &statement -> driver_stmt ),
3271                                 statement );
3272                     }
3273 
3274                     if ( !SQL_SUCCEEDED( ret ))
3275                     {
3276                         check_failed = 1;
3277                     }
3278                     else
3279                     {
3280                         ret = SQLEXECDIRECT(( &ptr -> connection ),
3281                                 statement -> driver_stmt,
3282                                 connection -> probe_sql,
3283                                 SQL_NTS );
3284 
3285                         if ( !SQL_SUCCEEDED( ret ))
3286                         {
3287                             check_failed = 1;
3288                         }
3289                         else
3290                         {
3291                             SQLSMALLINT column_count;
3292 
3293                             /*
3294                              * Check if there is a result set
3295                              */
3296 
3297                             ret = SQLNUMRESULTCOLS(( &ptr -> connection ),
3298                                 statement -> driver_stmt,
3299                                 &column_count );
3300 
3301                             if ( !SQL_SUCCEEDED( ret ))
3302                             {
3303                                 check_failed = 1;
3304                             }
3305                             else if ( column_count > 0 )
3306                             {
3307                                 do
3308                                 {
3309                                     ret = SQLFETCH(( &ptr -> connection ),
3310                                         statement -> driver_stmt );
3311                                 }
3312                                 while( SQL_SUCCEEDED( ret ));
3313 
3314                                 if ( ret != SQL_NO_DATA )
3315                                 {
3316                                     check_failed = 1;
3317                                 }
3318 
3319                                 ret = SQLFREESTMT(( &ptr -> connection ),
3320                                     statement -> driver_stmt,
3321                                     SQL_CLOSE );
3322 
3323                                 if ( !SQL_SUCCEEDED( ret ))
3324                                 {
3325                                     check_failed = 1;
3326                                 }
3327                             }
3328                         }
3329 
3330                         ret = SQLFREESTMT(( &ptr -> connection ),
3331                             statement -> driver_stmt,
3332                             SQL_DROP );
3333 
3334                         if ( !SQL_SUCCEEDED( ret ))
3335                         {
3336                             check_failed = 1;
3337                         }
3338                     }
3339 
3340                     __release_stmt( statement );
3341 
3342                     if ( check_failed )
3343                     {
3344                         /*
3345                          * disconnect and remove
3346                          */
3347 
3348                         close_pooled_connection( ptr );
3349 
3350                         if ( prev )
3351                         {
3352                             prev -> next = ptr -> next;
3353                             free( ptr );
3354                         }
3355                         else
3356                         {
3357                             pool_head = ptr -> next;
3358                             free( ptr );
3359                         }
3360                         goto restart;
3361                     }
3362                     else
3363                     {
3364                         has_checked = 1;
3365                     }
3366                 }
3367             }
3368         }
3369 
3370         if ( !has_checked )
3371         {
3372             /*
3373              * We can't know for sure if the connection is still valid ...
3374              */
3375         }
3376 
3377         /*
3378          * at this point we have something that should work, lets use it
3379          */
3380 
3381         ptr -> in_use = 1;
3382         ptr -> expiry_time = current_time + ptr -> timeout;
3383         connection -> pooling_timeout = ptr -> timeout;
3384 
3385         /*
3386          * copy all the info over
3387          */
3388 
3389         connection -> pooled_connection = ptr;
3390 
3391         connection -> state = ptr -> connection.state;
3392         connection -> dl_handle = ptr -> connection.dl_handle;
3393         connection -> functions = ptr -> connection.functions;
3394         connection -> unicode_driver = ptr -> connection.unicode_driver;
3395         connection -> driver_env = ptr -> connection.driver_env;
3396         connection -> driver_dbc = ptr -> connection.driver_dbc;
3397         connection -> driver_version = ptr -> connection.driver_version;
3398         connection -> driver_act_ver = ptr -> connection.driver_act_ver;
3399         connection -> statement_count = 0;
3400 
3401         connection -> access_mode = ptr -> connection.access_mode;
3402         connection -> access_mode_set = ptr -> connection.access_mode_set;
3403         connection -> login_timeout = ptr -> connection.login_timeout;
3404         connection -> login_timeout_set = ptr -> connection.login_timeout_set;
3405         connection -> auto_commit = ptr -> connection.auto_commit;
3406         connection -> auto_commit_set = ptr -> connection.auto_commit_set;
3407         connection -> async_enable = ptr -> connection.async_enable;
3408         connection -> async_enable_set = ptr -> connection.async_enable_set;
3409         connection -> auto_ipd = ptr -> connection.auto_ipd;
3410         connection -> auto_ipd_set = ptr -> connection.auto_ipd_set;
3411         connection -> connection_timeout = ptr -> connection.connection_timeout;
3412         connection -> connection_timeout_set = ptr -> connection.connection_timeout_set;
3413         connection -> metadata_id = ptr -> connection.metadata_id;
3414         connection -> metadata_id_set = ptr -> connection.metadata_id_set;
3415         connection -> packet_size = ptr -> connection.packet_size;
3416         connection -> packet_size_set = ptr -> connection.packet_size_set;
3417         connection -> quite_mode = ptr -> connection.quite_mode;
3418         connection -> quite_mode_set = ptr -> connection.quite_mode_set;
3419         connection -> txn_isolation = ptr -> connection.txn_isolation;
3420         connection -> txn_isolation_set = ptr -> connection.txn_isolation_set;
3421 
3422         connection -> cursors = ptr -> connection.cursors;
3423         connection -> cl_handle = ptr -> connection.cl_handle;
3424 
3425         connection -> env_list_ent = ptr -> connection.env_list_ent;
3426         strcpy( connection -> probe_sql, ptr -> connection.probe_sql );
3427 
3428         connection -> ex_fetch_mapping = ptr -> connection.ex_fetch_mapping;
3429         connection -> dont_dlclose = ptr -> connection.dont_dlclose;
3430         connection -> bookmarks_on = ptr -> connection.bookmarks_on;
3431 
3432 #ifdef HAVE_ICONV
3433     	connection -> iconv_cd_uc_to_ascii = ptr -> connection.iconv_cd_uc_to_ascii;
3434     	connection -> iconv_cd_ascii_to_uc = ptr -> connection.iconv_cd_ascii_to_uc;
3435 #endif
3436 
3437         /*
3438          * copy current environment into the pooled connection
3439          */
3440 
3441         ptr -> connection.environment = connection -> environment;
3442 
3443         strcpy( connection -> dsn, ptr -> connection.dsn );
3444 
3445 #if defined( HAVE_LIBPTH ) || defined( HAVE_LIBPTHREAD ) || defined( HAVE_LIBTHREAD )
3446         dbc_change_thread_support(connection, ptr -> connection.protection_level);
3447 #endif
3448 
3449         mutex_pool_exit();
3450 
3451         return TRUE;
3452     }
3453 
3454     mutex_pool_exit();
3455     return FALSE;
3456 }
3457 
return_to_pool(DMHDBC connection)3458 void return_to_pool( DMHDBC connection )
3459 {
3460     CPOOL *ptr;
3461     time_t current_time;
3462 
3463     mutex_pool_entry();
3464 
3465     ptr = connection -> pooled_connection;
3466     current_time = time( NULL );
3467 
3468     /*
3469      * is it a old entry ?
3470      */
3471 
3472     if ( connection -> pooled_connection )
3473     {
3474         ptr -> in_use = 0;
3475         ptr -> expiry_time = current_time + ptr -> timeout;
3476 #ifdef HAVE_ICONV
3477 	    connection -> iconv_cd_uc_to_ascii = (iconv_t) -1;
3478 	    connection -> iconv_cd_ascii_to_uc = (iconv_t) -1;
3479 #endif
3480     }
3481     else
3482     {
3483         ptr = calloc( sizeof( CPOOL ), 1 );
3484         if ( !ptr )
3485         {
3486             mutex_pool_exit();
3487             return;
3488         }
3489 
3490         /*
3491          * copy everything over
3492          */
3493 
3494         ptr -> in_use = 0;
3495         ptr -> expiry_time = current_time + connection -> pooling_timeout;
3496         ptr -> timeout = connection -> pooling_timeout;
3497         ptr -> ttl = connection -> ttl;
3498         ptr -> cursors = connection -> cursors;
3499 
3500         /*
3501          * copy all the info over
3502          */
3503 
3504         ptr -> connection.state = connection -> state;
3505         ptr -> connection.dl_handle = connection -> dl_handle;
3506         ptr -> connection.functions = connection -> functions;
3507         ptr -> connection.driver_env = connection -> driver_env;
3508         ptr -> connection.driver_dbc = connection -> driver_dbc;
3509         ptr -> connection.driver_version = connection -> driver_version;
3510         ptr -> connection.driver_act_ver = connection -> driver_act_ver;
3511 
3512         ptr -> connection.access_mode = connection -> access_mode;
3513         ptr -> connection.access_mode_set = connection -> access_mode_set;
3514         ptr -> connection.login_timeout = connection -> login_timeout;
3515         ptr -> connection.login_timeout_set = connection -> login_timeout_set;
3516         ptr -> connection.auto_commit = connection -> auto_commit;
3517         ptr -> connection.auto_commit_set = connection -> auto_commit_set;
3518         ptr -> connection.async_enable = connection -> async_enable;
3519         ptr -> connection.async_enable_set = connection -> async_enable_set;
3520         ptr -> connection.auto_ipd = connection -> auto_ipd;
3521         ptr -> connection.auto_ipd_set = connection -> auto_ipd_set;
3522         ptr -> connection.connection_timeout = connection -> connection_timeout;
3523         ptr -> connection.connection_timeout_set = connection -> connection_timeout_set;
3524         ptr -> connection.metadata_id = connection -> metadata_id;
3525         ptr -> connection.metadata_id_set = connection -> metadata_id_set;
3526         ptr -> connection.packet_size = connection -> packet_size;
3527         ptr -> connection.packet_size_set = connection -> packet_size_set;
3528         ptr -> connection.quite_mode = connection -> quite_mode;
3529         ptr -> connection.quite_mode_set = connection -> quite_mode_set;
3530         ptr -> connection.txn_isolation = connection -> txn_isolation;
3531         ptr -> connection.txn_isolation_set = connection -> txn_isolation_set;
3532         ptr -> connection.unicode_driver = connection ->unicode_driver;
3533 
3534         ptr -> connection.cursors = connection -> cursors;
3535         ptr -> connection.cl_handle = connection -> cl_handle;
3536 
3537 #ifdef HAVE_LIBPTHREAD
3538         ptr -> connection.mutex = connection -> mutex;
3539         ptr -> connection.protection_level = connection -> protection_level;
3540 #elif HAVE_LIBTHREAD
3541         ptr -> connection.mutex = connection -> mutex;
3542         ptr -> connection.protection_level = connection -> protection_level;
3543 #endif
3544 
3545         ptr -> connection.pooling_timeout = ptr -> timeout;
3546 
3547         ptr -> connection.ex_fetch_mapping = connection -> ex_fetch_mapping;
3548         ptr -> connection.dont_dlclose = connection -> dont_dlclose;
3549         ptr -> connection.bookmarks_on = connection -> bookmarks_on;
3550 
3551         ptr -> connection.env_list_ent = connection -> env_list_ent;
3552         ptr -> connection.environment = connection -> environment;
3553         strcpy( ptr -> connection.probe_sql, connection -> probe_sql );
3554 
3555 #ifdef HAVE_ICONV
3556     	ptr -> connection.iconv_cd_uc_to_ascii = connection -> iconv_cd_uc_to_ascii;
3557     	ptr -> connection.iconv_cd_ascii_to_uc = connection -> iconv_cd_ascii_to_uc;
3558 	    connection -> iconv_cd_uc_to_ascii = (iconv_t) -1;
3559 	    connection -> iconv_cd_ascii_to_uc = (iconv_t) -1;
3560 #endif
3561 
3562         if ( connection -> server_length < 0 )
3563         {
3564             strcpy( ptr -> server, connection -> server );
3565         }
3566         else
3567         {
3568             memcpy( ptr -> server, connection -> server, connection -> server_length );
3569         }
3570         ptr -> server_length = connection -> server_length;
3571 
3572         if ( connection -> user_length < 0 )
3573         {
3574             strcpy( ptr -> user, connection -> user );
3575         }
3576         else
3577         {
3578             memcpy( ptr -> user, connection -> user, connection -> user_length );
3579         }
3580         ptr -> user_length = connection -> user_length;
3581 
3582         if ( connection -> password_length < 0 )
3583         {
3584             strcpy( ptr -> password, connection -> password );
3585         }
3586         else
3587         {
3588             memcpy( ptr -> password, connection -> password, connection -> password_length );
3589         }
3590         ptr -> password_length = connection -> password_length;
3591 
3592         if ( connection -> dsn_length < 0 )
3593         {
3594             strcpy( ptr -> driver_connect_string, connection -> driver_connect_string );
3595         }
3596         else
3597         {
3598             memcpy( ptr -> driver_connect_string, connection -> driver_connect_string,
3599                     connection -> dsn_length );
3600         }
3601         ptr -> dsn_length = connection -> dsn_length;
3602 
3603         strcpy( ptr -> connection.dsn, connection -> dsn );
3604 
3605         /*
3606          * add to the list
3607          */
3608 
3609         ptr -> next = pool_head;
3610         pool_head = ptr;
3611     }
3612 
3613     /*
3614      * allow the driver to reset itself if it's a 3.8 driver
3615      */
3616 
3617     if ( connection -> driver_version == SQL_OV_ODBC3_80 )
3618     {
3619         if ( CHECK_SQLSETCONNECTATTR( connection ))
3620         {
3621             SQLSETCONNECTATTR( connection,
3622                     connection -> driver_dbc,
3623                     SQL_ATTR_RESET_CONNECTION,
3624                     SQL_RESET_CONNECTION_YES,
3625                     0 );
3626         }
3627     }
3628 
3629     /*
3630      * remove all information from the connection
3631      */
3632 
3633     connection -> state = STATE_C2;
3634     connection -> driver_env = 0;
3635     connection -> driver_dbc = 0;
3636     connection -> dl_handle = 0;
3637     connection -> cl_handle = 0;
3638     connection -> functions = 0;
3639     connection -> pooled_connection = 0;
3640 
3641     mutex_pool_exit();
3642 }
3643 
__handle_attr_extensions(DMHDBC connection,char * dsn,char * driver_name)3644 void __handle_attr_extensions( DMHDBC connection, char *dsn, char *driver_name )
3645 {
3646     char txt[ 1024 ];
3647 
3648     if ( dsn && strlen( dsn ))
3649     {
3650         SQLGetPrivateProfileString( dsn, "DMEnvAttr", "",
3651                     txt, sizeof( txt ),
3652                     "ODBC.INI" );
3653 
3654         if ( strlen( txt ))
3655         {
3656             __parse_attribute_string( &connection -> env_attribute,
3657                 txt, strlen( txt ));
3658         }
3659 
3660         SQLGetPrivateProfileString( dsn, "DMConnAttr", "",
3661                     txt, sizeof( txt ),
3662                     "ODBC.INI" );
3663 
3664         if ( strlen( txt ))
3665         {
3666             __parse_attribute_string( &connection -> dbc_attribute,
3667                 txt, strlen( txt ));
3668         }
3669 
3670         SQLGetPrivateProfileString( dsn, "DMStmtAttr", "",
3671                     txt, sizeof( txt ),
3672                     "ODBC.INI" );
3673 
3674         if ( strlen( txt ))
3675         {
3676             __parse_attribute_string( &connection -> stmt_attribute,
3677                 txt, strlen( txt ));
3678         }
3679     }
3680 
3681     if ( driver_name && strlen( driver_name ))
3682     {
3683         SQLGetPrivateProfileString( driver_name, "DMEnvAttr", "",
3684                           txt, sizeof( txt ),
3685                           "ODBCINST.INI" );
3686 
3687         if ( strlen( txt ))
3688         {
3689             __parse_attribute_string( &connection -> env_attribute,
3690                          txt, strlen( txt ));
3691         }
3692     }
3693 }
3694 
SQLConnectA(SQLHDBC connection_handle,SQLCHAR * server_name,SQLSMALLINT name_length1,SQLCHAR * user_name,SQLSMALLINT name_length2,SQLCHAR * authentication,SQLSMALLINT name_length3)3695 SQLRETURN SQLConnectA( SQLHDBC connection_handle,
3696            SQLCHAR *server_name,
3697            SQLSMALLINT name_length1,
3698            SQLCHAR *user_name,
3699            SQLSMALLINT name_length2,
3700            SQLCHAR *authentication,
3701            SQLSMALLINT name_length3 )
3702 {
3703     return SQLConnect( connection_handle,
3704                         server_name,
3705                         name_length1,
3706                         user_name,
3707                         name_length2,
3708                         authentication,
3709                         name_length3 );
3710 }
3711 
SQLConnect(SQLHDBC connection_handle,SQLCHAR * server_name,SQLSMALLINT name_length1,SQLCHAR * user_name,SQLSMALLINT name_length2,SQLCHAR * authentication,SQLSMALLINT name_length3)3712 SQLRETURN SQLConnect( SQLHDBC connection_handle,
3713            SQLCHAR *server_name,
3714            SQLSMALLINT name_length1,
3715            SQLCHAR *user_name,
3716            SQLSMALLINT name_length2,
3717            SQLCHAR *authentication,
3718            SQLSMALLINT name_length3 )
3719 {
3720     DMHDBC connection = (DMHDBC)connection_handle;
3721     int len, ret_from_connect;
3722     char dsn[ SQL_MAX_DSN_LENGTH + 1 ];
3723     char lib_name[ INI_MAX_PROPERTY_VALUE + 1 ];
3724     char driver_name[ INI_MAX_PROPERTY_VALUE + 1 ];
3725     SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ], s2[ 100 + LOG_MESSAGE_LEN ], s3[ 100 + LOG_MESSAGE_LEN ];
3726     int warnings;
3727 
3728     /*
3729      * check connection
3730      */
3731     if ( !__validate_dbc( connection ))
3732     {
3733         dm_log_write( __FILE__,
3734                 __LINE__,
3735                     LOG_INFO,
3736                     LOG_INFO,
3737                     "Error: SQL_INVALID_HANDLE" );
3738 
3739         return SQL_INVALID_HANDLE;
3740     }
3741 
3742     function_entry( connection );
3743 
3744     if ( log_info.log_flag )
3745     {
3746         sprintf( connection -> msg, "\n\t\tEntry:\
3747 \n\t\t\tConnection = %p\
3748 \n\t\t\tServer Name = %s\
3749 \n\t\t\tUser Name = %s\
3750 \n\t\t\tAuthentication = %s",
3751                 connection,
3752                 __string_with_length( s1, server_name, name_length1 ),
3753                 __string_with_length( s2, user_name, name_length2 ),
3754                 __string_with_length_pass( s3, authentication, name_length3 ));
3755 
3756         dm_log_write( __FILE__,
3757                 __LINE__,
3758                 LOG_INFO,
3759                 LOG_INFO,
3760                 connection -> msg );
3761     }
3762 
3763     thread_protect( SQL_HANDLE_DBC, connection );
3764 
3765     if (( name_length1 < 0 && name_length1 != SQL_NTS ) ||
3766         ( name_length2 < 0 && name_length2 != SQL_NTS ) ||
3767         ( name_length3 < 0 && name_length3 != SQL_NTS ))
3768 
3769     {
3770         dm_log_write( __FILE__,
3771                 __LINE__,
3772                 LOG_INFO,
3773                 LOG_INFO,
3774                 "Error: HY090" );
3775 
3776         __post_internal_error( &connection -> error,
3777                 ERROR_HY090, NULL,
3778                 connection -> environment -> requested_version );
3779 
3780         return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3781     }
3782 
3783     /*
3784      * check the state of the connection
3785      */
3786     if ( connection -> state != STATE_C2 )
3787     {
3788         dm_log_write( __FILE__,
3789                 __LINE__,
3790                 LOG_INFO,
3791                 LOG_INFO,
3792                 "Error: 08002" );
3793 
3794         __post_internal_error( &connection -> error,
3795                 ERROR_08002, NULL,
3796                 connection -> environment -> requested_version );
3797 
3798         return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3799     }
3800 
3801     if ( name_length1 && server_name )
3802     {
3803         if ( name_length1 == SQL_NTS )
3804         {
3805             len = strlen((char*) server_name );
3806 
3807             if ( len > SQL_MAX_DSN_LENGTH )
3808             {
3809                 dm_log_write( __FILE__,
3810                         __LINE__,
3811                         LOG_INFO,
3812                         LOG_INFO,
3813                         "Error: HY090" );
3814 
3815                 __post_internal_error( &connection -> error,
3816                         ERROR_HY090, NULL,
3817                         connection -> environment -> requested_version );
3818 
3819                 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3820             }
3821         }
3822         else
3823         {
3824             len = name_length1;
3825 
3826             if ( len > SQL_MAX_DSN_LENGTH )
3827             {
3828                 dm_log_write( __FILE__,
3829                         __LINE__,
3830                         LOG_INFO,
3831                         LOG_INFO,
3832                         "Error: HY090" );
3833 
3834                 __post_internal_error( &connection -> error,
3835                         ERROR_HY090, NULL,
3836                         connection -> environment -> requested_version );
3837 
3838                 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3839             }
3840         }
3841 
3842         memcpy( dsn, server_name, len );
3843         dsn[ len ] ='\0';
3844     }
3845     else if ( name_length1 > SQL_MAX_DSN_LENGTH )
3846     {
3847         dm_log_write( __FILE__,
3848                 __LINE__,
3849                 LOG_INFO,
3850                 LOG_INFO,
3851                 "Error: IM010" );
3852 
3853         __post_internal_error( &connection -> error,
3854                 ERROR_IM010, NULL,
3855                 connection -> environment -> requested_version );
3856 
3857         return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3858     }
3859     else
3860     {
3861         strcpy( dsn, "DEFAULT" );
3862     }
3863 
3864     /*
3865      * can we find a pooled connection to use here ?
3866      */
3867 
3868     connection -> pooled_connection = NULL;
3869 
3870     if ( pooling_enabled && search_for_pool( connection,
3871                                                 server_name, name_length1,
3872                                                 user_name, name_length2,
3873                                                 authentication, name_length3,
3874                                                 NULL, 0 ))
3875     {
3876         ret_from_connect = SQL_SUCCESS;
3877 
3878         if ( log_info.log_flag )
3879         {
3880             sprintf( connection -> msg,
3881                     "\n\t\tExit:[%s]",
3882                         __get_return_status( ret_from_connect, s1 ));
3883 
3884             dm_log_write( __FILE__,
3885                         __LINE__,
3886                     LOG_INFO,
3887                     LOG_INFO,
3888                     connection -> msg );
3889         }
3890 
3891         connection -> state = STATE_C4;
3892 
3893         return function_return_nodrv( SQL_HANDLE_DBC, connection, ret_from_connect );
3894     }
3895 
3896     /*
3897      * else safe the info for later
3898      */
3899 
3900     if ( pooling_enabled )
3901     {
3902         connection -> dsn_length = 0;
3903 
3904         if ( server_name )
3905         {
3906             if ( name_length1 < 0 )
3907             {
3908                 strcpy( connection -> server, (char*)server_name );
3909             }
3910             else
3911             {
3912                 memcpy( connection -> server, server_name, name_length1 );
3913             }
3914         }
3915         else
3916         {
3917             strcpy( connection -> server, "" );
3918         }
3919         connection -> server_length = name_length1;
3920 
3921         if ( user_name )
3922         {
3923             if ( name_length2 < 0 )
3924             {
3925                 strcpy( connection -> user, (char*)user_name );
3926             }
3927             else
3928             {
3929                 memcpy( connection -> user, user_name, name_length2 );
3930             }
3931         }
3932         else
3933         {
3934             strcpy( connection -> user, "" );
3935         }
3936         connection -> user_length = name_length2;
3937 
3938         if ( authentication )
3939         {
3940             if ( name_length3 )
3941             {
3942                 strcpy( connection -> password, (char*)authentication );
3943             }
3944             else
3945             {
3946                 memcpy( connection -> password, authentication, name_length3 );
3947             }
3948         }
3949         else
3950         {
3951             strcpy( connection -> password, "" );
3952         }
3953         connection -> password_length = name_length3;
3954     }
3955 
3956     if ( !*dsn || !__find_lib_name( dsn, lib_name, driver_name ))
3957     {
3958         /*
3959          * if not found look for a default
3960          */
3961 
3962         if ( !__find_lib_name( "DEFAULT", lib_name, driver_name ))
3963         {
3964             dm_log_write( __FILE__,
3965                     __LINE__,
3966                     LOG_INFO,
3967                     LOG_INFO,
3968                     "Error: IM002" );
3969 
3970             __post_internal_error( &connection -> error,
3971                     ERROR_IM002, NULL,
3972                     connection -> environment -> requested_version );
3973 
3974             return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3975         }
3976     }
3977 
3978 
3979     /*
3980      * do we have any Environment, Connection, or Statement attributes set in the ini ?
3981      */
3982 
3983     __handle_attr_extensions( connection, dsn, driver_name );
3984 
3985     /*
3986      * if necessary change the threading level
3987      */
3988 
3989     warnings = 0;
3990 
3991     if ( !__connect_part_one( connection, lib_name, driver_name, &warnings ))
3992     {
3993         __disconnect_part_four( connection );       /* release unicode handles */
3994 
3995         return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3996     }
3997 
3998     if ( !CHECK_SQLCONNECT( connection ) &&
3999         !CHECK_SQLCONNECTW( connection ))
4000     {
4001         dm_log_write( __FILE__,
4002                 __LINE__,
4003                 LOG_INFO,
4004                 LOG_INFO,
4005                 "Error: IM001" );
4006 
4007         __disconnect_part_one( connection );
4008         __disconnect_part_four( connection );       /* release unicode handles */
4009         __post_internal_error( &connection -> error,
4010                 ERROR_IM001, NULL,
4011                 connection -> environment -> requested_version );
4012 
4013         return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
4014     }
4015 
4016     if ( CHECK_SQLCONNECT( connection ))
4017     {
4018         /*
4019         if ( CHECK_SQLSETCONNECTATTR( connection ))
4020         {
4021             int lret;
4022 
4023             lret = SQLSETCONNECTATTR( connection,
4024                     connection -> driver_dbc,
4025                     SQL_ATTR_ANSI_APP,
4026                     SQL_AA_TRUE,
4027                     0 );
4028         }
4029         */
4030 
4031         ret_from_connect = SQLCONNECT( connection,
4032                 connection -> driver_dbc,
4033                 dsn, SQL_NTS,
4034                 user_name, name_length2,
4035                 authentication, name_length3 );
4036 
4037         if ( ret_from_connect != SQL_SUCCESS )
4038         {
4039             SQLCHAR sqlstate[ 6 ];
4040             SQLINTEGER native_error;
4041             SQLSMALLINT ind;
4042             SQLCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
4043             SQLRETURN ret;
4044 
4045             /*
4046              * get the errors from the driver before
4047              * loseing the connection
4048              */
4049 
4050             if ( CHECK_SQLERROR( connection ))
4051             {
4052                 do
4053                 {
4054                     ret = SQLERROR( connection,
4055                             SQL_NULL_HENV,
4056                             connection -> driver_dbc,
4057                             SQL_NULL_HSTMT,
4058                             sqlstate,
4059                             &native_error,
4060                             message_text,
4061                             sizeof( message_text ),
4062                             &ind );
4063 
4064                     if ( SQL_SUCCEEDED( ret ))
4065                     {
4066                         __post_internal_error_ex( &connection -> error,
4067                                 sqlstate,
4068                                 native_error,
4069                                 message_text,
4070                                 SUBCLASS_ODBC, SUBCLASS_ODBC );
4071 
4072                         sprintf( connection -> msg, "\t\tDIAG [%s] %s",
4073                                 sqlstate, message_text );
4074 
4075                         dm_log_write_diag( connection -> msg );
4076                     }
4077                 }
4078                 while( SQL_SUCCEEDED( ret ));
4079             }
4080             else if ( CHECK_SQLGETDIAGREC( connection ))
4081             {
4082                 int rec = 1;
4083 
4084                 do
4085                 {
4086                     ret = SQLGETDIAGREC( connection,
4087                             SQL_HANDLE_DBC,
4088                             connection -> driver_dbc,
4089                             rec ++,
4090                             sqlstate,
4091                             &native_error,
4092                             message_text,
4093                             sizeof( message_text ),
4094                             &ind );
4095 
4096 
4097                     if ( SQL_SUCCEEDED( ret ))
4098                     {
4099                         __post_internal_error_ex( &connection -> error,
4100                                 sqlstate,
4101                                 native_error,
4102                                 message_text,
4103                                 SUBCLASS_ODBC, SUBCLASS_ODBC );
4104 
4105                         sprintf( connection -> msg, "\t\tDIAG [%s] %s",
4106                             sqlstate, message_text );
4107 
4108                         dm_log_write_diag( connection -> msg );
4109                     }
4110                 }
4111                 while( SQL_SUCCEEDED( ret ));
4112             }
4113         }
4114 
4115         /*
4116          * if it was a error then return now
4117          */
4118 
4119         if ( !SQL_SUCCEEDED( ret_from_connect ))
4120         {
4121             __disconnect_part_one( connection );
4122             __disconnect_part_four( connection );
4123 
4124             sprintf( connection -> msg,
4125                     "\n\t\tExit:[%s]",
4126                         __get_return_status( ret_from_connect, s1 ));
4127 
4128             dm_log_write( __FILE__,
4129                     __LINE__,
4130                     LOG_INFO,
4131                     LOG_INFO,
4132                     connection -> msg );
4133 
4134             return function_return( SQL_HANDLE_DBC, connection, ret_from_connect, DEFER_R0 );
4135         }
4136 
4137 	connection -> unicode_driver = 0;
4138     }
4139     else
4140     {
4141         SQLWCHAR * uc_dsn, *uc_user, *uc_auth;
4142 
4143         uc_dsn = ansi_to_unicode_alloc((SQLCHAR*) dsn, SQL_NTS, connection, NULL );
4144         uc_user = ansi_to_unicode_alloc( user_name, name_length2, connection, NULL );
4145         uc_auth = ansi_to_unicode_alloc( authentication, name_length3, connection, NULL );
4146 
4147         if ( CHECK_SQLSETCONNECTATTR( connection ))
4148         {
4149             SQLSETCONNECTATTR( connection,
4150                     connection -> driver_dbc,
4151                     SQL_ATTR_ANSI_APP,
4152                     SQL_AA_FALSE,
4153                     0 );
4154         }
4155 
4156         ret_from_connect = SQLCONNECTW( connection,
4157                 connection -> driver_dbc,
4158                 uc_dsn, SQL_NTS,
4159                 uc_user, name_length2,
4160                 uc_auth, name_length3 );
4161 
4162         if ( uc_dsn )
4163             free( uc_dsn );
4164         if ( uc_user )
4165             free( uc_user );
4166         if ( uc_auth )
4167             free( uc_auth );
4168 
4169         if ( ret_from_connect != SQL_SUCCESS )
4170         {
4171             SQLWCHAR sqlstate[ 6 ];
4172             SQLINTEGER native_error;
4173             SQLSMALLINT ind;
4174             SQLWCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
4175             SQLRETURN ret;
4176 
4177             /*
4178              * get the errors from the driver before
4179              * looseing the connection
4180              */
4181 
4182             if ( CHECK_SQLERRORW( connection ))
4183             {
4184                 do
4185                 {
4186                     ret = SQLERRORW( connection,
4187                             SQL_NULL_HENV,
4188                             connection -> driver_dbc,
4189                             SQL_NULL_HSTMT,
4190                             sqlstate,
4191                             &native_error,
4192                             message_text,
4193                             sizeof( message_text )/sizeof(SQLWCHAR),
4194                             &ind );
4195 
4196 
4197                     if ( SQL_SUCCEEDED( ret ))
4198                     {
4199                         SQLCHAR *as1, *as2;
4200 
4201                         __post_internal_error_ex_w( &connection -> error,
4202                                 sqlstate,
4203                                 native_error,
4204                                 message_text,
4205                                 SUBCLASS_ODBC, SUBCLASS_ODBC );
4206 
4207                         as1 = (SQLCHAR *) unicode_to_ansi_alloc( sqlstate, SQL_NTS, connection, NULL );
4208                         as2 = (SQLCHAR *) unicode_to_ansi_alloc( message_text, SQL_NTS, connection, NULL );
4209 
4210                         sprintf( connection -> msg, "\t\tDIAG [%s] %s",
4211                                 as1, as2 );
4212 
4213                         if ( as1 ) free( as1 );
4214                         if ( as2 ) free( as2 );
4215 
4216                         dm_log_write_diag( connection -> msg );
4217                     }
4218                 }
4219                 while( SQL_SUCCEEDED( ret ));
4220             }
4221             else if ( CHECK_SQLGETDIAGRECW( connection ))
4222             {
4223                 int rec = 1;
4224 
4225                 do
4226                 {
4227 
4228                     ret = SQLGETDIAGRECW( connection,
4229                             SQL_HANDLE_DBC,
4230                             connection -> driver_dbc,
4231                             rec ++,
4232                             sqlstate,
4233                             &native_error,
4234                             message_text,
4235                             sizeof( message_text )/sizeof(SQLWCHAR),
4236                             &ind );
4237 
4238                     if ( SQL_SUCCEEDED( ret ))
4239                     {
4240                         SQLCHAR *as1, *as2;
4241 
4242                         __post_internal_error_ex_w( &connection -> error,
4243                                 sqlstate,
4244                                 native_error,
4245                                 message_text,
4246                                 SUBCLASS_ODBC, SUBCLASS_ODBC );
4247 
4248                         as1 = (SQLCHAR *) unicode_to_ansi_alloc( sqlstate, SQL_NTS, connection, NULL );
4249                         as2 = (SQLCHAR *) unicode_to_ansi_alloc( message_text, SQL_NTS, connection, NULL );
4250 
4251                         sprintf( connection -> msg, "\t\tDIAG [%s] %s",
4252                                 as1, as2 );
4253 
4254                         if ( as1 ) free( as1 );
4255                         if ( as2 ) free( as2 );
4256 
4257                         dm_log_write_diag( connection -> msg );
4258                     }
4259                 }
4260                 while( SQL_SUCCEEDED( ret ));
4261             }
4262         }
4263 
4264         /*
4265          * if it was a error then return now
4266          */
4267 
4268         if ( !SQL_SUCCEEDED( ret_from_connect ))
4269         {
4270             __disconnect_part_one( connection );
4271             __disconnect_part_four( connection );
4272 
4273             sprintf( connection -> msg,
4274                     "\n\t\tExit:[%s]",
4275                         __get_return_status( ret_from_connect, s1 ));
4276 
4277             dm_log_write( __FILE__,
4278                     __LINE__,
4279                     LOG_INFO,
4280                     LOG_INFO,
4281                     connection -> msg );
4282 
4283             return function_return( SQL_HANDLE_DBC, connection, ret_from_connect, DEFER_R0 );
4284         }
4285 
4286         connection -> unicode_driver = 1;
4287     }
4288 
4289     /*
4290      * we should be connected now
4291      */
4292     connection -> state = STATE_C4;
4293     strcpy( connection -> dsn, dsn );
4294 
4295     /*
4296      * did we get the type we wanted
4297      */
4298 
4299     if ( connection -> driver_version !=
4300             connection -> environment -> requested_version )
4301     {
4302         connection -> driver_version =
4303             connection -> environment -> requested_version;
4304 
4305         __post_internal_error( &connection -> error,
4306                 ERROR_01000, "Driver does not support the requested version",
4307                 connection -> environment -> requested_version );
4308         ret_from_connect = SQL_SUCCESS_WITH_INFO;
4309     }
4310 
4311     if ( !__connect_part_two( connection ))
4312     {
4313         /*
4314          * the cursor lib can kill us here, so be careful
4315          */
4316 
4317         __disconnect_part_two( connection );
4318         __disconnect_part_one( connection );
4319         __disconnect_part_four( connection );
4320 
4321         connection -> state = STATE_C3;
4322 
4323         return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR, DEFER_R0 );
4324     }
4325 
4326     if ( log_info.log_flag )
4327     {
4328         sprintf( connection -> msg,
4329                 "\n\t\tExit:[%s]",
4330                     __get_return_status( ret_from_connect, s1 ));
4331 
4332         dm_log_write( __FILE__,
4333                 __LINE__,
4334                 LOG_INFO,
4335                 LOG_INFO,
4336                 connection -> msg );
4337     }
4338 
4339     if ( warnings && ret_from_connect == SQL_SUCCESS )
4340     {
4341         ret_from_connect = SQL_SUCCESS_WITH_INFO;
4342     }
4343 
4344     return function_return_nodrv( SQL_HANDLE_DBC, connection, ret_from_connect );
4345 }
4346 
4347 /*
4348  * connection pooling setup, just stubs for the moment
4349  */
4350 
ODBCSetTryWaitValue(DWORD dwValue)4351 BOOL ODBCSetTryWaitValue ( DWORD dwValue )
4352 {
4353 	return 0;
4354 }
4355 
4356 #ifdef __cplusplus
ODBCGetTryWaitValue()4357 DWORD ODBCGetTryWaitValue ( )
4358 #else
4359 DWORD ODBCGetTryWaitValue ( void )
4360 #endif
4361 {
4362 	return 0;
4363 }
4364