1 /* $Cambridge: exim/src/src/lookups/oracle.c,v 1.6 2009/11/16 19:50:38 nm4 Exp $ */
3 /*************************************************
4 * Exim - an Internet mail transport agent *
5 *************************************************/
7 /* Copyright (c) University of Cambridge 1995 - 2009 */
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.
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. */
54 /* Internal/external datatype codes */
63 /* ORACLE error codes used in demonstration programs */
65 #define VAR_NOT_IN_LIST 1007
66 #define NO_DATA_FOUND 1403
68 typedef struct Ora_Describe {
71 sb1 buf[MAX_ITEM_BUFFER_SIZE];
79 typedef struct Ora_Define {
80 ub1 buf[MAX_ITEM_BUFFER_SIZE];
84 ub2 col_retlen, col_retcode;
87 /* Structure and anchor for caching connections. */
89 typedef struct oracle_connection {
90 struct oracle_connection *next;
92 struct cda_def *handle;
96 static oracle_connection *oracle_connections = NULL;
102 /*************************************************
103 * Set up message after error *
104 *************************************************/
106 /* Sets up a message from a local string plus whatever Oracle gives.
109 oracle_handle the handle of the connection
111 msg local text message
115 oracle_error(struct cda_def *oracle_handle, int rc, uschar *msg)
118 oerhms(oracle_handle, rc, tmp, sizeof(tmp));
119 return string_sprintf("ORACLE %s: %s", msg, tmp);
124 /*************************************************
125 * Describe and define the select list items *
126 *************************************************/
128 /* Figures out sizes, types, and numbers.
133 desc descriptions put here
135 Returns: number of fields
139 describe_define(Cda_Def *cda, Ora_Define *def, Ora_Describe *desc)
141 sword col, deflen, deftyp;
143 static sword numwidth = 8;
145 /* Describe the select-list items. */
147 for (col = 0; col < MAX_SELECT_LIST_SIZE; col++)
149 desc[col].buflen = MAX_ITEM_BUFFER_SIZE;
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)
157 /* Break on end of select list. */
158 if (cda->rc == VAR_NOT_IN_LIST) break; else return -1;
161 /* Adjust sizes and types for display, handling NUMBER with scale as float. */
163 if (desc[col].dbtype == NUMBER_TYPE)
165 desc[col].dbsize = numwidth;
166 if (desc[col].scale != 0)
168 defptr = (ub1 *)&def[col].flt_buf;
169 deflen = (sword) sizeof(float);
171 desc[col].dbtype = FLOAT_TYPE;
175 defptr = (ub1 *)&def[col].int_buf;
176 deflen = (sword) sizeof(sword);
178 desc[col].dbtype = INT_TYPE;
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;
194 /* Define an output variable */
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)
202 } /* Loop for each column */
209 /*************************************************
211 *************************************************/
213 /* See local README for interface description. */
216 oracle_open(uschar *filename, uschar **errmsg)
218 return (void *)(1); /* Just return something non-null */
223 /*************************************************
225 *************************************************/
227 /* See local README for interface description. */
232 oracle_connection *cn;
233 while ((cn = oracle_connections) != NULL)
235 oracle_connections = cn->next;
236 DEBUG(D_lookup) debug_printf("close ORACLE connection: %s\n", cn->server);
243 /*************************************************
244 * Internal search function *
245 *************************************************/
247 /* This function is called from the find entry point to do the search for a
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
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.
261 Returns: OK, FAIL, or DEFER
265 perform_oracle_search(uschar *query, uschar *server, uschar **resultptr,
266 uschar **errmsg, BOOL *defer_break)
269 struct cda_def *oracle_handle = NULL;
270 Ora_Describe *desc = NULL;
271 Ora_Define *def = NULL;
278 unsigned int num_fields = 0;
279 uschar *result = NULL;
280 oracle_connection *cn = NULL;
281 uschar *server_copy = NULL;
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. */
290 for (i = 3; i > 0; i--)
292 uschar *pp = Ustrrchr(server, '/');
295 *errmsg = string_sprintf("incomplete ORACLE server data: %s", server);
301 if (i == 3) server_copy = string_copy(server); /* sans password */
303 sdata[0] = server; /* What's left at the start */
305 /* If the database is the empty string, set it NULL - the query must then
308 if (sdata[1][0] == 0) sdata[1] = NULL;
310 /* See if we have a cached connection to the server */
312 for (cn = oracle_connections; cn != NULL; cn = cn->next)
314 if (strcmp(cn->server, server_copy) == 0)
316 oracle_handle = cn->handle;
322 /* If no cached connection, we must set one up */
326 DEBUG(D_lookup) debug_printf("ORACLE new connection: host=%s database=%s "
327 "user=%s\n", sdata[0], sdata[1], sdata[2]);
329 /* Get store for a new connection, initialize it, and connect to the server */
331 oracle_handle = store_get(sizeof(struct cda_def));
332 hda = store_get(HDA_SIZE);
333 memset(hda,'\0',HDA_SIZE);
336 * Perform a default (blocking) login
338 * sdata[0] = tnsname (service name - typically host name)
339 * sdata[1] = dbname - not used at present
340 * sdata[2] = username
344 if(olog(oracle_handle, hda, sdata[2], -1, sdata[3], -1, sdata[0], -1,
345 (ub4)OCI_LM_DEF) != 0)
347 *errmsg = oracle_error(oracle_handle, oracle_handle->rc,
348 US"connection failed");
349 *defer_break = FALSE;
350 goto ORACLE_EXIT_NO_VALS;
353 /* Add the connection to the cache */
355 cn = store_get(sizeof(oracle_connection));
356 cn->server = server_copy;
357 cn->handle = oracle_handle;
358 cn->next = oracle_connections;
360 oracle_connections = cn;
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. */
369 debug_printf("ORACLE using cached connection for %s\n", server_copy);
372 /* We have a connection. Open a cursor and run the query */
374 cda = store_get(sizeof(Cda_Def));
376 if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
378 *errmsg = oracle_error(oracle_handle, cda->rc, "failed to open cursor");
379 *defer_break = FALSE;
380 goto ORACLE_EXIT_NO_VALS;
383 if (oparse(cda, (text *)query, (sb4) -1,
384 (sword)PARSE_NO_DEFER, (ub4)PARSE_V7_LNG) != 0)
386 *errmsg = oracle_error(oracle_handle, cda->rc, "query failed");
387 *defer_break = FALSE;
389 goto ORACLE_EXIT_NO_VALS;
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. */
395 def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE);
396 desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE);
398 if ((num_fields = describe_define(cda,def,desc)) == -1)
400 *errmsg = oracle_error(oracle_handle, cda->rc, "describe_define failed");
401 *defer_break = FALSE;
407 *errmsg = oracle_error(oracle_handle, cda->rc, "oexec failed");
408 *defer_break = FALSE;
412 /* Get the fields and construct the result string. If there is more than one
413 row, we insert '\n' between them. */
415 while (cda->rc != NO_DATA_FOUND) /* Loop for each row */
418 if(cda->rc == NO_DATA_FOUND) break;
420 if (result != NULL) result = string_cat(result, &ssize, &offset, "\n", 1);
422 /* Single field - just add on the data */
425 result = string_cat(result, &ssize, &offset, def[0].buf, def[0].col_retlen);
427 /* Multiple fields - precede by file name, removing {lead,trail}ing WS */
429 else for (i = 0; i < num_fields; i++)
432 uschar *s = US desc[i].buf;
434 while (*s != 0 && isspace(*s)) 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);
440 /* int and float type wont ever need escaping. Otherwise, quote the value
441 if it contains spaces or is empty. */
443 if (desc[i].dbtype != INT_TYPE && desc[i].dbtype != FLOAT_TYPE &&
444 (def[i].buf[0] == 0 || strchr(def[i].buf, ' ') != NULL))
447 result = string_cat(result, &ssize, &offset, "\"", 1);
448 for (j = 0; j < def[i].col_retlen; j++)
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);
454 result = string_cat(result, &ssize, &offset, "\"", 1);
457 else switch(desc[i].dbtype)
460 sprintf(CS tmp, "%d", def[i].int_buf);
461 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
465 sprintf(CS tmp, "%f", def[i].flt_buf);
466 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
470 result = string_cat(result, &ssize, &offset, def[i].buf,
475 *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype);
476 *defer_break = FALSE;
481 result = string_cat(result, &ssize, &offset, " ", 1);
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. */
492 *errmsg = "ORACLE: no data found";
497 store_reset(result + offset + 1);
500 /* Get here by goto from various error checks. */
504 /* Close the cursor; don't close the connection, as it is cached. */
510 /* Non-NULL result indicates a sucessful result */
519 DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
520 return yield; /* FAIL or DEFER */
527 /*************************************************
529 *************************************************/
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. */
536 oracle_find(void *handle, uschar *filename, uschar *query, int length,
537 uschar **result, uschar **errmsg, BOOL *do_cache)
541 uschar *list = oracle_servers;
544 do_cache = do_cache; /* Placate picky compilers */
546 DEBUG(D_lookup) debug_printf("ORACLE query: %s\n", query);
548 while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
551 int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
552 if (rc != DEFER || defer_break) return rc;
555 if (oracle_servers == NULL)
556 *errmsg = "no ORACLE servers defined (oracle_servers option)";
563 /*************************************************
564 * Quote entry point *
565 *************************************************/
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.
574 s the string to be quoted
575 opt additional option text or NULL if none
577 Returns: the processed string or NULL for a bad option
581 oracle_quote(uschar *s, uschar *opt)
588 if (opt != NULL) return NULL; /* No options are recognized */
590 while ((c = *t++) != 0)
591 if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
593 if (count == 0) return s;
594 t = quoted = store_get((int)strlen(s) + count + 1);
596 while ((c = *s++) != 0)
598 if (strchr("\n\t\r\b\'\"\\", c) != NULL)
603 case '\n': *t++ = 'n';
605 case '\t': *t++ = 't';
607 case '\r': *t++ = 'r';
609 case '\b': *t++ = 'b';
622 #endif /* LOOKUP_ORACLE */
624 /* End of lookups/oracle.c */