The unified diff between revisions [65f52f37..] and [36cf2167..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'sqlite-backend.c'

#
#
# patch "sqlite-backend.c"
#  from [af95cdd5712ae796993989b936e174564c6d3c72]
#    to [4be9ea4621c58f7736a6fa49103d27643c14a946]
#
============================================================
--- sqlite-backend.c	af95cdd5712ae796993989b936e174564c6d3c72
+++ sqlite-backend.c	4be9ea4621c58f7736a6fa49103d27643c14a946
@@ -30,9 +30,12 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sqlite3.h>
+#include <unistd.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <time.h>
+#include <pwd.h>

 #define ROOT_DIRECTORY_PARENT			-1
 #define ROOT_DIRECTORY_NAME			""
@@ -112,6 +115,7 @@ update_failure (GError **err)
 static void
 update_failure (GError **err)
 {
+	return; // TODO: don't leave this commented out!
 	g_set_error (err, GCONF_ERROR,
 			GCONF_ERROR_FAILED,
 			_("Failed to write some configuration data to disk\n"));
@@ -125,6 +129,7 @@ get_directory (SqliteSource *ss, SqliteD
 static gboolean
 get_directory (SqliteSource *ss, SqliteDirectory *parent, const char *name, SqliteDirectory *dir)
 {
+	long long int id;
 	char *query, *tail;
 	gboolean rv;
 	long long int nrow;
@@ -151,7 +156,7 @@ get_directory (SqliteSource *ss, SqliteD
 		res = sqlite3_step (statement);
 		if (res == SQLITE_ROW) {
 			nrow++;
-			dir->id = sqlite3_column_int64(statement, 0);
+			id = sqlite3_column_int64(statement, 0);
 		} else if (res == SQLITE_DONE) {
 			break;
 		} else {
@@ -159,6 +164,7 @@ get_directory (SqliteSource *ss, SqliteD
 				SQLITE_BUSY || res == SQLITE_ERROR || res == SQLITE_MISUSE
 			*/
 			gconf_log (GCL_ERR, "(get_directory) query error\n");
+			rv = FALSE;
 			break;
 		}
 	}
@@ -166,6 +172,9 @@ get_directory (SqliteSource *ss, SqliteD
 	if (nrow != 1)
 		rv = FALSE;

+	if (rv)
+		dir->id = id;
+
 	sqlite3_finalize (statement);
 	sqlite3_free (query);

@@ -256,13 +265,246 @@ traverse_to_directory (SqliteSource *ss,
 	return rv;
 }

+static char *
+get_username (void)
+{
+	uid_t uid;
+	struct passwd *pw;
+
+	uid = getuid();
+	if (uid < 0)
+		return NULL;
+	pw = getpwuid(uid);
+	if (!pw)
+		return NULL;
+	return g_strdup(pw->pw_name);
+}
+
+static gboolean
+start_transaction (SqliteSource *ss)
+{
+	gboolean rv;
+	char *query, *err_mesg;
+
+	rv = TRUE;
+	query = "BEGIN";
+	if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) {
+		gconf_log (GCL_ERR, "(start_transaction) SQL error: %s", err_mesg);
+		sqlite3_free (err_mesg);
+		rv = FALSE;
+	}
+	return rv;
+}
+
+static gboolean
+abort_transaction (SqliteSource *ss)
+{
+	gboolean rv;
+	char *query, *err_mesg;
+
+	rv = TRUE;
+	query = "ABORT";
+	if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) {
+		gconf_log (GCL_ERR, "(abort_transaction) SQL error: %s", err_mesg);
+		sqlite3_free (err_mesg);
+		rv = FALSE;
+	}
+	return rv;
+}
+
+static gboolean
+commit_transaction (SqliteSource *ss)
+{
+	gboolean rv;
+	char *query, *err_mesg;
+
+	rv = TRUE;
+	query = "COMMIT";
+	if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) {
+		gconf_log (GCL_ERR, "(commit_transaction) SQL error: %s", err_mesg);
+		sqlite3_free (err_mesg);
+		rv = FALSE;
+	}
+	return rv;
+}
+
 gboolean
-set_value_in_directory (SqliteSource *ss, SqliteDirectory *dir, const char *name, gboolean do_create, GError **error)
+get_value_id_in_directory (SqliteSource *ss, SqliteDirectory *dir, const char *name, long long int *id)
 {
+	long long int possible_id, nrow;
+	char *query, *tail;
+	gboolean rv;
+	int res;
+	sqlite3_stmt *statement;
+
 	g_return_val_if_fail (ss != NULL, FALSE);
 	g_return_val_if_fail (dir != NULL, FALSE);
 	g_return_val_if_fail (name != NULL, FALSE);

+	query = sqlite3_mprintf ("SELECT id FROM keys WHERE directory_id=%lld AND name='%q'", dir->id, name);
+	if (sqlite3_prepare (ss->db, query, strlen(query), &statement, (const char **)&tail) != SQLITE_OK) {
+		gconf_log (GCL_ERR, "(get_value_id_in_directory) Unable to compile query: %s", query);
+		sqlite3_free (query);
+		return FALSE;
+	}
+
+	nrow = 0;
+	rv = TRUE;
+
+	for (;;) {
+		res = sqlite3_step (statement);
+		if (res == SQLITE_ROW) {
+			nrow++;
+			possible_id = sqlite3_column_int64 (statement, 0);
+		} else if (res == SQLITE_DONE) {
+			break;
+		} else {
+			/* ought to be one of:
+				SQLITE_BUSY || res == SQLITE_ERROR || res == SQLITE_MISUSE
+			*/
+			gconf_log (GCL_ERR, "(get_directory) query error\n");
+			break;
+		}
+	}
+
+	if (nrow != 1)
+		rv = FALSE;
+
+	if (rv)
+		*id = possible_id;
+
+	sqlite3_free (query);
+	sqlite3_finalize (statement);
+	return rv;
+}
+
+gboolean
+delete_old_list (SqliteSource *ss, long long int id)
+{
+	gboolean rv;
+	char *query, *err_mesg;
+
+	rv = TRUE;
+	query = sqlite3_mprintf ("DELETE FROM lists WHERE key_id=%lld", id);
+	if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) {
+		gconf_log (GCL_ERR, "(delete_old_list) SQL error: %s", err_mesg);
+		sqlite3_free (err_mesg);
+		rv = FALSE;
+	}
+
+	sqlite3_free (query);
+	return rv;
+}
+
+gboolean
+delete_old_pair (SqliteSource *ss, long long int id)
+{
+	gboolean rv;
+	char *query, *err_mesg;
+
+	rv = TRUE;
+	query = sqlite3_mprintf ("DELETE FROM pairs WHERE key_id=%lld", id);
+	if (sqlite3_exec (ss->db, query, NULL, NULL, &err_mesg) != SQLITE_OK) {
+		gconf_log (GCL_ERR, "(delete_old_pair) SQL error: %s", err_mesg);
+		sqlite3_free (err_mesg);
+		rv = FALSE;
+	}
+
+	sqlite3_free (query);
+	return rv;
+}
+
+gboolean
+set_value_in_directory (SqliteSource *ss, SqliteDirectory *dir, const char *name, const GConfValue *value, GError **error)
+{
+	char *query = NULL;
+	GTime mod_time;
+	gchar *mod_user;
+	gboolean rv;
+	long long int existing_id;
+
+	g_return_val_if_fail (ss != NULL, FALSE);
+	g_return_val_if_fail (dir != NULL, FALSE);
+	g_return_val_if_fail (name != NULL, FALSE);
+
+	/*
+	 * we need to handle several things here
+	 *
+	 * first consideration; this might be a new key, or it might be an update to an existing key
+	 * if we're updating, we need to handle non-scalar types correctly. this basically means removing
+	 * the old list / pair and then adding a new one in.
+	 *
+	 * second consideration; need to do clean insert of non-scalar types.
+	 *
+	 * third consideration; make sure we do it all in a transaction block, and abort the transaction
+	 * appropriately if something goes wrong.
+	 */
+
+	rv = TRUE;
+	mod_time = time (NULL);
+	mod_user = get_username ();
+
+	do {
+		if (!start_transaction (ss)) {
+			rv = FALSE;
+			break;
+		}
+		if (get_value_id_in_directory (ss, dir, name, &existing_id)) {
+			if (!delete_old_list (ss, existing_id)) {
+				rv = FALSE;
+				break;
+			}
+			if (!delete_old_pair (ss, existing_id)) {
+				rv = FALSE;
+				break;
+			}
+		}
+		/*
+		if (!insert_or_update (ss, value)) {
+			rv = FALSE;
+			break;
+		} */
+	} while (0);
+
+	if (rv) {
+		commit_transaction (ss);
+	} else {
+		abort_transaction (ss);
+	}
+
+	switch (value->type) {
+		case GCONF_VALUE_STRING:
+			query = sqlite3_mprintf ("INSERT OR REPLACE INTO keys (name, directory_id, value_type, value) VALUES ('%q', %lld, '%c', '%q')",
+					name, dir->id, 's', gconf_value_get_string (value));
+			break;
+		case GCONF_VALUE_INT:
+			query = g_strdup("int");
+			break;
+		case GCONF_VALUE_FLOAT:
+			query = g_strdup("float");
+			break;
+		case GCONF_VALUE_BOOL:
+			query = g_strdup("bool");
+			break;
+		case GCONF_VALUE_LIST:
+			query = g_strdup("list");
+			break;
+		case GCONF_VALUE_PAIR:
+			query = g_strdup("pair");
+			break;
+		case GCONF_VALUE_INVALID:
+		default:
+			/* invalid */
+			break;
+	}
+
+	if (!query)
+		return FALSE;
+
+	printf("query is: %s\n", query);
+
+	sqlite3_free (query);
+
 	return FALSE;
 }

@@ -481,8 +723,9 @@ set_value (GConfSource      *source,
 			update_failure (err);
 			break;
 		}
-		if (!set_value_in_directory ((SqliteSource *)source, dir, relative_key, TRUE, err)) {
+		if (!set_value_in_directory ((SqliteSource *)source, dir, relative_key, value, err)) {
 			update_failure (err);
+			break;
 		}
 	} while (0);