5997f199d2ce8d09e1dbb9460addeb714ee9cdbc
[users/jgh/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 /* 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 That was years ago. Jin Choi suggested (March 2007) that this change should
48 be made in the source, as at worst it wastes 256 bytes, and it saves people
49 having to discover about this for themselves as more and more systems are
50 64-bit. So I have changed 256 to 512. */
51
52 #define HDA_SIZE 512
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
68 typedef 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
79 typedef 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
89 typedef struct oracle_connection {
90   struct oracle_connection *next;
91   uschar *server;
92   struct cda_def *handle;
93   void   *hda_mem;
94 } oracle_connection;
95
96 static 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
108 Arguments:
109   oracle_handle   the handle of the connection
110   rc              the return code
111   msg             local text message
112 */
113
114 static uschar *
115 oracle_error(struct cda_def *oracle_handle, int rc, uschar *msg)
116 {
117 uschar tmp[1024];
118 oerhms(oracle_handle, rc, tmp, sizeof(tmp));
119 return 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
130 Arguments:
131   cda        the connection
132   def
133   desc       descriptions put here
134
135 Returns:     number of fields
136 */
137
138 static sword
139 describe_define(Cda_Def *cda, Ora_Define *def, Ora_Describe *desc)
140 {
141 sword col, deflen, deftyp;
142 static ub1 *defptr;
143 static sword numwidth = 8;
144
145 /* Describe the select-list items. */
146
147 for (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
204 return col;
205 }
206
207
208
209 /*************************************************
210 *              Open entry point                  *
211 *************************************************/
212
213 /* See local README for interface description. */
214
215 void *
216 oracle_open(uschar *filename, uschar **errmsg)
217 {
218 return (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
229 void
230 oracle_tidy(void)
231 {
232 oracle_connection *cn;
233 while ((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
248 single server.
249
250 Arguments:
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
257 The server string is of the form "host/dbname/user/password", for compatibility
258 with MySQL and pgsql, but at present, the dbname is not used. This string is in
259 a nextinlist temporary buffer, so can be overwritten.
260
261 Returns:       OK, FAIL, or DEFER
262 */
263
264 static int
265 perform_oracle_search(uschar *query, uschar *server, uschar **resultptr,
266   uschar **errmsg, BOOL *defer_break)
267 {
268 Cda_Def *cda = NULL;
269 struct cda_def *oracle_handle = NULL;
270 Ora_Describe *desc = NULL;
271 Ora_Define *def = NULL;
272 void *hda = NULL;
273
274 int i;
275 int ssize = 0;
276 int offset = 0;
277 int yield = DEFER;
278 unsigned int num_fields = 0;
279 uschar *result = NULL;
280 oracle_connection *cn = NULL;
281 uschar *server_copy = NULL;
282 uschar *sdata[4];
283 uschar tmp[1024];
284
285 /* Disaggregate the parameters from the server argument. The order is host,
286 database, user, password. We can write to the string, since it is in a
287 nextinlist temporary buffer. The copy of the string that is used for caching
288 has the password removed. This copy is also used for debugging output. */
289
290 for (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   }
303 sdata[0] = server;   /* What's left at the start */
304
305 /* If the database is the empty string, set it NULL - the query must then
306 define it. */
307
308 if (sdata[1][0] == 0) sdata[1] = NULL;
309
310 /* See if we have a cached connection to the server */
311
312 for (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
324 if (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
364 to obliterate the password because it is in a nextinlist temporary buffer. */
365
366 else
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
374 cda = store_get(sizeof(Cda_Def));
375
376 if (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
383 if (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
393 is one, we don't add field names to the data. Otherwise we do. */
394
395 def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE);
396 desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE);
397
398 if ((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
405 if (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
413 row, we insert '\n' between them. */
414
415 while (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.
486 Otherwise, we must terminate the string which has been built; string_cat()
487 always leaves enough room for a terminating zero. */
488
489 if (result == NULL)
490   {
491   yield = FAIL;
492   *errmsg = "ORACLE: no data found";
493   }
494 else
495   {
496   result[offset] = 0;
497   store_reset(result + offset + 1);
498   }
499
500 /* Get here by goto from various error checks. */
501
502 ORACLE_EXIT:
503
504 /* Close the cursor; don't close the connection, as it is cached. */
505
506 oclose(cda);
507
508 ORACLE_EXIT_NO_VALS:
509
510 /* Non-NULL result indicates a sucessful result */
511
512 if (result != NULL)
513   {
514   *resultptr = result;
515   return OK;
516   }
517 else
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
532 arguments are not used. Loop through a list of servers while the query is
533 deferred with a retryable error. */
534
535 int
536 oracle_find(void *handle, uschar *filename, uschar *query, int length,
537   uschar **result, uschar **errmsg, BOOL *do_cache)
538 {
539 int sep = 0;
540 uschar *server;
541 uschar *list = oracle_servers;
542 uschar buffer[512];
543
544 do_cache = do_cache;   /* Placate picky compilers */
545
546 DEBUG(D_lookup) debug_printf("ORACLE query: %s\n", query);
547
548 while ((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
555 if (oracle_servers == NULL)
556   *errmsg = "no ORACLE servers defined (oracle_servers option)";
557
558 return 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,
568 tab, carriage return, backspace, backslash itself, and the quote characters.
569 Percent and underscore are not escaped. They are only special in contexts where
570 they can be wild cards, and this isn't usually the case for data inserted from
571 messages, since that isn't likely to be treated as a pattern of any kind.
572
573 Arguments:
574   s          the string to be quoted
575   opt        additional option text or NULL if none
576
577 Returns:     the processed string or NULL for a bad option
578 */
579
580 uschar *
581 oracle_quote(uschar *s, uschar *opt)
582 {
583 register int c;
584 int count = 0;
585 uschar *t = s;
586 uschar *quoted;
587
588 if (opt != NULL) return NULL;    /* No options are recognized */
589
590 while ((c = *t++) != 0)
591   if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
592
593 if (count == 0) return s;
594 t = quoted = store_get((int)strlen(s) + count + 1);
595
596 while ((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;
619 return quoted;
620 }
621
622 #endif  /* LOOKUP_ORACLE */
623
624 /* End of lookups/oracle.c */