Skip to content

Commit cdcf0ba

Browse files
mkgrgisМихаил
andauthored
Add force_readonly option for owner of a FOREIGN SERVER in context of SQLite connection management (#78)
Co-authored-by: Михаил <mihail.aksenov@bk.ru>
1 parent 7f7132e commit cdcf0ba

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+3181
-452
lines changed

GitHubActions/detect_targets.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
################################################################################
44
#
5-
# This script detects target PostgreSQL versions for sqlite_fdw testing from
5+
# This script detects target PostgreSQL versions for sqlite_fdw testing from
66
# directory names in ./sql directory. Detected versions will be outputed to
77
# the standard output as an array of string like ["15.4","16.0"].
88
#

GitHubActions/install_locales.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# tests in Ubuntu.
77
#
88
# Usage: ./install_locales.sh
9-
#
9+
#
1010
# Requirements:
1111
# - having superuser privileges
1212
#

README.md

Lines changed: 87 additions & 54 deletions
Large diffs are not rendered by default.

connection.c

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ typedef struct ConnCacheEntry
4141
bool keep_connections; /* setting value of keep_connections
4242
* server option */
4343
bool truncatable; /* check table can truncate or not */
44+
bool readonly; /* option force_readonly, readonly SQLite file mode */
4445
bool invalidated; /* true if reconnect is pending */
4546
Oid serverid; /* foreign server OID used to get server name */
4647
List *stmtList; /* list stmt associated with conn */
@@ -60,7 +61,7 @@ PG_FUNCTION_INFO_V1(sqlite_fdw_get_connections);
6061
PG_FUNCTION_INFO_V1(sqlite_fdw_disconnect);
6162
PG_FUNCTION_INFO_V1(sqlite_fdw_disconnect_all);
6263

63-
static sqlite3 *sqlite_open_db(const char *dbpath);
64+
static sqlite3 *sqlite_open_db(const char *dbpath, int flags);
6465
static void sqlite_make_new_connection(ConnCacheEntry *entry, ForeignServer *server);
6566
void sqlite_do_sql_command(sqlite3 * conn, const char *sql, int level, List **busy_connection);
6667
static void sqlite_begin_remote_xact(ConnCacheEntry *entry);
@@ -184,21 +185,21 @@ sqlite_get_connection(ForeignServer *server, bool truncatable)
184185
}
185186

186187
/*
187-
* Open remote sqlite database using specified database path.
188+
* Open remote sqlite database using specified database path
189+
* and flags of opened file descriptor mode.
188190
*/
189191
static sqlite3 *
190-
sqlite_open_db(const char *dbpath)
192+
sqlite_open_db(const char *dbpath, int flags)
191193
{
192194
sqlite3 *conn = NULL;
193195
int rc;
194196
char *err;
195-
196-
rc = sqlite3_open(dbpath, &conn);
197+
const char *zVfs = NULL;
198+
rc = sqlite3_open_v2(dbpath, &conn, flags, zVfs);
197199
if (rc != SQLITE_OK)
198200
ereport(ERROR,
199201
(errcode(ERRCODE_FDW_UNABLE_TO_ESTABLISH_CONNECTION),
200-
errmsg("failed to open SQLite DB. rc=%d path=%s", rc, dbpath)));
201-
202+
errmsg("Failed to open SQLite DB, file '%s', result code %d", dbpath, rc)));
202203
/* make 'LIKE' of SQLite case sensitive like PostgreSQL */
203204
rc = sqlite3_exec(conn, "pragma case_sensitive_like=1",
204205
NULL, NULL, &err);
@@ -208,9 +209,10 @@ sqlite_open_db(const char *dbpath)
208209

209210
sqlite3_free(err);
210211
sqlite3_close(conn);
212+
conn = NULL;
211213
ereport(ERROR,
212214
(errcode(ERRCODE_FDW_UNABLE_TO_ESTABLISH_CONNECTION),
213-
errmsg("failed to open SQLite DB. rc=%d err=%s", rc, perr)));
215+
errmsg("Failed to open SQLite DB, file '%s', SQLite error '%s', result code %d", dbpath, perr, rc)));
214216
}
215217
/* add included inner SQLite functions from separate c file
216218
* for using in data unifying during deparsing
@@ -219,6 +221,7 @@ sqlite_open_db(const char *dbpath)
219221
return conn;
220222
}
221223

224+
222225
/*
223226
* Reset all transient state fields in the cached connection entry and
224227
* establish new connection to the remote server.
@@ -228,6 +231,7 @@ sqlite_make_new_connection(ConnCacheEntry *entry, ForeignServer *server)
228231
{
229232
const char *dbpath = NULL;
230233
ListCell *lc;
234+
int flags = 0;
231235

232236
Assert(entry->conn == NULL);
233237

@@ -236,6 +240,7 @@ sqlite_make_new_connection(ConnCacheEntry *entry, ForeignServer *server)
236240
entry->invalidated = false;
237241
entry->stmtList = NULL;
238242
entry->keep_connections = true;
243+
entry->readonly = false;
239244
entry->server_hashvalue =
240245
GetSysCacheHashValue1(FOREIGNSERVEROID,
241246
ObjectIdGetDatum(server->serverid));
@@ -247,10 +252,13 @@ sqlite_make_new_connection(ConnCacheEntry *entry, ForeignServer *server)
247252
dbpath = defGetString(def);
248253
else if (strcmp(def->defname, "keep_connections") == 0)
249254
entry->keep_connections = defGetBoolean(def);
255+
else if (strcmp(def->defname, "force_readonly") == 0)
256+
entry->readonly = defGetBoolean(def);
250257
}
251258

259+
flags = flags | (entry->readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE);
252260
/* Try to make the connection */
253-
entry->conn = sqlite_open_db(dbpath);
261+
entry->conn = sqlite_open_db(dbpath, flags);
254262
}
255263

256264
/*
@@ -282,8 +290,9 @@ sqlite_cleanup_connection(void)
282290
{
283291
ereport(ERROR,
284292
(errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION),
285-
errmsg("close connection failed: %s rc=%d", sqlite3_errmsg(entry->conn), rc)
286-
));
293+
errmsg("Failed to close SQLite DB"),
294+
errhint("SQLite error '%s', SQLite result code %d", sqlite3_errmsg(entry->conn), rc)
295+
));
287296
}
288297
}
289298
}
@@ -327,15 +336,18 @@ sqlite_do_sql_command(sqlite3 * conn, const char *sql, int level, List **busy_co
327336
{
328337
ereport(level,
329338
(errcode(ERRCODE_FDW_ERROR),
330-
errmsg("SQLite failed to execute sql: %s %s", sql, perr)
331-
));
339+
errmsg("SQLite failed to execute a query"),
340+
errcontext("SQL query: %s", sql),
341+
errhint("SQLite error '%s'", perr)));
342+
332343
pfree(perr);
333344
}
334345
}
335346
else
336347
ereport(level,
337348
(errcode(ERRCODE_FDW_ERROR),
338-
errmsg("SQLite failed to execute sql: %s", sql)
349+
errmsg("SQLite failed to execute a query"),
350+
errcontext("SQL query: %s", sql)
339351
));
340352
}
341353
}
@@ -401,10 +413,10 @@ sqlitefdw_report_error(int elevel, sqlite3_stmt * stmt, sqlite3 * conn,
401413
}
402414
ereport(ERROR,
403415
(errcode(sqlstate),
404-
errmsg("failed to execute remote SQL: rc=%d %s \n sql=%s",
405-
rc, message ? message : "", sql ? sql : "")
406-
));
407-
416+
errmsg("Failed to execute remote SQL"),
417+
errcontext("SQL query: %s", sql ? sql : ""),
418+
errhint("SQLite error '%s', SQLite result code %d", message ? message : "", rc)
419+
));
408420
}
409421

410422

@@ -903,9 +915,12 @@ sqlitefdw_abort_cleanup(ConnCacheEntry *entry, bool toplevel, List **busy_connec
903915
{
904916
char sql[100];
905917
int curlevel = GetCurrentTransactionNestLevel();
906-
snprintf(sql, sizeof(sql),
907-
"ROLLBACK TO SAVEPOINT s%d; RELEASE SAVEPOINT s%d",
908-
curlevel, curlevel);
918+
snprintf(sql,
919+
sizeof(sql),
920+
"ROLLBACK TO SAVEPOINT s%d; RELEASE SAVEPOINT s%d",
921+
curlevel,
922+
curlevel
923+
);
909924
if (!sqlite3_get_autocommit(entry->conn))
910925
sqlite_do_sql_command(entry->conn, sql, ERROR, busy_connection);
911926
}

expected/12.16/extra/bool.out

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,9 @@ INSERT INTO "type_BOOLEANpk" VALUES (TRUE);
238238
INSERT INTO "type_BOOLEANpk" VALUES (FALSE);
239239
--Testcase 44: ERR - primary key
240240
INSERT INTO "type_BOOLEANpk" VALUES (TRUE);
241-
ERROR: failed to execute remote SQL: rc=19 UNIQUE constraint failed: type_BOOLEANpk.col
242-
sql=INSERT INTO main."type_BOOLEANpk"(`col`) VALUES (?)
241+
ERROR: Failed to execute remote SQL
242+
HINT: SQLite error 'UNIQUE constraint failed: type_BOOLEANpk.col', SQLite result code 19
243+
CONTEXT: SQL query: INSERT INTO main."type_BOOLEANpk"(`col`) VALUES (?)
243244
--Testcase 45:
244245
DELETE FROM "type_BOOLEANpk";
245246
--Testcase 46:

expected/12.16/extra/insert.out

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ OPTIONS (database '/tmp/sqlite_fdw_test/core.db');
1010
CREATE FOREIGN TABLE inserttest01 (col1 int4, col2 int4 NOT NULL, col3 text default 'testing') SERVER sqlite_svr;
1111
--Testcase 1:
1212
insert into inserttest01 (col1, col2, col3) values (DEFAULT, DEFAULT, DEFAULT);
13-
ERROR: failed to execute remote SQL: rc=19 NOT NULL constraint failed: inserttest01.col2
14-
sql=INSERT INTO main."inserttest01"(`col1`, `col2`, `col3`) VALUES (?, ?, ?)
13+
ERROR: Failed to execute remote SQL
14+
HINT: SQLite error 'NOT NULL constraint failed: inserttest01.col2', SQLite result code 19
15+
CONTEXT: SQL query: INSERT INTO main."inserttest01"(`col1`, `col2`, `col3`) VALUES (?, ?, ?)
1516
--Testcase 2:
1617
insert into inserttest01 (col2, col3) values (3, DEFAULT);
1718
--Testcase 3:

expected/12.16/extra/sqlite_fdw_post.out

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1; -- should work
133133
ALTER SERVER sqlite_svr OPTIONS (SET database 'no such database');
134134
--Testcase 7:
135135
SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1; -- should fail
136-
ERROR: SQL error during prepare: no such table: main.T 1 SELECT `C 1`, `c3`, `c4` FROM main."T 1" ORDER BY `c3` ASC NULLS LAST, `C 1` ASC NULLS LAST LIMIT 1
136+
ERROR: Failed to open SQLite DB, file 'no such database', result code 14
137137
DO $d$
138138
BEGIN
139139
EXECUTE $$ALTER SERVER sqlite_svr
@@ -6424,8 +6424,9 @@ ALTER FOREIGN TABLE ft1 RENAME TO ft1_org;
64246424
ALTER FOREIGN TABLE ft1_constraint RENAME TO ft1;
64256425
--Testcase 319:
64266426
INSERT INTO ft1(c1, c2) VALUES(11, 12); -- duplicate key
6427-
ERROR: failed to execute remote SQL: rc=19 UNIQUE constraint failed: t1_constraint.c1
6428-
sql=INSERT INTO main."t1_constraint"(`c1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
6427+
ERROR: Failed to execute remote SQL
6428+
HINT: SQLite error 'UNIQUE constraint failed: t1_constraint.c1', SQLite result code 19
6429+
CONTEXT: SQL query: INSERT INTO main."t1_constraint"(`c1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
64296430
--Testcase 320:
64306431
INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO NOTHING; -- unsupported
64316432
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
@@ -6434,12 +6435,14 @@ INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO UPDATE SET c3 = '
64346435
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
64356436
--Testcase 743:
64366437
INSERT INTO ft1(c1, c2) VALUES(1111, -2); -- c2positive
6437-
ERROR: failed to execute remote SQL: rc=19 CHECK constraint failed: c2 >= 0
6438-
sql=INSERT INTO main."t1_constraint"(`c1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
6438+
ERROR: Failed to execute remote SQL
6439+
HINT: SQLite error 'CHECK constraint failed: c2 >= 0', SQLite result code 19
6440+
CONTEXT: SQL query: INSERT INTO main."t1_constraint"(`c1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
64396441
--Testcase 744:
64406442
UPDATE ft1 SET c2 = -c2 WHERE c1 = 1; -- c2positive
6441-
ERROR: failed to execute remote SQL: rc=19 CHECK constraint failed: c2 >= 0
6442-
sql=UPDATE main."t1_constraint" SET `c2` = (- `c2`) WHERE ((`c1` = 1))
6443+
ERROR: Failed to execute remote SQL
6444+
HINT: SQLite error 'CHECK constraint failed: c2 >= 0', SQLite result code 19
6445+
CONTEXT: SQL query: UPDATE main."t1_constraint" SET `c2` = (- `c2`) WHERE ((`c1` = 1))
64436446
--Testcase 750:
64446447
ALTER FOREIGN TABLE ft1 RENAME TO ft1_constraint;
64456448
--Testcase 751:
@@ -6840,12 +6843,14 @@ RESET constraint_exclusion;
68406843
-- check constraint is enforced on the remote side, not locally
68416844
--Testcase 745:
68426845
INSERT INTO ft1(c1, c2) VALUES(1111, -2); -- c2positive
6843-
ERROR: failed to execute remote SQL: rc=19 CHECK constraint failed: c2 >= 0
6844-
sql=INSERT INTO main."t1_constraint"(`c1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
6846+
ERROR: Failed to execute remote SQL
6847+
HINT: SQLite error 'CHECK constraint failed: c2 >= 0', SQLite result code 19
6848+
CONTEXT: SQL query: INSERT INTO main."t1_constraint"(`c1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`, `c8`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
68456849
--Testcase 746:
68466850
UPDATE ft1 SET c2 = -c2 WHERE c1 = 1; -- c2positive
6847-
ERROR: failed to execute remote SQL: rc=19 CHECK constraint failed: c2 >= 0
6848-
sql=UPDATE main."t1_constraint" SET `c2` = (- `c2`) WHERE ((`c1` = 1))
6851+
ERROR: Failed to execute remote SQL
6852+
HINT: SQLite error 'CHECK constraint failed: c2 >= 0', SQLite result code 19
6853+
CONTEXT: SQL query: UPDATE main."t1_constraint" SET `c2` = (- `c2`) WHERE ((`c1` = 1))
68496854
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2positive;
68506855
-- But inconsistent check constraints provide inconsistent results
68516856
ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2negative CHECK (c2 < 0);

expected/12.16/extra/uuid.out

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,8 +521,9 @@ SELECT * FROM "type_UUIDpk";
521521

522522
--Testcase 105: ERR - primary key
523523
INSERT INTO "type_UUIDpk" VALUES ('{b0eebc99-9c0b4ef8-bb6d6bb9-bd380a12}');
524-
ERROR: failed to execute remote SQL: rc=19 UNIQUE constraint failed: type_UUIDpk.col
525-
sql=INSERT INTO main."type_UUIDpk"(`col`) VALUES (?)
524+
ERROR: Failed to execute remote SQL
525+
HINT: SQLite error 'UNIQUE constraint failed: type_UUIDpk.col', SQLite result code 19
526+
CONTEXT: SQL query: INSERT INTO main."type_UUIDpk"(`col`) VALUES (?)
526527
--Testcase 106:
527528
ALTER FOREIGN TABLE "type_UUIDpk" ALTER COLUMN col OPTIONS (SET column_type 'BLOB');
528529
--Testcase 107: NO ERR, but the same semantics!

0 commit comments

Comments
 (0)