Blame SOURCES/nfs-utils-1.3.0-nfsdcltrack-v2schema-update.patch

e19a30
diff -up nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c.orig nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c
e19a30
--- nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c.orig	2016-02-10 10:46:23.100398000 -0500
e19a30
+++ nfs-utils-1.3.0/utils/nfsdcltrack/sqlite.c	2016-02-10 10:46:59.540317000 -0500
e19a30
@@ -29,7 +29,9 @@
e19a30
  *
e19a30
  * clients: an "id" column containing a BLOB with the long-form clientid as
e19a30
  * 	    sent by the client, a "time" column containing a timestamp (in
e19a30
- * 	    epoch seconds) of when the record was last updated.
e19a30
+ * 	    epoch seconds) of when the record was last updated, and a
e19a30
+ * 	    "has_session" column containing a boolean value indicating
e19a30
+ * 	    whether the client has sessions (v4.1+) or not (v4.0).
e19a30
  */
e19a30
 
e19a30
 #ifdef HAVE_CONFIG_H
e19a30
@@ -50,7 +52,7 @@
e19a30
 
e19a30
 #include "xlog.h"
e19a30
 
e19a30
-#define CLTRACK_SQLITE_LATEST_SCHEMA_VERSION 1
e19a30
+#define CLTRACK_SQLITE_LATEST_SCHEMA_VERSION 2
e19a30
 
e19a30
 /* in milliseconds */
e19a30
 #define CLTRACK_SQLITE_BUSY_TIMEOUT 10000
e19a30
@@ -120,6 +122,81 @@ out:
e19a30
 	return ret;
e19a30
 }
e19a30
 
e19a30
+static int
e19a30
+sqlite_maindb_update_v1_to_v2(void)
e19a30
+{
e19a30
+	int ret, ret2;
e19a30
+	char *err;
e19a30
+
e19a30
+	/* begin transaction */
e19a30
+	ret = sqlite3_exec(dbh, "BEGIN EXCLUSIVE TRANSACTION;", NULL, NULL,
e19a30
+				&err;;
e19a30
+	if (ret != SQLITE_OK) {
e19a30
+		xlog(L_ERROR, "Unable to begin transaction: %s", err);
e19a30
+		goto rollback;
e19a30
+	}
e19a30
+
e19a30
+	/*
e19a30
+	 * Check schema version again. This time, under an exclusive
e19a30
+	 * transaction to guard against racing DB setup attempts
e19a30
+	 */
e19a30
+	ret = sqlite_query_schema_version();
e19a30
+	switch (ret) {
e19a30
+	case 1:
e19a30
+		/* Still at v1 -- do conversion */
e19a30
+		break;
e19a30
+	case CLTRACK_SQLITE_LATEST_SCHEMA_VERSION:
e19a30
+		/* Someone else raced in and set it up */
e19a30
+		ret = 0;
e19a30
+		goto rollback;
e19a30
+	default:
e19a30
+		/* Something went wrong -- fail! */
e19a30
+		ret = -EINVAL;
e19a30
+		goto rollback;
e19a30
+	}
e19a30
+
e19a30
+	/* create v2 clients table */
e19a30
+	ret = sqlite3_exec(dbh, "ALTER TABLE clients ADD COLUMN "
e19a30
+				"has_session INTEGER;",
e19a30
+				NULL, NULL, &err;;
e19a30
+	if (ret != SQLITE_OK) {
e19a30
+		xlog(L_ERROR, "Unable to update clients table: %s", err);
e19a30
+		goto rollback;
e19a30
+	}
e19a30
+
e19a30
+	ret = snprintf(buf, sizeof(buf), "UPDATE parameters SET value = %d "
e19a30
+			"WHERE key = \"version\";",
e19a30
+			CLTRACK_SQLITE_LATEST_SCHEMA_VERSION);
e19a30
+	if (ret < 0) {
e19a30
+		xlog(L_ERROR, "sprintf failed!");
e19a30
+		goto rollback;
e19a30
+	} else if ((size_t)ret >= sizeof(buf)) {
e19a30
+		xlog(L_ERROR, "sprintf output too long! (%d chars)", ret);
e19a30
+		ret = -EINVAL;
e19a30
+		goto rollback;
e19a30
+	}
e19a30
+
e19a30
+	ret = sqlite3_exec(dbh, (const char *)buf, NULL, NULL, &err;;
e19a30
+	if (ret != SQLITE_OK) {
e19a30
+		xlog(L_ERROR, "Unable to update schema version: %s", err);
e19a30
+		goto rollback;
e19a30
+	}
e19a30
+
e19a30
+	ret = sqlite3_exec(dbh, "COMMIT TRANSACTION;", NULL, NULL, &err;;
e19a30
+	if (ret != SQLITE_OK) {
e19a30
+		xlog(L_ERROR, "Unable to commit transaction: %s", err);
e19a30
+		goto rollback;
e19a30
+	}
e19a30
+out:
e19a30
+	sqlite3_free(err);
e19a30
+	return ret;
e19a30
+rollback:
e19a30
+	ret2 = sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err;;
e19a30
+	if (ret2 != SQLITE_OK)
e19a30
+		xlog(L_ERROR, "Unable to rollback transaction: %s", err);
e19a30
+	goto out;
e19a30
+}
e19a30
+
e19a30
 /*
e19a30
  * Start an exclusive transaction and recheck the DB schema version. If it's
e19a30
  * still zero (indicating a new database) then set it up. If that all works,
e19a30
@@ -127,9 +204,9 @@ out:
e19a30
  * transaction. On any error, rollback the transaction.
e19a30
  */
e19a30
 int
e19a30
-sqlite_maindb_init_v1(void)
e19a30
+sqlite_maindb_init_v2(void)
e19a30
 {
e19a30
-	int ret;
e19a30
+	int ret, ret2;
e19a30
 	char *err = NULL;
e19a30
 
e19a30
 	/* Start a transaction */
e19a30
@@ -169,7 +246,7 @@ sqlite_maindb_init_v1(void)
e19a30
 
e19a30
 	/* create the "clients" table */
e19a30
 	ret = sqlite3_exec(dbh, "CREATE TABLE clients (id BLOB PRIMARY KEY, "
e19a30
-				"time INTEGER);",
e19a30
+				"time INTEGER, has_session INTEGER);",
e19a30
 				NULL, NULL, &err;;
e19a30
 	if (ret != SQLITE_OK) {
e19a30
 		xlog(L_ERROR, "Unable to create clients table: %s", err);
e19a30
@@ -207,7 +284,9 @@ out:
e19a30
 
e19a30
 rollback:
e19a30
 	/* Attempt to rollback the transaction */
e19a30
-	sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err;;
e19a30
+	ret2 = sqlite3_exec(dbh, "ROLLBACK TRANSACTION;", NULL, NULL, &err;;
e19a30
+	if (ret2 != SQLITE_OK)
e19a30
+		xlog(L_ERROR, "Unable to rollback transaction: %s", err);
e19a30
 	goto out;
e19a30
 }
e19a30
 
e19a30
@@ -255,9 +334,15 @@ sqlite_prepare_dbh(const char *topdir)
e19a30
 		/* DB is already set up. Do nothing */
e19a30
 		ret = 0;
e19a30
 		break;
e19a30
+	case 1:
e19a30
+		/* Old DB -- update to new schema */
e19a30
+		ret = sqlite_maindb_update_v1_to_v2();
e19a30
+		if (ret)
e19a30
+			goto out_close;
e19a30
+		break;
e19a30
 	case 0:
e19a30
 		/* Query failed -- try to set up new DB */
e19a30
-		ret = sqlite_maindb_init_v1();
e19a30
+		ret = sqlite_maindb_init_v2();
e19a30
 		if (ret)
e19a30
 			goto out_close;
e19a30
 		break;