@@ -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);
6061PG_FUNCTION_INFO_V1 (sqlite_fdw_disconnect );
6162PG_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 );
6465static void sqlite_make_new_connection (ConnCacheEntry * entry , ForeignServer * server );
6566void sqlite_do_sql_command (sqlite3 * conn , const char * sql , int level , List * * busy_connection );
6667static 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 */
189191static 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 }
0 commit comments