1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include <libwebsockets.h>
26d4afb5ceSopenharmony_ci#include <private-lib-core.h>
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci#include <sqlite3.h>
29d4afb5ceSopenharmony_ci
30d4afb5ceSopenharmony_ci/*
31d4afb5ceSopenharmony_ci * we get one of these per matching result from the query
32d4afb5ceSopenharmony_ci */
33d4afb5ceSopenharmony_ci
34d4afb5ceSopenharmony_cistatic int
35d4afb5ceSopenharmony_cilws_struct_sq3_deser_cb(void *priv, int cols, char **cv, char **cn)
36d4afb5ceSopenharmony_ci{
37d4afb5ceSopenharmony_ci	lws_struct_args_t *a = (lws_struct_args_t *)priv;
38d4afb5ceSopenharmony_ci	char *u = lwsac_use_zero(&a->ac, a->dest_len, a->ac_block_size);
39d4afb5ceSopenharmony_ci	lws_dll2_owner_t *o = (lws_dll2_owner_t *)a->cb_arg;
40d4afb5ceSopenharmony_ci	const lws_struct_map_t *map = a->map_st[0];
41d4afb5ceSopenharmony_ci	int n, mems = (int)(ssize_t)a->map_entries_st[0];
42d4afb5ceSopenharmony_ci	long long li;
43d4afb5ceSopenharmony_ci	size_t lim;
44d4afb5ceSopenharmony_ci	char **pp;
45d4afb5ceSopenharmony_ci	char *s;
46d4afb5ceSopenharmony_ci
47d4afb5ceSopenharmony_ci	if (!u) {
48d4afb5ceSopenharmony_ci		lwsl_err("OOM\n");
49d4afb5ceSopenharmony_ci
50d4afb5ceSopenharmony_ci		return 1;
51d4afb5ceSopenharmony_ci	}
52d4afb5ceSopenharmony_ci
53d4afb5ceSopenharmony_ci	lws_dll2_add_tail((lws_dll2_t *)((char *)u + a->toplevel_dll2_ofs), o);
54d4afb5ceSopenharmony_ci
55d4afb5ceSopenharmony_ci	while (mems--) {
56d4afb5ceSopenharmony_ci		for (n = 0; n < cols; n++) {
57d4afb5ceSopenharmony_ci			if (!cv[n] || strcmp(cn[n], map->colname))
58d4afb5ceSopenharmony_ci				continue;
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_ci			switch (map->type) {
61d4afb5ceSopenharmony_ci			case LSMT_SIGNED:
62d4afb5ceSopenharmony_ci				if (map->aux == sizeof(signed char)) {
63d4afb5ceSopenharmony_ci					signed char *pc;
64d4afb5ceSopenharmony_ci					pc = (signed char *)(u + map->ofs);
65d4afb5ceSopenharmony_ci					*pc = (signed char)atoi(cv[n]);
66d4afb5ceSopenharmony_ci					break;
67d4afb5ceSopenharmony_ci				}
68d4afb5ceSopenharmony_ci				if (map->aux == sizeof(short)) {
69d4afb5ceSopenharmony_ci					short *ps;
70d4afb5ceSopenharmony_ci					ps = (short *)(u + map->ofs);
71d4afb5ceSopenharmony_ci					*ps = (short)atoi(cv[n]);
72d4afb5ceSopenharmony_ci					break;
73d4afb5ceSopenharmony_ci				}
74d4afb5ceSopenharmony_ci				if (map->aux == sizeof(int)) {
75d4afb5ceSopenharmony_ci					int *pi;
76d4afb5ceSopenharmony_ci					pi = (int *)(u + map->ofs);
77d4afb5ceSopenharmony_ci					*pi = (int)atoll(cv[n]); /* 32-bit OS */
78d4afb5ceSopenharmony_ci					break;
79d4afb5ceSopenharmony_ci				}
80d4afb5ceSopenharmony_ci				if (map->aux == sizeof(long)) {
81d4afb5ceSopenharmony_ci					long *pl;
82d4afb5ceSopenharmony_ci					pl = (long *)(u + map->ofs);
83d4afb5ceSopenharmony_ci					*pl = (long)atoll(cv[n]); /* 32-bit OS */
84d4afb5ceSopenharmony_ci					break;
85d4afb5ceSopenharmony_ci				}
86d4afb5ceSopenharmony_ci				{
87d4afb5ceSopenharmony_ci					long long *pll;
88d4afb5ceSopenharmony_ci					pll = (long long *)(u + map->ofs);
89d4afb5ceSopenharmony_ci					*pll = atoll(cv[n]);
90d4afb5ceSopenharmony_ci				}
91d4afb5ceSopenharmony_ci				break;
92d4afb5ceSopenharmony_ci
93d4afb5ceSopenharmony_ci			case LSMT_UNSIGNED:
94d4afb5ceSopenharmony_ci				if (map->aux == sizeof(unsigned char)) {
95d4afb5ceSopenharmony_ci					unsigned char *pc;
96d4afb5ceSopenharmony_ci					pc = (unsigned char *)(u + map->ofs);
97d4afb5ceSopenharmony_ci					*pc = (unsigned char)(unsigned int)atoi(cv[n]);
98d4afb5ceSopenharmony_ci					break;
99d4afb5ceSopenharmony_ci				}
100d4afb5ceSopenharmony_ci				if (map->aux == sizeof(unsigned short)) {
101d4afb5ceSopenharmony_ci					unsigned short *ps;
102d4afb5ceSopenharmony_ci					ps = (unsigned short *)(u + map->ofs);
103d4afb5ceSopenharmony_ci					*ps = (unsigned short)atoi(cv[n]);
104d4afb5ceSopenharmony_ci					break;
105d4afb5ceSopenharmony_ci				}
106d4afb5ceSopenharmony_ci				if (map->aux == sizeof(unsigned int)) {
107d4afb5ceSopenharmony_ci					unsigned int *pi;
108d4afb5ceSopenharmony_ci					pi = (unsigned int *)(u + map->ofs);
109d4afb5ceSopenharmony_ci					*pi = (unsigned int)atoi(cv[n]);
110d4afb5ceSopenharmony_ci					break;
111d4afb5ceSopenharmony_ci				}
112d4afb5ceSopenharmony_ci				if (map->aux == sizeof(unsigned long)) {
113d4afb5ceSopenharmony_ci					unsigned long *pl;
114d4afb5ceSopenharmony_ci					pl = (unsigned long *)(u + map->ofs);
115d4afb5ceSopenharmony_ci					*pl = (unsigned long)atol(cv[n]);
116d4afb5ceSopenharmony_ci					break;
117d4afb5ceSopenharmony_ci				}
118d4afb5ceSopenharmony_ci				{
119d4afb5ceSopenharmony_ci					unsigned long long *pll;
120d4afb5ceSopenharmony_ci					pll = (unsigned long long *)(u + map->ofs);
121d4afb5ceSopenharmony_ci					*pll = (unsigned long long)atoll(cv[n]);
122d4afb5ceSopenharmony_ci				}
123d4afb5ceSopenharmony_ci				break;
124d4afb5ceSopenharmony_ci
125d4afb5ceSopenharmony_ci			case LSMT_BOOLEAN:
126d4afb5ceSopenharmony_ci				li = 0;
127d4afb5ceSopenharmony_ci				if (!strcmp(cv[n], "true") ||
128d4afb5ceSopenharmony_ci				    !strcmp(cv[n], "TRUE") || cv[n][0] == '1')
129d4afb5ceSopenharmony_ci					li = 1;
130d4afb5ceSopenharmony_ci				if (map->aux == sizeof(char)) {
131d4afb5ceSopenharmony_ci					char *pc;
132d4afb5ceSopenharmony_ci					pc = (char *)(u + map->ofs);
133d4afb5ceSopenharmony_ci					*pc = (char)li;
134d4afb5ceSopenharmony_ci					break;
135d4afb5ceSopenharmony_ci				}
136d4afb5ceSopenharmony_ci				if (map->aux == sizeof(int)) {
137d4afb5ceSopenharmony_ci					int *pi;
138d4afb5ceSopenharmony_ci					pi = (int *)(u + map->ofs);
139d4afb5ceSopenharmony_ci					*pi = (int)li;
140d4afb5ceSopenharmony_ci				} else {
141d4afb5ceSopenharmony_ci					uint64_t *p64;
142d4afb5ceSopenharmony_ci					p64 = (uint64_t *)(u + map->ofs);
143d4afb5ceSopenharmony_ci					*p64 = (uint64_t)li;
144d4afb5ceSopenharmony_ci				}
145d4afb5ceSopenharmony_ci				break;
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ci			case LSMT_STRING_CHAR_ARRAY:
148d4afb5ceSopenharmony_ci				s = (char *)(u + map->ofs);
149d4afb5ceSopenharmony_ci				lim = map->aux;
150d4afb5ceSopenharmony_ci				lws_strncpy(s, cv[n], lim);
151d4afb5ceSopenharmony_ci				break;
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci			case LSMT_STRING_PTR:
154d4afb5ceSopenharmony_ci				pp = (char **)(u + map->ofs);
155d4afb5ceSopenharmony_ci				lim = strlen(cv[n]);
156d4afb5ceSopenharmony_ci				s = lwsac_use(&a->ac, lim + 1, a->ac_block_size);
157d4afb5ceSopenharmony_ci				if (!s)
158d4afb5ceSopenharmony_ci					return 1;
159d4afb5ceSopenharmony_ci				*pp = s;
160d4afb5ceSopenharmony_ci				memcpy(s, cv[n], lim);
161d4afb5ceSopenharmony_ci				s[lim] = '\0';
162d4afb5ceSopenharmony_ci				break;
163d4afb5ceSopenharmony_ci			default:
164d4afb5ceSopenharmony_ci				break;
165d4afb5ceSopenharmony_ci			}
166d4afb5ceSopenharmony_ci		}
167d4afb5ceSopenharmony_ci		map++;
168d4afb5ceSopenharmony_ci	}
169d4afb5ceSopenharmony_ci
170d4afb5ceSopenharmony_ci	return 0;
171d4afb5ceSopenharmony_ci}
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci/*
174d4afb5ceSopenharmony_ci * Call this with an LSM_SCHEMA map, its colname is the table name and its
175d4afb5ceSopenharmony_ci * type information describes the toplevel type.  Schema is dereferenced and
176d4afb5ceSopenharmony_ci * put in args before the actual sq3 query, which is given the child map.
177d4afb5ceSopenharmony_ci */
178d4afb5ceSopenharmony_ci
179d4afb5ceSopenharmony_ciint
180d4afb5ceSopenharmony_cilws_struct_sq3_deserialize(sqlite3 *pdb, const char *filter, const char *order,
181d4afb5ceSopenharmony_ci			   const lws_struct_map_t *schema, lws_dll2_owner_t *o,
182d4afb5ceSopenharmony_ci			   struct lwsac **ac, int start, int _limit)
183d4afb5ceSopenharmony_ci{
184d4afb5ceSopenharmony_ci	int limit = _limit < 0 ? -_limit : _limit;
185d4afb5ceSopenharmony_ci	char s[768], results[512], where[250];
186d4afb5ceSopenharmony_ci	lws_struct_args_t a;
187d4afb5ceSopenharmony_ci	int n, m;
188d4afb5ceSopenharmony_ci
189d4afb5ceSopenharmony_ci	if (!order)
190d4afb5ceSopenharmony_ci		order = "_lws_idx";
191d4afb5ceSopenharmony_ci
192d4afb5ceSopenharmony_ci	memset(&a, 0, sizeof(a));
193d4afb5ceSopenharmony_ci	a.ac = *ac;
194d4afb5ceSopenharmony_ci	a.cb_arg = o; /* lws_dll2_owner tracking query result objects */
195d4afb5ceSopenharmony_ci	a.map_st[0]  = schema->child_map;
196d4afb5ceSopenharmony_ci	a.map_entries_st[0] = schema->child_map_size;
197d4afb5ceSopenharmony_ci	a.dest_len = schema->aux; /* size of toplevel object to allocate */
198d4afb5ceSopenharmony_ci	a.toplevel_dll2_ofs = schema->ofs;
199d4afb5ceSopenharmony_ci
200d4afb5ceSopenharmony_ci	lws_dll2_owner_clear(o);
201d4afb5ceSopenharmony_ci
202d4afb5ceSopenharmony_ci	/*
203d4afb5ceSopenharmony_ci	 * Explicitly list the columns instead of use *, so we can skip blobs
204d4afb5ceSopenharmony_ci	 */
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci	m = 0;
207d4afb5ceSopenharmony_ci	for (n = 0; n < (int)schema->child_map_size; n++)
208d4afb5ceSopenharmony_ci		m += lws_snprintf(&results[m], sizeof(results) - (unsigned int)n - 1,
209d4afb5ceSopenharmony_ci				  "%s%c", schema->child_map[n].colname,
210d4afb5ceSopenharmony_ci				  n + 1 == (int)schema->child_map_size ? ' ' : ',');
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci	where[0] = '\0';
213d4afb5ceSopenharmony_ci	lws_snprintf(where, sizeof(where), " where _lws_idx >= %llu %s",
214d4afb5ceSopenharmony_ci			     (unsigned long long)start, filter ? filter : "");
215d4afb5ceSopenharmony_ci
216d4afb5ceSopenharmony_ci	lws_snprintf(s, sizeof(s) - 1, "select %s "
217d4afb5ceSopenharmony_ci		     "from %s %s order by %s %slimit %d;", results,
218d4afb5ceSopenharmony_ci		     schema->colname, where, order,
219d4afb5ceSopenharmony_ci				     _limit < 0 ? "desc " : "", limit);
220d4afb5ceSopenharmony_ci
221d4afb5ceSopenharmony_ci
222d4afb5ceSopenharmony_ci
223d4afb5ceSopenharmony_ci	if (sqlite3_exec(pdb, s, lws_struct_sq3_deser_cb, &a, NULL) != SQLITE_OK) {
224d4afb5ceSopenharmony_ci		lwsl_err("%s: %s: fail %s\n", __func__, sqlite3_errmsg(pdb), s);
225d4afb5ceSopenharmony_ci		lwsac_free(&a.ac);
226d4afb5ceSopenharmony_ci		return -1;
227d4afb5ceSopenharmony_ci	}
228d4afb5ceSopenharmony_ci
229d4afb5ceSopenharmony_ci	*ac = a.ac;
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci	return 0;
232d4afb5ceSopenharmony_ci}
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci/*
235d4afb5ceSopenharmony_ci * This takes a struct and turns it into an sqlite3 UPDATE, using the given
236d4afb5ceSopenharmony_ci * schema... which has one LSM_SCHEMA_DLL2 entry wrapping the actual schema
237d4afb5ceSopenharmony_ci */
238d4afb5ceSopenharmony_ci
239d4afb5ceSopenharmony_cistatic int
240d4afb5ceSopenharmony_ci_lws_struct_sq3_ser_one(sqlite3 *pdb, const lws_struct_map_t *schema,
241d4afb5ceSopenharmony_ci			uint32_t idx, void *st)
242d4afb5ceSopenharmony_ci{
243d4afb5ceSopenharmony_ci	const lws_struct_map_t *map = schema->child_map;
244d4afb5ceSopenharmony_ci	int n, m, pk = 0, nentries = (int)(ssize_t)schema->child_map_size, nef = 0, did;
245d4afb5ceSopenharmony_ci	size_t sql_est = 46 + strlen(schema->colname) + 1;
246d4afb5ceSopenharmony_ci		/* "insert into  (_lws_idx, ) values (00000001,);" ...
247d4afb5ceSopenharmony_ci		 * plus the table name */
248d4afb5ceSopenharmony_ci	uint8_t *stb = (uint8_t *)st;
249d4afb5ceSopenharmony_ci	const char *p;
250d4afb5ceSopenharmony_ci	char *sql;
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci	/*
253d4afb5ceSopenharmony_ci	 * Figure out effective number of columns, exluding BLOB.
254d4afb5ceSopenharmony_ci	 *
255d4afb5ceSopenharmony_ci	 * The first UNSIGNED is a hidden index.  Blobs are not handled by
256d4afb5ceSopenharmony_ci	 * lws_struct except to create the column in the schema.
257d4afb5ceSopenharmony_ci	 */
258d4afb5ceSopenharmony_ci
259d4afb5ceSopenharmony_ci	pk = 0;
260d4afb5ceSopenharmony_ci	nef = 0;
261d4afb5ceSopenharmony_ci	for (n = 0; n < nentries; n++) {
262d4afb5ceSopenharmony_ci		if (!pk && map[n].type == LSMT_UNSIGNED) {
263d4afb5ceSopenharmony_ci			pk = 1;
264d4afb5ceSopenharmony_ci			continue;
265d4afb5ceSopenharmony_ci		}
266d4afb5ceSopenharmony_ci		if (map[n].type == LSMT_BLOB_PTR)
267d4afb5ceSopenharmony_ci			continue;
268d4afb5ceSopenharmony_ci
269d4afb5ceSopenharmony_ci		nef++;
270d4afb5ceSopenharmony_ci	}
271d4afb5ceSopenharmony_ci
272d4afb5ceSopenharmony_ci	/*
273d4afb5ceSopenharmony_ci	 * Figure out an estimate for the length of the populated sqlite
274d4afb5ceSopenharmony_ci	 * command, and then malloc it up
275d4afb5ceSopenharmony_ci	 */
276d4afb5ceSopenharmony_ci
277d4afb5ceSopenharmony_ci	for (n = 0; n < nentries; n++) {
278d4afb5ceSopenharmony_ci		sql_est += strlen(map[n].colname) + 2;
279d4afb5ceSopenharmony_ci		switch (map[n].type) {
280d4afb5ceSopenharmony_ci		case LSMT_SIGNED:
281d4afb5ceSopenharmony_ci		case LSMT_UNSIGNED:
282d4afb5ceSopenharmony_ci		case LSMT_BOOLEAN:
283d4afb5ceSopenharmony_ci
284d4afb5ceSopenharmony_ci			switch (map[n].aux) {
285d4afb5ceSopenharmony_ci			case 1:
286d4afb5ceSopenharmony_ci				sql_est += 3 + 2;
287d4afb5ceSopenharmony_ci				break;
288d4afb5ceSopenharmony_ci			case 2:
289d4afb5ceSopenharmony_ci				sql_est += 5 + 2;
290d4afb5ceSopenharmony_ci				break;
291d4afb5ceSopenharmony_ci			case 4:
292d4afb5ceSopenharmony_ci				sql_est += 10 + 2;
293d4afb5ceSopenharmony_ci				break;
294d4afb5ceSopenharmony_ci			case 8:
295d4afb5ceSopenharmony_ci				sql_est += 20 + 2;
296d4afb5ceSopenharmony_ci				break;
297d4afb5ceSopenharmony_ci			}
298d4afb5ceSopenharmony_ci
299d4afb5ceSopenharmony_ci			if (map[n].type == LSMT_SIGNED)
300d4afb5ceSopenharmony_ci				sql_est++; /* minus sign */
301d4afb5ceSopenharmony_ci
302d4afb5ceSopenharmony_ci			break;
303d4afb5ceSopenharmony_ci		case LSMT_STRING_CHAR_ARRAY:
304d4afb5ceSopenharmony_ci			sql_est += (unsigned int)lws_sql_purify_len((const char *)st +
305d4afb5ceSopenharmony_ci							map[n].ofs) + 2;
306d4afb5ceSopenharmony_ci			break;
307d4afb5ceSopenharmony_ci
308d4afb5ceSopenharmony_ci		case LSMT_STRING_PTR:
309d4afb5ceSopenharmony_ci			p = *((const char * const *)&stb[map[n].ofs]);
310d4afb5ceSopenharmony_ci			sql_est += (unsigned int)((p ? lws_sql_purify_len(p) : 0) + 2);
311d4afb5ceSopenharmony_ci			break;
312d4afb5ceSopenharmony_ci
313d4afb5ceSopenharmony_ci		case LSMT_BLOB_PTR:
314d4afb5ceSopenharmony_ci			/* we don't deal with blobs actually */
315d4afb5ceSopenharmony_ci			sql_est -= strlen(map[n].colname) + 2;
316d4afb5ceSopenharmony_ci			break;
317d4afb5ceSopenharmony_ci
318d4afb5ceSopenharmony_ci		default:
319d4afb5ceSopenharmony_ci			lwsl_err("%s: unsupported type\n", __func__);
320d4afb5ceSopenharmony_ci			assert(0);
321d4afb5ceSopenharmony_ci			break;
322d4afb5ceSopenharmony_ci		}
323d4afb5ceSopenharmony_ci	}
324d4afb5ceSopenharmony_ci
325d4afb5ceSopenharmony_ci	sql = malloc(sql_est);
326d4afb5ceSopenharmony_ci	if (!sql)
327d4afb5ceSopenharmony_ci		return -1;
328d4afb5ceSopenharmony_ci
329d4afb5ceSopenharmony_ci	m = lws_snprintf(sql, sql_est, "insert into %s(_lws_idx, ",
330d4afb5ceSopenharmony_ci			 schema->colname);
331d4afb5ceSopenharmony_ci
332d4afb5ceSopenharmony_ci	/*
333d4afb5ceSopenharmony_ci	 * First explicit integer type is primary key autoincrement, should
334d4afb5ceSopenharmony_ci	 * not be specified
335d4afb5ceSopenharmony_ci	 */
336d4afb5ceSopenharmony_ci
337d4afb5ceSopenharmony_ci	pk = 0;
338d4afb5ceSopenharmony_ci	did = 0;
339d4afb5ceSopenharmony_ci	for (n = 0; n < nentries; n++) {
340d4afb5ceSopenharmony_ci		if (!pk && map[n].type == LSMT_UNSIGNED) {
341d4afb5ceSopenharmony_ci			pk = 1;
342d4afb5ceSopenharmony_ci			continue;
343d4afb5ceSopenharmony_ci		}
344d4afb5ceSopenharmony_ci		if (map[n].type == LSMT_BLOB_PTR)
345d4afb5ceSopenharmony_ci			continue;
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_ci		did++;
348d4afb5ceSopenharmony_ci		m += lws_snprintf(sql + m, sql_est - (unsigned int)m,
349d4afb5ceSopenharmony_ci				  did == nef ? "%s" : "%s, ",
350d4afb5ceSopenharmony_ci				  map[n].colname);
351d4afb5ceSopenharmony_ci	}
352d4afb5ceSopenharmony_ci
353d4afb5ceSopenharmony_ci	m += lws_snprintf(sql + m, sql_est - (unsigned int)m, ") values(%u, ", idx);
354d4afb5ceSopenharmony_ci
355d4afb5ceSopenharmony_ci	pk = 0;
356d4afb5ceSopenharmony_ci	did = 0;
357d4afb5ceSopenharmony_ci	for (n = 0; n < nentries; n++) {
358d4afb5ceSopenharmony_ci		uint64_t uu64;
359d4afb5ceSopenharmony_ci		size_t q;
360d4afb5ceSopenharmony_ci
361d4afb5ceSopenharmony_ci		if (!pk && map[n].type == LSMT_UNSIGNED) {
362d4afb5ceSopenharmony_ci			pk = 1;
363d4afb5ceSopenharmony_ci			continue;
364d4afb5ceSopenharmony_ci		}
365d4afb5ceSopenharmony_ci
366d4afb5ceSopenharmony_ci		switch (map[n].type) {
367d4afb5ceSopenharmony_ci		case LSMT_SIGNED:
368d4afb5ceSopenharmony_ci		case LSMT_UNSIGNED:
369d4afb5ceSopenharmony_ci		case LSMT_BOOLEAN:
370d4afb5ceSopenharmony_ci
371d4afb5ceSopenharmony_ci			uu64 = 0;
372d4afb5ceSopenharmony_ci			for (q = 0; q < map[n].aux; q++)
373d4afb5ceSopenharmony_ci				uu64 |= ((uint64_t)stb[map[n].ofs + q] <<
374d4afb5ceSopenharmony_ci								(q << 3));
375d4afb5ceSopenharmony_ci
376d4afb5ceSopenharmony_ci			if (map[n].type == LSMT_SIGNED)
377d4afb5ceSopenharmony_ci				m += lws_snprintf(sql + m, sql_est - (unsigned int)m, "%lld",
378d4afb5ceSopenharmony_ci						  (long long)(int64_t)uu64);
379d4afb5ceSopenharmony_ci			else
380d4afb5ceSopenharmony_ci				m += lws_snprintf(sql + m, sql_est - (unsigned int)m, "%llu",
381d4afb5ceSopenharmony_ci						  (unsigned long long)uu64);
382d4afb5ceSopenharmony_ci			break;
383d4afb5ceSopenharmony_ci
384d4afb5ceSopenharmony_ci		case LSMT_STRING_CHAR_ARRAY:
385d4afb5ceSopenharmony_ci			sql[m++] = '\'';
386d4afb5ceSopenharmony_ci			lws_sql_purify(sql + m, (const char *)&stb[map[n].ofs],
387d4afb5ceSopenharmony_ci				       sql_est - (size_t)(ssize_t)m - 4);
388d4afb5ceSopenharmony_ci			m += (int)(ssize_t)strlen(sql + m);
389d4afb5ceSopenharmony_ci			sql[m++] = '\'';
390d4afb5ceSopenharmony_ci			break;
391d4afb5ceSopenharmony_ci		case LSMT_STRING_PTR:
392d4afb5ceSopenharmony_ci			p = *((const char * const *)&stb[map[n].ofs]);
393d4afb5ceSopenharmony_ci			sql[m++] = '\'';
394d4afb5ceSopenharmony_ci			if (p) {
395d4afb5ceSopenharmony_ci				lws_sql_purify(sql + m, p, sql_est - (unsigned int)m - 4);
396d4afb5ceSopenharmony_ci				m += (int)(ssize_t)strlen(sql + m);
397d4afb5ceSopenharmony_ci			}
398d4afb5ceSopenharmony_ci			sql[m++] = '\'';
399d4afb5ceSopenharmony_ci			break;
400d4afb5ceSopenharmony_ci
401d4afb5ceSopenharmony_ci		case LSMT_BLOB_PTR:
402d4afb5ceSopenharmony_ci			continue;
403d4afb5ceSopenharmony_ci
404d4afb5ceSopenharmony_ci		default:
405d4afb5ceSopenharmony_ci			lwsl_err("%s: unsupported type\n", __func__);
406d4afb5ceSopenharmony_ci			assert(0);
407d4afb5ceSopenharmony_ci			break;
408d4afb5ceSopenharmony_ci		}
409d4afb5ceSopenharmony_ci
410d4afb5ceSopenharmony_ci		did++;
411d4afb5ceSopenharmony_ci		if (did != nef) {
412d4afb5ceSopenharmony_ci			if (sql_est - (unsigned int)m < 6)
413d4afb5ceSopenharmony_ci				return -1;
414d4afb5ceSopenharmony_ci			sql[m++] = ',';
415d4afb5ceSopenharmony_ci			sql[m++] = ' ';
416d4afb5ceSopenharmony_ci		}
417d4afb5ceSopenharmony_ci	}
418d4afb5ceSopenharmony_ci
419d4afb5ceSopenharmony_ci	lws_snprintf(sql + m, sql_est - (unsigned int)m, ");");
420d4afb5ceSopenharmony_ci
421d4afb5ceSopenharmony_ci	n = sqlite3_exec(pdb, sql, NULL, NULL, NULL);
422d4afb5ceSopenharmony_ci	if (n != SQLITE_OK) {
423d4afb5ceSopenharmony_ci		lwsl_err("%s\n", sql);
424d4afb5ceSopenharmony_ci		free(sql);
425d4afb5ceSopenharmony_ci		lwsl_err("%s: %s: fail\n", __func__, sqlite3_errmsg(pdb));
426d4afb5ceSopenharmony_ci		return -1;
427d4afb5ceSopenharmony_ci	}
428d4afb5ceSopenharmony_ci	free(sql);
429d4afb5ceSopenharmony_ci
430d4afb5ceSopenharmony_ci	return 0;
431d4afb5ceSopenharmony_ci}
432d4afb5ceSopenharmony_ci
433d4afb5ceSopenharmony_ciint
434d4afb5ceSopenharmony_cilws_struct_sq3_serialize(sqlite3 *pdb, const lws_struct_map_t *schema,
435d4afb5ceSopenharmony_ci			 lws_dll2_owner_t *owner, uint32_t manual_idx)
436d4afb5ceSopenharmony_ci{
437d4afb5ceSopenharmony_ci	uint32_t idx = manual_idx;
438d4afb5ceSopenharmony_ci
439d4afb5ceSopenharmony_ci	lws_start_foreach_dll(struct lws_dll2 *, p, owner->head) {
440d4afb5ceSopenharmony_ci		void *item = (void *)((uint8_t *)p - schema->ofs_clist);
441d4afb5ceSopenharmony_ci		if (_lws_struct_sq3_ser_one(pdb, schema, idx++, item))
442d4afb5ceSopenharmony_ci			return 1;
443d4afb5ceSopenharmony_ci
444d4afb5ceSopenharmony_ci	} lws_end_foreach_dll(p);
445d4afb5ceSopenharmony_ci
446d4afb5ceSopenharmony_ci	return 0;
447d4afb5ceSopenharmony_ci}
448d4afb5ceSopenharmony_ci
449d4afb5ceSopenharmony_ciint
450d4afb5ceSopenharmony_cilws_struct_sq3_create_table(sqlite3 *pdb, const lws_struct_map_t *schema)
451d4afb5ceSopenharmony_ci{
452d4afb5ceSopenharmony_ci	const lws_struct_map_t *map = schema->child_map;
453d4afb5ceSopenharmony_ci	int map_size = (int)(ssize_t)schema->child_map_size, subsequent = 0;
454d4afb5ceSopenharmony_ci	char s[2048], *p = s, *end = &s[sizeof(s) - 1],
455d4afb5ceSopenharmony_ci	     *pri = " primary key autoincrement", *use;
456d4afb5ceSopenharmony_ci
457d4afb5ceSopenharmony_ci	p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p),
458d4afb5ceSopenharmony_ci			  "create table if not exists %s (_lws_idx integer, ",
459d4afb5ceSopenharmony_ci			  schema->colname);
460d4afb5ceSopenharmony_ci
461d4afb5ceSopenharmony_ci	while (map_size--) {
462d4afb5ceSopenharmony_ci		if (map->type > LSMT_STRING_PTR && map->type != LSMT_BLOB_PTR) {
463d4afb5ceSopenharmony_ci			map++;
464d4afb5ceSopenharmony_ci			continue;
465d4afb5ceSopenharmony_ci		}
466d4afb5ceSopenharmony_ci		if (subsequent && (end - p) > 4) {
467d4afb5ceSopenharmony_ci			*p++ = ',';
468d4afb5ceSopenharmony_ci			*p++ = ' ';
469d4afb5ceSopenharmony_ci		}
470d4afb5ceSopenharmony_ci		subsequent = 1;
471d4afb5ceSopenharmony_ci		if (map->type == LSMT_BLOB_PTR) {
472d4afb5ceSopenharmony_ci
473d4afb5ceSopenharmony_ci			p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p), "%s blob", map->colname);
474d4afb5ceSopenharmony_ci
475d4afb5ceSopenharmony_ci		} else {
476d4afb5ceSopenharmony_ci			if (map->type < LSMT_STRING_CHAR_ARRAY) {
477d4afb5ceSopenharmony_ci				use = "";
478d4afb5ceSopenharmony_ci				if (map->colname[0] != '_') /* _lws_idx is not primary key */
479d4afb5ceSopenharmony_ci					use = pri;
480d4afb5ceSopenharmony_ci				p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p), "%s integer%s",
481d4afb5ceSopenharmony_ci						map->colname, use);
482d4afb5ceSopenharmony_ci				if (map->colname[0] != '_')
483d4afb5ceSopenharmony_ci					pri = "";
484d4afb5ceSopenharmony_ci			} else
485d4afb5ceSopenharmony_ci				p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p), "%s varchar",
486d4afb5ceSopenharmony_ci						map->colname);
487d4afb5ceSopenharmony_ci		}
488d4afb5ceSopenharmony_ci
489d4afb5ceSopenharmony_ci		map++;
490d4afb5ceSopenharmony_ci	}
491d4afb5ceSopenharmony_ci
492d4afb5ceSopenharmony_ci	p += lws_snprintf(p, (unsigned int)lws_ptr_diff(end, p), ");");
493d4afb5ceSopenharmony_ci
494d4afb5ceSopenharmony_ci	if (sqlite3_exec(pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
495d4afb5ceSopenharmony_ci		lwsl_err("%s: %s: fail\n", __func__, sqlite3_errmsg(pdb));
496d4afb5ceSopenharmony_ci
497d4afb5ceSopenharmony_ci		return -1;
498d4afb5ceSopenharmony_ci	}
499d4afb5ceSopenharmony_ci
500d4afb5ceSopenharmony_ci	return 0;
501d4afb5ceSopenharmony_ci}
502d4afb5ceSopenharmony_ci
503d4afb5ceSopenharmony_ciint
504d4afb5ceSopenharmony_cilws_struct_sq3_open(struct lws_context *context, const char *sqlite3_path,
505d4afb5ceSopenharmony_ci		    char create_if_missing, sqlite3 **pdb)
506d4afb5ceSopenharmony_ci{
507d4afb5ceSopenharmony_ci#if !defined(WIN32)
508d4afb5ceSopenharmony_ci	uid_t uid = 0;
509d4afb5ceSopenharmony_ci	gid_t gid = 0;
510d4afb5ceSopenharmony_ci#endif
511d4afb5ceSopenharmony_ci
512d4afb5ceSopenharmony_ci	if (sqlite3_open_v2(sqlite3_path, pdb,
513d4afb5ceSopenharmony_ci			    SQLITE_OPEN_READWRITE |
514d4afb5ceSopenharmony_ci			    (create_if_missing ? SQLITE_OPEN_CREATE : 0),
515d4afb5ceSopenharmony_ci			    NULL) != SQLITE_OK) {
516d4afb5ceSopenharmony_ci		lwsl_info("%s: Unable to open db %s: %s\n",
517d4afb5ceSopenharmony_ci			 __func__, sqlite3_path, sqlite3_errmsg(*pdb));
518d4afb5ceSopenharmony_ci
519d4afb5ceSopenharmony_ci		return 1;
520d4afb5ceSopenharmony_ci	}
521d4afb5ceSopenharmony_ci
522d4afb5ceSopenharmony_ci#if !defined(WIN32)
523d4afb5ceSopenharmony_ci	lws_get_effective_uid_gid(context, &uid, &gid);
524d4afb5ceSopenharmony_ci	if (uid)
525d4afb5ceSopenharmony_ci		if (chown(sqlite3_path, uid, gid))
526d4afb5ceSopenharmony_ci			lwsl_err("%s: failed to chown %s\n", __func__, sqlite3_path);
527d4afb5ceSopenharmony_ci	chmod(sqlite3_path, 0600);
528d4afb5ceSopenharmony_ci
529d4afb5ceSopenharmony_ci	lwsl_debug("%s: created %s owned by %u:%u mode 0600\n", __func__,
530d4afb5ceSopenharmony_ci			sqlite3_path, (unsigned int)uid, (unsigned int)gid);
531d4afb5ceSopenharmony_ci#else
532d4afb5ceSopenharmony_ci	lwsl_debug("%s: created %s\n", __func__, sqlite3_path);
533d4afb5ceSopenharmony_ci#endif
534d4afb5ceSopenharmony_ci	sqlite3_extended_result_codes(*pdb, 1);
535d4afb5ceSopenharmony_ci
536d4afb5ceSopenharmony_ci	return 0;
537d4afb5ceSopenharmony_ci}
538d4afb5ceSopenharmony_ci
539d4afb5ceSopenharmony_ciint
540d4afb5ceSopenharmony_cilws_struct_sq3_close(sqlite3 **pdb)
541d4afb5ceSopenharmony_ci{
542d4afb5ceSopenharmony_ci	int n;
543d4afb5ceSopenharmony_ci
544d4afb5ceSopenharmony_ci	if (!*pdb)
545d4afb5ceSopenharmony_ci		return 0;
546d4afb5ceSopenharmony_ci
547d4afb5ceSopenharmony_ci	n = sqlite3_close(*pdb);
548d4afb5ceSopenharmony_ci	if (n != SQLITE_OK) {
549d4afb5ceSopenharmony_ci		/*
550d4afb5ceSopenharmony_ci		 * trouble...
551d4afb5ceSopenharmony_ci		 */
552d4afb5ceSopenharmony_ci		lwsl_err("%s: failed to close: %d\n", __func__, n);
553d4afb5ceSopenharmony_ci		return 1;
554d4afb5ceSopenharmony_ci	}
555d4afb5ceSopenharmony_ci	*pdb = NULL;
556d4afb5ceSopenharmony_ci
557d4afb5ceSopenharmony_ci	return 0;
558d4afb5ceSopenharmony_ci}
559