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