Change HDA_SIZE in oracle.c from 256 to 512. This is needed for 64-bit
[exim.git] / src / src / lookups / oracle.c
CommitLineData
dee5a20a 1/* $Cambridge: exim/src/src/lookups/oracle.c,v 1.5 2007/03/13 09:59:07 ph10 Exp $ */
0756eb3c
PH
2
3/*************************************************
4* Exim - an Internet mail transport agent *
5*************************************************/
6
184e8823 7/* Copyright (c) University of Cambridge 1995 - 2007 */
0756eb3c
PH
8/* See the file NOTICE for conditions of use and distribution. */
9
10/* Interface to an Oracle database. This code was originally supplied by
11Paul Kelly, but I have hacked it around for various reasons, and tried to add
12some comments from my position of Oracle ignorance. */
13
14
15#include "../exim.h"
16
17
18/* We can't just compile this code and allow the library mechanism to omit the
19functions if they are not wanted, because we need to have the ORACLE headers
20available for compiling. Therefore, compile these functions only if
21LOOKUP_ORACLE is defined. However, some compilers don't like compiling empty
22modules, so keep them happy with a dummy when skipping the rest. Make it
23reference itself to stop picky compilers complaining that it is unused, and put
24in a dummy argument to stop even pickier compilers complaining about infinite
25loops. */
26
27#ifndef LOOKUP_ORACLE
28static void dummy(int x) { dummy(x-1); }
29#else
30
31/* The Oracle system headers */
32
33#include <oratypes.h>
34#include <ocidfn.h>
35#include <ocikpr.h>
36
37#include "oracle.h" /* The local header */
38
39#define PARSE_NO_DEFER 0 /* parse straight away */
40#define PARSE_V7_LNG 2
41#define MAX_ITEM_BUFFER_SIZE 1024 /* largest size of a cell of data */
42#define MAX_SELECT_LIST_SIZE 32 /* maximum number of columns (not rows!) */
43
44/* Paul's comment on this was "change this to 512 for 64bit cpu", but I don't
dee5a20a 45understand why. The Oracle manual just asks for 256 bytes.
0756eb3c 46
dee5a20a
PH
47That was years ago. Jin Choi suggested (March 2007) that this change should
48be made in the source, as at worst it wastes 256 bytes, and it saves people
49having to discover about this for themselves as more and more systems are
5064-bit. So I have changed 256 to 512. */
51
52#define HDA_SIZE 512
0756eb3c
PH
53
54/* Internal/external datatype codes */
55
56#define NUMBER_TYPE 2
57#define INT_TYPE 3
58#define FLOAT_TYPE 4
59#define STRING_TYPE 5
60#define ROWID_TYPE 11
61#define DATE_TYPE 12
62
63/* ORACLE error codes used in demonstration programs */
64
65#define VAR_NOT_IN_LIST 1007
66#define NO_DATA_FOUND 1403
67
68typedef struct Ora_Describe {
69 sb4 dbsize;
70 sb2 dbtype;
71 sb1 buf[MAX_ITEM_BUFFER_SIZE];
72 sb4 buflen;
73 sb4 dsize;
74 sb2 precision;
75 sb2 scale;
76 sb2 nullok;
77} Ora_Describe;
78
79typedef struct Ora_Define {
80 ub1 buf[MAX_ITEM_BUFFER_SIZE];
81 float flt_buf;
82 sword int_buf;
83 sb2 indp;
84 ub2 col_retlen, col_retcode;
85} Ora_Define;
86
87/* Structure and anchor for caching connections. */
88
89typedef struct oracle_connection {
90 struct oracle_connection *next;
91 uschar *server;
92 struct cda_def *handle;
93 void *hda_mem;
94} oracle_connection;
95
96static oracle_connection *oracle_connections = NULL;
97
98
99
100
101
102/*************************************************
103* Set up message after error *
104*************************************************/
105
106/* Sets up a message from a local string plus whatever Oracle gives.
107
108Arguments:
109 oracle_handle the handle of the connection
110 rc the return code
111 msg local text message
112*/
113
114static uschar *
115oracle_error(struct cda_def *oracle_handle, int rc, uschar *msg)
116{
117uschar tmp[1024];
118oerhms(oracle_handle, rc, tmp, sizeof(tmp));
119return string_sprintf("ORACLE %s: %s", msg, tmp);
120}
121
122
123
124/*************************************************
125* Describe and define the select list items *
126*************************************************/
127
128/* Figures out sizes, types, and numbers.
129
130Arguments:
131 cda the connection
132 def
133 desc descriptions put here
134
135Returns: number of fields
136*/
137
138static sword
139describe_define(Cda_Def *cda, Ora_Define *def, Ora_Describe *desc)
140{
141sword col, deflen, deftyp;
142static ub1 *defptr;
143static sword numwidth = 8;
144
145/* Describe the select-list items. */
146
147for (col = 0; col < MAX_SELECT_LIST_SIZE; col++)
148 {
149 desc[col].buflen = MAX_ITEM_BUFFER_SIZE;
150
151 if (odescr(cda, col + 1, &desc[col].dbsize,
152 &desc[col].dbtype, &desc[col].buf[0],
153 &desc[col].buflen, &desc[col].dsize,
154 &desc[col].precision, &desc[col].scale,
155 &desc[col].nullok) != 0)
156 {
157 /* Break on end of select list. */
158 if (cda->rc == VAR_NOT_IN_LIST) break; else return -1;
159 }
160
161 /* Adjust sizes and types for display, handling NUMBER with scale as float. */
162
163 if (desc[col].dbtype == NUMBER_TYPE)
164 {
165 desc[col].dbsize = numwidth;
166 if (desc[col].scale != 0)
167 {
168 defptr = (ub1 *)&def[col].flt_buf;
169 deflen = (sword) sizeof(float);
170 deftyp = FLOAT_TYPE;
171 desc[col].dbtype = FLOAT_TYPE;
172 }
173 else
174 {
175 defptr = (ub1 *)&def[col].int_buf;
176 deflen = (sword) sizeof(sword);
177 deftyp = INT_TYPE;
178 desc[col].dbtype = INT_TYPE;
179 }
180 }
181 else
182 {
183 if (desc[col].dbtype == DATE_TYPE)
184 desc[col].dbsize = 9;
185 if (desc[col].dbtype == ROWID_TYPE)
186 desc[col].dbsize = 18;
187 defptr = def[col].buf;
188 deflen = desc[col].dbsize > MAX_ITEM_BUFFER_SIZE ?
189 MAX_ITEM_BUFFER_SIZE : desc[col].dbsize + 1;
190 deftyp = STRING_TYPE;
191 desc[col].dbtype = STRING_TYPE;
192 }
193
194 /* Define an output variable */
195
196 if (odefin(cda, col + 1,
197 defptr, deflen, deftyp,
198 -1, &def[col].indp, (text *) 0, -1, -1,
199 &def[col].col_retlen,
200 &def[col].col_retcode) != 0)
201 return -1;
202 } /* Loop for each column */
203
204return col;
205}
206
207
208
209/*************************************************
210* Open entry point *
211*************************************************/
212
213/* See local README for interface description. */
214
215void *
216oracle_open(uschar *filename, uschar **errmsg)
217{
218return (void *)(1); /* Just return something non-null */
219}
220
221
222
223/*************************************************
224* Tidy entry point *
225*************************************************/
226
227/* See local README for interface description. */
228
229void
230oracle_tidy(void)
231{
232oracle_connection *cn;
233while ((cn = oracle_connections) != NULL)
234 {
235 oracle_connections = cn->next;
236 DEBUG(D_lookup) debug_printf("close ORACLE connection: %s\n", cn->server);
237 ologof(cn->handle);
238 }
239}
240
241
242
243/*************************************************
244* Internal search function *
245*************************************************/
246
247/* This function is called from the find entry point to do the search for a
248single server.
249
250Arguments:
251 query the query string
252 server the server string
253 resultptr where to store the result
254 errmsg where to point an error message
255 defer_break TRUE if no more servers are to be tried after DEFER
256
257The server string is of the form "host/dbname/user/password", for compatibility
258with MySQL and pgsql, but at present, the dbname is not used. This string is in
259a nextinlist temporary buffer, so can be overwritten.
260
261Returns: OK, FAIL, or DEFER
262*/
263
264static int
265perform_oracle_search(uschar *query, uschar *server, uschar **resultptr,
266 uschar **errmsg, BOOL *defer_break)
267{
268Cda_Def *cda = NULL;
269struct cda_def *oracle_handle = NULL;
270Ora_Describe *desc = NULL;
271Ora_Define *def = NULL;
272void *hda = NULL;
273
274int i;
275int ssize = 0;
276int offset = 0;
277int yield = DEFER;
278unsigned int num_fields = 0;
279uschar *result = NULL;
280oracle_connection *cn = NULL;
281uschar *server_copy = NULL;
282uschar *sdata[4];
283uschar tmp[1024];
284
285/* Disaggregate the parameters from the server argument. The order is host,
286database, user, password. We can write to the string, since it is in a
287nextinlist temporary buffer. The copy of the string that is used for caching
288has the password removed. This copy is also used for debugging output. */
289
290for (i = 3; i > 0; i--)
291 {
292 uschar *pp = Ustrrchr(server, '/');
293 if (pp == NULL)
294 {
295 *errmsg = string_sprintf("incomplete ORACLE server data: %s", server);
296 *defer_break = TRUE;
297 return DEFER;
298 }
299 *pp++ = 0;
300 sdata[i] = pp;
301 if (i == 3) server_copy = string_copy(server); /* sans password */
302 }
303sdata[0] = server; /* What's left at the start */
304
305/* If the database is the empty string, set it NULL - the query must then
306define it. */
307
308if (sdata[1][0] == 0) sdata[1] = NULL;
309
310/* See if we have a cached connection to the server */
311
312for (cn = oracle_connections; cn != NULL; cn = cn->next)
313 {
314 if (strcmp(cn->server, server_copy) == 0)
315 {
316 oracle_handle = cn->handle;
317 hda = cn->hda_mem;
318 break;
319 }
320 }
321
322/* If no cached connection, we must set one up */
323
324if (cn == NULL)
325 {
326 DEBUG(D_lookup) debug_printf("ORACLE new connection: host=%s database=%s "
327 "user=%s\n", sdata[0], sdata[1], sdata[2]);
328
329 /* Get store for a new connection, initialize it, and connect to the server */
330
331 oracle_handle = store_get(sizeof(struct cda_def));
332 hda = store_get(HDA_SIZE);
333 memset(hda,'\0',HDA_SIZE);
334
335 /*
336 * Perform a default (blocking) login
337 *
338 * sdata[0] = tnsname (service name - typically host name)
339 * sdata[1] = dbname - not used at present
340 * sdata[2] = username
341 * sdata[3] = passwd
342 */
343
344 if(olog(oracle_handle, hda, sdata[2], -1, sdata[3], -1, sdata[0], -1,
345 (ub4)OCI_LM_DEF) != 0)
346 {
347 *errmsg = oracle_error(oracle_handle, oracle_handle->rc,
348 US"connection failed");
349 *defer_break = FALSE;
350 goto ORACLE_EXIT_NO_VALS;
351 }
352
353 /* Add the connection to the cache */
354
355 cn = store_get(sizeof(oracle_connection));
356 cn->server = server_copy;
357 cn->handle = oracle_handle;
358 cn->next = oracle_connections;
359 cn->hda_mem = hda;
360 oracle_connections = cn;
361 }
362
363/* Else use a previously cached connection - we can write to the server string
364to obliterate the password because it is in a nextinlist temporary buffer. */
365
366else
367 {
368 DEBUG(D_lookup)
369 debug_printf("ORACLE using cached connection for %s\n", server_copy);
370 }
371
372/* We have a connection. Open a cursor and run the query */
373
374cda = store_get(sizeof(Cda_Def));
375
376if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
377 {
378 *errmsg = oracle_error(oracle_handle, cda->rc, "failed to open cursor");
379 *defer_break = FALSE;
380 goto ORACLE_EXIT_NO_VALS;
381 }
382
383if (oparse(cda, (text *)query, (sb4) -1,
384 (sword)PARSE_NO_DEFER, (ub4)PARSE_V7_LNG) != 0)
385 {
386 *errmsg = oracle_error(oracle_handle, cda->rc, "query failed");
387 *defer_break = FALSE;
388 oclose(cda);
389 goto ORACLE_EXIT_NO_VALS;
390 }
391
392/* Find the number of fields returned and sort out their types. If the number
393is one, we don't add field names to the data. Otherwise we do. */
394
395def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE);
396desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE);
397
398if ((num_fields = describe_define(cda,def,desc)) == -1)
399 {
400 *errmsg = oracle_error(oracle_handle, cda->rc, "describe_define failed");
401 *defer_break = FALSE;
402 goto ORACLE_EXIT;
403 }
404
405if (oexec(cda)!=0)
406 {
407 *errmsg = oracle_error(oracle_handle, cda->rc, "oexec failed");
408 *defer_break = FALSE;
409 goto ORACLE_EXIT;
410 }
411
412/* Get the fields and construct the result string. If there is more than one
413row, we insert '\n' between them. */
414
415while (cda->rc != NO_DATA_FOUND) /* Loop for each row */
416 {
417 ofetch(cda);
418 if(cda->rc == NO_DATA_FOUND) break;
419
420 if (result != NULL) result = string_cat(result, &ssize, &offset, "\n", 1);
421
422 /* Single field - just add on the data */
423
424 if (num_fields == 1)
425 result = string_cat(result, &ssize, &offset, def[0].buf, def[0].col_retlen);
426
427 /* Multiple fields - precede by file name, removing {lead,trail}ing WS */
428
429 else for (i = 0; i < num_fields; i++)
430 {
431 int slen;
432 uschar *s = US desc[i].buf;
433
434 while (*s != 0 && isspace(*s)) s++;
435 slen = Ustrlen(s);
436 while (slen > 0 && isspace(s[slen-1])) slen--;
437 result = string_cat(result, &ssize, &offset, s, slen);
438 result = string_cat(result, &ssize, &offset, US"=", 1);
439
440 /* int and float type wont ever need escaping. Otherwise, quote the value
441 if it contains spaces or is empty. */
442
443 if (desc[i].dbtype != INT_TYPE && desc[i].dbtype != FLOAT_TYPE &&
444 (def[i].buf[0] == 0 || strchr(def[i].buf, ' ') != NULL))
445 {
446 int j;
447 result = string_cat(result, &ssize, &offset, "\"", 1);
448 for (j = 0; j < def[i].col_retlen; j++)
449 {
450 if (def[i].buf[j] == '\"' || def[i].buf[j] == '\\')
451 result = string_cat(result, &ssize, &offset, "\\", 1);
452 result = string_cat(result, &ssize, &offset, def[i].buf+j, 1);
453 }
454 result = string_cat(result, &ssize, &offset, "\"", 1);
455 }
456
457 else switch(desc[i].dbtype)
458 {
459 case INT_TYPE:
460 sprintf(CS tmp, "%d", def[i].int_buf);
461 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
462 break;
463
464 case FLOAT_TYPE:
465 sprintf(CS tmp, "%f", def[i].flt_buf);
466 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
467 break;
468
469 case STRING_TYPE:
470 result = string_cat(result, &ssize, &offset, def[i].buf,
471 def[i].col_retlen);
472 break;
473
474 default:
475 *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype);
476 *defer_break = FALSE;
477 result = NULL;
478 goto ORACLE_EXIT;
479 }
480
481 result = string_cat(result, &ssize, &offset, " ", 1);
482 }
483 }
484
485/* If result is NULL then no data has been found and so we return FAIL.
486Otherwise, we must terminate the string which has been built; string_cat()
487always leaves enough room for a terminating zero. */
488
489if (result == NULL)
490 {
491 yield = FAIL;
492 *errmsg = "ORACLE: no data found";
493 }
494else
495 {
496 result[offset] = 0;
497 store_reset(result + offset + 1);
498 }
499
500/* Get here by goto from various error checks. */
501
502ORACLE_EXIT:
503
504/* Close the cursor; don't close the connection, as it is cached. */
505
506oclose(cda);
507
508ORACLE_EXIT_NO_VALS:
509
510/* Non-NULL result indicates a sucessful result */
511
512if (result != NULL)
513 {
514 *resultptr = result;
515 return OK;
516 }
517else
518 {
519 DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
520 return yield; /* FAIL or DEFER */
521 }
522}
523
524
525
526
527/*************************************************
528* Find entry point *
529*************************************************/
530
531/* See local README for interface description. The handle and filename
532arguments are not used. Loop through a list of servers while the query is
533deferred with a retryable error. */
534
535int
536oracle_find(void *handle, uschar *filename, uschar *query, int length,
537 uschar **result, uschar **errmsg, BOOL *do_cache)
538{
539int sep = 0;
540uschar *server;
541uschar *list = oracle_servers;
542uschar buffer[512];
543
544do_cache = do_cache; /* Placate picky compilers */
545
546DEBUG(D_lookup) debug_printf("ORACLE query: %s\n", query);
547
548while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
549 {
550 BOOL defer_break;
551 int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
552 if (rc != DEFER || defer_break) return rc;
553 }
554
555if (oracle_servers == NULL)
556 *errmsg = "no ORACLE servers defined (oracle_servers option)";
557
558return DEFER;
559}
560
561
562
563/*************************************************
564* Quote entry point *
565*************************************************/
566
567/* The only characters that need to be quoted (with backslash) are newline,
568tab, carriage return, backspace, backslash itself, and the quote characters.
569Percent and underscore are not escaped. They are only special in contexts where
570they can be wild cards, and this isn't usually the case for data inserted from
571messages, since that isn't likely to be treated as a pattern of any kind.
572
573Arguments:
574 s the string to be quoted
575 opt additional option text or NULL if none
576
577Returns: the processed string or NULL for a bad option
578*/
579
580uschar *
581oracle_quote(uschar *s, uschar *opt)
582{
583register int c;
584int count = 0;
585uschar *t = s;
586uschar *quoted;
587
588if (opt != NULL) return NULL; /* No options are recognized */
589
590while ((c = *t++) != 0)
591 if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
592
593if (count == 0) return s;
594t = quoted = store_get((int)strlen(s) + count + 1);
595
596while ((c = *s++) != 0)
597 {
598 if (strchr("\n\t\r\b\'\"\\", c) != NULL)
599 {
600 *t++ = '\\';
601 switch(c)
602 {
603 case '\n': *t++ = 'n';
604 break;
605 case '\t': *t++ = 't';
606 break;
607 case '\r': *t++ = 'r';
608 break;
609 case '\b': *t++ = 'b';
610 break;
611 default: *t++ = c;
612 break;
613 }
614 }
615 else *t++ = c;
616 }
617
618*t = 0;
619return quoted;
620}
621
622#endif /* LOOKUP_ORACLE */
623
624/* End of lookups/oracle.c */