debian experimental exim-daemon-heavy config
[exim.git] / src / src / lookups / sqlite.c
CommitLineData
13b685f9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
1e1ddfac 6/* Copyright (c) The Exim Maintainers 2020 */
13b685f9
PH
7/* See the file NOTICE for conditions of use and distribution. */
8
9#include "../exim.h"
10#include "lf_functions.h"
13b685f9 11
13b685f9
PH
12#include <sqlite3.h>
13
14
15/*************************************************
16* Open entry point *
17*************************************************/
18
19/* See local README for interface description. */
20
e6d225ae 21static void *
d447dbd1 22sqlite_open(const uschar * filename, uschar ** errmsg)
13b685f9
PH
23{
24sqlite3 *db = NULL;
25int ret;
26
298849d8
JH
27if (!filename || !*filename) filename = sqlite_dbfile;
28if (*filename != '/')
29 *errmsg = US"absolute file name expected for \"sqlite\" lookup";
30else if ((ret = sqlite3_open(CCS filename, &db)) != 0)
13b685f9
PH
31 {
32 *errmsg = (void *)sqlite3_errmsg(db);
298849d8 33 DEBUG(D_lookup) debug_printf_indent("Error opening database: %s\n", *errmsg);
13b685f9
PH
34 }
35
31480e42 36sqlite3_busy_timeout(db, 1000 * sqlite_lock_timeout);
13b685f9
PH
37return db;
38}
39
40
41/*************************************************
42* Find entry point *
43*************************************************/
44
45/* See local README for interface description. */
46
acec9514
JH
47static int
48sqlite_callback(void *arg, int argc, char **argv, char **azColName)
13b685f9 49{
acec9514 50gstring * res = *(gstring **)arg;
13b685f9
PH
51
52/* For second and subsequent results, insert \n */
53
acec9514
JH
54if (res)
55 res = string_catn(res, US"\n", 1);
13b685f9
PH
56
57if (argc > 1)
58 {
59 /* For multiple fields, include the field name too */
d7978c0f 60 for (int i = 0; i < argc; i++)
13b685f9
PH
61 {
62 uschar *value = US((argv[i] != NULL)? argv[i]:"<NULL>");
acec9514 63 res = lf_quote(US azColName[i], value, Ustrlen(value), res);
13b685f9
PH
64 }
65 }
66
67else
acec9514 68 res = string_cat(res, argv[0] ? US argv[0] : US "<NULL>");
13b685f9 69
acec9514 70*(gstring **)arg = res;
13b685f9
PH
71return 0;
72}
73
74
e6d225ae 75static int
d447dbd1 76sqlite_find(void * handle, const uschar * filename, const uschar * query,
67a57a5a
JH
77 int length, uschar ** result, uschar ** errmsg, uint * do_cache,
78 const uschar * opts)
13b685f9
PH
79{
80int ret;
acec9514 81gstring * res = NULL;
13b685f9 82
137ae145 83ret = sqlite3_exec(handle, CS query, sqlite_callback, &res, CSS errmsg);
13b685f9
PH
84if (ret != SQLITE_OK)
85 {
42c7f0b4 86 debug_printf_indent("sqlite3_exec failed: %s\n", *errmsg);
13b685f9
PH
87 return FAIL;
88 }
89
acec9514 90if (!res) *do_cache = 0;
13b685f9 91
acec9514 92*result = string_from_gstring(res);
13b685f9
PH
93return OK;
94}
95
96
97
98/*************************************************
99* Close entry point *
100*************************************************/
101
102/* See local README for interface description. */
103
e6d225ae 104static void sqlite_close(void *handle)
13b685f9
PH
105{
106sqlite3_close(handle);
107}
108
109
110
111/*************************************************
112* Quote entry point *
113*************************************************/
114
115/* From what I have found so far, the only character that needs to be quoted
116for sqlite is the single quote, and it is quoted by doubling.
117
118Arguments:
119 s the string to be quoted
120 opt additional option text or NULL if none
121
122Returns: the processed string or NULL for a bad option
123*/
124
e6d225ae 125static uschar *
13b685f9
PH
126sqlite_quote(uschar *s, uschar *opt)
127{
128register int c;
129int count = 0;
130uschar *t = s;
131uschar *quoted;
132
133if (opt != NULL) return NULL; /* No options recognized */
134
135while ((c = *t++) != 0) if (c == '\'') count++;
136
137if (count == 0) return s;
f3ebb786 138t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
13b685f9
PH
139
140while ((c = *s++) != 0)
141 {
142 if (c == '\'') *t++ = '\'';
143 *t++ = c;
144 }
145
146*t = 0;
147return quoted;
148}
149
6545de78
PP
150
151
152/*************************************************
153* Version reporting entry point *
154*************************************************/
155
156/* See local README for interface description. */
157
158#include "../version.h"
159
160void
161sqlite_version_report(FILE *f)
162{
163fprintf(f, "Library version: SQLite: Compile: %s\n"
164 " Runtime: %s\n",
165 SQLITE_VERSION, sqlite3_libversion());
166#ifdef DYNLOOKUP
167fprintf(f, " Exim version %s\n", EXIM_VERSION_STR);
168#endif
169}
170
e6d225ae 171static lookup_info _lookup_info = {
9f400174
JH
172 .name = US"sqlite", /* lookup name */
173 .type = lookup_absfilequery, /* query-style lookup, starts with file name */
174 .open = sqlite_open, /* open function */
175 .check = NULL, /* no check function */
176 .find = sqlite_find, /* find function */
177 .close = sqlite_close, /* close function */
178 .tidy = NULL, /* no tidy function */
179 .quote = sqlite_quote, /* quoting function */
180 .version_report = sqlite_version_report /* version reporting */
e6d225ae
DW
181};
182
183#ifdef DYNLOOKUP
184#define sqlite_lookup_module_info _lookup_module_info
185#endif
186
187static lookup_info *_lookup_list[] = { &_lookup_info };
188lookup_module_info sqlite_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
13b685f9
PH
189
190/* End of lookups/sqlite.c */