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