<p>Stefan Sperling <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/11898">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Neels Hofmeyr: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add database schema versioning to the HLR database<br><br>Make use of pragma user_version to store our database schema version.<br>The present schema is now identitifed as 'version 0', which is also<br>the default value for databases on which we never ran the statement<br>'pragma user_version' before.<br><br>Only bootstrap the database if it hasn't been bootstrapped yet.<br>Previously, bootstrap SQL statements ran every time osmo-hlr<br>opened the database, and any errors were being ignored in SQL.<br>Instead, we now first run a query which checks whether tables<br>already exist, and only create them if necessary.<br>This change will allow future schema updates to work properly.<br><br>Prepare for future schema upgrades by adding a new command-line<br>option which enables upgrades. This option defaults to 'false'<br>in order to avoid accidental upgrades.<br><br>Change-Id: I8aeaa9a404b622657cbc7138106f38aa6ad8d01b<br>Related: OS#2838<br>---<br>M sql/hlr.sql<br>M src/db.c<br>M src/db.h<br>M src/hlr.c<br>M src/hlr_db_tool.c<br>M tests/db/db_test.c<br>6 files changed, 128 insertions(+), 25 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/sql/hlr.sql b/sql/hlr.sql</span><br><span>index 80eb3e5..3499109 100644</span><br><span>--- a/sql/hlr.sql</span><br><span>+++ b/sql/hlr.sql</span><br><span>@@ -1,4 +1,4 @@</span><br><span style="color: hsl(0, 100%, 40%);">-CREATE TABLE IF NOT EXISTS subscriber (</span><br><span style="color: hsl(120, 100%, 40%);">+CREATE TABLE subscriber (</span><br><span> -- OsmoHLR's DB scheme is modelled roughly after TS 23.008 version 13.3.0</span><br><span>     id              INTEGER PRIMARY KEY,</span><br><span>         -- Chapter 2.1.1.1</span><br><span>@@ -39,24 +39,24 @@</span><br><span>     ms_purged_ps    BOOLEAN NOT NULL DEFAULT 0</span><br><span> );</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-CREATE TABLE IF NOT EXISTS subscriber_apn (</span><br><span style="color: hsl(120, 100%, 40%);">+CREATE TABLE subscriber_apn (</span><br><span>       subscriber_id   INTEGER,                -- subscriber.id</span><br><span>     apn             VARCHAR(256) NOT NULL</span><br><span> );</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-CREATE TABLE IF NOT EXISTS subscriber_multi_msisdn (</span><br><span style="color: hsl(120, 100%, 40%);">+CREATE TABLE subscriber_multi_msisdn (</span><br><span> -- Chapter 2.1.3</span><br><span>      subscriber_id   INTEGER,                -- subscriber.id</span><br><span>     msisdn          VARCHAR(15) NOT NULL</span><br><span> );</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-CREATE TABLE IF NOT EXISTS auc_2g (</span><br><span style="color: hsl(120, 100%, 40%);">+CREATE TABLE auc_2g (</span><br><span>     subscriber_id   INTEGER PRIMARY KEY,    -- subscriber.id</span><br><span>     algo_id_2g      INTEGER NOT NULL,       -- enum osmo_auth_algo value</span><br><span>         ki              VARCHAR(32) NOT NULL    -- hex string: subscriber's secret key (128bit)</span><br><span> );</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-CREATE TABLE IF NOT EXISTS auc_3g (</span><br><span style="color: hsl(120, 100%, 40%);">+CREATE TABLE auc_3g (</span><br><span>      subscriber_id   INTEGER PRIMARY KEY,    -- subscriber.id</span><br><span>     algo_id_3g      INTEGER NOT NULL,       -- enum osmo_auth_algo value</span><br><span>         k               VARCHAR(32) NOT NULL,   -- hex string: subscriber's secret key (128bit)</span><br><span>@@ -66,4 +66,7 @@</span><br><span>      ind_bitlen      INTEGER NOT NULL DEFAULT 5      -- nr of index bits at lower SQN end</span><br><span> );</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-CREATE UNIQUE INDEX IF NOT EXISTS idx_subscr_imsi ON subscriber (imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- Set HLR database schema version number</span><br><span style="color: hsl(120, 100%, 40%);">+PRAGMA user_version = 0;</span><br><span>diff --git a/src/db.c b/src/db.c</span><br><span>index bcf83c6..df52f9b 100644</span><br><span>--- a/src/db.c</span><br><span>+++ b/src/db.c</span><br><span>@@ -27,6 +27,8 @@</span><br><span> #include "db.h"</span><br><span> #include "db_bootstrap.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define CURRENT_SCHEMA_VERSION        0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define SEL_COLUMNS \</span><br><span>         "id," \</span><br><span>    "imsi," \</span><br><span>@@ -197,36 +199,90 @@</span><br><span>  for (i = 0; i < ARRAY_SIZE(stmt_bootstrap_sql); i++) {</span><br><span>            int rc;</span><br><span>              sqlite3_stmt *stmt;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             rc = sqlite3_prepare_v2(dbc->db, stmt_bootstrap_sql[i], -1,</span><br><span style="color: hsl(0, 100%, 40%);">-                                  &stmt, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = sqlite3_prepare_v2(dbc->db, stmt_bootstrap_sql[i], -1, &stmt, NULL);</span><br><span>             if (rc != SQLITE_OK) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                            stmt_bootstrap_sql[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                  LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", stmt_bootstrap_sql[i]);</span><br><span>                    return rc;</span><br><span>           }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           /* execute the statement */</span><br><span>          rc = sqlite3_step(stmt);</span><br><span>             db_remove_reset(stmt);</span><br><span>               sqlite3_finalize(stmt);</span><br><span>              if (rc != SQLITE_DONE) {</span><br><span>                     LOGP(DDB, LOGL_ERROR, "Cannot bootstrap database: SQL error: (%d) %s,"</span><br><span>                          " during stmt '%s'",</span><br><span style="color: hsl(0, 100%, 40%);">-                          rc, sqlite3_errmsg(dbc->db),</span><br><span style="color: hsl(0, 100%, 40%);">-                         stmt_bootstrap_sql[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc, sqlite3_errmsg(dbc->db), stmt_bootstrap_sql[i]);</span><br><span>                         return rc;</span><br><span>           }</span><br><span>    }</span><br><span>    return SQLITE_OK;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logging)</span><br><span style="color: hsl(120, 100%, 40%);">+/* https://www.sqlite.org/fileformat2.html#storage_of_the_sql_database_schema */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool db_table_exists(struct db_context *dbc, const char *table_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *table_exists_sql = "SELECT name FROM sqlite_master WHERE type='table' AND name=?";</span><br><span style="color: hsl(120, 100%, 40%);">+      sqlite3_stmt *stmt;</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = sqlite3_prepare_v2(dbc->db, table_exists_sql, -1, &stmt, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc != SQLITE_OK) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", table_exists_sql);</span><br><span style="color: hsl(120, 100%, 40%);">+          return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!db_bind_text(stmt, NULL, table_name))</span><br><span style="color: hsl(120, 100%, 40%);">+            return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = sqlite3_step(stmt);</span><br><span style="color: hsl(120, 100%, 40%);">+      db_remove_reset(stmt);</span><br><span style="color: hsl(120, 100%, 40%);">+        sqlite3_finalize(stmt);</span><br><span style="color: hsl(120, 100%, 40%);">+       return (rc == SQLITE_ROW);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Indicate whether the database is initialized with tables for schema version 0.</span><br><span style="color: hsl(120, 100%, 40%);">+ * We only check for the 'subscriber' table here because Neels said so. */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool db_is_bootstrapped_v0(struct db_context *dbc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!db_table_exists(dbc, "subscriber")) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DDB, LOGL_DEBUG, "Table 'subscriber' not found in database '%s'\n", dbc->fname);</span><br><span style="color: hsl(120, 100%, 40%);">+            return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int db_get_user_version(struct db_context *dbc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *user_version_sql = "PRAGMA user_version";</span><br><span style="color: hsl(120, 100%, 40%);">+       sqlite3_stmt *stmt;</span><br><span style="color: hsl(120, 100%, 40%);">+   int version, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = sqlite3_prepare_v2(dbc->db, user_version_sql, -1, &stmt, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc != SQLITE_OK) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", user_version_sql);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = sqlite3_step(stmt);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc == SQLITE_ROW) {</span><br><span style="color: hsl(120, 100%, 40%);">+               version = sqlite3_column_int(stmt, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DDB, LOGL_ERROR, "SQL statement '%s' failed: %d\n", user_version_sql, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+             version = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   db_remove_reset(stmt);</span><br><span style="color: hsl(120, 100%, 40%);">+        sqlite3_finalize(stmt);</span><br><span style="color: hsl(120, 100%, 40%);">+       return version;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logging, bool allow_upgrade)</span><br><span> {</span><br><span>  struct db_context *dbc = talloc_zero(ctx, struct db_context);</span><br><span>        unsigned int i;</span><br><span>      int rc;</span><br><span>      bool has_sqlite_config_sqllog = false;</span><br><span style="color: hsl(120, 100%, 40%);">+        int version;</span><br><span> </span><br><span>     LOGP(DDB, LOGL_NOTICE, "using database: %s\n", fname);</span><br><span>     LOGP(DDB, LOGL_INFO, "Compiled against SQLite3 lib version %s\n", SQLITE_VERSION);</span><br><span>@@ -275,10 +331,40 @@</span><br><span>                 LOGP(DDB, LOGL_ERROR, "Unable to set Write-Ahead Logging: %s\n",</span><br><span>                   err_msg);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   rc = db_bootstrap(dbc);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc != SQLITE_OK) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DDB, LOGL_ERROR, "Failed to bootstrap DB: (rc=%d) %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                 rc, sqlite3_errmsg(dbc->db));</span><br><span style="color: hsl(120, 100%, 40%);">+      version = db_get_user_version(dbc);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (version < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DDB, LOGL_ERROR, "Unable to read user version number from database '%s'\n", dbc->fname);</span><br><span style="color: hsl(120, 100%, 40%);">+            goto out_free;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* An empty database will always report version zero. */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (version == 0 && !db_is_bootstrapped_v0(dbc)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DDB, LOGL_NOTICE, "Missing database tables detected; Bootstrapping database '%s'\n", dbc->fname);</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = db_bootstrap(dbc);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (rc != SQLITE_OK) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DDB, LOGL_ERROR, "Failed to bootstrap DB: (rc=%d) %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            rc, sqlite3_errmsg(dbc->db));</span><br><span style="color: hsl(120, 100%, 40%);">+                 goto out_free;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DDB, LOGL_NOTICE, "Database '%s' has HLR DB schema version %d\n", dbc->fname, version);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (version < CURRENT_SCHEMA_VERSION && allow_upgrade) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Future version upgrades will happen here. */</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (version != CURRENT_SCHEMA_VERSION) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (version < CURRENT_SCHEMA_VERSION) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOGP(DDB, LOGL_NOTICE, "HLR DB schema version %d is outdated\n", version);</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (!allow_upgrade) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         LOGP(DDB, LOGL_ERROR, "Not upgrading HLR database to schema version %d; "</span><br><span style="color: hsl(120, 100%, 40%);">+                                "use the --db-upgrade option to allow HLR database upgrades\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     CURRENT_SCHEMA_VERSION);</span><br><span style="color: hsl(120, 100%, 40%);">+                 }</span><br><span style="color: hsl(120, 100%, 40%);">+             } else</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DDB, LOGL_ERROR, "HLR DB schema version %d is unknown\n", version);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                 goto out_free;</span><br><span>       }</span><br><span> </span><br><span>diff --git a/src/db.h b/src/db.h</span><br><span>index 34582c8..66dfe57 100644</span><br><span>--- a/src/db.h</span><br><span>+++ b/src/db.h</span><br><span>@@ -39,7 +39,7 @@</span><br><span> bool db_bind_int(sqlite3_stmt *stmt, const char *param_name, int nr);</span><br><span> bool db_bind_int64(sqlite3_stmt *stmt, const char *param_name, int64_t nr);</span><br><span> void db_close(struct db_context *dbc);</span><br><span style="color: hsl(0, 100%, 40%);">-struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite3_logging);</span><br><span style="color: hsl(120, 100%, 40%);">+struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite3_logging, bool allow_upgrades);</span><br><span> </span><br><span> #include <osmocom/crypt/auth.h></span><br><span> </span><br><span>diff --git a/src/hlr.c b/src/hlr.c</span><br><span>index 78d6c91..14945b6 100644</span><br><span>--- a/src/hlr.c</span><br><span>+++ b/src/hlr.c</span><br><span>@@ -483,6 +483,7 @@</span><br><span>  printf("  -s --disable-color         Do not print ANSI colors in the log\n");</span><br><span>      printf("  -T --timestamp             Prefix every log line with a timestamp.\n");</span><br><span>  printf("  -e --log-level number      Set a global loglevel.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("  -U --db-upgrade            Allow HLR database schema upgrades.\n");</span><br><span>      printf("  -V --version               Print the version of OsmoHLR.\n");</span><br><span> }</span><br><span> </span><br><span>@@ -490,10 +491,12 @@</span><br><span>   const char *config_file;</span><br><span>     const char *db_file;</span><br><span>         bool daemonize;</span><br><span style="color: hsl(120, 100%, 40%);">+       bool db_upgrade;</span><br><span> } cmdline_opts = {</span><br><span>       .config_file = "osmo-hlr.cfg",</span><br><span>     .db_file = "hlr.db",</span><br><span>       .daemonize = false,</span><br><span style="color: hsl(120, 100%, 40%);">+   .db_upgrade = false,</span><br><span> };</span><br><span> </span><br><span> static void handle_options(int argc, char **argv)</span><br><span>@@ -509,11 +512,12 @@</span><br><span>                  {"disable-color", 0, 0, 's'},</span><br><span>                      {"log-level", 1, 0, 'e'},</span><br><span>                  {"timestamp", 0, 0, 'T'},</span><br><span style="color: hsl(120, 100%, 40%);">+                   {"db-upgrade", 0, 0, 'U' },</span><br><span>                        {"version", 0, 0, 'V' },</span><br><span>                   {0, 0, 0, 0}</span><br><span>                 };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-          c = getopt_long(argc, argv, "hc:l:d:Dse:TV",</span><br><span style="color: hsl(120, 100%, 40%);">+                c = getopt_long(argc, argv, "hc:l:d:Dse:TUV",</span><br><span>                              long_options, &option_index);</span><br><span>            if (c == -1)</span><br><span>                         break;</span><br><span>@@ -544,6 +548,9 @@</span><br><span>                 case 'T':</span><br><span>                    log_set_print_timestamp(osmo_stderr_target, 1);</span><br><span>                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'U':</span><br><span style="color: hsl(120, 100%, 40%);">+                     cmdline_opts.db_upgrade = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</span><br><span>               case 'V':</span><br><span>                    print_version(1);</span><br><span>                    exit(0);</span><br><span>@@ -637,7 +644,7 @@</span><br><span>               exit(1);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   g_hlr->dbc = db_open(hlr_ctx, cmdline_opts.db_file, true);</span><br><span style="color: hsl(120, 100%, 40%);">+ g_hlr->dbc = db_open(hlr_ctx, cmdline_opts.db_file, true, cmdline_opts.db_upgrade);</span><br><span>       if (!g_hlr->dbc) {</span><br><span>                LOGP(DMAIN, LOGL_FATAL, "Error opening database\n");</span><br><span>               exit(1);</span><br><span>diff --git a/src/hlr_db_tool.c b/src/hlr_db_tool.c</span><br><span>index e83b098..1a9c60c 100644</span><br><span>--- a/src/hlr_db_tool.c</span><br><span>+++ b/src/hlr_db_tool.c</span><br><span>@@ -44,8 +44,10 @@</span><br><span>       const char *db_file;</span><br><span>         bool bootstrap;</span><br><span>      const char *import_nitb_db;</span><br><span style="color: hsl(120, 100%, 40%);">+   bool db_upgrade;</span><br><span> } cmdline_opts = {</span><br><span>       .db_file = "hlr.db",</span><br><span style="color: hsl(120, 100%, 40%);">+        .db_upgrade = false,</span><br><span> };</span><br><span> </span><br><span> static void print_help()</span><br><span>@@ -59,6 +61,7 @@</span><br><span>       printf("  -s --disable-color         Do not print ANSI colors in the log\n");</span><br><span>      printf("  -T --timestamp             Prefix every log line with a timestamp.\n");</span><br><span>  printf("  -e --log-level number      Set a global loglevel.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("  -U --db-upgrade            Allow HLR database schema upgrades.\n");</span><br><span>      printf("  -V --version               Print the version of OsmoHLR-db-tool.\n");</span><br><span>    printf("\n");</span><br><span>      printf("Commands:\n");</span><br><span>@@ -96,11 +99,12 @@</span><br><span>                       {"disable-color", 0, 0, 's'},</span><br><span>                      {"timestamp", 0, 0, 'T'},</span><br><span>                  {"log-level", 1, 0, 'e'},</span><br><span style="color: hsl(120, 100%, 40%);">+                   {"db-upgrade", 0, 0, 'U' },</span><br><span>                        {"version", 0, 0, 'V' },</span><br><span>                   {0, 0, 0, 0}</span><br><span>                 };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-          c = getopt_long(argc, argv, "hl:d:sTe:V",</span><br><span style="color: hsl(120, 100%, 40%);">+           c = getopt_long(argc, argv, "hl:d:sTe:UV",</span><br><span>                                 long_options, &option_index);</span><br><span>            if (c == -1)</span><br><span>                         break;</span><br><span>@@ -124,6 +128,9 @@</span><br><span>                 case 'e':</span><br><span>                    log_set_log_level(osmo_stderr_target, atoi(optarg));</span><br><span>                         break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'U':</span><br><span style="color: hsl(120, 100%, 40%);">+                     cmdline_opts.db_upgrade = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</span><br><span>               case 'V':</span><br><span>                    print_version(1);</span><br><span>                    exit(EXIT_SUCCESS);</span><br><span>@@ -409,7 +416,7 @@</span><br><span>            exit(EXIT_FAILURE);</span><br><span>  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   g_hlr_db_tool_ctx->dbc = db_open(g_hlr_db_tool_ctx, cmdline_opts.db_file, true);</span><br><span style="color: hsl(120, 100%, 40%);">+   g_hlr_db_tool_ctx->dbc = db_open(g_hlr_db_tool_ctx, cmdline_opts.db_file, true, cmdline_opts.db_upgrade);</span><br><span>         if (!g_hlr_db_tool_ctx->dbc) {</span><br><span>            LOGP(DMAIN, LOGL_FATAL, "Error opening database\n");</span><br><span>               exit(EXIT_FAILURE);</span><br><span>diff --git a/tests/db/db_test.c b/tests/db/db_test.c</span><br><span>index 058588b..c4ed6ed 100644</span><br><span>--- a/tests/db/db_test.c</span><br><span>+++ b/tests/db/db_test.c</span><br><span>@@ -850,7 +850,7 @@</span><br><span>       log_set_log_level(osmo_stderr_target, LOGL_ERROR);</span><br><span>   /* Disable SQLite logging so that we're not vulnerable on SQLite error messages changing across</span><br><span>   * library versions. */</span><br><span style="color: hsl(0, 100%, 40%);">- dbc = db_open(ctx, "db_test.db", false);</span><br><span style="color: hsl(120, 100%, 40%);">+    dbc = db_open(ctx, "db_test.db", false, false);</span><br><span>    log_set_log_level(osmo_stderr_target, 0);</span><br><span>    OSMO_ASSERT(dbc);</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/11898">change 11898</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/11898"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-hlr </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I8aeaa9a404b622657cbc7138106f38aa6ad8d01b </div>
<div style="display:none"> Gerrit-Change-Number: 11898 </div>
<div style="display:none"> Gerrit-PatchSet: 10 </div>
<div style="display:none"> Gerrit-Owner: Stefan Sperling <ssperling@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>
<div style="display:none"> Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Pau Espin Pedrol <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Stefan Sperling <ssperling@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Vadim Yanitskiy <axilirator@gmail.com> </div>