Improve error handling in dbopen(). If PRAGMA SQL statements fail,
authorschwarze <schwarze@openbsd.org>
Sun, 27 Apr 2014 23:03:52 +0000 (23:03 +0000)
committerschwarze <schwarze@openbsd.org>
Sun, 27 Apr 2014 23:03:52 +0000 (23:03 +0000)
report the error, close the database, and return failure from dbopen(),
such that the main program can recover and rebuild the database.

As noticed by stsp@, this can happen when database files are
accessible, but corrupt or in the wrong format, which will now
automatically be repaired.

Besides, use a safer idiom after sqlite3_open*() failure that also
handles out-of-memory situations correctly, and do not forget to
close the database after CREATE TABLE failure.

usr.bin/mandoc/mandocdb.c

index 0c59b86..de63566 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mandocdb.c,v 1.102 2014/04/25 12:12:35 schwarze Exp $ */
+/*     $Id: mandocdb.c,v 1.103 2014/04/27 23:03:52 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -2201,7 +2201,7 @@ dbopen(int real)
                rc = sqlite3_open_v2(MANDOC_DB, &db, ofl, NULL);
                if (SQLITE_OK != rc) {
                        exitcode = (int)MANDOCLEVEL_SYSERR;
-                       say(MANDOC_DB, "%s", sqlite3_errmsg(db));
+                       say(MANDOC_DB, "%s", sqlite3_errstr(rc));
                        return(0);
                }
                goto prepare_statements;
@@ -2215,7 +2215,7 @@ dbopen(int real)
                goto create_tables;
        if (MPARSE_QUICK & mparse_options) {
                exitcode = (int)MANDOCLEVEL_SYSERR;
-               say(MANDOC_DB "~", "%s", sqlite3_errmsg(db));
+               say(MANDOC_DB "~", "%s", sqlite3_errstr(rc));
                return(0);
        }
 
@@ -2231,7 +2231,7 @@ dbopen(int real)
        rc = sqlite3_open_v2(tempfilename, &db, ofl, NULL);
        if (SQLITE_OK != rc) {
                exitcode = (int)MANDOCLEVEL_SYSERR;
-               say("", "%s: %s", tempfilename, sqlite3_errmsg(db));
+               say("", "%s: %s", tempfilename, sqlite3_errstr(rc));
                return(0);
        }
 
@@ -2269,11 +2269,20 @@ create_tables:
        if (SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, NULL)) {
                exitcode = (int)MANDOCLEVEL_SYSERR;
                say(MANDOC_DB, "%s", sqlite3_errmsg(db));
+               sqlite3_close(db);
                return(0);
        }
 
 prepare_statements:
-       SQL_EXEC("PRAGMA foreign_keys = ON");
+       if (SQLITE_OK != sqlite3_exec(db,
+           "PRAGMA foreign_keys = ON", NULL, NULL, NULL)) {
+               exitcode = (int)MANDOCLEVEL_SYSERR;
+               say(MANDOC_DB, "PRAGMA foreign_keys: %s",
+                   sqlite3_errmsg(db));
+               sqlite3_close(db);
+               return(0);
+       }
+
        sql = "DELETE FROM mpages WHERE pageid IN "
                "(SELECT pageid FROM mlinks WHERE "
                "sec=? AND arch=? AND name=?)";
@@ -2296,8 +2305,14 @@ prepare_statements:
         * synchronous mode for much better performance.
         */
 
-       if (real)
-               SQL_EXEC("PRAGMA synchronous = OFF");
+       if (real && SQLITE_OK != sqlite3_exec(db,
+           "PRAGMA synchronous = OFF", NULL, NULL, NULL)) {
+               exitcode = (int)MANDOCLEVEL_SYSERR;
+               say(MANDOC_DB, "PRAGMA synchronous: %s",
+                   sqlite3_errmsg(db));
+               sqlite3_close(db);
+               return(0);
+       }
 
        return(1);
 }