1 /* $Cambridge: exim/src/src/lookups/oracle.c,v 1.1 2004/10/07 13:10:01 ph10 Exp $ */
3 /*************************************************
4 * Exim - an Internet mail transport agent *
5 *************************************************/
7 /* Copyright (c) University of Cambridge 1995 - 2004 */
8 /* See the file NOTICE for conditions of use and distribution. */
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. */
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
28 static void dummy(int x) { dummy(x-1); }
31 /* The Oracle system headers */
37 #include "oracle.h" /* The local header */
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!) */
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. */
49 /* Internal/external datatype codes */
58 /* ORACLE error codes used in demonstration programs */
60 #define VAR_NOT_IN_LIST 1007
61 #define NO_DATA_FOUND 1403
63 typedef struct Ora_Describe {
66 sb1 buf[MAX_ITEM_BUFFER_SIZE];
74 typedef struct Ora_Define {
75 ub1 buf[MAX_ITEM_BUFFER_SIZE];
79 ub2 col_retlen, col_retcode;
82 /* Structure and anchor for caching connections. */
84 typedef struct oracle_connection {
85 struct oracle_connection *next;
87 struct cda_def *handle;
91 static oracle_connection *oracle_connections = NULL;
97 /*************************************************
98 * Set up message after error *
99 *************************************************/
101 /* Sets up a message from a local string plus whatever Oracle gives.
104 oracle_handle the handle of the connection
106 msg local text message
110 oracle_error(struct cda_def *oracle_handle, int rc, uschar *msg)
113 oerhms(oracle_handle, rc, tmp, sizeof(tmp));
114 return string_sprintf("ORACLE %s: %s", msg, tmp);
119 /*************************************************
120 * Describe and define the select list items *
121 *************************************************/
123 /* Figures out sizes, types, and numbers.
128 desc descriptions put here
130 Returns: number of fields
134 describe_define(Cda_Def *cda, Ora_Define *def, Ora_Describe *desc)
136 sword col, deflen, deftyp;
138 static sword numwidth = 8;
140 /* Describe the select-list items. */
142 for (col = 0; col < MAX_SELECT_LIST_SIZE; col++)
144 desc[col].buflen = MAX_ITEM_BUFFER_SIZE;
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)
152 /* Break on end of select list. */
153 if (cda->rc == VAR_NOT_IN_LIST) break; else return -1;
156 /* Adjust sizes and types for display, handling NUMBER with scale as float. */
158 if (desc[col].dbtype == NUMBER_TYPE)
160 desc[col].dbsize = numwidth;
161 if (desc[col].scale != 0)
163 defptr = (ub1 *)&def[col].flt_buf;
164 deflen = (sword) sizeof(float);
166 desc[col].dbtype = FLOAT_TYPE;
170 defptr = (ub1 *)&def[col].int_buf;
171 deflen = (sword) sizeof(sword);
173 desc[col].dbtype = INT_TYPE;
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;
189 /* Define an output variable */
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)
197 } /* Loop for each column */
204 /*************************************************
206 *************************************************/
208 /* See local README for interface description. */
211 oracle_open(uschar *filename, uschar **errmsg)
213 return (void *)(1); /* Just return something non-null */
218 /*************************************************
220 *************************************************/
222 /* See local README for interface description. */
227 oracle_connection *cn;
228 while ((cn = oracle_connections) != NULL)
230 oracle_connections = cn->next;
231 DEBUG(D_lookup) debug_printf("close ORACLE connection: %s\n", cn->server);
238 /*************************************************
239 * Internal search function *
240 *************************************************/
242 /* This function is called from the find entry point to do the search for a
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
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.
256 Returns: OK, FAIL, or DEFER
260 perform_oracle_search(uschar *query, uschar *server, uschar **resultptr,
261 uschar **errmsg, BOOL *defer_break)
264 struct cda_def *oracle_handle = NULL;
265 Ora_Describe *desc = NULL;
266 Ora_Define *def = NULL;
273 unsigned int num_fields = 0;
274 uschar *result = NULL;
275 oracle_connection *cn = NULL;
276 uschar *server_copy = NULL;
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. */
285 for (i = 3; i > 0; i--)
287 uschar *pp = Ustrrchr(server, '/');
290 *errmsg = string_sprintf("incomplete ORACLE server data: %s", server);
296 if (i == 3) server_copy = string_copy(server); /* sans password */
298 sdata[0] = server; /* What's left at the start */
300 /* If the database is the empty string, set it NULL - the query must then
303 if (sdata[1][0] == 0) sdata[1] = NULL;
305 /* See if we have a cached connection to the server */
307 for (cn = oracle_connections; cn != NULL; cn = cn->next)
309 if (strcmp(cn->server, server_copy) == 0)
311 oracle_handle = cn->handle;
317 /* If no cached connection, we must set one up */
321 DEBUG(D_lookup) debug_printf("ORACLE new connection: host=%s database=%s "
322 "user=%s\n", sdata[0], sdata[1], sdata[2]);
324 /* Get store for a new connection, initialize it, and connect to the server */
326 oracle_handle = store_get(sizeof(struct cda_def));
327 hda = store_get(HDA_SIZE);
328 memset(hda,'\0',HDA_SIZE);
331 * Perform a default (blocking) login
333 * sdata[0] = tnsname (service name - typically host name)
334 * sdata[1] = dbname - not used at present
335 * sdata[2] = username
339 if(olog(oracle_handle, hda, sdata[2], -1, sdata[3], -1, sdata[0], -1,
340 (ub4)OCI_LM_DEF) != 0)
342 *errmsg = oracle_error(oracle_handle, oracle_handle->rc,
343 US"connection failed");
344 *defer_break = FALSE;
345 goto ORACLE_EXIT_NO_VALS;
348 /* Add the connection to the cache */
350 cn = store_get(sizeof(oracle_connection));
351 cn->server = server_copy;
352 cn->handle = oracle_handle;
353 cn->next = oracle_connections;
355 oracle_connections = cn;
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. */
364 debug_printf("ORACLE using cached connection for %s\n", server_copy);
367 /* We have a connection. Open a cursor and run the query */
369 cda = store_get(sizeof(Cda_Def));
371 if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
373 *errmsg = oracle_error(oracle_handle, cda->rc, "failed to open cursor");
374 *defer_break = FALSE;
375 goto ORACLE_EXIT_NO_VALS;
378 if (oparse(cda, (text *)query, (sb4) -1,
379 (sword)PARSE_NO_DEFER, (ub4)PARSE_V7_LNG) != 0)
381 *errmsg = oracle_error(oracle_handle, cda->rc, "query failed");
382 *defer_break = FALSE;
384 goto ORACLE_EXIT_NO_VALS;
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. */
390 def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE);
391 desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE);
393 if ((num_fields = describe_define(cda,def,desc)) == -1)
395 *errmsg = oracle_error(oracle_handle, cda->rc, "describe_define failed");
396 *defer_break = FALSE;
402 *errmsg = oracle_error(oracle_handle, cda->rc, "oexec failed");
403 *defer_break = FALSE;
407 /* Get the fields and construct the result string. If there is more than one
408 row, we insert '\n' between them. */
410 while (cda->rc != NO_DATA_FOUND) /* Loop for each row */
413 if(cda->rc == NO_DATA_FOUND) break;
415 if (result != NULL) result = string_cat(result, &ssize, &offset, "\n", 1);
417 /* Single field - just add on the data */
420 result = string_cat(result, &ssize, &offset, def[0].buf, def[0].col_retlen);
422 /* Multiple fields - precede by file name, removing {lead,trail}ing WS */
424 else for (i = 0; i < num_fields; i++)
427 uschar *s = US desc[i].buf;
429 while (*s != 0 && isspace(*s)) 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);
435 /* int and float type wont ever need escaping. Otherwise, quote the value
436 if it contains spaces or is empty. */
438 if (desc[i].dbtype != INT_TYPE && desc[i].dbtype != FLOAT_TYPE &&
439 (def[i].buf[0] == 0 || strchr(def[i].buf, ' ') != NULL))
442 result = string_cat(result, &ssize, &offset, "\"", 1);
443 for (j = 0; j < def[i].col_retlen; j++)
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);
449 result = string_cat(result, &ssize, &offset, "\"", 1);
452 else switch(desc[i].dbtype)
455 sprintf(CS tmp, "%d", def[i].int_buf);
456 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
460 sprintf(CS tmp, "%f", def[i].flt_buf);
461 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
465 result = string_cat(result, &ssize, &offset, def[i].buf,
470 *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype);
471 *defer_break = FALSE;
476 result = string_cat(result, &ssize, &offset, " ", 1);
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. */
487 *errmsg = "ORACLE: no data found";
492 store_reset(result + offset + 1);
495 /* Get here by goto from various error checks. */
499 /* Close the cursor; don't close the connection, as it is cached. */
505 /* Non-NULL result indicates a sucessful result */
514 DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
515 return yield; /* FAIL or DEFER */
522 /*************************************************
524 *************************************************/
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. */
531 oracle_find(void *handle, uschar *filename, uschar *query, int length,
532 uschar **result, uschar **errmsg, BOOL *do_cache)
536 uschar *list = oracle_servers;
539 do_cache = do_cache; /* Placate picky compilers */
541 DEBUG(D_lookup) debug_printf("ORACLE query: %s\n", query);
543 while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
546 int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
547 if (rc != DEFER || defer_break) return rc;
550 if (oracle_servers == NULL)
551 *errmsg = "no ORACLE servers defined (oracle_servers option)";
558 /*************************************************
559 * Quote entry point *
560 *************************************************/
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.
569 s the string to be quoted
570 opt additional option text or NULL if none
572 Returns: the processed string or NULL for a bad option
576 oracle_quote(uschar *s, uschar *opt)
583 if (opt != NULL) return NULL; /* No options are recognized */
585 while ((c = *t++) != 0)
586 if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
588 if (count == 0) return s;
589 t = quoted = store_get((int)strlen(s) + count + 1);
591 while ((c = *s++) != 0)
593 if (strchr("\n\t\r\b\'\"\\", c) != NULL)
598 case '\n': *t++ = 'n';
600 case '\t': *t++ = 't';
602 case '\r': *t++ = 'r';
604 case '\b': *t++ = 'b';
617 #endif /* LOOKUP_ORACLE */
619 /* End of lookups/oracle.c */