In the past normal migration was possible only if the actual
schema version differed from the version used in DB by 1. For
example, if DB uses an old version 3 and you need to use it
with the code written for version 5, the check_db_revision()
will convert it to 4 and DB will still use incompatible schema
version during Osmo-NITB running time. After next run it will
be converted to version 5.

This patch replaces a set of 'else-if' checks by a 'switch'
without 'break' statements between 'case' labels (waterfall).
It makes you able to migrate from current version to the
latest despite any difference between them.

Also fixed the sms_from_result_v3() to avoid large depth of
function calls, because they can be changed in the future
and lose compatibility with old table schemas.

Also fixed db_test and now it is successful.

Signed-off-by: Vadim Yanitskiy <[email protected]>
---
 openbsc/src/libmsc/db.c      | 65 ++++++++++++++++++++++++++++----------------
 openbsc/tests/db/db_test.c   |  1 +
 openbsc/tests/db/db_test.err |  3 ++
 3 files changed, 45 insertions(+), 24 deletions(-)

diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
index 04aee79..ad5afca 100644
--- a/openbsc/src/libmsc/db.c
+++ b/openbsc/src/libmsc/db.c
@@ -225,23 +225,27 @@ static struct gsm_sms *sms_from_result_v3(dbi_result 
result)
 {
        struct gsm_sms *sms = sms_alloc();
        long long unsigned int sender_id;
-       struct gsm_subscriber *sender;
-       const char *text, *daddr;
+       const char *text, *daddr, *extension;
        const unsigned char *user_data;
-       char buf[32];
+       dbi_result sender_result;

        if (!sms)
                return NULL;

-       sms->id = dbi_result_get_ulonglong(result, "id");
-
        sender_id = dbi_result_get_ulonglong(result, "sender_id");
-       snprintf(buf, sizeof(buf), "%llu", sender_id);
-       sender = db_get_subscriber(GSM_SUBSCRIBER_ID, buf);
-       OSMO_ASSERT(sender);
-       strncpy(sms->src.addr, sender->extension, sizeof(sms->src.addr)-1);
-       subscr_direct_free(sender);
-       sender = NULL;
+       sms->id   = dbi_result_get_ulonglong(result, "id");
+
+       sender_result = dbi_conn_queryf(conn,
+               "SELECT * FROM Subscriber "
+               "WHERE id = %llu", sender_id);
+
+       if (sender_result) {
+               if (dbi_result_next_row(sender_result)) {
+                       extension = dbi_result_get_string(sender_result, 
"extension");
+                       strncpy(sms->src.addr, extension, sizeof(sms->src.addr) 
- 1);
+               }
+               dbi_result_free(sender_result);
+       }

        sms->reply_path_req = dbi_result_get_ulonglong(result, 
"reply_path_req");
        sms->status_rep_req = dbi_result_get_ulonglong(result, 
"status_rep_req");
@@ -477,16 +481,20 @@ static int check_db_revision(void)
 {
        dbi_result result;
        const char *rev_s;
+       int db_rev = 0;

+       /* Make a query */
        result = dbi_conn_query(conn,
-                               "SELECT value FROM Meta WHERE key='revision'");
+                               "SELECT value FROM Meta "
+                               "WHERE key = 'revision'");
        if (!result)
                return -EINVAL;
-
        if (!dbi_result_next_row(result)) {
                dbi_result_free(result);
                return -EINVAL;
        }
+
+       /* Fetch the DB schema revision */
        rev_s = dbi_result_get_string(result, "value");
        if (!rev_s) {
                dbi_result_free(result);
@@ -494,28 +502,37 @@ static int check_db_revision(void)
        }

        if (!strcmp(rev_s, SCHEMA_REVISION)) {
-               /* everything is fine */
-       } else if (!strcmp(rev_s, "2")) {
+               /* Everything is fine */
+               dbi_result_free(result);
+               return 0;
+       }
+
+       db_rev = atoi(rev_s);
+       dbi_result_free(result);
+
+       /* Incremental migration waterfall */
+       switch (db_rev) {
+       case 2:
                if (update_db_revision_2())
                        goto error;
-       } else if (!strcmp(rev_s, "3")) {
+       case 3:
                if (update_db_revision_3())
                        goto error;
-       } else if (!strcmp(rev_s, "4")) {
+       case 4:
                if (update_db_revision_4())
-                       goto error;     
-       } else {
-               LOGP(DDB, LOGL_FATAL, "Invalid database schema revision 
'%s'.\n", rev_s);
-               dbi_result_free(result);
+                       goto error;
+
+               /* The end of waterfall */
+               break;
+       default:
+               LOGP(DDB, LOGL_FATAL, "Invalid database schema revision 
'%d'.\n", db_rev);
                return -EINVAL;
        }

-       dbi_result_free(result);
        return 0;

 error:
-       LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision 
'%s'.\n", rev_s);
-       dbi_result_free(result);
+       LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision 
'%d'.\n", db_rev);
        return -EINVAL;
 }

diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c
index a02d1f8..2fdd830 100644
--- a/openbsc/tests/db/db_test.c
+++ b/openbsc/tests/db/db_test.c
@@ -187,6 +187,7 @@ int main()

        char *alice_imsi = "3243245432345";
        alice = db_create_subscriber(alice_imsi);
+       db_subscriber_alloc_tmsi(alice);
        db_sync_subscriber(alice);
        alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice->imsi);
        COMPARE(alice, alice_db);
diff --git a/openbsc/tests/db/db_test.err b/openbsc/tests/db/db_test.err
index fa9a54c..d8a3e7f 100644
--- a/openbsc/tests/db/db_test.err
+++ b/openbsc/tests/db/db_test.err
@@ -1,2 +1,5 @@
 Going to migrate from revision 3
+Migration complete.
+Going to migrate from revision 4
+Migration complete.
 
\ No newline at end of file
-- 
2.8.0

Reply via email to