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
597static 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
615static 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
739CPOOL *pool_head = NULL;
740int 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
751static 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
793struct 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
807static struct lib_count *lib_list = NULL;
808static struct lib_count single_lib_count;
809static char single_lib_name[ INI_MAX_PROPERTY_VALUE + 1 ];
810
811static 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
880static 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
954int __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 HAVE_ICONV
1084 SQLGetPrivateProfileString( driver_name, "IconvEncoding", DEFAULT_ICONV_ENCODING,
1085 connection->unicode_string, sizeof( connection->unicode_string ),
1086 "ODBCINST.INI" );
1087#endif
1088
1089 /*
1090 * initialize unicode
1091 */
1092
1093 if ( !unicode_setup( connection ))
1094 {
1095 char txt[ 256 ];
1096
1097 sprintf( txt, "Can't initiate unicode conversion" );
1098
1099 dm_log_write( __FILE__,
1100 __LINE__,
1101 LOG_INFO,
1102 LOG_INFO,
1103 txt );
1104
1105 __post_internal_error( &connection -> error,
1106 ERROR_IM003, txt,
1107 connection -> environment -> requested_version );
1108
1109 *warnings = TRUE;
1110 }
1111
1112 /*
1113 * initialize libtool
1114 */
1115
1116 mutex_lib_entry(); /* warning, this doesn't protect from other libs in the application */
1117 /* in their own threads calling dlinit(); */
1118 lt_dlinit();
1119 mutex_lib_exit();
1120
1121 /*
1122 * open the lib
1123 */
1124
1125 connection -> driver_env = (DRV_SQLHANDLE)NULL;
1126 connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
1127 connection -> functions = NULL;
1128 connection -> dl_handle = NULL;
1129
1130 if ( !(connection -> dl_handle = odbc_dlopen( driver_lib, &err )))
1131 {
1132 char txt[ 2048 ];
1133
1134 sprintf( txt, "Can't open lib '%s' : %s",
1135 driver_lib, err ? err : "NULL ERROR RETURN" );
1136
1137 dm_log_write( __FILE__,
1138 __LINE__,
1139 LOG_INFO,
1140 LOG_INFO,
1141 txt );
1142
1143 __post_internal_error( &connection -> error,
1144 ERROR_01000, txt,
1145 connection -> environment -> requested_version );
1146
1147 return 0;
1148 }
1149
1150 /*
1151 * try and extract the ini and fini functions, and call ini if it's
1152 * found
1153 */
1154
1155 connection -> ini_func.func =
1156 (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle,
1157 ODBC_INI_FUNCTION );
1158
1159 connection -> fini_func.func =
1160 (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle,
1161 ODBC_FINI_FUNCTION );
1162
1163 if ( connection -> ini_func.func )
1164 {
1165 connection -> ini_func.func();
1166 }
1167
1168 /*
1169 * extract all the function entry points
1170 */
1171 if ( !(connection -> functions = malloc( sizeof( template_func ))))
1172 {
1173 dm_log_write( __FILE__,
1174 __LINE__,
1175 LOG_INFO,
1176 LOG_INFO,
1177 "Error: IM001" );
1178
1179 __post_internal_error( &connection -> error,
1180 ERROR_HY001, NULL,
1181 connection -> environment -> requested_version );
1182 return 0;
1183 }
1184
1185 memcpy( connection -> functions, template_func,
1186 sizeof( template_func ));
1187
1188 for ( i = 0;
1189 i < sizeof( template_func ) / sizeof( template_func[ 0 ] );
1190 i ++ )
1191 {
1192 char name[ 128 ];
1193
1194 connection -> functions[ i ].func =
1195 (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle,
1196 connection -> functions[ i ].name );
1197
1198 if ( connection -> functions[ i ].dm_funcW )
1199 {
1200 /*
1201 * get ANSI version from driver
1202 */
1203
1204 if ( fake_unicode )
1205 {
1206 sprintf( name, "%sW", connection -> functions[ i ].name );
1207 }
1208 else
1209 {
1210 sprintf( name, "%sA", connection -> functions[ i ].name );
1211 }
1212 connection -> functions[ i ].funcA =
1213 (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle, name );
1214
1215 if ( connection -> functions[ i ].funcA &&
1216 !connection -> functions[ i ].func )
1217 {
1218 connection -> functions[ i ].func =
1219 connection -> functions[ i ].funcA;
1220 }
1221 else if ( connection -> functions[ i ].func &&
1222 !connection -> functions[ i ].funcA )
1223 {
1224 connection -> functions[ i ].funcA =
1225 connection -> functions[ i ].func;
1226 }
1227
1228 /*
1229 * get UNICODE version from driver
1230 */
1231
1232 sprintf( name, "%sW", connection -> functions[ i ].name );
1233 connection -> functions[ i ].funcW =
1234 (SQLRETURN (*)()) lt_dlsym( connection -> dl_handle, name );
1235 }
1236 else
1237 {
1238 connection -> functions[ i ].funcA =
1239 connection -> functions[ i ].funcW = NULL;
1240 }
1241
1242 /*
1243 * blank out ones that are in the DM to fix a big
1244 * with glib 2.0.6
1245 */
1246
1247 if ( connection -> functions[ i ].func &&
1248 (void*)connection -> functions[ i ].func ==
1249 (void*)connection -> functions[ i ].dm_func )
1250 {
1251 connection -> functions[ i ].func = NULL;
1252 }
1253
1254 if ( connection -> functions[ i ].funcW &&
1255 (void*)connection -> functions[ i ].funcW ==
1256 (void*)connection -> functions[ i ].dm_funcW )
1257 {
1258 connection -> functions[ i ].funcW = NULL;
1259 }
1260
1261 connection -> functions[ i ].can_supply =
1262 ( connection -> functions[ i ].func != NULL ) ||
1263 ( connection -> functions[ i ].funcW != NULL );
1264 }
1265
1266 /*
1267 * check if this is the first time this driver has been loaded under this
1268 * lib, if not then reuse the env, else get the env from the driver
1269 */
1270
1271 mutex_lib_entry();
1272
1273 env_lib_list = connection -> environment -> env_lib_list;
1274 env_lib_prev = NULL;
1275
1276 while( env_lib_list )
1277 {
1278 if ( strcmp( driver_lib, env_lib_list -> lib_name ) == 0 )
1279 {
1280 break;
1281 }
1282 env_lib_prev = env_lib_list;
1283 env_lib_list = env_lib_list -> next;
1284 }
1285
1286 connection -> driver_act_ver = 0;
1287 if ( env_lib_list )
1288 {
1289 /*
1290 * Fix by qcai@starquest.com
1291 */
1292 SQLUINTEGER actual_version = 0;
1293 int ret;
1294
1295 env_lib_list -> count ++;
1296 connection -> driver_env = env_lib_list -> env_handle;
1297 connection -> env_list_ent = env_lib_list;
1298
1299 /*
1300 * Fix by qcai@starquest.com, Feb 5, 2003
1301 *
1302 * Since the driver was already loaded before, the version number
1303 * has been properly figured out. This connection just need to get
1304 * it from priviously set value. Without it, the version number is
1305 * at initial value of 0 which causes this and subsequence connection
1306 * to return a warning message "Driver does not support the requested
1307 * version".
1308 */
1309
1310 /*
1311 * Change from Rafie Einstein to check SQLGETENVATTR is valid
1312 */
1313 if ((CHECK_SQLGETENVATTR( connection )))
1314 {
1315 ret = SQLGETENVATTR( connection,
1316 connection -> driver_env,
1317 SQL_ATTR_ODBC_VERSION,
1318 &actual_version,
1319 0,
1320 NULL );
1321 }
1322 else
1323 {
1324 ret = SQL_SUCCESS;
1325 actual_version = SQL_OV_ODBC2;
1326 }
1327
1328 if ( !ret )
1329 {
1330 connection -> driver_version = actual_version;
1331 }
1332 else
1333 {
1334 connection -> driver_version =
1335 connection -> environment -> requested_version;
1336 }
1337 /* end of fix */
1338
1339 /*
1340 * get value that has been pushed up by the initial connection to this driver
1341 */
1342
1343 connection -> driver_act_ver = connection -> environment -> driver_act_ver;
1344 }
1345 else
1346 {
1347 env_lib_list = calloc( 1, sizeof( struct env_lib_struct ));
1348
1349 env_lib_list -> count = 1;
1350 env_lib_list -> next = connection -> environment -> env_lib_list;
1351 env_lib_list -> lib_name = strdup( driver_lib );
1352 connection -> env_list_ent = env_lib_list;
1353
1354 connection -> environment -> env_lib_list = env_lib_list;
1355
1356 __set_local_attributes( connection, SQL_HANDLE_ENV );
1357
1358 /*
1359 * allocate a env handle
1360 */
1361
1362 if ( CHECK_SQLALLOCHANDLE( connection ))
1363 {
1364 ret = SQLALLOCHANDLE( connection,
1365 SQL_HANDLE_ENV,
1366 SQL_NULL_HENV,
1367 &connection -> driver_env,
1368 connection );
1369 connection -> driver_act_ver = SQL_OV_ODBC3;
1370 }
1371 else if ( CHECK_SQLALLOCENV( connection ))
1372 {
1373 ret = SQLALLOCENV( connection,
1374 &connection -> driver_env );
1375 connection -> driver_act_ver = SQL_OV_ODBC2;
1376 }
1377 else
1378 {
1379 dm_log_write( __FILE__,
1380 __LINE__,
1381 LOG_INFO,
1382 LOG_INFO,
1383 "Error: IM004" );
1384
1385 __post_internal_error( &connection -> error,
1386 ERROR_IM004, NULL,
1387 connection -> environment -> requested_version );
1388
1389 if ( env_lib_list -> count == 1 )
1390 {
1391 if ( env_lib_prev )
1392 {
1393 env_lib_prev -> next = env_lib_list -> next;
1394 }
1395 else
1396 {
1397 connection -> environment -> env_lib_list = env_lib_list -> next;
1398 }
1399
1400 free( env_lib_list -> lib_name );
1401 free( env_lib_list );
1402 }
1403 else
1404 {
1405 env_lib_list -> count --;
1406 }
1407
1408 mutex_lib_exit();
1409 return 0;
1410 }
1411
1412 /*
1413 * push up to environment to be reused
1414 */
1415
1416 connection -> environment -> driver_act_ver = connection -> driver_act_ver;
1417
1418 env_lib_list -> env_handle = connection -> driver_env;
1419
1420 if ( ret )
1421 {
1422 dm_log_write( __FILE__,
1423 __LINE__,
1424 LOG_INFO,
1425 LOG_INFO,
1426 "Error: IM004" );
1427
1428 __post_internal_error( &connection -> error,
1429 ERROR_IM004, NULL,
1430 connection -> environment -> requested_version );
1431
1432 if ( env_lib_list -> count == 1 )
1433 {
1434 if ( env_lib_prev )
1435 {
1436 env_lib_prev -> next = env_lib_list -> next;
1437 }
1438 else
1439 {
1440 connection -> environment -> env_lib_list = env_lib_list -> next;
1441 }
1442
1443 free( env_lib_list -> lib_name );
1444 free( env_lib_list );
1445 }
1446 else
1447 {
1448 env_lib_list -> count --;
1449 }
1450
1451 mutex_lib_exit();
1452 return 0;
1453 }
1454
1455 /*
1456 * if it looks like a 3.x driver, try setting the interface type
1457 * to 3.x
1458 */
1459 if ( connection -> driver_act_ver >= SQL_OV_ODBC3 && CHECK_SQLSETENVATTR( connection ))
1460 {
1461 ret = SQLSETENVATTR( connection,
1462 connection -> driver_env,
1463 SQL_ATTR_ODBC_VERSION,
1464 connection -> environment -> requested_version,
1465 0 );
1466
1467 /*
1468 * if it don't set then assume a 2.x driver
1469 */
1470
1471 if ( ret )
1472 {
1473 connection -> driver_version = SQL_OV_ODBC2;
1474 }
1475 else
1476 {
1477 if ( CHECK_SQLGETENVATTR( connection ))
1478 {
1479 SQLINTEGER actual_version;
1480
1481 ret = SQLGETENVATTR( connection,
1482 connection -> driver_env,
1483 SQL_ATTR_ODBC_VERSION,
1484 &actual_version,
1485 0,
1486 NULL );
1487
1488 if ( !ret )
1489 {
1490 connection -> driver_version = actual_version;
1491 }
1492 else
1493 {
1494 connection -> driver_version =
1495 connection -> environment -> requested_version;
1496 }
1497 }
1498 else
1499 {
1500 connection -> driver_version =
1501 connection -> environment -> requested_version;
1502 }
1503 }
1504 }
1505 else
1506 {
1507 connection -> driver_version = SQL_OV_ODBC2;
1508 }
1509
1510 /*
1511 * set any env attributes
1512 */
1513 __set_attributes( connection, SQL_HANDLE_ENV );
1514 }
1515
1516 mutex_lib_exit();
1517
1518 /*
1519 * allocate a connection handle
1520 */
1521
1522 if ( connection -> driver_version >= SQL_OV_ODBC3 )
1523 {
1524 ret = SQL_SUCCESS;
1525
1526 if ( CHECK_SQLALLOCHANDLE( connection ))
1527 {
1528 ret = SQLALLOCHANDLE( connection,
1529 SQL_HANDLE_DBC,
1530 connection -> driver_env,
1531 &connection -> driver_dbc,
1532 connection );
1533
1534 if ( ret )
1535 {
1536 dm_log_write( __FILE__,
1537 __LINE__,
1538 LOG_INFO,
1539 LOG_INFO,
1540 "Error: IM005" );
1541
1542 __post_internal_error( &connection -> error,
1543 ERROR_IM005, NULL,
1544 connection -> environment -> requested_version );
1545 }
1546 }
1547 else if ( CHECK_SQLALLOCCONNECT( connection ))
1548 {
1549 ret = SQLALLOCCONNECT( connection,
1550 connection -> driver_env,
1551 &connection -> driver_dbc );
1552
1553 if ( ret )
1554 {
1555 dm_log_write( __FILE__,
1556 __LINE__,
1557 LOG_INFO,
1558 LOG_INFO,
1559 "Error: IM005" );
1560
1561 __post_internal_error( &connection -> error,
1562 ERROR_IM005, NULL,
1563 connection -> environment -> requested_version );
1564 }
1565 }
1566 else
1567 {
1568 dm_log_write( __FILE__,
1569 __LINE__,
1570 LOG_INFO,
1571 LOG_INFO,
1572 "Error: IM005" );
1573
1574 __post_internal_error( &connection -> error,
1575 ERROR_IM005, NULL,
1576 connection -> environment -> requested_version );
1577 return 0;
1578 }
1579
1580 if ( ret )
1581 {
1582 SQLCHAR sqlstate[ 6 ];
1583 SQLINTEGER native_error;
1584 SQLSMALLINT ind;
1585 SQLCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
1586 SQLRETURN ret;
1587
1588 /*
1589 * get the errors from the driver before
1590 * loseing the connection
1591 */
1592
1593 if ( CHECK_SQLGETDIAGREC( connection ))
1594 {
1595 int rec = 1;
1596
1597 do
1598 {
1599 ret = SQLGETDIAGREC( connection,
1600 SQL_HANDLE_ENV,
1601 connection -> driver_env,
1602 rec ++,
1603 sqlstate,
1604 &native_error,
1605 message_text,
1606 sizeof( message_text ),
1607 &ind );
1608
1609
1610 if ( SQL_SUCCEEDED( ret ))
1611 {
1612 __post_internal_error_ex( &connection -> error,
1613 sqlstate,
1614 native_error,
1615 message_text,
1616 SUBCLASS_ODBC, SUBCLASS_ODBC );
1617
1618 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1619 sqlstate, message_text );
1620
1621 dm_log_write_diag( connection -> msg );
1622 }
1623 }
1624 while( SQL_SUCCEEDED( ret ));
1625 }
1626 else if ( CHECK_SQLERROR( connection ))
1627 {
1628 do
1629 {
1630 ret = SQLERROR( connection,
1631 connection -> driver_env,
1632 SQL_NULL_HDBC,
1633 SQL_NULL_HSTMT,
1634 sqlstate,
1635 &native_error,
1636 message_text,
1637 sizeof( message_text ),
1638 &ind );
1639
1640
1641 if ( SQL_SUCCEEDED( ret ))
1642 {
1643 __post_internal_error_ex( &connection -> error,
1644 sqlstate,
1645 native_error,
1646 message_text,
1647 SUBCLASS_ODBC, SUBCLASS_ODBC );
1648
1649 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1650 sqlstate, message_text );
1651
1652 dm_log_write_diag( connection -> msg );
1653 }
1654 }
1655 while( SQL_SUCCEEDED( ret ));
1656 }
1657 return 0;
1658 }
1659 }
1660 else
1661 {
1662 ret = SQL_SUCCESS;
1663
1664 if ( CHECK_SQLALLOCCONNECT( connection ))
1665 {
1666 ret = SQLALLOCCONNECT( connection,
1667 connection -> driver_env,
1668 &connection -> driver_dbc );
1669
1670 if ( ret )
1671 {
1672 dm_log_write( __FILE__,
1673 __LINE__,
1674 LOG_INFO,
1675 LOG_INFO,
1676 "Error: IM005" );
1677
1678 __post_internal_error( &connection -> error,
1679 ERROR_IM005, NULL,
1680 connection -> environment -> requested_version );
1681 }
1682 }
1683 else if ( CHECK_SQLALLOCHANDLE( connection ))
1684 {
1685 ret = SQLALLOCHANDLE( connection,
1686 SQL_HANDLE_DBC,
1687 connection -> driver_env,
1688 &connection -> driver_dbc,
1689 connection );
1690
1691 if ( ret )
1692 {
1693 dm_log_write( __FILE__,
1694 __LINE__,
1695 LOG_INFO,
1696 LOG_INFO,
1697 "Error: IM005" );
1698
1699 __post_internal_error( &connection -> error,
1700 ERROR_IM005, NULL,
1701 connection -> environment -> requested_version );
1702 }
1703 }
1704 else
1705 {
1706 dm_log_write( __FILE__,
1707 __LINE__,
1708 LOG_INFO,
1709 LOG_INFO,
1710 "Error: IM005" );
1711
1712 __post_internal_error( &connection -> error,
1713 ERROR_IM005, NULL,
1714 connection -> environment -> requested_version );
1715 return 0;
1716 }
1717
1718 if ( ret )
1719 {
1720 SQLCHAR sqlstate[ 6 ];
1721 SQLINTEGER native_error;
1722 SQLSMALLINT ind;
1723 SQLCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
1724 SQLRETURN ret;
1725
1726 /*
1727 * get the errors from the driver before
1728 * loseing the connection
1729 */
1730
1731 if ( CHECK_SQLERROR( connection ))
1732 {
1733 do
1734 {
1735 ret = SQLERROR( connection,
1736 connection -> driver_env,
1737 SQL_NULL_HDBC,
1738 SQL_NULL_HSTMT,
1739 sqlstate,
1740 &native_error,
1741 message_text,
1742 sizeof( message_text ),
1743 &ind );
1744
1745
1746 if ( SQL_SUCCEEDED( ret ))
1747 {
1748 __post_internal_error_ex( &connection -> error,
1749 sqlstate,
1750 native_error,
1751 message_text,
1752 SUBCLASS_ODBC, SUBCLASS_ODBC );
1753
1754 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1755 sqlstate, message_text );
1756
1757 dm_log_write_diag( connection -> msg );
1758 }
1759 }
1760 while( SQL_SUCCEEDED( ret ));
1761 }
1762 else if ( CHECK_SQLGETDIAGREC( connection ))
1763 {
1764 int rec = 1;
1765
1766 do
1767 {
1768 ret = SQLGETDIAGREC( connection,
1769 SQL_HANDLE_ENV,
1770 connection -> driver_env,
1771 rec ++,
1772 sqlstate,
1773 &native_error,
1774 message_text,
1775 sizeof( message_text ),
1776 &ind );
1777
1778
1779 if ( SQL_SUCCEEDED( ret ))
1780 {
1781 __post_internal_error_ex( &connection -> error,
1782 sqlstate,
1783 native_error,
1784 message_text,
1785 SUBCLASS_ODBC, SUBCLASS_ODBC );
1786
1787 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
1788 sqlstate, message_text );
1789
1790 dm_log_write_diag( connection -> msg );
1791 }
1792 }
1793 while( SQL_SUCCEEDED( ret ));
1794 }
1795 return 0;
1796 }
1797 }
1798
1799 /*
1800 * set any connection atributes
1801 */
1802
1803 DO_ATTR( connection, access_mode, SQL_ATTR_ACCESS_MODE, SQL_ACCESS_MODE );
1804 DO_ATTR( connection, login_timeout, SQL_ATTR_LOGIN_TIMEOUT, SQL_LOGIN_TIMEOUT );
1805 DO_ATTR( connection, auto_commit, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT );
1806 DO_ATTR( connection, async_enable, SQL_ATTR_ASYNC_ENABLE, SQL_ASYNC_ENABLE );
1807 DO_ATTR( connection, auto_ipd, SQL_ATTR_AUTO_IPD, 0 );
1808 DO_ATTR( connection, connection_timeout, SQL_ATTR_CONNECTION_TIMEOUT, 0 );
1809 DO_ATTR( connection, metadata_id, SQL_ATTR_METADATA_ID, 0 );
1810 DO_ATTR( connection, packet_size, SQL_ATTR_PACKET_SIZE, SQL_PACKET_SIZE );
1811 DO_ATTR( connection, quite_mode, SQL_ATTR_QUIET_MODE, SQL_QUIET_MODE );
1812 DO_ATTR( connection, txn_isolation, SQL_ATTR_TXN_ISOLATION, SQL_TXN_ISOLATION );
1813
1814 while ( connection -> save_attr )
1815 {
1816 struct save_attr *sa;
1817
1818 sa = connection -> save_attr;
1819
1820 if ( sa -> str_attr )
1821 {
1822 if (CHECK_SQLSETCONNECTATTR( connection ))
1823 {
1824 SQLSETCONNECTATTR(connection,
1825 connection -> driver_dbc,
1826 sa -> attr_type,
1827 sa -> str_attr,
1828 sa -> str_len );
1829 }
1830 else if (CHECK_SQLSETCONNECTOPTION(connection))
1831 {
1832 SQLSETCONNECTOPTION(connection,
1833 connection -> driver_dbc,
1834 sa -> attr_type,
1835 sa -> str_attr );
1836 }
1837
1838 free( sa -> str_attr );
1839 }
1840 else
1841 {
1842 if (CHECK_SQLSETCONNECTATTR( connection ))
1843 {
1844 SQLSETCONNECTATTR(connection,
1845 connection -> driver_dbc,
1846 sa -> attr_type,
1847 sa -> int_attr,
1848 sa -> str_len );
1849 }
1850 else if (CHECK_SQLSETCONNECTOPTION(connection))
1851 {
1852 SQLSETCONNECTOPTION(connection,
1853 connection -> driver_dbc,
1854 sa -> attr_type,
1855 sa -> int_attr );
1856 }
1857 }
1858
1859 connection -> save_attr = sa -> next;
1860 free( sa );
1861 }
1862
1863 /*
1864 * set any preset connection attributes
1865 */
1866
1867 __set_attributes( connection, SQL_HANDLE_DBC );
1868
1869 return 1;
1870}
1871
1872/*
1873 * extract the available functions and call SQLSetConnectAttr
1874 */
1875
1876int __connect_part_two( DMHDBC connection )
1877{
1878 int i, use_cursor;
1879
1880 /*
1881 * Call SQLFunctions to get the supported list and
1882 * mask out those that are exported but not supported
1883 */
1884
1885 if ( CHECK_SQLGETFUNCTIONS( connection ) && !connection -> disable_gf )
1886 {
1887 SQLRETURN ret;
1888 SQLUSMALLINT supported_funcs[ SQL_API_ODBC3_ALL_FUNCTIONS_SIZE ];
1889 SQLUSMALLINT supported_array[ 100 ];
1890
1891 /*
1892 * try using fast version, but only if the driver is set to ODBC 3,
1893 * some drivers (SAPDB) fail to return the correct values in this situation
1894 */
1895
1896 if ( connection -> driver_act_ver >= SQL_OV_ODBC3 )
1897 {
1898 ret = SQLGETFUNCTIONS( connection,
1899 connection -> driver_dbc,
1900 SQL_API_ODBC3_ALL_FUNCTIONS,
1901 supported_funcs );
1902 }
1903 else
1904 {
1905 ret = SQLGETFUNCTIONS( connection,
1906 connection -> driver_dbc,
1907 SQL_API_ALL_FUNCTIONS,
1908 supported_array );
1909 }
1910
1911 if ( ret == SQL_SUCCESS )
1912 {
1913 for ( i = 0;
1914 i < sizeof( template_func ) / sizeof( template_func[ 0 ] );
1915 i ++ )
1916 {
1917 if ( connection -> functions[ i ].func )
1918 {
1919 SQLRETURN ret;
1920 SQLUSMALLINT supported;
1921
1922 if ( connection -> driver_act_ver >= SQL_OV_ODBC3 )
1923 {
1924 supported = SQL_FUNC_EXISTS( supported_funcs, connection -> functions[ i ].ordinal );
1925
1926 if ( supported == SQL_FALSE )
1927 {
1928 connection -> functions[ i ].func = NULL;
1929 connection -> functions[ i ].can_supply = 0;
1930 }
1931 }
1932 else
1933 {
1934 if ( connection -> functions[ i ].ordinal >= 100 )
1935 {
1936 ret = SQLGETFUNCTIONS( connection,
1937 connection -> driver_dbc,
1938 connection -> functions[ i ].ordinal,
1939 &supported );
1940 }
1941 else
1942 {
1943 supported = supported_array[ connection -> functions[ i ].ordinal ];
1944 ret = SQL_SUCCESS;
1945 }
1946
1947 if ( supported == SQL_FALSE || ret != SQL_SUCCESS )
1948 {
1949 connection -> functions[ i ].func = NULL;
1950 connection -> functions[ i ].can_supply = 0;
1951 }
1952 }
1953 }
1954 }
1955 }
1956 else
1957 {
1958 for ( i = 0;
1959 i < sizeof( template_func ) / sizeof( template_func[ 0 ] );
1960 i ++ )
1961 {
1962 if ( connection -> functions[ i ].func )
1963 {
1964 SQLRETURN ret;
1965 SQLUSMALLINT supported;
1966
1967 ret = SQLGETFUNCTIONS( connection,
1968 connection -> driver_dbc,
1969 connection -> functions[ i ].ordinal,
1970 &supported );
1971
1972 if ( supported == SQL_FALSE || ret != SQL_SUCCESS )
1973 {
1974 connection -> functions[ i ].func = NULL;
1975 connection -> functions[ i ].can_supply = 0;
1976 }
1977 }
1978 }
1979 }
1980 }
1981
1982 /*
1983 * CoLAttributes is the same as ColAttribute
1984 */
1985
1986 if ( connection -> functions[ DM_SQLCOLATTRIBUTE ].func &&
1987 !connection -> functions[ DM_SQLCOLATTRIBUTES ].func )
1988 {
1989 connection -> functions[ DM_SQLCOLATTRIBUTES ].can_supply = 1;
1990 }
1991 if ( connection -> functions[ DM_SQLCOLATTRIBUTES ].func &&
1992 !connection -> functions[ DM_SQLCOLATTRIBUTE ].func )
1993 {
1994 connection -> functions[ DM_SQLCOLATTRIBUTE ].can_supply = 1;
1995 }
1996
1997 /*
1998 * mark the functions that the driver manager does
1999 */
2000
2001 /*
2002 * SQLDatasources
2003 */
2004 connection -> functions[ DM_SQLDATASOURCES ].can_supply = 1;
2005
2006 /*
2007 * SQLDrivers
2008 */
2009 connection -> functions[ DM_SQLDRIVERS ].can_supply = 1;
2010
2011 /*
2012 * SQLAllocHandleStd
2013 */
2014 connection -> functions[ DM_SQLALLOCHANDLESTD ].can_supply = 1;
2015
2016 /*
2017 * add all the functions that are supported via ODBC 2<->3
2018 * issues
2019 */
2020 if ( !connection -> functions[ DM_SQLALLOCENV ].func &&
2021 connection -> functions[ DM_SQLALLOCHANDLE ].func )
2022 {
2023 connection -> functions[ DM_SQLALLOCENV ].can_supply = 1;
2024 }
2025 if ( !connection -> functions[ DM_SQLALLOCCONNECT ].func &&
2026 connection -> functions[ DM_SQLALLOCHANDLE ].func )
2027 {
2028 connection -> functions[ DM_SQLALLOCCONNECT ].can_supply = 1;
2029 }
2030 if ( !connection -> functions[ DM_SQLALLOCSTMT ].func &&
2031 connection -> functions[ DM_SQLALLOCHANDLE ].func )
2032 {
2033 connection -> functions[ DM_SQLALLOCSTMT ].can_supply = 1;
2034 }
2035 if ( !connection -> functions[ DM_SQLFREEENV ].func &&
2036 connection -> functions[ DM_SQLFREEHANDLE ].func )
2037 {
2038 connection -> functions[ DM_SQLFREEENV ].can_supply = 1;
2039 }
2040 if ( !connection -> functions[ DM_SQLFREECONNECT ].func &&
2041 connection -> functions[ DM_SQLFREEHANDLE ].func )
2042 {
2043 connection -> functions[ DM_SQLFREECONNECT ].can_supply = 1;
2044 }
2045 if ( !connection -> functions[ DM_SQLGETDIAGREC ].func &&
2046 connection -> functions[ DM_SQLERROR ].func )
2047 {
2048 connection -> functions[ DM_SQLGETDIAGREC ].can_supply = 1;
2049 }
2050 if ( !connection -> functions[ DM_SQLGETDIAGFIELD ].func &&
2051 connection -> functions[ DM_SQLERROR ].func )
2052 {
2053 connection -> functions[ DM_SQLGETDIAGFIELD ].can_supply = 1;
2054 }
2055 if ( !connection -> functions[ DM_SQLERROR ].func &&
2056 connection -> functions[ DM_SQLGETDIAGREC ].func )
2057 {
2058 connection -> functions[ DM_SQLERROR ].can_supply = 1;
2059 }
2060
2061 /*
2062 * ODBC 3 still needs SQLFreeStmt
2063 */
2064
2065 /*
2066 * this is only partial, as we can't support a descriptor alloc
2067 */
2068 if ( !connection -> functions[ DM_SQLALLOCHANDLE ].func &&
2069 connection -> functions[ DM_SQLALLOCENV ].func &&
2070 connection -> functions[ DM_SQLALLOCCONNECT ].func &&
2071 connection -> functions[ DM_SQLALLOCHANDLE ].func )
2072 {
2073 connection -> functions[ DM_SQLALLOCHANDLE ].can_supply = 1;
2074 }
2075 if ( !connection -> functions[ DM_SQLFREEHANDLE ].func &&
2076 connection -> functions[ DM_SQLFREEENV ].func &&
2077 connection -> functions[ DM_SQLFREECONNECT ].func &&
2078 connection -> functions[ DM_SQLFREEHANDLE ].func )
2079 {
2080 connection -> functions[ DM_SQLFREEHANDLE ].can_supply = 1;
2081 }
2082
2083 if ( !connection -> functions[ DM_SQLBINDPARAM ].func &&
2084 connection -> functions[ DM_SQLBINDPARAMETER ].func )
2085 {
2086 connection -> functions[ DM_SQLBINDPARAM ].can_supply = 1;
2087 }
2088 else if ( !connection -> functions[ DM_SQLBINDPARAMETER ].func &&
2089 connection -> functions[ DM_SQLBINDPARAM ].func )
2090 {
2091 connection -> functions[ DM_SQLBINDPARAMETER ].can_supply = 1;
2092 }
2093
2094 if ( !connection -> functions[ DM_SQLGETCONNECTOPTION ].func &&
2095 connection -> functions[ DM_SQLGETCONNECTATTR ].func )
2096 {
2097 connection -> functions[ DM_SQLGETCONNECTOPTION ].can_supply = 1;
2098 }
2099 else if ( !connection -> functions[ DM_SQLGETCONNECTATTR ].func &&
2100 connection -> functions[ DM_SQLGETCONNECTOPTION ].func )
2101 {
2102 connection -> functions[ DM_SQLGETCONNECTATTR ].can_supply = 1;
2103 }
2104
2105 if ( !connection -> functions[ DM_SQLGETSTMTOPTION ].func &&
2106 connection -> functions[ DM_SQLGETSTMTATTR ].func )
2107 {
2108 connection -> functions[ DM_SQLGETSTMTOPTION ].can_supply = 1;
2109 }
2110 else if ( !connection -> functions[ DM_SQLGETSTMTATTR ].func &&
2111 connection -> functions[ DM_SQLGETSTMTOPTION ].func )
2112 {
2113 connection -> functions[ DM_SQLGETSTMTATTR ].can_supply = 1;
2114 }
2115
2116 if ( !connection -> functions[ DM_SQLPARAMOPTIONS ].func &&
2117 connection -> functions[ DM_SQLSETSTMTATTR ].func )
2118 {
2119 connection -> functions[ DM_SQLPARAMOPTIONS ].can_supply = 1;
2120 }
2121
2122 if ( !connection -> functions[ DM_SQLSETCONNECTOPTION ].func &&
2123 connection -> functions[ DM_SQLSETCONNECTATTR ].func )
2124 {
2125 connection -> functions[ DM_SQLSETCONNECTOPTION ].can_supply = 1;
2126 }
2127 else if ( !connection -> functions[ DM_SQLSETCONNECTATTR ].func &&
2128 connection -> functions[ DM_SQLSETCONNECTOPTION ].func )
2129 {
2130 connection -> functions[ DM_SQLSETCONNECTATTR ].can_supply = 1;
2131 }
2132
2133 if ( !connection -> functions[ DM_SQLSETPARAM ].func &&
2134 connection -> functions[ DM_SQLBINDPARAMETER ].func )
2135 {
2136 connection -> functions[ DM_SQLSETPARAM ].can_supply = 1;
2137 }
2138
2139 if ( !connection -> functions[ DM_SQLSETSCROLLOPTIONS ].func &&
2140 connection -> functions[ DM_SQLSETSTMTATTR ].func )
2141 {
2142 connection -> functions[ DM_SQLSETSCROLLOPTIONS ].can_supply = 1;
2143 }
2144
2145 if ( !connection -> functions[ DM_SQLSETSTMTOPTION ].func &&
2146 connection -> functions[ DM_SQLSETSTMTATTR ].func )
2147 {
2148 connection -> functions[ DM_SQLSETSTMTOPTION ].can_supply = 1;
2149 }
2150 else if ( !connection -> functions[ DM_SQLSETSTMTATTR ].func &&
2151 connection -> functions[ DM_SQLSETSTMTOPTION ].func )
2152 {
2153 connection -> functions[ DM_SQLSETSTMTATTR ].can_supply = 1;
2154 }
2155
2156 if ( !connection -> functions[ DM_SQLTRANSACT ].func &&
2157 connection -> functions[ DM_SQLENDTRAN ].func )
2158 {
2159 connection -> functions[ DM_SQLTRANSACT ].can_supply = 1;
2160 }
2161 else if ( !connection -> functions[ DM_SQLENDTRAN ].func &&
2162 connection -> functions[ DM_SQLTRANSACT ].func )
2163 {
2164 connection -> functions[ DM_SQLENDTRAN ].can_supply = 1;
2165 }
2166
2167 /*
2168 * we can always do this
2169 */
2170
2171 if ( !connection -> functions[ DM_SQLGETFUNCTIONS ].func )
2172 {
2173 connection -> functions[ DM_SQLGETFUNCTIONS ].can_supply = 1;
2174 }
2175
2176 /*
2177 * TO_DO get some driver settings, such as the GETDATA_EXTENSTION
2178 * it supports
2179 */
2180
2181 if ( CHECK_SQLGETINFO( connection ) || CHECK_SQLGETINFOW( connection ))
2182 {
2183 char txt[ 20 ];
2184 SQLRETURN ret;
2185
2186 if ( connection -> driver_act_ver >= SQL_OV_ODBC3 )
2187 {
2188 ret = __SQLGetInfo( connection,
2189 SQL_XOPEN_CLI_YEAR,
2190 txt,
2191 sizeof( connection -> cli_year ),
2192 NULL );
2193
2194 if ( SQL_SUCCEEDED( ret ))
2195 {
2196 strcpy( connection -> cli_year, txt );
2197 }
2198 }
2199 }
2200
2201 /*
2202 * TO_DO now we should pass any SQLSetEnvAttr settings
2203 */
2204
2205 /*
2206 * now we have a connection handle, and we can check to see if
2207 * we need to use the cursor library
2208 */
2209
2210 if ( connection -> cursors == SQL_CUR_USE_ODBC )
2211 {
2212 use_cursor = 1;
2213 }
2214 else if ( connection -> cursors == SQL_CUR_USE_IF_NEEDED )
2215 {
2216 /*
2217 * get scrollable info
2218 */
2219
2220 if ( !CHECK_SQLGETINFO( connection ) && !CHECK_SQLGETINFOW( connection ))
2221 {
2222 /*
2223 * bit of a retarded driver, better give up
2224 */
2225 use_cursor = 0;
2226 }
2227 else
2228 {
2229 SQLRETURN ret;
2230 SQLUINTEGER val;
2231
2232 /*
2233 * check if static cursors support scrolling
2234 */
2235
2236 if ( connection -> driver_act_ver >=
2237 SQL_OV_ODBC3 )
2238 {
2239 ret = __SQLGetInfo( connection,
2240 SQL_STATIC_CURSOR_ATTRIBUTES1,
2241 &val,
2242 sizeof( val ),
2243 NULL );
2244
2245 if ( ret != SQL_SUCCESS )
2246 {
2247 use_cursor = 1;
2248 }
2249 else
2250 {
2251 /*
2252 * do we need it ?
2253 */
2254 if ( !( val & SQL_CA1_ABSOLUTE ))
2255 {
2256 use_cursor = 1;
2257 }
2258 else
2259 {
2260 use_cursor = 0;
2261 }
2262 }
2263 }
2264 else
2265 {
2266 ret = __SQLGetInfo( connection,
2267 SQL_FETCH_DIRECTION,
2268 &val,
2269 sizeof( val ),
2270 NULL );
2271
2272 if ( ret != SQL_SUCCESS )
2273 {
2274 use_cursor = 1;
2275 }
2276 else
2277 {
2278 /*
2279 * are we needed
2280 */
2281
2282 if ( !( val & SQL_FD_FETCH_PRIOR ))
2283 {
2284 use_cursor = 1;
2285 }
2286 else
2287 {
2288 use_cursor = 0;
2289 }
2290 }
2291 }
2292 }
2293 }
2294 else
2295 {
2296 use_cursor = 0;
2297 }
2298
2299 /*
2300 * if required connect to the cursor lib
2301 */
2302
2303 if ( use_cursor )
2304 {
2305 char ext[ 32 ];
2306 char name[ ODBC_FILENAME_MAX * 2 + 1 ];
2307 int (*cl_connect)(void*, struct driver_helper_funcs*);
2308 char *err;
2309 struct driver_helper_funcs dh;
2310
2311 /*
2312 * SHLIBEXT can end up unset on some distributions (suze)
2313 */
2314
2315 if ( strlen( SHLIBEXT ) == 0 )
2316 {
2317 strcpy( ext, ".so" );
2318 }
2319 else
2320 {
2321 if ( strlen( SHLIBEXT ) + 1 > sizeof( ext )) {
2322 fprintf( stderr, "internal error, unexpected SHLIBEXT value ('%s') may indicate a problem with configure\n", SHLIBEXT );
2323 abort();
2324 }
2325 strcpy( ext, SHLIBEXT );
2326 }
2327
2328#ifdef CURSOR_LIB_VER
2329 sprintf( name, "%s%s.%s", CURSOR_LIB, ext, CURSOR_LIB_VER );
2330#else
2331 sprintf( name, "%s%s", CURSOR_LIB, ext );
2332#endif
2333
2334 if ( !(connection -> cl_handle = odbc_dlopen( name, &err )))
2335 {
2336 char b1[ ODBC_FILENAME_MAX + 1 ];
2337 /*
2338 * try again
2339 */
2340
2341#ifdef CURSOR_LIB_VER
2342#ifdef __VMS
2343 sprintf( name, "%s:%s%s.%s", odbcinst_system_file_path( b1 ), CURSOR_LIB, ext, CURSOR_LIB_VER );
2344#else
2345#ifdef __OS2__
2346 /* OS/2 does not use the system_lib_path or version defines to construct a name */
2347 sprintf( name, "%s.%s", CURSOR_LIB, ext );
2348#else
2349 sprintf( name, "%s/%s%s.%s", odbcinst_system_file_path( b1 ), CURSOR_LIB, ext, CURSOR_LIB_VER );
2350#endif
2351#endif
2352#else
2353#ifdef __VMS
2354 sprintf( name, "%s:%s%s", odbcinst_system_file_path( b1 ), CURSOR_LIB, ext );
2355#else
2356#ifdef __OS2__
2357 /* OS/2 does not use the system_lib_path or version defines to construct a name */
2358 sprintf( name, "%s%s", CURSOR_LIB, ext );
2359#else
2360 sprintf( name, "%s/%s%s", odbcinst_system_file_path( b1 ), CURSOR_LIB, ext );
2361#endif
2362#endif
2363#endif
2364 if ( !(connection -> cl_handle = odbc_dlopen( name, &err )))
2365 {
2366 char txt[ 256 ];
2367
2368 sprintf( txt, "Can't open cursor lib '%s' : %s",
2369 name, err ? err : "NULL ERROR RETURN" );
2370
2371 dm_log_write( __FILE__,
2372 __LINE__,
2373 LOG_INFO,
2374 LOG_INFO,
2375 txt );
2376
2377 __post_internal_error( &connection -> error,
2378 ERROR_01000, txt,
2379 connection -> environment -> requested_version );
2380
2381 return 0;
2382 }
2383 }
2384
2385 if ( !( cl_connect = (int(*)(void*, struct driver_helper_funcs* ))lt_dlsym( connection -> cl_handle,
2386 "CLConnect" )))
2387 {
2388 dm_log_write( __FILE__,
2389 __LINE__,
2390 LOG_INFO,
2391 LOG_INFO,
2392 "Error: 01000 Unable to load Cursor Lib" );
2393
2394 __post_internal_error( &connection -> error,
2395 ERROR_01000, "Unable to load cursor library",
2396 connection -> environment -> requested_version );
2397
2398 odbc_dlclose( connection -> cl_handle );
2399 connection -> cl_handle = NULL;
2400
2401 return 0;
2402 }
2403
2404 /*
2405 * setup helper functions
2406 */
2407
2408 dh.__post_internal_error_ex = __post_internal_error_ex;
2409 dh.__post_internal_error = __post_internal_error;
2410 dh.dm_log_write = dm_log_write;
2411
2412 if ( cl_connect( connection, &dh ) != SQL_SUCCESS )
2413 {
2414 odbc_dlclose( connection -> cl_handle );
2415 connection -> cl_handle = NULL;
2416 return 0;
2417 }
2418 }
2419 else
2420 {
2421 connection -> cl_handle = NULL;
2422 }
2423
2424 return 1;
2425}
2426
2427static void release_env( DMHDBC connection )
2428{
2429 struct env_lib_struct *env_lib_list, *env_lib_prev;
2430 int ret;
2431
2432 if ( connection -> driver_env )
2433 {
2434 env_lib_prev = env_lib_list = NULL;
2435
2436 mutex_lib_entry();
2437
2438 if ( connection -> env_list_ent && connection -> environment )
2439 {
2440 env_lib_list = connection -> environment -> env_lib_list;
2441 while( env_lib_list )
2442 {
2443 if ( env_lib_list == connection -> env_list_ent )
2444 {
2445 break;
2446 }
2447 env_lib_prev = env_lib_list;
2448 env_lib_list = env_lib_list -> next;
2449 }
2450 }
2451
2452 if ( env_lib_list && env_lib_list -> count > 1 )
2453 {
2454 env_lib_list -> count --;
2455 }
2456 else
2457 {
2458 if ( connection -> driver_version >= SQL_OV_ODBC3 )
2459 {
2460 ret = SQL_ERROR;
2461 if ( CHECK_SQLFREEHANDLE( connection ))
2462 {
2463 ret = SQLFREEHANDLE( connection,
2464 SQL_HANDLE_ENV,
2465 connection -> driver_env );
2466 }
2467 else if ( CHECK_SQLFREEENV( connection ))
2468 {
2469 ret = SQLFREEENV( connection,
2470 connection -> driver_env );
2471 }
2472 if ( !ret )
2473 connection -> driver_env = (DRV_SQLHANDLE)NULL;
2474 }
2475 else
2476 {
2477 ret = SQL_ERROR;
2478 if ( CHECK_SQLFREEENV( connection ))
2479 {
2480 ret = SQLFREEENV( connection,
2481 connection -> driver_env );
2482 }
2483 else if ( CHECK_SQLFREEHANDLE( connection ))
2484 {
2485 ret = SQLFREEHANDLE( connection,
2486 SQL_HANDLE_ENV,
2487 connection -> driver_env );
2488 }
2489
2490 if ( !ret )
2491 connection -> driver_env = (DRV_SQLHANDLE)NULL;
2492 }
2493
2494 /*
2495 * remove the entry
2496 */
2497
2498 if ( env_lib_prev )
2499 {
2500 env_lib_prev -> next = env_lib_list -> next;
2501 }
2502 else
2503 {
2504 if ( env_lib_list )
2505 {
2506 connection -> environment -> env_lib_list = env_lib_list -> next;
2507 }
2508 }
2509
2510 if ( env_lib_list )
2511 {
2512 free( env_lib_list -> lib_name );
2513 free( env_lib_list );
2514 }
2515 }
2516
2517 mutex_lib_exit();
2518 }
2519}
2520
2521/*
2522 * clean up after the first part of the connect
2523 */
2524
2525void __disconnect_part_one( DMHDBC connection )
2526{
2527 int ret = SQL_ERROR;
2528
2529 /*
2530 * try a version 3 disconnect first on the connection
2531 */
2532 if ( connection -> driver_dbc )
2533 {
2534 if ( connection -> driver_version >= SQL_OV_ODBC3 )
2535 {
2536 if ( CHECK_SQLFREEHANDLE( connection ))
2537 {
2538 ret = SQLFREEHANDLE( connection,
2539 SQL_HANDLE_DBC,
2540 connection -> driver_dbc );
2541 }
2542 else if ( CHECK_SQLFREECONNECT( connection ))
2543 {
2544 ret = SQLFREECONNECT( connection,
2545 connection -> driver_dbc );
2546 }
2547
2548 if ( !ret )
2549 {
2550 connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
2551 }
2552 }
2553 else
2554 {
2555 if ( CHECK_SQLFREECONNECT( connection ))
2556 {
2557 ret = SQLFREECONNECT( connection,
2558 connection -> driver_dbc );
2559 }
2560 else if ( CHECK_SQLFREEHANDLE( connection ))
2561 {
2562 ret = SQLFREEHANDLE( connection,
2563 SQL_HANDLE_DBC,
2564 connection -> driver_dbc );
2565 }
2566
2567 if ( !ret )
2568 {
2569 connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
2570 }
2571 }
2572 connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
2573 }
2574
2575 /*
2576 * now disconnect the environment, if it's the last usage on the connection
2577 */
2578
2579 if ( connection -> driver_env )
2580 {
2581 release_env( connection );
2582 }
2583
2584 connection -> driver_env = (DRV_SQLHANDLE)NULL;
2585
2586 /*
2587 * unload the lib
2588 */
2589 if ( connection -> cl_handle )
2590 {
2591 odbc_dlclose( connection -> cl_handle );
2592 connection -> cl_handle = NULL;
2593 }
2594
2595 if ( connection -> dl_handle )
2596 {
2597 if ( !connection -> dont_dlclose )
2598 {
2599 /*
2600 * call fini function if found
2601 */
2602
2603 if ( connection -> fini_func.func )
2604 {
2605 connection -> fini_func.func();
2606 }
2607
2608 odbc_dlclose( connection -> dl_handle );
2609 }
2610 connection -> dl_handle = NULL;
2611 }
2612
2613 /*
2614 * free some memory
2615 */
2616
2617 if ( connection -> functions )
2618 {
2619 free( connection -> functions );
2620 connection -> functions = NULL;
2621 }
2622}
2623
2624void __disconnect_part_two( DMHDBC connection )
2625{
2626 if ( CHECK_SQLDISCONNECT( connection ))
2627 {
2628 SQLDISCONNECT( connection,
2629 connection -> driver_dbc );
2630 }
2631}
2632
2633/*
2634 * final clean up
2635 */
2636
2637void __disconnect_part_four( DMHDBC connection )
2638{
2639 /*
2640 * now disconnect the environment, if it's the last usage on the connection
2641 */
2642
2643 release_env( connection );
2644
2645 connection -> driver_env = (DRV_SQLHANDLE)NULL;
2646
2647 /*
2648 * unload the lib
2649 */
2650
2651 if ( connection -> cl_handle )
2652 {
2653 odbc_dlclose( connection -> cl_handle );
2654 connection -> cl_handle = NULL;
2655 }
2656
2657 if ( connection -> dl_handle )
2658 {
2659 /*
2660 * this is safe, because the dlopen function will reuse the handle if we
2661 * open the same lib again
2662 */
2663 if ( !connection -> dont_dlclose )
2664 {
2665 if ( connection -> fini_func.func )
2666 {
2667 connection -> fini_func.func();
2668 }
2669
2670 odbc_dlclose( connection -> dl_handle );
2671 }
2672 connection -> dl_handle = NULL;
2673 }
2674
2675 /*
2676 * free some memory
2677 */
2678
2679 if ( connection -> functions )
2680 {
2681 free( connection -> functions );
2682 connection -> functions = NULL;
2683 }
2684 connection -> state = STATE_C2;
2685
2686 /*
2687 * now clean up any statements that are left about
2688 */
2689
2690 __clean_stmt_from_dbc( connection );
2691 __clean_desc_from_dbc( connection );
2692}
2693
2694/*
2695 * normal disconnect
2696 */
2697
2698void __disconnect_part_three( DMHDBC connection )
2699{
2700 if ( connection -> driver_version >= SQL_OV_ODBC3 )
2701 {
2702 if ( CHECK_SQLFREEHANDLE( connection ))
2703 {
2704 SQLFREEHANDLE( connection,
2705 SQL_HANDLE_DBC,
2706 connection -> driver_dbc );
2707 }
2708 else if ( CHECK_SQLFREECONNECT( connection ))
2709 {
2710 SQLFREECONNECT( connection,
2711 connection -> driver_dbc );
2712 }
2713 }
2714 else
2715 {
2716 if ( CHECK_SQLFREECONNECT( connection ))
2717 {
2718 SQLFREECONNECT( connection,
2719 connection -> driver_dbc );
2720 }
2721 else if ( CHECK_SQLFREEHANDLE( connection ))
2722 {
2723 SQLFREEHANDLE( connection,
2724 SQL_HANDLE_DBC,
2725 connection -> driver_dbc );
2726 }
2727 }
2728
2729 connection -> driver_dbc = (DRV_SQLHANDLE)NULL;
2730
2731 __disconnect_part_four( connection );
2732}
2733
2734/*
2735 * interface for SQLGetFunctions
2736 */
2737
2738void __check_for_function( DMHDBC connection,
2739 SQLUSMALLINT function_id,
2740 SQLUSMALLINT *supported )
2741{
2742 int i;
2743
2744 if ( !supported )
2745 {
2746 return;
2747 }
2748
2749 if ( function_id == SQL_API_ODBC3_ALL_FUNCTIONS )
2750 {
2751 for ( i = 0; i < SQL_API_ODBC3_ALL_FUNCTIONS_SIZE; i ++ )
2752 {
2753 supported[ i ] = 0x0000;
2754 }
2755 for ( i = 0; i < sizeof( template_func ) / sizeof( template_func[ 0 ] ); i ++ )
2756 {
2757 int id = connection -> functions[ i ].ordinal;
2758
2759 if ( connection -> functions[ i ].can_supply )
2760 supported[ id >> 4 ] |= ( 1 << ( id & 0x000F ));
2761 }
2762 }
2763 else if ( function_id == SQL_API_ALL_FUNCTIONS )
2764 {
2765 for ( i = 0; i < 100; i ++ )
2766 {
2767 supported[ i ] = SQL_FALSE;
2768 }
2769 for ( i = 0; i < sizeof( template_func ) / sizeof( template_func[ 0 ] ); i ++ )
2770 {
2771 if ( connection -> functions[ i ].ordinal < 100 )
2772 {
2773 if ( connection -> functions[ i ].can_supply )
2774 supported[ connection -> functions[ i ].ordinal ] =
2775 SQL_TRUE;
2776 }
2777 }
2778 }
2779 else
2780 {
2781 *supported = SQL_FALSE;
2782 for ( i = 0; i < sizeof( template_func ) / sizeof( template_func[ 0 ] ); i ++ )
2783 {
2784 if ( connection->functions[ i ].ordinal == function_id )
2785 {
2786 if ( connection -> functions[ i ].can_supply )
2787 *supported = SQL_TRUE;
2788 break;
2789 }
2790 }
2791 }
2792}
2793
2794static int sql_strcmp( SQLCHAR *s1, SQLCHAR *s2, SQLSMALLINT l1, SQLSMALLINT l2 )
2795{
2796 if ( l1 != l2 )
2797 {
2798 return 1;
2799 }
2800
2801 if ( l1 == SQL_NTS )
2802 {
2803 return strcmp((char*) s1, (char*)s2 );
2804 }
2805 else
2806 {
2807 return memcmp( s1, s2, l1 );
2808 }
2809}
2810
2811static void close_pooled_connection( CPOOL *ptr )
2812{
2813 SQLRETURN ret;
2814
2815 /*
2816 * disconnect from the driver
2817 */
2818
2819 if ( !CHECK_SQLDISCONNECT(( &ptr->connection )))
2820 {
2821 return;
2822 }
2823
2824 ret = SQLDISCONNECT(( &ptr -> connection ),
2825 ptr -> connection.driver_dbc );
2826
2827 if ( SQL_SUCCEEDED( ret ))
2828 {
2829 /*
2830 * complete disconnection from driver
2831 */
2832
2833 if ( ptr -> connection.driver_version >= SQL_OV_ODBC3 )
2834 {
2835 if ( CHECK_SQLFREEHANDLE(( &ptr -> connection )))
2836 {
2837 SQLFREEHANDLE(( &ptr -> connection ),
2838 SQL_HANDLE_DBC,
2839 ptr -> connection.driver_dbc );
2840 }
2841 else if ( CHECK_SQLFREECONNECT(( &ptr -> connection )))
2842 {
2843 SQLFREECONNECT(( &ptr -> connection ),
2844 ptr -> connection.driver_dbc );
2845 }
2846 }
2847 else
2848 {
2849 if ( CHECK_SQLFREECONNECT(( &ptr -> connection )))
2850 {
2851 SQLFREECONNECT(( &ptr -> connection ),
2852 ptr -> connection.driver_dbc );
2853 }
2854 else if ( CHECK_SQLFREEHANDLE(( &ptr -> connection )))
2855 {
2856 SQLFREEHANDLE(( &ptr -> connection ),
2857 SQL_HANDLE_DBC,
2858 ptr -> connection.driver_dbc );
2859 }
2860 }
2861
2862 ptr -> connection.driver_dbc = (DRV_SQLHANDLE)NULL;
2863
2864 /*
2865 * Only call freeenv if it's the last connection to the driver
2866 */
2867
2868 release_env( &ptr -> connection );
2869
2870 ptr -> connection.driver_env = (DRV_SQLHANDLE)NULL;
2871
2872 /*
2873 * unload the lib
2874 */
2875
2876 if ( ptr -> connection.cl_handle )
2877 {
2878 odbc_dlclose( ptr -> connection.cl_handle );
2879 ptr -> connection.cl_handle = NULL;
2880 }
2881
2882 if ( ptr -> connection.dl_handle )
2883 {
2884 /*
2885 * this is safe, because the dlopen function will reuse the handle if we
2886 * open the same lib again
2887 */
2888 if ( !ptr -> connection.dont_dlclose )
2889 {
2890 /*
2891 * call fini function if found
2892 */
2893
2894 if ( ptr -> connection.fini_func.func )
2895 {
2896 ptr -> connection.fini_func.func();
2897 }
2898
2899 odbc_dlclose( ptr -> connection.dl_handle );
2900 }
2901 ptr -> connection.dl_handle = NULL;
2902 }
2903
2904 /*
2905 * free some memory
2906 */
2907
2908 if ( ptr -> connection.functions )
2909 {
2910 free( ptr -> connection.functions );
2911 ptr -> connection.functions = NULL;
2912 }
2913 }
2914 else
2915 {
2916 /*
2917 * All we can do is tidy up
2918 */
2919
2920 ptr -> connection.driver_dbc = (DRV_SQLHANDLE)NULL;
2921 ptr -> connection.driver_env = (DRV_SQLHANDLE)NULL;
2922
2923 /*
2924 * unload the lib
2925 */
2926
2927 if ( ptr -> connection.cl_handle )
2928 {
2929 odbc_dlclose( ptr -> connection.cl_handle );
2930 ptr -> connection.cl_handle = NULL;
2931 }
2932
2933 if ( ptr -> connection.dl_handle )
2934 {
2935 /*
2936 * this is safe, because the dlopen function will reuse the handle if we
2937 * open the same lib again
2938 */
2939 if ( !ptr -> connection.dont_dlclose )
2940 {
2941 /*
2942 * call fini function if found
2943 */
2944
2945 if ( ptr -> connection.fini_func.func )
2946 {
2947 ptr -> connection.fini_func.func();
2948 }
2949
2950 odbc_dlclose( ptr -> connection.dl_handle );
2951 }
2952 ptr -> connection.dl_handle = NULL;
2953 }
2954
2955 /*
2956 * free some memory
2957 */
2958
2959 if ( ptr -> connection.functions )
2960 {
2961 free( ptr -> connection.functions );
2962 ptr -> connection.functions = NULL;
2963 }
2964 }
2965
2966 /*
2967 * now clean up any statements that are left about
2968 */
2969
2970 __clean_stmt_from_dbc( &ptr -> connection );
2971 __clean_desc_from_dbc( &ptr -> connection );
2972}
2973
2974/*
2975 * if a environment gets released from the application, we need to remove any referenvce to that environment
2976 * in pooled connections that belong to that environment
2977 */
2978
2979void __strip_from_pool( DMHENV env )
2980{
2981 time_t current_time;
2982 SQLINTEGER dead;
2983 CPOOL *ptr, *prev;
2984 int has_checked = 0;
2985
2986 mutex_pool_entry();
2987
2988 current_time = time( NULL );
2989
2990 /*
2991 * look in the list of connections for one that matches
2992 */
2993
2994 for( ptr = pool_head, prev = NULL; ptr; prev = ptr, ptr = ptr -> next )
2995 {
2996 if ( ptr -> connection.environment == env ) {
2997
2998 ptr -> connection.environment = NULL;
2999 }
3000 }
3001
3002 mutex_pool_exit();
3003}
3004
3005
3006int search_for_pool( DMHDBC connection,
3007 SQLCHAR *server_name,
3008 SQLSMALLINT name_length1,
3009 SQLCHAR *user_name,
3010 SQLSMALLINT name_length2,
3011 SQLCHAR *authentication,
3012 SQLSMALLINT name_length3,
3013 SQLCHAR *connect_string,
3014 SQLSMALLINT connect_string_length )
3015{
3016 time_t current_time;
3017 SQLINTEGER dead;
3018 CPOOL *ptr, *prev;
3019 int has_checked = 0;
3020
3021 mutex_pool_entry();
3022
3023 current_time = time( NULL );
3024
3025 /*
3026 * look in the list of connections for one that matches
3027 */
3028
3029restart:;
3030
3031 for( ptr = pool_head, prev = NULL; ptr; prev = ptr, ptr = ptr -> next )
3032 {
3033 has_checked = 0;
3034
3035 if ( ptr -> in_use )
3036 {
3037 continue;
3038 }
3039
3040 /*
3041 * has it expired ? Do some cleaning up first
3042 */
3043
3044 if ( ptr -> expiry_time < current_time )
3045 {
3046 /*
3047 * disconnect and remove
3048 */
3049
3050 close_pooled_connection( ptr );
3051
3052 if ( prev )
3053 {
3054 prev -> next = ptr -> next;
3055 free( ptr );
3056 }
3057 else
3058 {
3059 pool_head = ptr -> next;
3060 free( ptr );
3061 }
3062
3063 goto restart;
3064 }
3065
3066 /*
3067 * has the time-to-live got to one ?
3068 */
3069
3070 if ( ptr -> ttl == 1 )
3071 {
3072 /*
3073 * disconnect and remove
3074 */
3075
3076 close_pooled_connection( ptr );
3077
3078 if ( prev )
3079 {
3080 prev -> next = ptr -> next;
3081 free( ptr );
3082 }
3083 else
3084 {
3085 pool_head = ptr -> next;
3086 free( ptr );
3087 }
3088
3089 goto restart;
3090 }
3091 else if ( ptr -> ttl > 1 )
3092 {
3093 ptr -> ttl --;
3094 }
3095
3096 if ( server_name )
3097 {
3098 if ( ptr -> server_length == 0 )
3099 {
3100 continue;
3101 }
3102 if ( ptr -> server_length != name_length1 ||
3103 sql_strcmp( server_name, (SQLCHAR*)ptr -> server,
3104 name_length1, ptr -> server_length ))
3105 {
3106 continue;
3107 }
3108 if ( ptr -> user_length != name_length2 ||
3109 sql_strcmp( user_name, (SQLCHAR*)ptr -> user,
3110 name_length2, ptr -> user_length ))
3111 {
3112 continue;
3113 }
3114 if ( ptr -> password_length != name_length3 ||
3115 sql_strcmp( authentication, (SQLCHAR*)ptr -> password,
3116 name_length3, ptr -> password_length ))
3117 {
3118 continue;
3119 }
3120 }
3121 else
3122 {
3123 if ( ptr -> dsn_length == 0 )
3124 {
3125 continue;
3126 }
3127 if ( ptr -> dsn_length != connect_string_length ||
3128 sql_strcmp( connect_string, (SQLCHAR*)ptr -> driver_connect_string,
3129 connect_string_length, ptr -> dsn_length ))
3130 {
3131 continue;
3132 }
3133 }
3134
3135 /*
3136 * is it the same cursor usage ?
3137 */
3138
3139 if ( ptr -> cursors != connection -> cursors )
3140 {
3141 continue;
3142 }
3143
3144
3145 /*
3146 * ok so far, is it still alive ?
3147 */
3148
3149 if ( CHECK_SQLGETCONNECTATTR(( &ptr -> connection )))
3150 {
3151 SQLRETURN ret;
3152
3153 ret = SQLGETCONNECTATTR(( &ptr -> connection ),
3154 ptr -> connection.driver_dbc,
3155 SQL_ATTR_CONNECTION_DEAD,
3156 &dead,
3157 0,
3158 0 );
3159
3160 /*
3161 * if it failed assume that it's because it doesn't support
3162 * it, but it's ok
3163 */
3164
3165 if ( SQL_SUCCEEDED( ret ))
3166 {
3167 if ( dead == SQL_CD_TRUE )
3168 {
3169 /*
3170 * disconnect and remove
3171 */
3172
3173 close_pooled_connection( ptr );
3174
3175 if ( prev )
3176 {
3177 prev -> next = ptr -> next;
3178 free( ptr );
3179 goto restart;
3180 }
3181 else
3182 {
3183 pool_head = ptr -> next;
3184 free( ptr );
3185 goto restart;
3186 }
3187 }
3188 has_checked = 1;
3189 }
3190 }
3191
3192 if ( !has_checked && CHECK_SQLGETCONNECTOPTION(( &ptr -> connection )))
3193 {
3194 SQLRETURN ret;
3195
3196 ret = SQLGETCONNECTOPTION(( &ptr->connection ),
3197 ptr -> connection.driver_dbc,
3198 SQL_ATTR_CONNECTION_DEAD,
3199 &dead );
3200
3201 /*
3202 * if it failed assume that it's because it doesn't support
3203 * it, but it's ok
3204 */
3205
3206 if ( SQL_SUCCEEDED( ret ))
3207 {
3208 if ( dead == SQL_CD_TRUE )
3209 {
3210 /*
3211 * disconnect and remove
3212 */
3213
3214 close_pooled_connection( ptr );
3215
3216 if ( prev )
3217 {
3218 prev -> next = ptr -> next;
3219 free( ptr );
3220 goto restart;
3221 }
3222 else
3223 {
3224 pool_head = ptr -> next;
3225 free( ptr );
3226 goto restart;
3227 }
3228 }
3229 has_checked = 1;
3230 }
3231 }
3232
3233 /*
3234 * Need some other way of checking, This isn't safe to pool...
3235 * But it needs to be something thats not slower than connecting...
3236 * I have put this off, so its after the check that the server_name and all
3237 * the rest is ok to avoid waiting time, as the check could take time
3238 */
3239
3240 if ( !has_checked )
3241 {
3242 if ( strlen( connection -> probe_sql ) > 0 )
3243 {
3244 /*
3245 * Execute the query, check we have all we need
3246 */
3247
3248 if ( CHECK_SQLEXECDIRECT(( &ptr -> connection )) &&
3249 ( CHECK_SQLALLOCHANDLE(( &ptr -> connection )) || CHECK_SQLALLOCSTMT(( &ptr -> connection ))) &&
3250 CHECK_SQLNUMRESULTCOLS(( &ptr -> connection )) &&
3251 CHECK_SQLFETCH(( &ptr -> connection )) &&
3252 CHECK_SQLFREESTMT(( &ptr -> connection )))
3253 {
3254 DMHSTMT statement;
3255 int ret;
3256 int check_failed = 0;
3257
3258 statement = __alloc_stmt();
3259
3260 if ( CHECK_SQLALLOCHANDLE(( &ptr -> connection )))
3261 {
3262 ret = SQLALLOCHANDLE(( &ptr -> connection ),
3263 SQL_HANDLE_STMT,
3264 ptr -> connection.driver_dbc,
3265 ( &statement -> driver_stmt ),
3266 statement );
3267
3268 }
3269 else
3270 {
3271 ret = SQLALLOCSTMT(( &ptr -> connection ),
3272 ptr -> connection.driver_dbc,
3273 ( &statement -> driver_stmt ),
3274 statement );
3275 }
3276
3277 if ( !SQL_SUCCEEDED( ret ))
3278 {
3279 check_failed = 1;
3280 }
3281 else
3282 {
3283 ret = SQLEXECDIRECT(( &ptr -> connection ),
3284 statement -> driver_stmt,
3285 connection -> probe_sql,
3286 SQL_NTS );
3287
3288 if ( !SQL_SUCCEEDED( ret ))
3289 {
3290 check_failed = 1;
3291 }
3292 else
3293 {
3294 SQLSMALLINT column_count;
3295
3296 /*
3297 * Check if there is a result set
3298 */
3299
3300 ret = SQLNUMRESULTCOLS(( &ptr -> connection ),
3301 statement -> driver_stmt,
3302 &column_count );
3303
3304 if ( !SQL_SUCCEEDED( ret ))
3305 {
3306 check_failed = 1;
3307 }
3308 else if ( column_count > 0 )
3309 {
3310 do
3311 {
3312 ret = SQLFETCH(( &ptr -> connection ),
3313 statement -> driver_stmt );
3314 }
3315 while( SQL_SUCCEEDED( ret ));
3316
3317 if ( ret != SQL_NO_DATA )
3318 {
3319 check_failed = 1;
3320 }
3321
3322 ret = SQLFREESTMT(( &ptr -> connection ),
3323 statement -> driver_stmt,
3324 SQL_CLOSE );
3325
3326 if ( !SQL_SUCCEEDED( ret ))
3327 {
3328 check_failed = 1;
3329 }
3330 }
3331 }
3332
3333 ret = SQLFREESTMT(( &ptr -> connection ),
3334 statement -> driver_stmt,
3335 SQL_DROP );
3336
3337 if ( !SQL_SUCCEEDED( ret ))
3338 {
3339 check_failed = 1;
3340 }
3341 }
3342
3343 __release_stmt( statement );
3344
3345 if ( check_failed )
3346 {
3347 /*
3348 * disconnect and remove
3349 */
3350
3351 close_pooled_connection( ptr );
3352
3353 if ( prev )
3354 {
3355 prev -> next = ptr -> next;
3356 free( ptr );
3357 }
3358 else
3359 {
3360 pool_head = ptr -> next;
3361 free( ptr );
3362 }
3363 goto restart;
3364 }
3365 else
3366 {
3367 has_checked = 1;
3368 }
3369 }
3370 }
3371 }
3372
3373 if ( !has_checked )
3374 {
3375 /*
3376 * We can't knwo for sure if the connection is still valid ...
3377 */
3378 }
3379
3380 /*
3381 * at this point we have something that should work, lets use it
3382 */
3383
3384 ptr -> in_use = 1;
3385 ptr -> expiry_time = current_time + ptr -> timeout;
3386 connection -> pooling_timeout = ptr -> timeout;
3387
3388 /*
3389 * copy all the info over
3390 */
3391
3392 connection -> pooled_connection = ptr;
3393
3394 connection -> state = ptr -> connection.state;
3395 connection -> dl_handle = ptr -> connection.dl_handle;
3396 connection -> functions = ptr -> connection.functions;
3397 connection -> unicode_driver = ptr -> connection.unicode_driver;
3398 connection -> driver_env = ptr -> connection.driver_env;
3399 connection -> driver_dbc = ptr -> connection.driver_dbc;
3400 connection -> driver_version = ptr -> connection.driver_version;
3401 connection -> driver_act_ver = ptr -> connection.driver_act_ver;
3402 connection -> statement_count = 0;
3403
3404 connection -> access_mode = ptr -> connection.access_mode;
3405 connection -> access_mode_set = ptr -> connection.access_mode_set;
3406 connection -> login_timeout = ptr -> connection.login_timeout;
3407 connection -> login_timeout_set = ptr -> connection.login_timeout_set;
3408 connection -> auto_commit = ptr -> connection.auto_commit;
3409 connection -> auto_commit_set = ptr -> connection.auto_commit_set;
3410 connection -> async_enable = ptr -> connection.async_enable;
3411 connection -> async_enable_set = ptr -> connection.async_enable_set;
3412 connection -> auto_ipd = ptr -> connection.auto_ipd;
3413 connection -> auto_ipd_set = ptr -> connection.auto_ipd_set;
3414 connection -> connection_timeout = ptr -> connection.connection_timeout;
3415 connection -> connection_timeout_set = ptr -> connection.connection_timeout_set;
3416 connection -> metadata_id = ptr -> connection.metadata_id;
3417 connection -> metadata_id_set = ptr -> connection.metadata_id_set;
3418 connection -> packet_size = ptr -> connection.packet_size;
3419 connection -> packet_size_set = ptr -> connection.packet_size_set;
3420 connection -> quite_mode = ptr -> connection.quite_mode;
3421 connection -> quite_mode_set = ptr -> connection.quite_mode_set;
3422 connection -> txn_isolation = ptr -> connection.txn_isolation;
3423 connection -> txn_isolation_set = ptr -> connection.txn_isolation_set;
3424
3425 connection -> cursors = ptr -> connection.cursors;
3426 connection -> cl_handle = ptr -> connection.cl_handle;
3427
3428 connection -> env_list_ent = ptr -> connection.env_list_ent;
3429 strcpy( connection -> probe_sql, ptr -> connection.probe_sql );
3430
3431 connection -> ex_fetch_mapping = ptr -> connection.ex_fetch_mapping;
3432 connection -> dont_dlclose = ptr -> connection.dont_dlclose;
3433 connection -> bookmarks_on = ptr -> connection.bookmarks_on;
3434
3435 /*
3436 * copy current environment into the pooled connection
3437 */
3438
3439 ptr -> connection.environment = connection -> environment;
3440
3441 strcpy( connection -> dsn, ptr -> connection.dsn );
3442
3443#if defined( HAVE_LIBPTH ) || defined( HAVE_LIBPTHREAD ) || defined( HAVE_LIBTHREAD )
3444 dbc_change_thread_support(connection, ptr -> connection.protection_level);
3445#endif
3446
3447 mutex_pool_exit();
3448
3449 return TRUE;
3450 }
3451
3452 mutex_pool_exit();
3453 return FALSE;
3454}
3455
3456void return_to_pool( DMHDBC connection )
3457{
3458 CPOOL *ptr;
3459 time_t current_time;
3460
3461 mutex_pool_entry();
3462
3463 ptr = connection -> pooled_connection;
3464 current_time = time( NULL );
3465
3466 /*
3467 * is it a old entry ?
3468 */
3469
3470 if ( connection -> pooled_connection )
3471 {
3472 ptr -> in_use = 0;
3473 ptr -> expiry_time = current_time + ptr -> timeout;
3474 }
3475 else
3476 {
3477 ptr = calloc( sizeof( CPOOL ), 1 );
3478 if ( !ptr )
3479 {
3480 mutex_pool_exit();
3481 return;
3482 }
3483
3484 /*
3485 * copy everything over
3486 */
3487
3488 ptr -> in_use = 0;
3489 ptr -> expiry_time = current_time + connection -> pooling_timeout;
3490 ptr -> timeout = connection -> pooling_timeout;
3491 ptr -> ttl = connection -> ttl;
3492 ptr -> cursors = connection -> cursors;
3493
3494 /*
3495 * copy all the info over
3496 */
3497
3498 ptr -> connection.state = connection -> state;
3499 ptr -> connection.dl_handle = connection -> dl_handle;
3500 ptr -> connection.functions = connection -> functions;
3501 ptr -> connection.driver_env = connection -> driver_env;
3502 ptr -> connection.driver_dbc = connection -> driver_dbc;
3503 ptr -> connection.driver_version = connection -> driver_version;
3504 ptr -> connection.driver_act_ver = connection -> driver_act_ver;
3505
3506 ptr -> connection.access_mode = connection -> access_mode;
3507 ptr -> connection.access_mode_set = connection -> access_mode_set;
3508 ptr -> connection.login_timeout = connection -> login_timeout;
3509 ptr -> connection.login_timeout_set = connection -> login_timeout_set;
3510 ptr -> connection.auto_commit = connection -> auto_commit;
3511 ptr -> connection.auto_commit_set = connection -> auto_commit_set;
3512 ptr -> connection.async_enable = connection -> async_enable;
3513 ptr -> connection.async_enable_set = connection -> async_enable_set;
3514 ptr -> connection.auto_ipd = connection -> auto_ipd;
3515 ptr -> connection.auto_ipd_set = connection -> auto_ipd_set;
3516 ptr -> connection.connection_timeout = connection -> connection_timeout;
3517 ptr -> connection.connection_timeout_set = connection -> connection_timeout_set;
3518 ptr -> connection.metadata_id = connection -> metadata_id;
3519 ptr -> connection.metadata_id_set = connection -> metadata_id_set;
3520 ptr -> connection.packet_size = connection -> packet_size;
3521 ptr -> connection.packet_size_set = connection -> packet_size_set;
3522 ptr -> connection.quite_mode = connection -> quite_mode;
3523 ptr -> connection.quite_mode_set = connection -> quite_mode_set;
3524 ptr -> connection.txn_isolation = connection -> txn_isolation;
3525 ptr -> connection.txn_isolation_set = connection -> txn_isolation_set;
3526 ptr -> connection.unicode_driver = connection ->unicode_driver;
3527
3528 ptr -> connection.cursors = connection -> cursors;
3529 ptr -> connection.cl_handle = connection -> cl_handle;
3530
3531#ifdef HAVE_LIBPTHREAD
3532 ptr -> connection.mutex = connection -> mutex;
3533 ptr -> connection.protection_level = connection -> protection_level;
3534#elif HAVE_LIBTHREAD
3535 ptr -> connection.mutex = connection -> mutex;
3536 ptr -> connection.protection_level = connection -> protection_level;
3537#endif
3538
3539 ptr -> connection.pooling_timeout = ptr -> timeout;
3540
3541 ptr -> connection.ex_fetch_mapping = connection -> ex_fetch_mapping;
3542 ptr -> connection.dont_dlclose = connection -> dont_dlclose;
3543 ptr -> connection.bookmarks_on = connection -> bookmarks_on;
3544
3545 ptr -> connection.env_list_ent = connection -> env_list_ent;
3546 ptr -> connection.environment = connection -> environment;
3547 strcpy( ptr -> connection.probe_sql, connection -> probe_sql );
3548
3549#ifdef HAVE_ICONV
3550 ptr -> connection.iconv_cd_uc_to_ascii = connection -> iconv_cd_uc_to_ascii;
3551 ptr -> connection.iconv_cd_ascii_to_uc = connection -> iconv_cd_ascii_to_uc;
3552 connection -> iconv_cd_uc_to_ascii = (iconv_t) -1;
3553 connection -> iconv_cd_ascii_to_uc = (iconv_t) -1;
3554#endif
3555
3556 if ( connection -> server_length < 0 )
3557 {
3558 strcpy( ptr -> server, connection -> server );
3559 }
3560 else
3561 {
3562 memcpy( ptr -> server, connection -> server, connection -> server_length );
3563 }
3564 ptr -> server_length = connection -> server_length;
3565
3566 if ( connection -> user_length < 0 )
3567 {
3568 strcpy( ptr -> user, connection -> user );
3569 }
3570 else
3571 {
3572 memcpy( ptr -> user, connection -> user, connection -> user_length );
3573 }
3574 ptr -> user_length = connection -> user_length;
3575
3576 if ( connection -> password_length < 0 )
3577 {
3578 strcpy( ptr -> password, connection -> password );
3579 }
3580 else
3581 {
3582 memcpy( ptr -> password, connection -> password, connection -> password_length );
3583 }
3584 ptr -> password_length = connection -> password_length;
3585
3586 if ( connection -> dsn_length < 0 )
3587 {
3588 strcpy( ptr -> driver_connect_string, connection -> driver_connect_string );
3589 }
3590 else
3591 {
3592 memcpy( ptr -> driver_connect_string, connection -> driver_connect_string,
3593 connection -> dsn_length );
3594 }
3595 ptr -> dsn_length = connection -> dsn_length;
3596
3597 strcpy( ptr -> connection.dsn, connection -> dsn );
3598
3599 /*
3600 * add to the list
3601 */
3602
3603 ptr -> next = pool_head;
3604 pool_head = ptr;
3605 }
3606
3607 /*
3608 * allow the driver to reset itself if it's a 3.8 driver
3609 */
3610
3611 if ( connection -> driver_version == SQL_OV_ODBC3_80 )
3612 {
3613 if ( CHECK_SQLSETCONNECTATTR( connection ))
3614 {
3615 SQLSETCONNECTATTR( connection,
3616 connection -> driver_dbc,
3617 SQL_ATTR_RESET_CONNECTION,
3618 SQL_RESET_CONNECTION_YES,
3619 0 );
3620 }
3621 }
3622
3623 /*
3624 * remove all information from the connection
3625 */
3626
3627 connection -> state = STATE_C2;
3628 connection -> driver_env = 0;
3629 connection -> driver_dbc = 0;
3630 connection -> dl_handle = 0;
3631 connection -> cl_handle = 0;
3632 connection -> functions = 0;
3633 connection -> pooled_connection = 0;
3634
3635 mutex_pool_exit();
3636}
3637
3638void __handle_attr_extensions( DMHDBC connection, char *dsn, char *driver_name )
3639{
3640 char txt[ 1024 ];
3641
3642 if ( dsn && strlen( dsn ))
3643 {
3644 SQLGetPrivateProfileString( dsn, "DMEnvAttr", "",
3645 txt, sizeof( txt ),
3646 "ODBC.INI" );
3647
3648 if ( strlen( txt ))
3649 {
3650 __parse_attribute_string( &connection -> env_attribute,
3651 txt, strlen( txt ));
3652 }
3653
3654 SQLGetPrivateProfileString( dsn, "DMConnAttr", "",
3655 txt, sizeof( txt ),
3656 "ODBC.INI" );
3657
3658 if ( strlen( txt ))
3659 {
3660 __parse_attribute_string( &connection -> dbc_attribute,
3661 txt, strlen( txt ));
3662 }
3663
3664 SQLGetPrivateProfileString( dsn, "DMStmtAttr", "",
3665 txt, sizeof( txt ),
3666 "ODBC.INI" );
3667
3668 if ( strlen( txt ))
3669 {
3670 __parse_attribute_string( &connection -> stmt_attribute,
3671 txt, strlen( txt ));
3672 }
3673 }
3674
3675 if ( driver_name && strlen( driver_name ))
3676 {
3677 SQLGetPrivateProfileString( driver_name, "DMEnvAttr", "",
3678 txt, sizeof( txt ),
3679 "ODBCINST.INI" );
3680
3681 if ( strlen( txt ))
3682 {
3683 __parse_attribute_string( &connection -> env_attribute,
3684 txt, strlen( txt ));
3685 }
3686 }
3687}
3688
3689SQLRETURN SQLConnectA( SQLHDBC connection_handle,
3690 SQLCHAR *server_name,
3691 SQLSMALLINT name_length1,
3692 SQLCHAR *user_name,
3693 SQLSMALLINT name_length2,
3694 SQLCHAR *authentication,
3695 SQLSMALLINT name_length3 )
3696{
3697 return SQLConnect( connection_handle,
3698 server_name,
3699 name_length1,
3700 user_name,
3701 name_length2,
3702 authentication,
3703 name_length3 );
3704}
3705
3706SQLRETURN SQLConnect( SQLHDBC connection_handle,
3707 SQLCHAR *server_name,
3708 SQLSMALLINT name_length1,
3709 SQLCHAR *user_name,
3710 SQLSMALLINT name_length2,
3711 SQLCHAR *authentication,
3712 SQLSMALLINT name_length3 )
3713{
3714 DMHDBC connection = (DMHDBC)connection_handle;
3715 int len, ret_from_connect;
3716 char dsn[ SQL_MAX_DSN_LENGTH + 1 ];
3717 char lib_name[ INI_MAX_PROPERTY_VALUE + 1 ];
3718 char driver_name[ INI_MAX_PROPERTY_VALUE + 1 ];
3719 SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ], s2[ 100 + LOG_MESSAGE_LEN ], s3[ 100 + LOG_MESSAGE_LEN ];
3720 int warnings;
3721
3722 /*
3723 * check connection
3724 */
3725 if ( !__validate_dbc( connection ))
3726 {
3727 dm_log_write( __FILE__,
3728 __LINE__,
3729 LOG_INFO,
3730 LOG_INFO,
3731 "Error: SQL_INVALID_HANDLE" );
3732
3733 return SQL_INVALID_HANDLE;
3734 }
3735
3736 function_entry( connection );
3737
3738 if ( log_info.log_flag )
3739 {
3740 sprintf( connection -> msg, "\n\t\tEntry:\
3741\n\t\t\tConnection = %p\
3742\n\t\t\tServer Name = %s\
3743\n\t\t\tUser Name = %s\
3744\n\t\t\tAuthentication = %s",
3745 connection,
3746 __string_with_length( s1, server_name, name_length1 ),
3747 __string_with_length( s2, user_name, name_length2 ),
3748 __string_with_length_pass( s3, authentication, name_length3 ));
3749
3750 dm_log_write( __FILE__,
3751 __LINE__,
3752 LOG_INFO,
3753 LOG_INFO,
3754 connection -> msg );
3755 }
3756
3757 thread_protect( SQL_HANDLE_DBC, connection );
3758
3759 if (( name_length1 < 0 && name_length1 != SQL_NTS ) ||
3760 ( name_length2 < 0 && name_length2 != SQL_NTS ) ||
3761 ( name_length3 < 0 && name_length3 != SQL_NTS ))
3762
3763 {
3764 dm_log_write( __FILE__,
3765 __LINE__,
3766 LOG_INFO,
3767 LOG_INFO,
3768 "Error: HY090" );
3769
3770 __post_internal_error( &connection -> error,
3771 ERROR_HY090, NULL,
3772 connection -> environment -> requested_version );
3773
3774 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3775 }
3776
3777 /*
3778 * check the state of the connection
3779 */
3780 if ( connection -> state != STATE_C2 )
3781 {
3782 dm_log_write( __FILE__,
3783 __LINE__,
3784 LOG_INFO,
3785 LOG_INFO,
3786 "Error: 08002" );
3787
3788 __post_internal_error( &connection -> error,
3789 ERROR_08002, NULL,
3790 connection -> environment -> requested_version );
3791
3792 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3793 }
3794
3795 if ( name_length1 && server_name )
3796 {
3797 if ( name_length1 == SQL_NTS )
3798 {
3799 len = strlen((char*) server_name );
3800
3801 if ( len > SQL_MAX_DSN_LENGTH )
3802 {
3803 dm_log_write( __FILE__,
3804 __LINE__,
3805 LOG_INFO,
3806 LOG_INFO,
3807 "Error: HY090" );
3808
3809 __post_internal_error( &connection -> error,
3810 ERROR_HY090, NULL,
3811 connection -> environment -> requested_version );
3812
3813 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3814 }
3815 }
3816 else
3817 {
3818 len = name_length1;
3819
3820 if ( len > SQL_MAX_DSN_LENGTH )
3821 {
3822 dm_log_write( __FILE__,
3823 __LINE__,
3824 LOG_INFO,
3825 LOG_INFO,
3826 "Error: HY090" );
3827
3828 __post_internal_error( &connection -> error,
3829 ERROR_HY090, NULL,
3830 connection -> environment -> requested_version );
3831
3832 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3833 }
3834 }
3835
3836 memcpy( dsn, server_name, len );
3837 dsn[ len ] ='\0';
3838 }
3839 else if ( name_length1 > SQL_MAX_DSN_LENGTH )
3840 {
3841 dm_log_write( __FILE__,
3842 __LINE__,
3843 LOG_INFO,
3844 LOG_INFO,
3845 "Error: IM010" );
3846
3847 __post_internal_error( &connection -> error,
3848 ERROR_IM010, NULL,
3849 connection -> environment -> requested_version );
3850
3851 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3852 }
3853 else
3854 {
3855 strcpy( dsn, "DEFAULT" );
3856 }
3857
3858 /*
3859 * can we find a pooled connection to use here ?
3860 */
3861
3862 connection -> pooled_connection = NULL;
3863
3864 if ( pooling_enabled && search_for_pool( connection,
3865 server_name, name_length1,
3866 user_name, name_length2,
3867 authentication, name_length3,
3868 NULL, 0 ))
3869 {
3870 ret_from_connect = SQL_SUCCESS;
3871
3872 if ( log_info.log_flag )
3873 {
3874 sprintf( connection -> msg,
3875 "\n\t\tExit:[%s]",
3876 __get_return_status( ret_from_connect, s1 ));
3877
3878 dm_log_write( __FILE__,
3879 __LINE__,
3880 LOG_INFO,
3881 LOG_INFO,
3882 connection -> msg );
3883 }
3884
3885 connection -> state = STATE_C4;
3886
3887 return function_return_nodrv( SQL_HANDLE_DBC, connection, ret_from_connect );
3888 }
3889
3890 /*
3891 * else safe the info for later
3892 */
3893
3894 if ( pooling_enabled )
3895 {
3896 connection -> dsn_length = 0;
3897
3898 if ( server_name )
3899 {
3900 if ( name_length1 < 0 )
3901 {
3902 strcpy( connection -> server, (char*)server_name );
3903 }
3904 else
3905 {
3906 memcpy( connection -> server, server_name, name_length1 );
3907 }
3908 }
3909 else
3910 {
3911 strcpy( connection -> server, "" );
3912 }
3913 connection -> server_length = name_length1;
3914
3915 if ( user_name )
3916 {
3917 if ( name_length2 < 0 )
3918 {
3919 strcpy( connection -> user, (char*)user_name );
3920 }
3921 else
3922 {
3923 memcpy( connection -> user, user_name, name_length2 );
3924 }
3925 }
3926 else
3927 {
3928 strcpy( connection -> user, "" );
3929 }
3930 connection -> user_length = name_length2;
3931
3932 if ( authentication )
3933 {
3934 if ( name_length3 )
3935 {
3936 strcpy( connection -> password, (char*)authentication );
3937 }
3938 else
3939 {
3940 memcpy( connection -> password, authentication, name_length3 );
3941 }
3942 }
3943 else
3944 {
3945 strcpy( connection -> password, "" );
3946 }
3947 connection -> password_length = name_length3;
3948 }
3949
3950 if ( !*dsn || !__find_lib_name( dsn, lib_name, driver_name ))
3951 {
3952 /*
3953 * if not found look for a default
3954 */
3955
3956 if ( !__find_lib_name( "DEFAULT", lib_name, driver_name ))
3957 {
3958 dm_log_write( __FILE__,
3959 __LINE__,
3960 LOG_INFO,
3961 LOG_INFO,
3962 "Error: IM002" );
3963
3964 __post_internal_error( &connection -> error,
3965 ERROR_IM002, NULL,
3966 connection -> environment -> requested_version );
3967
3968 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3969 }
3970 }
3971
3972
3973 /*
3974 * do we have any Environment, Connection, or Statement attributes set in the ini ?
3975 */
3976
3977 __handle_attr_extensions( connection, dsn, driver_name );
3978
3979 /*
3980 * if necessary change the threading level
3981 */
3982
3983 warnings = 0;
3984
3985 if ( !__connect_part_one( connection, lib_name, driver_name, &warnings ))
3986 {
3987 __disconnect_part_four( connection ); /* release unicode handles */
3988
3989 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
3990 }
3991
3992 if ( !CHECK_SQLCONNECT( connection ) &&
3993 !CHECK_SQLCONNECTW( connection ))
3994 {
3995 dm_log_write( __FILE__,
3996 __LINE__,
3997 LOG_INFO,
3998 LOG_INFO,
3999 "Error: IM001" );
4000
4001 __disconnect_part_one( connection );
4002 __disconnect_part_four( connection ); /* release unicode handles */
4003 __post_internal_error( &connection -> error,
4004 ERROR_IM001, NULL,
4005 connection -> environment -> requested_version );
4006
4007 return function_return_nodrv( SQL_HANDLE_DBC, connection, SQL_ERROR );
4008 }
4009
4010 if ( CHECK_SQLCONNECT( connection ))
4011 {
4012 /*
4013 if ( CHECK_SQLSETCONNECTATTR( connection ))
4014 {
4015 int lret;
4016
4017 lret = SQLSETCONNECTATTR( connection,
4018 connection -> driver_dbc,
4019 SQL_ATTR_ANSI_APP,
4020 SQL_AA_TRUE,
4021 0 );
4022 }
4023 */
4024
4025 ret_from_connect = SQLCONNECT( connection,
4026 connection -> driver_dbc,
4027 dsn, SQL_NTS,
4028 user_name, name_length2,
4029 authentication, name_length3 );
4030
4031 if ( ret_from_connect != SQL_SUCCESS )
4032 {
4033 SQLCHAR sqlstate[ 6 ];
4034 SQLINTEGER native_error;
4035 SQLSMALLINT ind;
4036 SQLCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
4037 SQLRETURN ret;
4038
4039 /*
4040 * get the errors from the driver before
4041 * loseing the connection
4042 */
4043
4044 if ( CHECK_SQLERROR( connection ))
4045 {
4046 do
4047 {
4048 ret = SQLERROR( connection,
4049 SQL_NULL_HENV,
4050 connection -> driver_dbc,
4051 SQL_NULL_HSTMT,
4052 sqlstate,
4053 &native_error,
4054 message_text,
4055 sizeof( message_text ),
4056 &ind );
4057
4058 if ( SQL_SUCCEEDED( ret ))
4059 {
4060 __post_internal_error_ex( &connection -> error,
4061 sqlstate,
4062 native_error,
4063 message_text,
4064 SUBCLASS_ODBC, SUBCLASS_ODBC );
4065
4066 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
4067 sqlstate, message_text );
4068
4069 dm_log_write_diag( connection -> msg );
4070 }
4071 }
4072 while( SQL_SUCCEEDED( ret ));
4073 }
4074 else if ( CHECK_SQLGETDIAGREC( connection ))
4075 {
4076 int rec = 1;
4077
4078 do
4079 {
4080 ret = SQLGETDIAGREC( connection,
4081 SQL_HANDLE_DBC,
4082 connection -> driver_dbc,
4083 rec ++,
4084 sqlstate,
4085 &native_error,
4086 message_text,
4087 sizeof( message_text ),
4088 &ind );
4089
4090
4091 if ( SQL_SUCCEEDED( ret ))
4092 {
4093 __post_internal_error_ex( &connection -> error,
4094 sqlstate,
4095 native_error,
4096 message_text,
4097 SUBCLASS_ODBC, SUBCLASS_ODBC );
4098
4099 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
4100 sqlstate, message_text );
4101
4102 dm_log_write_diag( connection -> msg );
4103 }
4104 }
4105 while( SQL_SUCCEEDED( ret ));
4106 }
4107 }
4108
4109 /*
4110 * if it was a error then return now
4111 */
4112
4113 if ( !SQL_SUCCEEDED( ret_from_connect ))
4114 {
4115 __disconnect_part_one( connection );
4116 __disconnect_part_four( connection );
4117
4118 sprintf( connection -> msg,
4119 "\n\t\tExit:[%s]",
4120 __get_return_status( ret_from_connect, s1 ));
4121
4122 dm_log_write( __FILE__,
4123 __LINE__,
4124 LOG_INFO,
4125 LOG_INFO,
4126 connection -> msg );
4127
4128 return function_return( SQL_HANDLE_DBC, connection, ret_from_connect );
4129 }
4130
4131 connection -> unicode_driver = 0;
4132 }
4133 else
4134 {
4135 SQLWCHAR * uc_dsn, *uc_user, *uc_auth;
4136
4137 uc_dsn = ansi_to_unicode_alloc((SQLCHAR*) dsn, SQL_NTS, connection, NULL );
4138 uc_user = ansi_to_unicode_alloc( user_name, name_length2, connection, NULL );
4139 uc_auth = ansi_to_unicode_alloc( authentication, name_length3, connection, NULL );
4140
4141 if ( CHECK_SQLSETCONNECTATTR( connection ))
4142 {
4143 int lret;
4144
4145 lret = SQLSETCONNECTATTR( connection,
4146 connection -> driver_dbc,
4147 SQL_ATTR_ANSI_APP,
4148 SQL_AA_FALSE,
4149 0 );
4150 }
4151
4152 ret_from_connect = SQLCONNECTW( connection,
4153 connection -> driver_dbc,
4154 uc_dsn, SQL_NTS,
4155 uc_user, name_length2,
4156 uc_auth, name_length3 );
4157
4158 if ( uc_dsn )
4159 free( uc_dsn );
4160 if ( uc_user )
4161 free( uc_user );
4162 if ( uc_auth )
4163 free( uc_auth );
4164
4165 if ( ret_from_connect != SQL_SUCCESS )
4166 {
4167 SQLWCHAR sqlstate[ 6 ];
4168 SQLINTEGER native_error;
4169 SQLSMALLINT ind;
4170 SQLWCHAR message_text[ SQL_MAX_MESSAGE_LENGTH + 1 ];
4171 SQLRETURN ret;
4172
4173 /*
4174 * get the errors from the driver before
4175 * looseing the connection
4176 */
4177
4178 if ( CHECK_SQLERRORW( connection ))
4179 {
4180 do
4181 {
4182 ret = SQLERRORW( connection,
4183 SQL_NULL_HENV,
4184 connection -> driver_dbc,
4185 SQL_NULL_HSTMT,
4186 sqlstate,
4187 &native_error,
4188 message_text,
4189 sizeof( message_text ),
4190 &ind );
4191
4192
4193 if ( SQL_SUCCEEDED( ret ))
4194 {
4195 SQLCHAR *as1, *as2;
4196
4197 __post_internal_error_ex_w( &connection -> error,
4198 sqlstate,
4199 native_error,
4200 message_text,
4201 SUBCLASS_ODBC, SUBCLASS_ODBC );
4202
4203 as1 = (SQLCHAR *) unicode_to_ansi_alloc( sqlstate, SQL_NTS, connection, NULL );
4204 as2 = (SQLCHAR *) unicode_to_ansi_alloc( message_text, SQL_NTS, connection, NULL );
4205
4206 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
4207 as1, as2 );
4208
4209 if ( as1 ) free( as1 );
4210 if ( as2 ) free( as2 );
4211
4212 dm_log_write_diag( connection -> msg );
4213 }
4214 }
4215 while( SQL_SUCCEEDED( ret ));
4216 }
4217 else if ( CHECK_SQLGETDIAGRECW( connection ))
4218 {
4219 int rec = 1;
4220
4221 do
4222 {
4223
4224 ret = SQLGETDIAGRECW( connection,
4225 SQL_HANDLE_DBC,
4226 connection -> driver_dbc,
4227 rec ++,
4228 sqlstate,
4229 &native_error,
4230 message_text,
4231 sizeof( message_text ),
4232 &ind );
4233
4234 if ( SQL_SUCCEEDED( ret ))
4235 {
4236 SQLCHAR *as1, *as2;
4237
4238 __post_internal_error_ex_w( &connection -> error,
4239 sqlstate,
4240 native_error,
4241 message_text,
4242 SUBCLASS_ODBC, SUBCLASS_ODBC );
4243
4244 as1 = (SQLCHAR *) unicode_to_ansi_alloc( sqlstate, SQL_NTS, connection, NULL );
4245 as2 = (SQLCHAR *) unicode_to_ansi_alloc( message_text, SQL_NTS, connection, NULL );
4246
4247 sprintf( connection -> msg, "\t\tDIAG [%s] %s",
4248 as1, as2 );
4249
4250 if ( as1 ) free( as1 );
4251 if ( as2 ) free( as2 );
4252
4253 dm_log_write_diag( connection -> msg );
4254 }
4255 }
4256 while( SQL_SUCCEEDED( ret ));
4257 }
4258 }
4259
4260 /*
4261 * if it was a error then return now
4262 */
4263
4264 if ( !SQL_SUCCEEDED( ret_from_connect ))
4265 {
4266 __disconnect_part_one( connection );
4267 __disconnect_part_four( connection );
4268
4269 sprintf( connection -> msg,
4270 "\n\t\tExit:[%s]",
4271 __get_return_status( ret_from_connect, s1 ));
4272
4273 dm_log_write( __FILE__,
4274 __LINE__,
4275 LOG_INFO,
4276 LOG_INFO,
4277 connection -> msg );
4278
4279 return function_return( SQL_HANDLE_DBC, connection, ret_from_connect );
4280 }
4281
4282 connection -> unicode_driver = 1;
4283 }
4284
4285 /*
4286 * we should be connected now
4287 */
4288 connection -> state = STATE_C4;
4289 strcpy( connection -> dsn, dsn );
4290
4291 /*
4292 * did we get the type we wanted
4293 */
4294
4295 if ( connection -> driver_version !=
4296 connection -> environment -> requested_version )
4297 {
4298 connection -> driver_version =
4299 connection -> environment -> requested_version;
4300
4301 __post_internal_error( &connection -> error,
4302 ERROR_01000, "Driver does not support the requested version",
4303 connection -> environment -> requested_version );
4304 ret_from_connect = SQL_SUCCESS_WITH_INFO;
4305 }
4306
4307 if ( !__connect_part_two( connection ))
4308 {
4309 /*
4310 * the cursor lib can kill us here, so be careful
4311 */
4312
4313 __disconnect_part_two( connection );
4314 __disconnect_part_one( connection );
4315 __disconnect_part_four( connection );
4316
4317 connection -> state = STATE_C3;
4318
4319 return function_return( SQL_HANDLE_DBC, connection, SQL_ERROR );
4320 }
4321
4322 if ( log_info.log_flag )
4323 {
4324 sprintf( connection -> msg,
4325 "\n\t\tExit:[%s]",
4326 __get_return_status( ret_from_connect, s1 ));
4327
4328 dm_log_write( __FILE__,
4329 __LINE__,
4330 LOG_INFO,
4331 LOG_INFO,
4332 connection -> msg );
4333 }
4334
4335 if ( warnings && ret_from_connect == SQL_SUCCESS )
4336 {
4337 ret_from_connect = SQL_SUCCESS_WITH_INFO;
4338 }
4339
4340 return function_return_nodrv( SQL_HANDLE_DBC, connection, ret_from_connect );
4341}
4342
4343/*
4344 * connection pooling setup, just stubs for the moment
4345 */
4346
4347BOOL ODBCSetTryWaitValue ( DWORD dwValue )
4348{
4349 return 0;
4350}
4351
4352#ifdef __cplusplus
4353DWORD ODBCGetTryWaitValue ( )
4354#else
4355DWORD ODBCGetTryWaitValue ( void )
4356#endif
4357{
4358 return 0;
4359}
4360