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