1 // Copyright (c) 1999-2018 David Muse
2 // See the file COPYING for more information
3 
4 #include <rudiments/dynamiclib.h>
5 #include <rudiments/file.h>
6 
7 
8 // FIXME: for now, assume version 8i+
9 #undef HAVE_ORACLE_8i
10 #define HAVE_ORACLE_8i	1
11 
12 
13 // types...
14 #define CONST const
15 #define dvoid void
16 typedef signed int sword;
17 typedef unsigned char ub1;
18 typedef unsigned short ub2;
19 typedef short sb2;
20 typedef unsigned int ub4;
21 typedef int sb4;
22 typedef int boolean;
23 typedef unsigned char text;
24 typedef unsigned char OraText;
25 typedef unsigned short OCIDuration;
26 
27 
28 // structs...
29 struct OCIParam;
30 struct OCIEnv;
31 struct OCIServer;
32 struct OCIError;
33 struct OCISvcCtx;
34 struct OCISession;
35 struct OCITrans;
36 struct OCISession;
37 struct OCIStmt;
38 struct OCIDefine;
39 struct OCILobLocator;
40 struct OCIBind;
41 struct OCISnapshot;
42 
43 
44 // date/time structs need to be defined...
45 struct OCITime {
46 	ub1 OCITimeHH;
47 	ub1 OCITimeMI;
48 	ub1 OCITimeSS;
49 };
50 
51 struct OCIDate {
52 	sb2 OCIDateYYYY;
53 	ub1 OCIDateMM;
54 	ub1 OCIDateDD;
55 	OCITime OCIDateTime;
56 };
57 
58 
59 // function pointers...
60 sword (*OCIEnvCreate)(OCIEnv **,
61 				ub4,
62 				void *,
63 				void *(*)(void *,size_t),
64 				void *(*)(void *,void *,size_t),
65 				void (*)(void *,void *),
66 				size_t,
67 				void **);
68 sword (*OCIInitialize)(ub4,
69 				void *,
70 				void *(*)(void *,size_t),
71 				void *(*)(void *,void *,size_t),
72 				void (*)(void *,void *));
73 sword (*OCIHandleAlloc)(const void *,
74 				void **,
75 				const ub4,
76 				const size_t,
77 				void **);
78 sword (*OCIServerAttach)(OCIServer *,
79 				OCIError *,
80 				const OraText *,
81 				sb4,
82 				ub4);
83 sword (*OCIServerDetach)(OCIServer *,
84 				OCIError *,
85 				ub4);
86 sword (*OCISessionBegin)(OCISvcCtx *,
87 				OCIError *,
88 				OCISession *,
89 				ub4,
90 				ub4);
91 sword (*OCISessionEnd)(OCISvcCtx *,
92 				OCIError *,
93 				OCISession *,
94 				ub4);
95 sword (*OCIServerVersion)(void *,
96 				OCIError *,
97 				OraText *,
98 				ub4,
99 				ub1);
100 sword (*OCIStmtPrepare2)(OCISvcCtx *,
101 				OCIStmt **,
102 				OCIError *,
103 				const OraText *,
104 				ub4,
105 				const OraText *,
106 				ub4,
107 				ub4,
108 				ub4);
109 sword (*OCIStmtExecute)(OCISvcCtx *,
110 				OCIStmt *,
111 				OCIError *,
112 				ub4,
113 				ub4,
114 				const OCISnapshot *,
115 				OCISnapshot *,
116 				ub4);
117 sword (*OCIStmtRelease)(OCIStmt *,
118 				OCIError *,
119 				const OraText *,
120 				ub4,
121 				ub4);
122 sword (*OCIErrorGet)(void *,
123 				ub4,
124 				OraText *,
125 				sb4 *,
126 				OraText *,
127 				ub4,
128 				ub4);
129 sword (*OCIStmtPrepare)(OCIStmt *,
130 				OCIError *,
131 				const OraText *,
132 				ub4,
133 				ub4,
134 				ub4);
135 sword (*OCIBindByPos)(OCIStmt *,
136 				OCIBind **,
137 				OCIError *,
138 				ub4,
139 				void *,
140 				sb4,
141 				ub2,
142 				void *,
143 				ub2 *,
144 				ub2 *,
145 				ub4,
146 				ub4 *,
147 				ub4);
148 sword (*OCIBindByName)(OCIStmt *,
149 				OCIBind **,
150 				OCIError *,
151 				const OraText *,
152 				sb4,
153 				void *,
154 				sb4,
155 				ub2,
156 				void *,
157 				ub2 *,
158 				ub2 *,
159 				ub4,
160 				ub4 *,
161 				ub4);
162 sword (*OCIDescriptorAlloc)(const void *,
163 				void **,
164 				const ub4,
165 				const size_t,
166 				void **);
167 sword (*OCILobCreateTemporary)(OCISvcCtx *,
168 				OCIError *,
169 				OCILobLocator *,
170 				ub2,
171 				ub1,
172 				ub1,
173 				boolean,
174 				OCIDuration);
175 sword (*OCILobOpen)(OCISvcCtx *,
176 				OCIError *,
177 				OCILobLocator *,
178 				ub1);
179 sword (*OCILobFreeTemporary)(OCISvcCtx *,
180 				OCIError *,
181 				OCILobLocator *);
182 sword (*OCILobWrite)(OCISvcCtx *,
183 				OCIError *,
184 				OCILobLocator *,
185 				ub4 *,
186 				ub4,
187 				void *,
188 				ub4,
189 				ub1,
190 				void *,
191 				sb4 (*)(dvoid*,dvoid*,ub4*,ub1 *),
192 				ub2,
193 				ub1);
194 sword (*OCILobClose)(OCISvcCtx *,
195 				OCIError *,
196 				OCILobLocator *);
197 sword (*OCILobGetLength)(OCISvcCtx *,
198 				OCIError *,
199 				OCILobLocator *,
200 				ub4 *);
201 sword (*OCILobRead)(OCISvcCtx *,
202 				OCIError *,
203 				OCILobLocator *,
204 				ub4 *,
205 				ub4,
206 				void *,
207 				ub4,
208 				void *,
209 				sb4 (*)(dvoid *,CONST dvoid *,ub4,ub1),
210 				ub2,
211 				ub1);
212 sword (*OCIAttrSet)(void *,
213 				ub4,
214 				void *,
215 				ub4,
216 				ub4,
217 				OCIError *);
218 sword (*OCIAttrGet)(const void *,
219 				ub4,
220 				void *,
221 				ub4 *,
222 				ub4,
223 				OCIError *);
224 sword (*OCIDefineByPos)(OCIStmt *,
225 				OCIDefine **,
226 				OCIError *,
227 				ub4,
228 				void *,
229 				sb4,
230 				ub2,
231 				void *,
232 				ub2 *,
233 				ub2 *,
234 				ub4);
235 sword (*OCIStmtGetBindInfo)(OCIStmt *,
236 				OCIError *,
237 				ub4,
238 				ub4,
239 				sb4 *,
240 				OraText *[],
241 				ub1[],
242 				OraText *[],
243 				ub1[],
244 				ub1[],
245 				OCIBind **);
246 sword (*OCIStmtFetch)(OCIStmt *,
247 				OCIError *,
248 				ub4,
249 				ub2,
250 				ub4);
251 sword (*OCILobIsTemporary)(OCIEnv *,
252 				OCIError *,
253 				OCILobLocator *locp,
254 				boolean *);
255 sword (*OCIDescriptorFree)(void *descp,
256 				const ub4);
257 sword (*OCIHandleFree)(void *,
258 				const ub4);
259 sword (*OCIParamGet)(const void *,
260 				ub4,
261 				OCIError *,
262 				void **,
263 				ub4);
264 sword (*OCITransCommit)(OCISvcCtx *,
265 				OCIError *,
266 				ub4);
267 sword (*OCITransRollback)(OCISvcCtx *,
268 				OCIError *,
269 				ub4);
270 
271 
272 // date/time macros...
273 #define OCIDateSetDate(date,year,month,day) { \
274 	(date)->OCIDateYYYY=year; \
275 	(date)->OCIDateMM=month; \
276 	(date)->OCIDateDD=day; \
277 }
278 #define OCIDateSetTime(date,hour,min,sec) { \
279 	(date)->OCIDateTime.OCITimeHH=hour; \
280 	(date)->OCIDateTime.OCITimeMI=min; \
281 	(date)->OCIDateTime.OCITimeSS=sec; \
282 }
283 #define OCIDateGetDate(date,year,month,day) { \
284 	*year=(date)->OCIDateYYYY; \
285 	*month=(date)->OCIDateMM; \
286 	*day=(date)->OCIDateDD; \
287 }
288 #define OCIDateGetTime(date,hour,min,sec) { \
289 	*hour=(date)->OCIDateTime.OCITimeHH; \
290 	*min=(date)->OCIDateTime.OCITimeMI; \
291 	*sec=(date)->OCIDateTime.OCITimeSS; \
292 }
293 
294 
295 // constants...
296 #define OCI_DEFAULT		0x00000000
297 #define OCI_SUCCESS		0
298 #define OCI_SUCCESS_WITH_INFO	1
299 #define OCI_ERROR		-1
300 #define OCI_INVALID_HANDLE	-2
301 
302 #define OCI_OBJECT		0x00000002
303 
304 #define OCI_HTYPE_ENV		1
305 #define OCI_HTYPE_ERROR		2
306 #define OCI_HTYPE_SVCCTX	3
307 #define OCI_HTYPE_STMT		4
308 #define OCI_HTYPE_SERVER	8
309 #define OCI_HTYPE_SESSION	9
310 #define OCI_HTYPE_TRANS		10
311 
312 #define OCI_ATTR_DATA_SIZE	1
313 #define OCI_ATTR_DATA_TYPE	2
314 #define OCI_ATTR_NAME		4
315 #define OCI_ATTR_PRECISION	5
316 #define OCI_ATTR_SCALE		6
317 #define OCI_ATTR_IS_NULL	7
318 #define OCI_ATTR_TRANS		8
319 #define OCI_ATTR_ROW_COUNT	9
320 #define OCI_ATTR_PREFETCH_ROWS	11
321 #define OCI_ATTR_PARAM_COUNT	18
322 #define OCI_ATTR_USERNAME	22
323 #define OCI_ATTR_PASSWORD	23
324 #define OCI_ATTR_NOCACHE	87
325 #define OCI_ATTR_STMTCACHESIZE	176
326 
327 #define OCI_ATTR_SERVER		6
328 #define OCI_ATTR_SESSION	7
329 #define OCI_ATTR_STMT_TYPE	24
330 
331 #define OCI_CRED_RDBMS	1
332 #define OCI_CRED_EXT	2
333 #define OCI_CRED_PROXY	3
334 
335 // FIXME: for now, assume this is supported...
336 #define OCI_ATTR_PROXY_CREDENTIALS	99
337 
338 #define OCI_NTV_SYNTAX	1
339 
340 #define OCI_COMMIT_ON_SUCCESS	0x00000020
341 
342 #define OCI_STRLS_CACHE_DELETE	0x0010
343 
344 // FIXME: for now, assume this is supported...
345 #define OCI_STMT_CACHE	0x00000040
346 
347 #define OCI_STMT_SELECT	1
348 #define OCI_STMT_CREATE	5
349 #define OCI_STMT_DROP	6
350 #define OCI_STMT_ALTER	7
351 
352 #define OCI_PREP2_CACHE_SEARCHONLY	0x0010
353 
354 #define OCI_TEMP_BLOB	1
355 #define OCI_TEMP_CLOB	2
356 
357 #define OCI_DTYPE_LOB	50
358 #define OCI_DTYPE_PARAM	53
359 
360 #define OCI_DURATION_SESSION	10
361 
362 #define OCI_LOB_READWRITE	2
363 
364 #define OCI_ONE_PIECE	0
365 
366 #define OCI_NO_DATA	100
367 
368 #define OCI_STRLS_CACHE_DELETE	0x0010
369 
370 #define OCI_FETCH_NEXT	0x00000002
371 
372 #define SQLT_FLT	4
373 #define SQLT_STR	5
374 #define SQLT_CLOB	112
375 #define SQLT_BLOB	113
376 #define SQLT_RSET	116
377 #define SQLT_ODT	156
378 
379 #define SQLCS_IMPLICIT	1
380 
381 
382 // dlopen infrastructure...
383 static bool		alreadyopen=false;
384 static dynamiclib	lib;
385 
loadLibraries(stringbuffer * errormessage)386 static bool loadLibraries(stringbuffer *errormessage) {
387 
388 	// don't open multiple times...
389 	if (alreadyopen) {
390 		return true;
391 	}
392 	alreadyopen=true;
393 
394 	// build lib names
395 	const char	**libnames=new const char *[11];
396 	uint16_t	p=0;
397 	stringbuffer	libdir;
398 	const char	*oraclehome=environment::getValue("ORACLE_HOME");
399 	if (!charstring::isNullOrEmpty(oraclehome)) {
400 		libdir.append(oraclehome)->append("/lib/libclntsh.so");
401 		libnames[p++]=libdir.getString();
402 	}
403 
404 	if (sizeof(long)==8) {
405 		libnames[p++]="/usr/lib/oracle/12.1/client64/lib/libclntsh.so";
406 	} else {
407 		libnames[p++]="/usr/lib/oracle/12.1/client/lib/libclntsh.so";
408 	}
409 	libnames[p++]="/opt/instantclient_12_1/libclntsh.so.12.1";
410 	libnames[p++]="/usr/local/instantclient_12_1/libclntsh.so.12.1";
411 
412 	if (sizeof(long)==8) {
413 		libnames[p++]="/usr/lib/oracle/11.2/client64/lib/libclntsh.so";
414 	} else {
415 		libnames[p++]="/usr/lib/oracle/11.2/client/lib/libclntsh.so";
416 	}
417 	libnames[p++]="/opt/instantclient_11_2/libclntsh.so.11.2";
418 	libnames[p++]="/usr/local/instantclient_11_2/libclntsh.so.11.2";
419 
420 	if (sizeof(long)==8) {
421 		libnames[p++]="/usr/lib/oracle/10.2/client64/lib/libclntsh.so";
422 	} else {
423 		libnames[p++]="/usr/lib/oracle/10.2/client/lib/libclntsh.so";
424 	}
425 	libnames[p++]="/opt/instantclient_10_2/libclntsh.so.10.2";
426 	libnames[p++]="/usr/local/instantclient_10_2/libclntsh.so.10.2";
427 
428 	libnames[p++]=NULL;
429 
430 	// look for the library
431 	const char	**libname=libnames;
432 	while (*libname) {
433 		if (file::readable(*libname)) {
434 			break;
435 		}
436 		libname++;
437 	}
438 	if (!*libname) {
439 		errormessage->clear();
440 		errormessage->append("\nFailed to load Oracle libraries.\n");
441 		if (charstring::isNullOrEmpty(oraclehome)) {
442 			errormessage->append("ORACLE_HOME not set and none");
443 		} else {
444 			errormessage->append("None");
445 		}
446 		errormessage->append(" of these libraries were found:\n");
447 		libname=libnames;
448 		while (*libname) {
449 			errormessage->append('	');
450 			errormessage->append(*libname)->append('\n');
451 			libname++;
452 		}
453 		return false;
454 	}
455 
456 	// open the library
457 	if (!lib.open(*libname,true,true)) {
458 		goto error;
459 	}
460 
461 	// get the functions we need
462 	OCIEnvCreate=(sword (*)(OCIEnv **,
463 					ub4,
464 					void *,
465 					void *(*)(void *,size_t),
466 					void *(*)(void *,void *,size_t),
467 					void (*)(void *,void *),
468 					size_t,
469 					void **))
470 				lib.getSymbol("OCIEnvCreate");
471 	if (!OCIEnvCreate) {
472 		goto error;
473 	}
474 
475 	OCIInitialize=(sword (*)(ub4,
476 					void *,
477 					void *(*)(void *,size_t),
478 					void *(*ralocfp)(void *,void *,size_t),
479 					void (*)(void *,void *)))
480 				lib.getSymbol("OCIInitialize");
481 	if (!OCIInitialize) {
482 		goto error;
483 	}
484 
485 	OCIHandleAlloc=(sword (*)(const void *,
486 					void **,
487 					const ub4,
488 					const size_t,
489 					void **))
490 				lib.getSymbol("OCIHandleAlloc");
491 	if (!OCIHandleAlloc) {
492 		goto error;
493 	}
494 
495 	OCIServerAttach=(sword (*)(OCIServer *,
496 					OCIError *,
497 					const OraText *,
498 					sb4,
499 					ub4))
500 				lib.getSymbol("OCIServerAttach");
501 	if (!OCIServerAttach) {
502 		goto error;
503 	}
504 
505 	OCIServerDetach=(sword (*)(OCIServer *,
506 					OCIError *,
507 					ub4))
508 				lib.getSymbol("OCIServerDetach");
509 	if (!OCIServerDetach) {
510 		goto error;
511 	}
512 
513 	OCISessionBegin=(sword (*)(OCISvcCtx *,
514 					OCIError *,
515 					OCISession *,
516 					ub4,
517 					ub4))
518 				lib.getSymbol("OCISessionBegin");
519 	if (!OCISessionBegin) {
520 		goto error;
521 	}
522 
523 	OCISessionEnd=(sword (*)(OCISvcCtx *,
524 					OCIError *,
525 					OCISession *,
526 					ub4))
527 				lib.getSymbol("OCISessionEnd");
528 	if (!OCISessionEnd) {
529 		goto error;
530 	}
531 
532 	OCIServerVersion=(sword (*)(void *,
533 					OCIError *,
534 					OraText *,
535 					ub4,
536 					ub1))
537 				lib.getSymbol("OCIServerVersion");
538 	if (!OCIServerVersion) {
539 		goto error;
540 	}
541 
542 	OCIStmtPrepare2=(sword (*)(OCISvcCtx *,
543 					OCIStmt **,
544 					OCIError *,
545 					const OraText *,
546 					ub4,
547 					const OraText *,
548 					ub4,
549 					ub4,
550 					ub4))
551 				lib.getSymbol("OCIStmtPrepare2");
552 	if (!OCIStmtPrepare2) {
553 		goto error;
554 	}
555 
556 	OCIStmtExecute=(sword (*)(OCISvcCtx *,
557 					OCIStmt *,
558 					OCIError *,
559 					ub4,
560 					ub4,
561 					const OCISnapshot *,
562 					OCISnapshot *,
563 					ub4))
564 				lib.getSymbol("OCIStmtExecute");
565 	if (!OCIStmtExecute) {
566 		goto error;
567 	}
568 
569 	OCIStmtRelease=(sword (*)(OCIStmt *,
570 					OCIError *,
571 					const OraText *,
572 					ub4,
573 					ub4))
574 				lib.getSymbol("OCIStmtRelease");
575 	if (!OCIStmtRelease) {
576 		goto error;
577 	}
578 
579 	OCIErrorGet=(sword (*)(void *,
580 					ub4,
581 					OraText *,
582 					sb4 *,
583 					OraText *,
584 					ub4,
585 					ub4))
586 				lib.getSymbol("OCIErrorGet");
587 	if (!OCIErrorGet) {
588 		goto error;
589 	}
590 
591 	OCIStmtPrepare=(sword (*)(OCIStmt *,
592 					OCIError *,
593 					const OraText *,
594 					ub4,
595 					ub4,
596 					ub4))
597 				lib.getSymbol("OCIStmtPrepare");
598 	if (!OCIStmtPrepare) {
599 		goto error;
600 	}
601 
602 	OCIBindByPos=(sword (*)(OCIStmt *,
603 					OCIBind **,
604 					OCIError *,
605 					ub4,
606 					void *,
607 					sb4,
608 					ub2,
609 					void *,
610 					ub2 *,
611 					ub2 *,
612 					ub4,
613 					ub4 *,
614 					ub4))
615 				lib.getSymbol("OCIBindByPos");
616 	if (!OCIBindByPos) {
617 		goto error;
618 	}
619 
620 	OCIBindByName=(sword (*)(OCIStmt *,
621 					OCIBind **,
622 					OCIError *,
623 					const OraText *,
624 					sb4,
625 					void *,
626 					sb4,
627 					ub2,
628 					void *p,
629 					ub2 *,
630 					ub2 *,
631 					ub4,
632 					ub4 *,
633 					ub4))
634 				lib.getSymbol("OCIBindByName");
635 	if (!OCIBindByName) {
636 		goto error;
637 	}
638 
639 	OCIDescriptorAlloc=(sword (*)(const void *,
640 					void **,
641 					const ub4,
642 					const size_t,
643 					void **))
644 				lib.getSymbol("OCIDescriptorAlloc");
645 	if (!OCIDescriptorAlloc) {
646 		goto error;
647 	}
648 
649 	OCILobCreateTemporary=(sword (*)(OCISvcCtx *,
650 					OCIError *,
651 					OCILobLocator *,
652 					ub2,
653 					ub1,
654 					ub1,
655 					boolean,
656 					OCIDuration))
657 				lib.getSymbol("OCILobCreateTemporary");
658 	if (!OCILobCreateTemporary) {
659 		goto error;
660 	}
661 
662 	OCILobOpen=(sword (*)(OCISvcCtx *,
663 					OCIError *,
664 					OCILobLocator *,
665 					ub1))
666 				lib.getSymbol("OCILobOpen");
667 	if (!OCILobOpen) {
668 		goto error;
669 	}
670 
671 	OCILobFreeTemporary=(sword (*)(OCISvcCtx *,
672 					OCIError *,
673 					OCILobLocator *))
674 				lib.getSymbol("OCILobFreeTemporary");
675 	if (!OCILobFreeTemporary) {
676 		goto error;
677 	}
678 
679 	OCILobWrite=(sword (*)(OCISvcCtx *,
680 					OCIError *,
681 					OCILobLocator *,
682 					ub4 *,
683 					ub4,
684 					void *,
685 					ub4,
686 					ub1,
687 					void *,
688 					sb4 (*)(dvoid*,dvoid*,ub4*,ub1 *),
689 					ub2,
690 					ub1))
691 				lib.getSymbol("OCILobWrite");
692 	if (!OCILobWrite) {
693 		goto error;
694 	}
695 
696 	OCILobClose=(sword (*)(OCISvcCtx *,
697 					OCIError *,
698 					OCILobLocator *))
699 				lib.getSymbol("OCILobClose");
700 	if (!OCILobClose) {
701 		goto error;
702 	}
703 
704 	OCILobGetLength=(sword (*)(OCISvcCtx *,
705 					OCIError *,
706 					OCILobLocator *,
707 					ub4 *))
708 				lib.getSymbol("OCILobGetLength");
709 	if (!OCILobGetLength) {
710 		goto error;
711 	}
712 
713 	OCILobRead=(sword (*)(OCISvcCtx *,
714 					OCIError *,
715 					OCILobLocator *,
716 					ub4 *,
717 					ub4,
718 					void *,
719 					ub4,
720 					void *,
721 					sb4 (*)(dvoid *,CONST dvoid *,ub4,ub1),
722 					ub2,
723 					ub1))
724 				lib.getSymbol("OCILobRead");
725 	if (!OCILobRead) {
726 		goto error;
727 	}
728 
729 	OCIAttrSet=(sword (*)(void *,
730 					ub4,
731 					void *,
732 					ub4,
733 					ub4,
734 					OCIError *))
735 				lib.getSymbol("OCIAttrSet");
736 	if (!OCIAttrSet) {
737 		goto error;
738 	}
739 
740 	OCIAttrGet=(sword (*)(const void *,
741 					ub4,
742 					void *,
743 					ub4 *,
744 					ub4,
745 					OCIError *))
746 				lib.getSymbol("OCIAttrGet");
747 	if (!OCIAttrGet) {
748 		goto error;
749 	}
750 
751 	OCIDefineByPos=(sword (*)(OCIStmt *,
752 					OCIDefine **,
753 					OCIError *,
754 					ub4,
755 					void *,
756 					sb4,
757 					ub2,
758 					void *,
759 					ub2 *,
760 					ub2 *,
761 					ub4))
762 				lib.getSymbol("OCIDefineByPos");
763 	if (!OCIDefineByPos) {
764 		goto error;
765 	}
766 
767 	OCIStmtGetBindInfo=(sword (*)(OCIStmt *,
768 					OCIError *,
769 					ub4,
770 					ub4,
771 					sb4 *,
772 					OraText *[],
773 					ub1[],
774 					OraText *[],
775 					ub1[],
776 					ub1[],
777 					OCIBind **))
778 				lib.getSymbol("OCIStmtGetBindInfo");
779 	if (!OCIStmtGetBindInfo) {
780 		goto error;
781 	}
782 
783 	OCIStmtFetch=(sword (*)(OCIStmt *,
784 					OCIError *,
785 					ub4,
786 					ub2,
787 					ub4))
788 				lib.getSymbol("OCIStmtFetch");
789 	if (!OCIStmtFetch) {
790 		goto error;
791 	}
792 
793 	OCILobIsTemporary=(sword (*)(OCIEnv *,
794 					OCIError *,
795 					OCILobLocator *,
796 					boolean *))
797 				lib.getSymbol("OCILobIsTemporary");
798 	if (!OCILobIsTemporary) {
799 		goto error;
800 	}
801 
802 	OCIDescriptorFree=(sword (*)(void *,
803 					const ub4))
804 				lib.getSymbol("OCIDescriptorFree");
805 	if (!OCIDescriptorFree) {
806 		goto error;
807 	}
808 
809 	OCIHandleFree=(sword (*)(void *,
810 					const ub4))
811 				lib.getSymbol("OCIHandleFree");
812 	if (!OCIHandleFree) {
813 		goto error;
814 	}
815 
816 	OCIParamGet=(sword (*)(const void *,
817 					ub4,
818 					OCIError *,
819 					void **,
820 					ub4))
821 				lib.getSymbol("OCIParamGet");
822 	if (!OCIParamGet) {
823 		goto error;
824 	}
825 
826 	OCITransCommit=(sword (*)(OCISvcCtx *,
827 					OCIError *,
828 					ub4))
829 				lib.getSymbol("OCITransCommit");
830 	if (!OCITransCommit) {
831 		goto error;
832 	}
833 
834 	OCITransRollback=(sword (*)(OCISvcCtx *,
835 					OCIError *,
836 					ub4))
837 				lib.getSymbol("OCITransRollback");
838 	if (!OCITransRollback) {
839 		goto error;
840 	}
841 
842 	// success
843 	return true;
844 
845 	// error
846 error:
847 	char	*error=lib.getError();
848 	errormessage->clear();
849 	errormessage->append("\nFailed to load Oracle libraries.\n");
850 	errormessage->append(error)->append('\n');
851 	#ifndef _WIN32
852 	if (charstring::contains(error,"No such file or directory")) {
853 		char		*path=file::dirname(*libname);
854 		const char	*lib=(*libname)+charstring::length(path)+1;
855 		errormessage->append("\n(NOTE: The error message above may "
856 					"be misleading.  Most likely it means "
857 					"that a library that ");
858 		errormessage->append(lib);
859 		errormessage->append(" depends on could not be located.  ");
860 		errormessage->append(lib)->append(" was found in ");
861 		errormessage->append(path)->append(".  Verify that ");
862 		errormessage->append(path);
863 		errormessage->append(" and directories containing each of "
864 					"the libraries that ");
865 		errormessage->append(lib);
866 		errormessage->append(" depends on are included in your "
867 					"LD_LIBRARY_PATH, /etc/ld.so.conf, "
868 					"or /etc/ld.so.conf.d.  Try using "
869 					"ldd to show ");
870 		errormessage->append(path)->append('/')->append(lib);
871 		errormessage->append("'s dependencies.)\n");
872 		delete[] path;
873 	}
874 	#endif
875 	delete[] error;
876 	return false;
877 }
878