Software /
code /
prosody
Comparison
util/sqlite3.lua @ 12847:d6cdde74cd9b
util.sqlite3: Create util.error registry from headers
The 'type' fields are a first guess.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Fri, 01 Oct 2021 02:27:53 +0200 |
parent | 12845:f306336b7e99 |
child | 12848:ccb030d988ac |
comparison
equal
deleted
inserted
replaced
12846:1638991caed2 | 12847:d6cdde74cd9b |
---|---|
12 local log = require "util.logger".init("sql"); | 12 local log = require "util.logger".init("sql"); |
13 | 13 |
14 local lsqlite3 = require "lsqlite3"; | 14 local lsqlite3 = require "lsqlite3"; |
15 local build_url = require "socket.url".build; | 15 local build_url = require "socket.url".build; |
16 local ROW, DONE = lsqlite3.ROW, lsqlite3.DONE; | 16 local ROW, DONE = lsqlite3.ROW, lsqlite3.DONE; |
17 local err2str = { | 17 |
18 [0] = "OK"; | 18 -- from sqlite3.h, no copyright claimed |
19 "ERROR"; | 19 local sqlite_errors = require"util.error".init("util.sqlite3", { |
20 "INTERNAL"; | 20 -- FIXME xmpp error conditions? |
21 "PERM"; | 21 [1] = { code = 1; type = "modify"; condition = "ERROR"; text = "Generic error" }; |
22 "ABORT"; | 22 [2] = { code = 2; type = "cancel"; condition = "INTERNAL"; text = "Internal logic error in SQLite" }; |
23 "BUSY"; | 23 [3] = { code = 3; type = "auth"; condition = "PERM"; text = "Access permission denied" }; |
24 "LOCKED"; | 24 [4] = { code = 4; type = "cancel"; condition = "ABORT"; text = "Callback routine requested an abort" }; |
25 "NOMEM"; | 25 [5] = { code = 5; type = "wait"; condition = "BUSY"; text = "The database file is locked" }; |
26 "READONLY"; | 26 [6] = { code = 6; type = "wait"; condition = "LOCKED"; text = "A table in the database is locked" }; |
27 "INTERRUPT"; | 27 [7] = { code = 7; type = "wait"; condition = "NOMEM"; text = "A malloc() failed" }; |
28 "IOERR"; | 28 [8] = { code = 8; type = "cancel"; condition = "READONLY"; text = "Attempt to write a readonly database" }; |
29 "CORRUPT"; | 29 [9] = { code = 9; type = "cancel"; condition = "INTERRUPT"; text = "Operation terminated by sqlite3_interrupt()" }; |
30 "NOTFOUND"; | 30 [10] = { code = 10; type = "wait"; condition = "IOERR"; text = "Some kind of disk I/O error occurred" }; |
31 "FULL"; | 31 [11] = { code = 11; type = "cancel"; condition = "CORRUPT"; text = "The database disk image is malformed" }; |
32 "CANTOPEN"; | 32 [12] = { code = 12; type = "modify"; condition = "NOTFOUND"; text = "Unknown opcode in sqlite3_file_control()" }; |
33 "PROTOCOL"; | 33 [13] = { code = 13; type = "wait"; condition = "FULL"; text = "Insertion failed because database is full" }; |
34 "EMPTY"; | 34 [14] = { code = 14; type = "auth"; condition = "CANTOPEN"; text = "Unable to open the database file" }; |
35 "SCHEMA"; | 35 [15] = { code = 15; type = "cancel"; condition = "PROTOCOL"; text = "Database lock protocol error" }; |
36 "TOOBIG"; | 36 [16] = { code = 16; type = "continue"; condition = "EMPTY"; text = "Internal use only" }; |
37 "CONSTRAINT"; | 37 [17] = { code = 17; type = "modify"; condition = "SCHEMA"; text = "The database schema changed" }; |
38 "MISMATCH"; | 38 [18] = { code = 18; type = "modify"; condition = "TOOBIG"; text = "String or BLOB exceeds size limit" }; |
39 "MISUSE"; | 39 [19] = { code = 19; type = "modify"; condition = "CONSTRAINT"; text = "Abort due to constraint violation" }; |
40 "NOLFS"; | 40 [20] = { code = 20; type = "modify"; condition = "MISMATCH"; text = "Data type mismatch" }; |
41 [24] = "FORMAT"; | 41 [21] = { code = 21; type = "modify"; condition = "MISUSE"; text = "Library used incorrectly" }; |
42 [25] = "RANGE"; | 42 [22] = { code = 22; type = "cancel"; condition = "NOLFS"; text = "Uses OS features not supported on host" }; |
43 [26] = "NOTADB"; | 43 [23] = { code = 23; type = "auth"; condition = "AUTH"; text = "Authorization denied" }; |
44 [100] = "ROW"; | 44 [24] = { code = 24; type = "modify"; condition = "FORMAT"; text = "Not used" }; |
45 [101] = "DONE"; | 45 [25] = { code = 25; type = "modify"; condition = "RANGE"; text = "2nd parameter to sqlite3_bind out of range" }; |
46 }; | 46 [26] = { code = 26; type = "cancel"; condition = "NOTADB"; text = "File opened that is not a database file" }; |
47 [27] = { code = 27; type = "continue"; condition = "NOTICE"; text = "Notifications from sqlite3_log()" }; | |
48 [28] = { code = 28; type = "continue"; condition = "WARNING"; text = "Warnings from sqlite3_log()" }; | |
49 [100] = { code = 100; type = "continue"; condition = "ROW"; text = "sqlite3_step() has another row ready" }; | |
50 [101] = { code = 101; type = "continue"; condition = "DONE"; text = "sqlite3_step() has finished executing" }; | |
51 }); | |
47 | 52 |
48 local assert = function(cond, errno, err) | 53 local assert = function(cond, errno, err) |
49 return assert(cond, err or err2str[errno]); | 54 return assert(sqlite_errors.coerce(cond, err or errno)); |
50 end | 55 end |
51 local _ENV = nil; | 56 local _ENV = nil; |
52 -- luacheck: std none | 57 -- luacheck: std none |
53 | 58 |
54 local column_mt = {}; | 59 local column_mt = {}; |
135 function engine:connect() | 140 function engine:connect() |
136 if self.conn then return true; end | 141 if self.conn then return true; end |
137 | 142 |
138 local params = self.params; | 143 local params = self.params; |
139 assert(params.driver == "SQLite3", "Only sqlite3 is supported"); | 144 assert(params.driver == "SQLite3", "Only sqlite3 is supported"); |
140 local dbh, err = lsqlite3.open(params.database); | 145 local dbh, err = sqlite_errors.coerce(lsqlite3.open(params.database)); |
141 if not dbh then return nil, err2str[err]; end | 146 if not dbh then return nil, err; end |
142 self.conn = dbh; | 147 self.conn = dbh; |
143 self.prepared = {}; | 148 self.prepared = {}; |
144 local ok, err = self:set_encoding(); | 149 local ok, err = self:set_encoding(); |
145 if not ok then | 150 if not ok then |
146 return ok, err; | 151 return ok, err; |
161 | 166 |
162 local stmt = prepared[sql]; | 167 local stmt = prepared[sql]; |
163 if not stmt then | 168 if not stmt then |
164 local err; | 169 local err; |
165 stmt, err = self.conn:prepare(sql); | 170 stmt, err = self.conn:prepare(sql); |
166 if not stmt then return stmt, err; end | 171 if not stmt then |
172 err = sqlite_errors.new(err); | |
173 err.text = self.conn:errmsg(); | |
174 return stmt, err; | |
175 end | |
167 prepared[sql] = stmt; | 176 prepared[sql] = stmt; |
168 end | 177 end |
169 | 178 |
170 local ret = stmt:bind_values(...); | 179 local ret = stmt:bind_values(...); |
171 if ret ~= lsqlite3.OK then return nil, self.conn:errmsg(); end | 180 if ret ~= lsqlite3.OK then return nil, sqlite_errors.new(ret, { message = self.conn:errmsg() }); end |
172 return stmt; | 181 return stmt; |
173 end | 182 end |
174 | 183 |
175 local result_mt = { | 184 local result_mt = { |
176 __index = { | 185 __index = { |