1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge 1995 - 2009 */
6 /* See the file NOTICE for conditions of use and distribution. */
8 /* Interface to an Oracle database. This code was originally supplied by
9 Paul Kelly, but I have hacked it around for various reasons, and tried to add
10 some comments from my position of Oracle ignorance. */
16 /* The Oracle system headers */
22 #define PARSE_NO_DEFER 0 /* parse straight away */
23 #define PARSE_V7_LNG 2
24 #define MAX_ITEM_BUFFER_SIZE 1024 /* largest size of a cell of data */
25 #define MAX_SELECT_LIST_SIZE 32 /* maximum number of columns (not rows!) */
27 /* Paul's comment on this was "change this to 512 for 64bit cpu", but I don't
28 understand why. The Oracle manual just asks for 256 bytes.
30 That was years ago. Jin Choi suggested (March 2007) that this change should
31 be made in the source, as at worst it wastes 256 bytes, and it saves people
32 having to discover about this for themselves as more and more systems are
33 64-bit. So I have changed 256 to 512. */
37 /* Internal/external datatype codes */
46 /* ORACLE error codes used in demonstration programs */
48 #define VAR_NOT_IN_LIST 1007
49 #define NO_DATA_FOUND 1403
51 typedef struct Ora_Describe {
54 sb1 buf[MAX_ITEM_BUFFER_SIZE];
62 typedef struct Ora_Define {
63 ub1 buf[MAX_ITEM_BUFFER_SIZE];
67 ub2 col_retlen, col_retcode;
70 /* Structure and anchor for caching connections. */
72 typedef struct oracle_connection {
73 struct oracle_connection *next;
75 struct cda_def *handle;
79 static oracle_connection *oracle_connections = NULL;
85 /*************************************************
86 * Set up message after error *
87 *************************************************/
89 /* Sets up a message from a local string plus whatever Oracle gives.
92 oracle_handle the handle of the connection
94 msg local text message
98 oracle_error(struct cda_def *oracle_handle, int rc, uschar *msg)
101 oerhms(oracle_handle, rc, tmp, sizeof(tmp));
102 return string_sprintf("ORACLE %s: %s", msg, tmp);
107 /*************************************************
108 * Describe and define the select list items *
109 *************************************************/
111 /* Figures out sizes, types, and numbers.
116 desc descriptions put here
118 Returns: number of fields
122 describe_define(Cda_Def *cda, Ora_Define *def, Ora_Describe *desc)
124 sword col, deflen, deftyp;
126 static sword numwidth = 8;
128 /* Describe the select-list items. */
130 for (col = 0; col < MAX_SELECT_LIST_SIZE; col++)
132 desc[col].buflen = MAX_ITEM_BUFFER_SIZE;
134 if (odescr(cda, col + 1, &desc[col].dbsize,
135 &desc[col].dbtype, &desc[col].buf[0],
136 &desc[col].buflen, &desc[col].dsize,
137 &desc[col].precision, &desc[col].scale,
138 &desc[col].nullok) != 0)
140 /* Break on end of select list. */
141 if (cda->rc == VAR_NOT_IN_LIST) break; else return -1;
144 /* Adjust sizes and types for display, handling NUMBER with scale as float. */
146 if (desc[col].dbtype == NUMBER_TYPE)
148 desc[col].dbsize = numwidth;
149 if (desc[col].scale != 0)
151 defptr = (ub1 *)&def[col].flt_buf;
152 deflen = (sword) sizeof(float);
154 desc[col].dbtype = FLOAT_TYPE;
158 defptr = (ub1 *)&def[col].int_buf;
159 deflen = (sword) sizeof(sword);
161 desc[col].dbtype = INT_TYPE;
166 if (desc[col].dbtype == DATE_TYPE)
167 desc[col].dbsize = 9;
168 if (desc[col].dbtype == ROWID_TYPE)
169 desc[col].dbsize = 18;
170 defptr = def[col].buf;
171 deflen = desc[col].dbsize > MAX_ITEM_BUFFER_SIZE ?
172 MAX_ITEM_BUFFER_SIZE : desc[col].dbsize + 1;
173 deftyp = STRING_TYPE;
174 desc[col].dbtype = STRING_TYPE;
177 /* Define an output variable */
179 if (odefin(cda, col + 1,
180 defptr, deflen, deftyp,
181 -1, &def[col].indp, (text *) 0, -1, -1,
182 &def[col].col_retlen,
183 &def[col].col_retcode) != 0)
185 } /* Loop for each column */
192 /*************************************************
194 *************************************************/
196 /* See local README for interface description. */
199 oracle_open(uschar *filename, uschar **errmsg)
201 return (void *)(1); /* Just return something non-null */
206 /*************************************************
208 *************************************************/
210 /* See local README for interface description. */
215 oracle_connection *cn;
216 while ((cn = oracle_connections) != NULL)
218 oracle_connections = cn->next;
219 DEBUG(D_lookup) debug_printf("close ORACLE connection: %s\n", cn->server);
226 /*************************************************
227 * Internal search function *
228 *************************************************/
230 /* This function is called from the find entry point to do the search for a
234 query the query string
235 server the server string
236 resultptr where to store the result
237 errmsg where to point an error message
238 defer_break TRUE if no more servers are to be tried after DEFER
240 The server string is of the form "host/dbname/user/password", for compatibility
241 with MySQL and pgsql, but at present, the dbname is not used. This string is in
242 a nextinlist temporary buffer, so can be overwritten.
244 Returns: OK, FAIL, or DEFER
248 perform_oracle_search(uschar *query, uschar *server, uschar **resultptr,
249 uschar **errmsg, BOOL *defer_break)
252 struct cda_def *oracle_handle = NULL;
253 Ora_Describe *desc = NULL;
254 Ora_Define *def = NULL;
261 unsigned int num_fields = 0;
262 uschar *result = NULL;
263 oracle_connection *cn = NULL;
264 uschar *server_copy = NULL;
268 /* Disaggregate the parameters from the server argument. The order is host,
269 database, user, password. We can write to the string, since it is in a
270 nextinlist temporary buffer. The copy of the string that is used for caching
271 has the password removed. This copy is also used for debugging output. */
273 for (i = 3; i > 0; i--)
275 uschar *pp = Ustrrchr(server, '/');
278 *errmsg = string_sprintf("incomplete ORACLE server data: %s", server);
284 if (i == 3) server_copy = string_copy(server); /* sans password */
286 sdata[0] = server; /* What's left at the start */
288 /* If the database is the empty string, set it NULL - the query must then
291 if (sdata[1][0] == 0) sdata[1] = NULL;
293 /* See if we have a cached connection to the server */
295 for (cn = oracle_connections; cn != NULL; cn = cn->next)
297 if (strcmp(cn->server, server_copy) == 0)
299 oracle_handle = cn->handle;
305 /* If no cached connection, we must set one up */
309 DEBUG(D_lookup) debug_printf("ORACLE new connection: host=%s database=%s "
310 "user=%s\n", sdata[0], sdata[1], sdata[2]);
312 /* Get store for a new connection, initialize it, and connect to the server */
314 oracle_handle = store_get(sizeof(struct cda_def));
315 hda = store_get(HDA_SIZE);
316 memset(hda,'\0',HDA_SIZE);
319 * Perform a default (blocking) login
321 * sdata[0] = tnsname (service name - typically host name)
322 * sdata[1] = dbname - not used at present
323 * sdata[2] = username
327 if(olog(oracle_handle, hda, sdata[2], -1, sdata[3], -1, sdata[0], -1,
328 (ub4)OCI_LM_DEF) != 0)
330 *errmsg = oracle_error(oracle_handle, oracle_handle->rc,
331 US"connection failed");
332 *defer_break = FALSE;
333 goto ORACLE_EXIT_NO_VALS;
336 /* Add the connection to the cache */
338 cn = store_get(sizeof(oracle_connection));
339 cn->server = server_copy;
340 cn->handle = oracle_handle;
341 cn->next = oracle_connections;
343 oracle_connections = cn;
346 /* Else use a previously cached connection - we can write to the server string
347 to obliterate the password because it is in a nextinlist temporary buffer. */
352 debug_printf("ORACLE using cached connection for %s\n", server_copy);
355 /* We have a connection. Open a cursor and run the query */
357 cda = store_get(sizeof(Cda_Def));
359 if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
361 *errmsg = oracle_error(oracle_handle, cda->rc, "failed to open cursor");
362 *defer_break = FALSE;
363 goto ORACLE_EXIT_NO_VALS;
366 if (oparse(cda, (text *)query, (sb4) -1,
367 (sword)PARSE_NO_DEFER, (ub4)PARSE_V7_LNG) != 0)
369 *errmsg = oracle_error(oracle_handle, cda->rc, "query failed");
370 *defer_break = FALSE;
372 goto ORACLE_EXIT_NO_VALS;
375 /* Find the number of fields returned and sort out their types. If the number
376 is one, we don't add field names to the data. Otherwise we do. */
378 def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE);
379 desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE);
381 if ((num_fields = describe_define(cda,def,desc)) == -1)
383 *errmsg = oracle_error(oracle_handle, cda->rc, "describe_define failed");
384 *defer_break = FALSE;
390 *errmsg = oracle_error(oracle_handle, cda->rc, "oexec failed");
391 *defer_break = FALSE;
395 /* Get the fields and construct the result string. If there is more than one
396 row, we insert '\n' between them. */
398 while (cda->rc != NO_DATA_FOUND) /* Loop for each row */
401 if(cda->rc == NO_DATA_FOUND) break;
403 if (result != NULL) result = string_cat(result, &ssize, &offset, "\n", 1);
405 /* Single field - just add on the data */
408 result = string_cat(result, &ssize, &offset, def[0].buf, def[0].col_retlen);
410 /* Multiple fields - precede by file name, removing {lead,trail}ing WS */
412 else for (i = 0; i < num_fields; i++)
415 uschar *s = US desc[i].buf;
417 while (*s != 0 && isspace(*s)) s++;
419 while (slen > 0 && isspace(s[slen-1])) slen--;
420 result = string_cat(result, &ssize, &offset, s, slen);
421 result = string_cat(result, &ssize, &offset, US"=", 1);
423 /* int and float type wont ever need escaping. Otherwise, quote the value
424 if it contains spaces or is empty. */
426 if (desc[i].dbtype != INT_TYPE && desc[i].dbtype != FLOAT_TYPE &&
427 (def[i].buf[0] == 0 || strchr(def[i].buf, ' ') != NULL))
430 result = string_cat(result, &ssize, &offset, "\"", 1);
431 for (j = 0; j < def[i].col_retlen; j++)
433 if (def[i].buf[j] == '\"' || def[i].buf[j] == '\\')
434 result = string_cat(result, &ssize, &offset, "\\", 1);
435 result = string_cat(result, &ssize, &offset, def[i].buf+j, 1);
437 result = string_cat(result, &ssize, &offset, "\"", 1);
440 else switch(desc[i].dbtype)
443 sprintf(CS tmp, "%d", def[i].int_buf);
444 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
448 sprintf(CS tmp, "%f", def[i].flt_buf);
449 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
453 result = string_cat(result, &ssize, &offset, def[i].buf,
458 *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype);
459 *defer_break = FALSE;
464 result = string_cat(result, &ssize, &offset, " ", 1);
468 /* If result is NULL then no data has been found and so we return FAIL.
469 Otherwise, we must terminate the string which has been built; string_cat()
470 always leaves enough room for a terminating zero. */
475 *errmsg = "ORACLE: no data found";
480 store_reset(result + offset + 1);
483 /* Get here by goto from various error checks. */
487 /* Close the cursor; don't close the connection, as it is cached. */
493 /* Non-NULL result indicates a sucessful result */
502 DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
503 return yield; /* FAIL or DEFER */
510 /*************************************************
512 *************************************************/
514 /* See local README for interface description. The handle and filename
515 arguments are not used. Loop through a list of servers while the query is
516 deferred with a retryable error. */
519 oracle_find(void *handle, uschar *filename, uschar *query, int length,
520 uschar **result, uschar **errmsg, BOOL *do_cache)
524 uschar *list = oracle_servers;
527 do_cache = do_cache; /* Placate picky compilers */
529 DEBUG(D_lookup) debug_printf("ORACLE query: %s\n", query);
531 while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
534 int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
535 if (rc != DEFER || defer_break) return rc;
538 if (oracle_servers == NULL)
539 *errmsg = "no ORACLE servers defined (oracle_servers option)";
546 /*************************************************
547 * Quote entry point *
548 *************************************************/
550 /* The only characters that need to be quoted (with backslash) are newline,
551 tab, carriage return, backspace, backslash itself, and the quote characters.
552 Percent and underscore are not escaped. They are only special in contexts where
553 they can be wild cards, and this isn't usually the case for data inserted from
554 messages, since that isn't likely to be treated as a pattern of any kind.
557 s the string to be quoted
558 opt additional option text or NULL if none
560 Returns: the processed string or NULL for a bad option
564 oracle_quote(uschar *s, uschar *opt)
571 if (opt != NULL) return NULL; /* No options are recognized */
573 while ((c = *t++) != 0)
574 if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
576 if (count == 0) return s;
577 t = quoted = store_get((int)strlen(s) + count + 1);
579 while ((c = *s++) != 0)
581 if (strchr("\n\t\r\b\'\"\\", c) != NULL)
586 case '\n': *t++ = 'n';
588 case '\t': *t++ = 't';
590 case '\r': *t++ = 'r';
592 case '\b': *t++ = 'b';
606 /*************************************************
607 * Version reporting entry point *
608 *************************************************/
610 /* See local README for interface description. */
612 #include "../version.h"
615 oracle_version_report(FILE *f)
618 fprintf(f, "Library version: Oracle: Exim version %s\n", EXIM_VERSION_STR);
623 static lookup_info _lookup_info = {
624 US"oracle", /* lookup name */
625 lookup_querystyle, /* query-style lookup */
626 oracle_open, /* open function */
627 NULL, /* check function */
628 oracle_find, /* find function */
629 NULL, /* no close function */
630 oracle_tidy, /* tidy function */
631 oracle_quote, /* quoting function */
632 oracle_version_report /* version reporting */
636 #define oracle_lookup_module_info _lookup_module_info
639 static lookup_info *_lookup_list[] = { &_lookup_info };
640 lookup_module_info oracle_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
642 /* End of lookups/oracle.c */