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

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