chiark / gitweb /
CommodsDatabase: Work around problems with readonly db
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 3 Apr 2016 13:25:56 +0000 (14:25 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 3 Apr 2016 13:25:56 +0000 (14:25 +0100)
yarrg/CommodsDatabase.pm

index 0d491c4..1f977d4 100644 (file)
@@ -35,6 +35,7 @@ use warnings;
 
 use DBI;
 use POSIX;
+use DBD::SQLite;
 
 use Commods;
 
@@ -67,6 +68,31 @@ sub db_connect_core ($) {
     my $opts = { AutoCommit=>0,
                 RaiseError=>1, ShowErrorStatement=>1,
                 sqlite_unicode=>1 };
+
+    # DBI now wants to start a transaction whenever we even say
+    # SELECT.  But this doesn't work if the DB is readonly.  We can
+    # work around this by setting autocommit, in which case there is
+    # no need for a transaction for read-only db commands.  Autocommit
+    # is (obviously) safe with readonly operations.  But callers in
+    # yarrg do not specify to us whether they intend to write.  So we
+    # decide, by looking at the file mode.  And as belt-and-braces we
+    # set sqlite's own readonly flag as well.
+    # http://stackoverflow.com/questions/30082008/attempt-to-write-a-readonly-database-but-im-not
+    # http://stackoverflow.com/questions/35208727/can-sqlite-db-files-be-made-read-only
+    # http://cpansearch.perl.org/src/ISHIGAKI/DBD-SQLite-1.39/Changes
+    # (see entry for 1.38_01)
+    # http://stackoverflow.com/questions/17793672/perl-dbi-treats-setting-sqlite-db-cache-size-as-a-write-operation-when-subclassi
+    # https://rt.cpan.org/Public/Bug/Display.html?id=56444#
+    my $readonly =
+       (access $fn, POSIX::W_OK) ? 0 :
+       ($! == EACCES) ? 1 :
+       ($! == ENOENT) ? 0 :
+       die "$fn access(,W_OK) $!";
+    if ($readonly) {
+       $opts->{sqlite_open_flags} = DBD::SQLite::OPEN_READONLY;
+       $opts->{AutoCommit}=1;
+    }
+
     my $h= DBI->connect("dbi:SQLite:$fn",'','',$opts)
        or die "$fn $DBI::errstr ?";
     return $h;