Comparison

util/sqlite3.lua @ 13146:771eb453e03a

util.sqlite3: Deduplicate query methods There were 3 very similar methods: - :execute() - :execute_query() - :execute_update() The first one returns the prepared statement and is mainly used internally in the library for CREATE statements. The later two only really differ in how the results are returned. Those two are one main method and one small one that only picks out the iterator.
author Kim Alvefur <zash@zash.se>
date Sat, 10 Jun 2023 22:02:15 +0200
parent 13145:af251471d5ae
child 13147:e560f7c691ce
comparison
equal deleted inserted replaced
13145:af251471d5ae 13146:771eb453e03a
7 local error = error 7 local error = error
8 local type = type 8 local type = type
9 local t_concat = table.concat; 9 local t_concat = table.concat;
10 local t_insert = table.insert; 10 local t_insert = table.insert;
11 local s_char = string.char; 11 local s_char = string.char;
12 local array = require "prosody.util.array";
12 local log = require "prosody.util.logger".init("sql"); 13 local log = require "prosody.util.logger".init("sql");
13 14
14 local lsqlite3 = require "lsqlite3"; 15 local lsqlite3 = require "lsqlite3";
15 local build_url = require "socket.url".build; 16 local build_url = require "socket.url".build;
16 local ROW, DONE = lsqlite3.ROW, lsqlite3.DONE; 17 local ROW, DONE = lsqlite3.ROW, lsqlite3.DONE;
192 local ret = stmt:bind_values(...); 193 local ret = stmt:bind_values(...);
193 if ret ~= lsqlite3.OK then return nil, sqlite_errors.new(ret, { message = self.conn:errmsg() }); end 194 if ret ~= lsqlite3.OK then return nil, sqlite_errors.new(ret, { message = self.conn:errmsg() }); end
194 return stmt; 195 return stmt;
195 end 196 end
196 197
197 local result_mt = {
198 __index = {
199 affected = function(self) return self.__affected; end;
200 rowcount = function(self) return self.__rowcount; end;
201 },
202 };
203
204 local function iterator(table) 198 local function iterator(table)
205 local i = 0; 199 local i = 0;
206 return function() 200 return function()
207 i = i + 1; 201 i = i + 1;
208 local item = table[i]; 202 local item = table[i];
209 if item ~= nil then 203 if item ~= nil then
210 return item; 204 return item;
211 end 205 end
212 end 206 end
213 end 207 end
208
209 local result_mt = {
210 __len = function(self)
211 return self.__rowcount;
212 end;
213 __index = {
214 affected = function(self)
215 return self.__affected;
216 end;
217 rowcount = function(self)
218 return self.__rowcount;
219 end;
220 };
221 __call = function(self)
222 return iterator(self.__data);
223 end;
224 };
214 225
215 local function debugquery(where, sql, ...) 226 local function debugquery(where, sql, ...)
216 local i = 0; local a = {...} 227 local i = 0; local a = {...}
217 sql = sql:gsub("\n?\t+", " "); 228 sql = sql:gsub("\n?\t+", " ");
218 log("debug", "[%s] %s", where, (sql:gsub("%?", function () 229 log("debug", "[%s] %s", where, (sql:gsub("%?", function ()
223 end 234 end
224 return tostring(v); 235 return tostring(v);
225 end))); 236 end)));
226 end 237 end
227 238
228 function engine:execute_query(sql, ...) 239 function engine:execute_update(sql, ...)
229 local prepared = self.prepared; 240 local prepared = self.prepared;
230 local stmt = prepared[sql]; 241 local stmt = prepared[sql];
231 if stmt and stmt:isopen() then 242 if stmt and stmt:isopen() then
232 prepared[sql] = nil; -- Can't be used concurrently 243 prepared[sql] = nil; -- Can't be used concurrently
233 else 244 else
234 stmt = assert(self.conn:prepare(sql)); 245 stmt = assert(self.conn:prepare(sql));
235 end 246 end
236 local ret = stmt:bind_values(...); 247 local ret = stmt:bind_values(...);
237 if ret ~= lsqlite3.OK then error(self.conn:errmsg()); end 248 if ret ~= lsqlite3.OK then error(self.conn:errmsg()); end
238 local data, ret = {} 249 local data = array();
239 while stmt:step() == ROW do 250 for row in stmt:rows() do
240 t_insert(data, stmt:get_values()); 251 data:push(array(row));
241 end 252 end
242 -- FIXME Error handling, BUSY, ERROR, MISUSE 253 -- FIXME Error handling, BUSY, ERROR, MISUSE
243 if stmt:reset() == lsqlite3.OK then 254 if stmt:reset() == lsqlite3.OK then
244 prepared[sql] = stmt; 255 prepared[sql] = stmt;
245 end 256 end
246 return setmetatable({ __data = data }, { __index = result_mt.__index, __call = iterator(data) });
247 end
248 function engine:execute_update(sql, ...)
249 local prepared = self.prepared;
250 local stmt = prepared[sql];
251 if not stmt or not stmt:isopen() then
252 stmt = assert(self.conn:prepare(sql));
253 else
254 prepared[sql] = nil;
255 end
256 local ret = stmt:bind_values(...);
257 if ret ~= lsqlite3.OK then error(self.conn:errmsg()); end
258 local rowcount = 0;
259 repeat
260 ret = stmt:step();
261 if ret == lsqlite3.ROW then
262 rowcount = rowcount + 1;
263 end
264 until ret ~= lsqlite3.ROW;
265 local affected = self.conn:changes(); 257 local affected = self.conn:changes();
266 if stmt:reset() == lsqlite3.OK then 258 return setmetatable({ __affected = affected; __rowcount = #data; __data = data }, result_mt);
267 prepared[sql] = stmt; 259 end
268 end 260
269 return setmetatable({ __affected = affected, __rowcount = rowcount }, result_mt); 261 function engine:execute_query(sql, ...)
262 return self:execute_update(sql, ...)()
270 end 263 end
271 264
272 engine.insert = engine.execute_update; 265 engine.insert = engine.execute_update;
273 engine.select = engine.execute_query; 266 engine.select = engine.execute_query;
274 engine.delete = engine.execute_update; 267 engine.delete = engine.execute_update;