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