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 // types...
9 typedef void CS_VOID;
10 typedef unsigned char CS_BYTE;
11 typedef char CS_CHAR;
12 typedef short CS_SMALLINT;
13 typedef int CS_INT;
14 typedef int CS_BOOL;
15 typedef int CS_RETCODE;
16 typedef unsigned int CS_MSGNUM;
17
18
19 // structs...
20 struct CS_CONTEXT;
21 struct CS_CONNECTION;
22 struct CS_COMMAND;
23 struct CS_LOCALE;
24
25 struct CS_DATAFMT {
26 CS_CHAR name[256];
27 CS_INT namelen;
28 CS_INT datatype;
29 CS_INT format;
30 CS_INT maxlength;
31 CS_INT scale;
32 CS_INT precision;
33 CS_INT status;
34 CS_INT count;
35 CS_INT usertype;
36 CS_LOCALE *locale;
37 };
38
39 struct CS_DATEREC {
40 CS_INT dateyear;
41 CS_INT datemonth;
42 CS_INT datedmonth;
43 CS_INT datedyear;
44 CS_INT datedweek;
45 CS_INT datehour;
46 CS_INT dateminute;
47 CS_INT datesecond;
48 CS_INT datemsecond;
49 CS_INT datetzone;
50 CS_INT datesecfrac;
51 CS_INT datesecprec;
52 };
53
54 struct CS_DATETIME {
55 CS_INT dtdays;
56 CS_INT dttime;
57 };
58
59 struct CS_CLIENTMSG {
60 CS_INT severity;
61 CS_MSGNUM msgnumber;
62 CS_CHAR msgstring[1024];
63 CS_INT msgstringlen;
64 CS_INT osnumber;
65 CS_CHAR osstring[1024];
66 CS_INT osstringlen;
67 CS_INT status;
68 CS_BYTE sqlstate[8];
69 CS_INT sqlstatelen;
70 };
71
72 struct CS_SERVERMSG {
73 CS_MSGNUM msgnumber;
74 CS_INT state;
75 CS_INT severity;
76 CS_CHAR text[1024];
77 CS_INT textlen;
78 CS_CHAR svrname[256];
79 CS_INT svrnlen;
80 CS_CHAR proc[256];
81 CS_INT proclen;
82 CS_INT line;
83 CS_INT status;
84 CS_BYTE sqlstate[8];
85 CS_INT sqlstatelen;
86 };
87
88 #define CS_LAYER(L) (CS_MSGNUM) (((L) >> 24) & 0xff)
89 #define CS_ORIGIN(O) (CS_MSGNUM) (((O) >> 16) & 0xff)
90 #define CS_SEVERITY(S) (CS_MSGNUM) (((S) >> 8) & 0xff)
91 #define CS_NUMBER(N) (CS_MSGNUM) ((N) & 0xff)
92
93
94 // create aliases to prevent collisions
95 // eg. cs_ctx_alloc calls cs_config and if my function pointer is named
96 // cs_config, then when cs_ctx_alloc calls cs_config it ends up jumping to the
97 // location of the variable (not the location stored in the variable), rather
98 // than the location of the function.
99 #define ct_init ct_init_ptr
100 #define ct_callback ct_callback_ptr
101 #define ct_con_alloc ct_con_alloc_ptr
102 #define ct_con_props ct_con_props_ptr
103 #define ct_connect ct_connect_ptr
104 #define ct_cancel ct_cancel_ptr
105 #define ct_con_drop ct_con_drop_ptr
106 #define ct_exit ct_exit_ptr
107 #define ct_close ct_close_ptr
108 #define ct_cmd_alloc ct_cmd_alloc_ptr
109 #define ct_cmd_drop ct_cmd_drop_ptr
110 #define ct_cursor ct_cursor_ptr
111 #define ct_command ct_command_ptr
112 #define ct_param ct_param_ptr
113 #define ct_send ct_send_ptr
114 #define ct_results ct_results_ptr
115 #define ct_res_info ct_res_info_ptr
116 #define ct_bind ct_bind_ptr
117 #define ct_describe ct_describe_ptr
118 #define ct_fetch ct_fetch_ptr
119 #define cs_ctx_alloc cs_ctx_alloc_ptr
120 #define cs_config cs_config_ptr
121 #define cs_locale cs_locale_ptr
122 #define cs_loc_alloc cs_loc_alloc_ptr
123 #define cs_loc_drop cs_loc_drop_ptr
124 #define cs_ctx_drop cs_ctx_drop_ptr
125 #define cs_dt_crack cs_dt_crack_ptr
126
127
128 // function pointers...
129 CS_RETCODE (*ct_init)(
130 CS_CONTEXT *,
131 CS_INT);
132
133 CS_RETCODE (*ct_callback)(
134 CS_CONTEXT *,
135 CS_CONNECTION *,
136 CS_INT,
137 CS_INT,
138 CS_VOID *);
139
140 CS_RETCODE (*ct_con_alloc)(
141 CS_CONTEXT *,
142 CS_CONNECTION **);
143
144 CS_RETCODE (*ct_con_props)(
145 CS_CONNECTION *,
146 CS_INT,
147 CS_INT,
148 CS_VOID *,
149 CS_INT,
150 CS_INT *);
151
152 CS_RETCODE (*ct_connect)(
153 CS_CONNECTION *,
154 CS_CHAR *,
155 CS_INT);
156
157 CS_RETCODE (*ct_cancel)(
158 CS_CONNECTION *,
159 CS_COMMAND *,
160 CS_INT);
161
162 CS_RETCODE (*ct_con_drop)(
163 CS_CONNECTION *);
164
165 CS_RETCODE (*ct_exit)(
166 CS_CONTEXT *,
167 CS_INT);
168
169 CS_RETCODE (*ct_close)(
170 CS_CONNECTION *,
171 CS_INT);
172
173 CS_RETCODE (*ct_cmd_alloc)(
174 CS_CONNECTION *,
175 CS_COMMAND **);
176
177 CS_RETCODE (*ct_cmd_drop)(
178 CS_COMMAND *);
179
180 CS_RETCODE (*ct_cursor)(
181 CS_COMMAND *,
182 CS_INT,
183 CS_CHAR *,
184 CS_INT,
185 CS_CHAR *,
186 CS_INT,
187 CS_INT);
188
189 CS_RETCODE (*ct_command)(
190 CS_COMMAND *,
191 CS_INT,
192 CS_CHAR *,
193 CS_INT,
194 CS_INT);
195
196 CS_RETCODE (*ct_param)(
197 CS_COMMAND *,
198 CS_DATAFMT *,
199 CS_VOID *,
200 CS_INT,
201 CS_SMALLINT);
202
203 CS_RETCODE (*ct_send)(
204 CS_COMMAND *);
205
206 CS_RETCODE (*ct_results)(
207 CS_COMMAND *,
208 CS_INT *);
209
210 CS_RETCODE (*ct_res_info)(
211 CS_COMMAND *,
212 CS_INT,
213 CS_VOID *,
214 CS_INT,
215 CS_INT *);
216
217 CS_RETCODE (*ct_bind)(
218 CS_COMMAND *,
219 CS_INT,
220 CS_DATAFMT *,
221 CS_VOID *,
222 CS_INT *,
223 CS_SMALLINT *);
224
225 CS_RETCODE (*ct_describe)(
226 CS_COMMAND *,
227 CS_INT,
228 CS_DATAFMT *);
229
230 CS_RETCODE (*ct_fetch)(
231 CS_COMMAND *,
232 CS_INT,
233 CS_INT,
234 CS_INT,
235 CS_INT *);
236
237 CS_RETCODE (*cs_ctx_alloc)(
238 CS_INT,
239 CS_CONTEXT **);
240
241 CS_RETCODE (*cs_config)(
242 CS_CONTEXT *,
243 CS_INT,
244 CS_INT,
245 CS_VOID *,
246 CS_INT,
247 CS_INT *);
248
249 CS_RETCODE (*cs_locale)(
250 CS_CONTEXT *,
251 CS_INT,
252 CS_LOCALE *,
253 CS_INT,
254 CS_CHAR *,
255 CS_INT,
256 CS_INT *);
257
258 CS_RETCODE (*cs_loc_alloc)(
259 CS_CONTEXT *,
260 CS_LOCALE **);
261
262 CS_RETCODE (*cs_loc_drop)(
263 CS_CONTEXT *,
264 CS_LOCALE *);
265
266 CS_RETCODE (*cs_ctx_drop)(
267 CS_CONTEXT *);
268
269 CS_RETCODE (*cs_dt_crack)(
270 CS_CONTEXT *,
271 CS_INT,
272 CS_VOID *,
273 CS_DATEREC *);
274
275
276 // constants...
277 #define CS_VERSION_100 (CS_INT)113
278
279 #define CS_SET (CS_INT)34
280
281 #define CS_MESSAGE_CB (CS_INT)9119
282
283 #define CS_UNUSED (CS_INT)(-99999)
284
285 #define CS_SUCCEED (CS_RETCODE)1
286 #define CS_FAIL (CS_RETCODE)0
287
288 #define CS_SERVERMSG_CB (CS_INT)2
289 #define CS_CLIENTMSG_CB (CS_INT)3
290
291 #define CS_USERNAME (CS_INT)9100
292 #define CS_PASSWORD (CS_INT)9101
293 #define CS_APPNAME (CS_INT)9102
294 #define CS_HOSTNAME (CS_INT)9103
295 #define CS_PACKETSIZE (CS_INT)9107
296 #define CS_LOC_PROP (CS_INT)9125
297 #define CS_SEC_ENCRYPTION (CS_INT)9135
298
299 #define CS_TRUE (CS_BOOL)1
300 #define CS_FALSE (CS_BOOL)0
301
302 #define CS_SYB_LANG (CS_INT)8
303 #define CS_SYB_CHARSET (CS_INT)9
304
305 #define CS_LANG_CMD (CS_INT)148
306 #define CS_RPC_CMD (CS_INT)149
307
308 #define CS_ROW_RESULT (CS_INT)4040
309 #define CS_CURSOR_RESULT (CS_INT)4041
310 #define CS_PARAM_RESULT (CS_INT)4042
311 #define CS_COMPUTE_RESULT (CS_INT)4045
312 #define CS_CMD_SUCCEED (CS_INT)4047
313 #define CS_CMD_FAIL (CS_INT)4048
314
315 #define CS_ROW_COUNT (CS_INT)800
316 #define CS_NUMDATA (CS_INT)803
317
318 #define CS_CANCEL_CURRENT (CS_INT)6000
319 #define CS_CANCEL_ALL (CS_INT)6001
320
321 #define CS_ILLEGAL_TYPE (CS_INT)(-1)
322 #define CS_CHAR_TYPE (CS_INT)0
323 #define CS_BINARY_TYPE (CS_INT)1
324 #define CS_LONGCHAR_TYPE (CS_INT)2
325 #define CS_LONGBINARY_TYPE (CS_INT)3
326 #define CS_TEXT_TYPE (CS_INT)4
327 #define CS_IMAGE_TYPE (CS_INT)5
328 #define CS_TINYINT_TYPE (CS_INT)6
329 #define CS_SMALLINT_TYPE (CS_INT)7
330 #define CS_INT_TYPE (CS_INT)8
331 #define CS_REAL_TYPE (CS_INT)9
332 #define CS_FLOAT_TYPE (CS_INT)10
333 #define CS_BIT_TYPE (CS_INT)11
334 #define CS_DATETIME_TYPE (CS_INT)12
335 #define CS_DATETIME4_TYPE (CS_INT)13
336 #define CS_MONEY_TYPE (CS_INT)14
337 #define CS_MONEY4_TYPE (CS_INT)15
338 #define CS_NUMERIC_TYPE (CS_INT)16
339 #define CS_DECIMAL_TYPE (CS_INT)17
340 #define CS_VARCHAR_TYPE (CS_INT)18
341 #define CS_VARBINARY_TYPE (CS_INT)19
342 #define CS_LONG_TYPE (CS_INT)20
343 #define CS_SENSITIVITY_TYPE (CS_INT)21
344 #define CS_BOUNDARY_TYPE (CS_INT)22
345 #define CS_VOID_TYPE (CS_INT)23
346 #define CS_USHORT_TYPE (CS_INT)24
347 #define CS_BIGINT_TYPE (CS_INT)30
348 #define CS_UBIGINT_TYPE (CS_INT)33
349 #define CS_XML_TYPE (CS_INT)34
350
351 #define CS_FMT_NULLTERM (CS_INT)0x1
352
353 #define CS_CURSOR_DECLARE (CS_INT)700
354 #define CS_CURSOR_OPEN (CS_INT)701
355 #define CS_CURSOR_ROWS (CS_INT)703
356 #define CS_CURSOR_CLOSE (CS_INT)706
357
358 #define CS_DEALLOC (CS_INT)711
359
360 #define CS_READ_ONLY (CS_INT)0x0002
361
362 #define CS_EXTERNAL_ERR (CS_RETCODE)(-200)
363 #define CS_ROW_FAIL (CS_RETCODE)(CS_EXTERNAL_ERR - 3)
364 #define CS_END_RESULTS (CS_RETCODE)(CS_EXTERNAL_ERR - 5)
365
366 #define CS_FORCE_CLOSE (CS_INT)301
367
368 #define CS_FMT_UNUSED (CS_INT)0x0
369
370 #define CS_KEY (CS_INT)0x2
371 #define CS_VERSION_KEY (CS_INT)0x4
372 #define CS_CANBENULL (CS_INT)0x20
373 #define CS_INPUTVALUE (CS_INT)0x100
374 #define CS_IDENTITY (CS_INT)0x8000
375
376 #define CS_RETURN (CS_INT)0x400
377
378 #define CS_LC_ALL (CS_INT)7
379
380 #define CS_SV_RETRY_FAIL (CS_INT)2
381
382
383 // dlopen infrastructure...
384 static bool alreadyopen=false;
385 static dynamiclib lib;
386
loadLibraries(stringbuffer * errormessage)387 static bool loadLibraries(stringbuffer *errormessage) {
388
389 // don't open multiple times...
390 if (alreadyopen) {
391 return true;
392 }
393 alreadyopen=true;
394
395 // build path names
396 const char **pathnames=new const char *[12];
397 uint16_t p=0;
398 stringbuffer libdir16;
399 stringbuffer libdir15;
400 stringbuffer libdir125;
401 const char *sybase=environment::getValue("SYBASE");
402 if (!charstring::isNullOrEmpty(sybase)) {
403 libdir16.append(sybase)->append("/OCS-16_0/lib");
404 libdir15.append(sybase)->append("/OCS-15_0/lib");
405 libdir125.append(sybase)->append("/OCS-12_5/lib");
406 pathnames[p++]=libdir16.getString();
407 pathnames[p++]=libdir15.getString();
408 pathnames[p++]=libdir125.getString();
409 }
410 pathnames[p++]="/opt/sap/OCS-16_0/lib";
411 pathnames[p++]="/opt/sybase/OCS-15_0/lib";
412 pathnames[p++]="/opt/sybase/OCS-12_5/lib";
413 pathnames[p++]="/opt/sybase-12.5/OCS-12_5/lib";
414 pathnames[p++]="/opt/sybase-11.9.2/lib";
415 pathnames[p++]="/opt/sybase-11.0.3.3/lib";
416 pathnames[p++]="/opt/sybase/lib";
417 pathnames[p++]="/usr/local/sybase/lib";
418 pathnames[p++]=NULL;
419
420 // look for the library
421 const char *libname="libsybblk64.so";
422 stringbuffer libfilename;
423 const char **path=pathnames;
424 while (*path) {
425 libfilename.clear();
426 libfilename.append(*path)->append('/')->append(libname);
427 if (file::readable(libfilename.getString())) {
428 break;
429 }
430 path++;
431 }
432 if (!*path) {
433 errormessage->clear();
434 errormessage->append("\nFailed to load SAP libraries.\n");
435 if (charstring::isNullOrEmpty(sybase)) {
436 errormessage->append("SYBASE not set and ");
437 }
438 errormessage->append(libname)->append(" was not found in any "
439 "of these paths:\n");
440 path=pathnames;
441 while (*path) {
442 errormessage->append(' ')->append(*path)->append('\n');
443 path++;
444 }
445 return false;
446 }
447
448 // open the library
449 if (!lib.open(libfilename.getString(),true,true)) {
450 goto error;
451 }
452
453 // get the functions we need
454 ct_init=(CS_RETCODE (*)(
455 CS_CONTEXT *,
456 CS_INT))
457 lib.getSymbol("ct_init");
458 if (!ct_init) {
459 goto error;
460 }
461
462 ct_callback=(CS_RETCODE (*)(
463 CS_CONTEXT *,
464 CS_CONNECTION *,
465 CS_INT,
466 CS_INT,
467 CS_VOID *))
468 lib.getSymbol("ct_callback");
469 if (!ct_callback) {
470 goto error;
471 }
472
473 ct_con_alloc=(CS_RETCODE (*)(
474 CS_CONTEXT *,
475 CS_CONNECTION **))
476 lib.getSymbol("ct_con_alloc");
477 if (!ct_con_alloc) {
478 goto error;
479 }
480
481 ct_con_props=(CS_RETCODE (*)(
482 CS_CONNECTION *,
483 CS_INT,
484 CS_INT,
485 CS_VOID *,
486 CS_INT,
487 CS_INT *))
488 lib.getSymbol("ct_con_props");
489 if (!ct_con_props) {
490 goto error;
491 }
492
493 ct_connect=(CS_RETCODE (*)(
494 CS_CONNECTION *,
495 CS_CHAR *,
496 CS_INT))
497 lib.getSymbol("ct_connect");
498 if (!ct_connect) {
499 goto error;
500 }
501
502 ct_cancel=(CS_RETCODE (*)(
503 CS_CONNECTION *,
504 CS_COMMAND *,
505 CS_INT))
506 lib.getSymbol("ct_cancel");
507 if (!ct_cancel) {
508 goto error;
509 }
510
511 ct_con_drop=(CS_RETCODE (*)(
512 CS_CONNECTION *))
513 lib.getSymbol("ct_con_drop");
514 if (!ct_con_drop) {
515 goto error;
516 }
517
518 ct_exit=(CS_RETCODE (*)(
519 CS_CONTEXT *,
520 CS_INT))
521 lib.getSymbol("ct_exit");
522 if (!ct_exit) {
523 goto error;
524 }
525
526 ct_close=(CS_RETCODE (*)(
527 CS_CONNECTION *,
528 CS_INT))
529 lib.getSymbol("ct_close");
530 if (!ct_close) {
531 goto error;
532 }
533
534 ct_cmd_alloc=(CS_RETCODE (*)(
535 CS_CONNECTION *,
536 CS_COMMAND **))
537 lib.getSymbol("ct_cmd_alloc");
538 if (!ct_cmd_alloc) {
539 goto error;
540 }
541
542 ct_cmd_drop=(CS_RETCODE (*)(
543 CS_COMMAND *))
544 lib.getSymbol("ct_cmd_drop");
545 if (!ct_cmd_drop) {
546 goto error;
547 }
548
549 ct_cursor=(CS_RETCODE (*)(
550 CS_COMMAND *,
551 CS_INT,
552 CS_CHAR *,
553 CS_INT,
554 CS_CHAR *,
555 CS_INT,
556 CS_INT))
557 lib.getSymbol("ct_cursor");
558 if (!ct_cursor) {
559 goto error;
560 }
561
562 ct_command=(CS_RETCODE (*)(
563 CS_COMMAND *,
564 CS_INT,
565 CS_CHAR *,
566 CS_INT,
567 CS_INT))
568 lib.getSymbol("ct_command");
569 if (!ct_command) {
570 goto error;
571 }
572
573 ct_param=(CS_RETCODE (*)(
574 CS_COMMAND *,
575 CS_DATAFMT *,
576 CS_VOID *,
577 CS_INT,
578 CS_SMALLINT))
579 lib.getSymbol("ct_param");
580 if (!ct_param) {
581 goto error;
582 }
583
584 ct_send=(CS_RETCODE (*)(
585 CS_COMMAND *))
586 lib.getSymbol("ct_send");
587 if (!ct_send) {
588 goto error;
589 }
590
591 ct_results=(CS_RETCODE (*)(
592 CS_COMMAND *,
593 CS_INT *))
594 lib.getSymbol("ct_results");
595 if (!ct_results) {
596 goto error;
597 }
598
599 ct_res_info=(CS_RETCODE (*)(
600 CS_COMMAND *,
601 CS_INT,
602 CS_VOID *,
603 CS_INT,
604 CS_INT *))
605 lib.getSymbol("ct_res_info");
606 if (!ct_res_info) {
607 goto error;
608 }
609
610 ct_bind=(CS_RETCODE (*)(
611 CS_COMMAND *,
612 CS_INT,
613 CS_DATAFMT *,
614 CS_VOID *,
615 CS_INT *,
616 CS_SMALLINT *))
617 lib.getSymbol("ct_bind");
618 if (!ct_bind) {
619 goto error;
620 }
621
622 ct_describe=(CS_RETCODE (*)(
623 CS_COMMAND *,
624 CS_INT,
625 CS_DATAFMT *))
626 lib.getSymbol("ct_describe");
627 if (!ct_describe) {
628 goto error;
629 }
630
631 ct_fetch=(CS_RETCODE (*)(
632 CS_COMMAND *,
633 CS_INT,
634 CS_INT,
635 CS_INT,
636 CS_INT *))
637 lib.getSymbol("ct_fetch");
638 if (!ct_fetch) {
639 goto error;
640 }
641
642 cs_ctx_alloc=(CS_RETCODE (*)(
643 CS_INT,
644 CS_CONTEXT **))
645 lib.getSymbol("cs_ctx_alloc");
646 if (!cs_ctx_alloc) {
647 goto error;
648 }
649
650 cs_config=(CS_RETCODE (*)(
651 CS_CONTEXT *,
652 CS_INT,
653 CS_INT,
654 CS_VOID *,
655 CS_INT,
656 CS_INT *))
657 lib.getSymbol("cs_config");
658 if (!cs_config) {
659 goto error;
660 }
661
662 cs_locale=(CS_RETCODE (*)(
663 CS_CONTEXT *,
664 CS_INT,
665 CS_LOCALE *,
666 CS_INT,
667 CS_CHAR *,
668 CS_INT,
669 CS_INT *))
670 lib.getSymbol("cs_locale");
671 if (!cs_locale) {
672 goto error;
673 }
674
675 cs_loc_alloc=(CS_RETCODE (*)(
676 CS_CONTEXT *,
677 CS_LOCALE **))
678 lib.getSymbol("cs_loc_alloc");
679 if (!cs_loc_alloc) {
680 goto error;
681 }
682
683 cs_loc_drop=(CS_RETCODE (*)(
684 CS_CONTEXT *,
685 CS_LOCALE *))
686 lib.getSymbol("cs_loc_drop");
687 if (!cs_loc_drop) {
688 goto error;
689 }
690
691 cs_ctx_drop=(CS_RETCODE (*)(
692 CS_CONTEXT *))
693 lib.getSymbol("cs_ctx_drop");
694 if (!cs_ctx_drop) {
695 goto error;
696 }
697
698 cs_dt_crack=(CS_RETCODE (*)(
699 CS_CONTEXT *,
700 CS_INT,
701 CS_VOID *,
702 CS_DATEREC *))
703 lib.getSymbol("cs_dt_crack");
704 if (!cs_dt_crack) {
705 goto error;
706 }
707
708 // success
709 return true;
710
711 // error
712 error:
713 char *error=lib.getError();
714 errormessage->clear();
715 errormessage->append("\nFailed to load SAP libraries.\n");
716 errormessage->append(error)->append('\n');
717 #ifndef _WIN32
718 if (charstring::contains(error,"No such file or directory")) {
719 errormessage->append("\n(NOTE: The error message above may "
720 "be misleading. Most likely it means "
721 "that a library that ");
722 errormessage->append(libname);
723 errormessage->append(" depends on could not be located. ");
724 errormessage->append(libname)->append(" was found in ");
725 errormessage->append(*path)->append(". Verify that ");
726 errormessage->append(*path);
727 errormessage->append(" and directories containing each of "
728 "the libraries that ");
729 errormessage->append(libname);
730 errormessage->append(" depends on are included in your "
731 "LD_LIBRARY_PATH, /etc/ld.so.conf, "
732 "or /etc/ld.so.conf.d. Try using "
733 "ldd to show ");
734 errormessage->append(*path)->append('/')->append(libname);
735 errormessage->append("'s dependencies.)\n");
736 }
737 #endif
738 delete[] error;
739 return false;
740 }
741