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