summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-09-17 00:21:00 +0200
committerChristian Grothoff <christian@grothoff.org>2021-09-17 00:21:00 +0200
commit80fe273ef5d46e0d242017a5d1a04a5bd933c3d7 (patch)
tree2c2a0f5d512908ffbf11efb7a37e66f29eab669e /src
parent03bfa07732db97dfaa61b103e2cb30c08805d425 (diff)
downloadsync-80fe273ef5d46e0d242017a5d1a04a5bd933c3d7.tar.gz
sync-80fe273ef5d46e0d242017a5d1a04a5bd933c3d7.tar.bz2
sync-80fe273ef5d46e0d242017a5d1a04a5bd933c3d7.zip
initial debian package
Diffstat (limited to 'src')
-rw-r--r--src/include/sync_database_plugin.h31
-rw-r--r--src/sync/sync-httpd.c9
-rw-r--r--src/syncdb/Makefile.am9
-rw-r--r--src/syncdb/drop0001.sql34
-rw-r--r--src/syncdb/plugin_syncdb_postgres.c477
-rw-r--r--src/syncdb/sync-0000.sql293
-rw-r--r--src/syncdb/sync-0001.sql53
-rw-r--r--src/syncdb/sync-dbinit.c51
-rw-r--r--src/syncdb/sync_db_plugin.c8
-rw-r--r--src/syncdb/sync_db_postgres.conf8
-rw-r--r--src/syncdb/test_sync_db.c26
-rw-r--r--src/syncdb/test_sync_db_postgres.conf4
-rw-r--r--src/testing/test_sync_api.conf4
13 files changed, 779 insertions, 228 deletions
diff --git a/src/include/sync_database_plugin.h b/src/include/sync_database_plugin.h
index f14e007..a779fab 100644
--- a/src/include/sync_database_plugin.h
+++ b/src/include/sync_database_plugin.h
@@ -1,6 +1,6 @@
/*
This file is part of GNU Taler
- Copyright (C) 2019 Taler Systems SA
+ Copyright (C) 2019, 2021 Taler Systems SA
Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -116,8 +116,33 @@ struct SYNC_DatabasePlugin
* @param cls closure
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
- int
- (*drop_tables) (void *cls);
+ enum GNUNET_GenericReturnValue
+ (*drop_tables)(void *cls);
+
+
+ /**
+ * Create the necessary tables if they are not present
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ enum GNUNET_GenericReturnValue
+ (*create_tables)(void *cls);
+
+
+ /**
+ * Do a pre-flight check that we are not in an uncommitted transaction.
+ * If we are, try to commit the previous transaction and output a warning.
+ * Does not return anything, as we will continue regardless of the outcome.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @return #GNUNET_OK if everything is fine
+ * #GNUNET_NO if a transaction was rolled back
+ * #GNUNET_SYSERR on hard errors
+ */
+ enum GNUNET_GenericReturnValue
+ (*preflight)(void *cls);
+
/**
* Function called to perform "garbage collection" on the
diff --git a/src/sync/sync-httpd.c b/src/sync/sync-httpd.c
index 1b02fe2..edb8212 100644
--- a/src/sync/sync-httpd.c
+++ b/src/sync/sync-httpd.c
@@ -651,7 +651,14 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
-
+ if (GNUNET_OK !=
+ db->preflight (db->cls))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Database not setup. Did you run sync-dbinit?\n");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
fh = TALER_MHD_bind (config,
"sync",
&port);
diff --git a/src/syncdb/Makefile.am b/src/syncdb/Makefile.am
index 8e56d6c..830e51f 100644
--- a/src/syncdb/Makefile.am
+++ b/src/syncdb/Makefile.am
@@ -15,6 +15,13 @@ if USE_COVERAGE
XLIB = -lgcov
endif
+sqldir = $(prefix)/share/sync/sql/
+
+sql_DATA = \
+ sync-0000.sql \
+ sync-0001.sql \
+ drop0001.sql
+
bin_PROGRAMS = \
sync-dbinit
@@ -48,7 +55,7 @@ libsync_plugin_db_postgres_la_SOURCES = \
libsync_plugin_db_postgres_la_LIBADD = \
$(LTLIBINTL)
libsync_plugin_db_postgres_la_LDFLAGS = \
- $(TALER_PLUGIN_LDFLAGS) \
+ $(SYNC_PLUGIN_LDFLAGS) \
-lgnunetpq \
-lpq \
-ltalerpq \
diff --git a/src/syncdb/drop0001.sql b/src/syncdb/drop0001.sql
new file mode 100644
index 0000000..9253517
--- /dev/null
+++ b/src/syncdb/drop0001.sql
@@ -0,0 +1,34 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2021 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+-- Everything in one big transaction
+BEGIN;
+
+-- This script DROPs all of the tables we create.
+--
+-- Unlike the other SQL files, it SHOULD be updated to reflect the
+-- latest requirements for dropping tables.
+
+-- Drops for 0001.sql
+DROP TABLE IF EXISTS payments CASCADE;
+DROP TABLE IF EXISTS backups CASCADE;
+DROP TABLE IF EXISTS accounts CASCADE;
+
+-- Unregister patch (0001.sql)
+SELECT _v.unregister_patch('sync-0001');
+
+-- And we're out of here...
+COMMIT;
diff --git a/src/syncdb/plugin_syncdb_postgres.c b/src/syncdb/plugin_syncdb_postgres.c
index c432dde..8e294cb 100644
--- a/src/syncdb/plugin_syncdb_postgres.c
+++ b/src/syncdb/plugin_syncdb_postgres.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2014--2019 Taler Systems SA
+ (C) 2014--2021 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
@@ -39,6 +39,11 @@ struct PostgresClosure
struct GNUNET_PQ_Context *conn;
/**
+ * Directory with SQL statements to run to create tables.
+ */
+ char *sql_dir;
+
+ /**
* Underlying configuration.
*/
const struct GNUNET_CONFIGURATION_Handle *cfg;
@@ -52,6 +57,13 @@ struct PostgresClosure
* Currency we accept payments in.
*/
char *currency;
+
+ /**
+ * Did we initialize the prepared statements
+ * for this session?
+ */
+ bool init;
+
};
@@ -61,33 +73,220 @@ struct PostgresClosure
* @param cls closure our `struct Plugin`
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-static int
+static enum GNUNET_GenericReturnValue
postgres_drop_tables (void *cls)
{
struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS accounts CASCADE;"),
- GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS payments;"),
- GNUNET_PQ_make_try_execute ("DROP TABLE IF EXISTS backups;"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
+ struct GNUNET_PQ_Context *conn;
- return GNUNET_PQ_exec_statements (pg->conn,
- es);
+ conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
+ "syncdb-postgres",
+ "drop",
+ NULL,
+ NULL);
+ if (NULL == conn)
+ return GNUNET_SYSERR;
+ GNUNET_PQ_disconnect (conn);
+ return GNUNET_OK;
}
/**
- * Check that the database connection is still up.
+ * Establish connection to the database.
*
- * @param pg connection to check
+ * @param cls plugin context
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-static void
-check_connection (void *cls)
+static enum GNUNET_GenericReturnValue
+prepare_statements (void *cls)
{
struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_PreparedStatement ps[] = {
+ GNUNET_PQ_make_prepare ("account_insert",
+ "INSERT INTO accounts "
+ "(account_pub"
+ ",expiration_date"
+ ") VALUES "
+ "($1,$2);",
+ 2),
+ GNUNET_PQ_make_prepare ("payment_insert",
+ "INSERT INTO payments "
+ "(account_pub"
+ ",order_id"
+ ",token"
+ ",timestamp"
+ ",amount_val"
+ ",amount_frac"
+ ") VALUES "
+ "($1,$2,$3,$4,$5,$6);",
+ 6),
+ GNUNET_PQ_make_prepare ("payment_done",
+ "UPDATE payments "
+ "SET"
+ " paid=TRUE "
+ "WHERE"
+ " order_id=$1"
+ " AND"
+ " account_pub=$2"
+ " AND"
+ " paid=FALSE;",
+ 2),
+ GNUNET_PQ_make_prepare ("account_update",
+ "UPDATE accounts "
+ "SET"
+ " expiration_date=$1 "
+ "WHERE"
+ " account_pub=$2;",
+ 2),
+ GNUNET_PQ_make_prepare ("account_select",
+ "SELECT"
+ " expiration_date "
+ "FROM"
+ " accounts "
+ "WHERE"
+ " account_pub=$1;",
+ 1),
+ GNUNET_PQ_make_prepare ("payments_select",
+ "SELECT"
+ " account_pub"
+ ",order_id"
+ ",amount_val"
+ ",amount_frac"
+ " FROM payments"
+ " WHERE paid=FALSE;",
+ 0),
+ GNUNET_PQ_make_prepare ("payments_select_by_account",
+ "SELECT"
+ " timestamp"
+ ",order_id"
+ ",token"
+ ",amount_val"
+ ",amount_frac"
+ " FROM payments"
+ " WHERE"
+ " paid=FALSE"
+ " AND"
+ " account_pub=$1;",
+ 1),
+ GNUNET_PQ_make_prepare ("gc_accounts",
+ "DELETE FROM accounts "
+ "WHERE"
+ " expiration_date < $1;",
+ 1),
+ GNUNET_PQ_make_prepare ("gc_pending_payments",
+ "DELETE FROM payments "
+ "WHERE"
+ " paid=FALSE"
+ " AND"
+ " timestamp < $1;",
+ 1),
+ GNUNET_PQ_make_prepare ("backup_insert",
+ "INSERT INTO backups "
+ "(account_pub"
+ ",account_sig"
+ ",prev_hash"
+ ",backup_hash"
+ ",data"
+ ") VALUES "
+ "($1,$2,$3,$4,$5);",
+ 5),
+ GNUNET_PQ_make_prepare ("backup_update",
+ "UPDATE backups "
+ " SET"
+ " backup_hash=$1"
+ ",account_sig=$2"
+ ",prev_hash=$3"
+ ",data=$4"
+ " WHERE"
+ " account_pub=$5"
+ " AND"
+ " backup_hash=$6;",
+ 6),
+ GNUNET_PQ_make_prepare ("backup_select_hash",
+ "SELECT "
+ " backup_hash "
+ "FROM"
+ " backups "
+ "WHERE"
+ " account_pub=$1;",
+ 1),
+ GNUNET_PQ_make_prepare ("backup_select",
+ "SELECT "
+ " account_sig"
+ ",prev_hash"
+ ",backup_hash"
+ ",data "
+ "FROM"
+ " backups "
+ "WHERE"
+ " account_pub=$1;",
+ 1),
+ GNUNET_PQ_make_prepare ("do_commit",
+ "COMMIT",
+ 0),
+ GNUNET_PQ_PREPARED_STATEMENT_END
+ };
+ enum GNUNET_GenericReturnValue ret;
- GNUNET_PQ_reconnect_if_down (pg->conn);
+ ret = GNUNET_PQ_prepare_statements (pg->conn,
+ ps);
+ if (GNUNET_OK != ret)
+ return ret;
+ pg->init = true;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Connect to the database if the connection does not exist yet.
+ *
+ * @param pg the plugin-specific state
+ * @param skip_prepare true if we should skip prepared statement setup
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+internal_setup (struct PostgresClosure *pg,
+ bool skip_prepare)
+{
+ if (NULL == pg->conn)
+ {
+#if AUTO_EXPLAIN
+ /* Enable verbose logging to see where queries do not
+ properly use indices */
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
+ GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
+ GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
+ GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
+ /* https://wiki.postgresql.org/wiki/Serializable suggests to really
+ force the default to 'serializable' if SSI is to be used. */
+ GNUNET_PQ_make_try_execute (
+ "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
+ GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
+ GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+#else
+ struct GNUNET_PQ_ExecuteStatement *es = NULL;
+#endif
+ struct GNUNET_PQ_Context *db_conn;
+
+ db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
+ "syncdb-postgres",
+ NULL,
+ es,
+ NULL);
+ if (NULL == db_conn)
+ return GNUNET_SYSERR;
+ pg->conn = db_conn;
+ }
+ if (NULL == pg->transaction_name)
+ GNUNET_PQ_reconnect_if_down (pg->conn);
+ if (pg->init)
+ return GNUNET_OK;
+ if (skip_prepare)
+ return GNUNET_OK;
+ return prepare_statements (pg);
}
@@ -97,33 +296,58 @@ check_connection (void *cls)
* Does not return anything, as we will continue regardless of the outcome.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @return #GNUNET_OK if everything is fine
+ * #GNUNET_NO if a transaction was rolled back
+ * #GNUNET_SYSERR on hard errors
*/
-static void
+static enum GNUNET_GenericReturnValue
postgres_preflight (void *cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_execute ("COMMIT"),
+ GNUNET_PQ_make_execute ("ROLLBACK"),
GNUNET_PQ_EXECUTE_STATEMENT_END
};
+ if (! pg->init)
+ {
+ if (GNUNET_OK !=
+ internal_setup (pg,
+ false))
+ return GNUNET_SYSERR;
+ }
if (NULL == pg->transaction_name)
- return; /* all good */
+ return GNUNET_OK; /* all good */
if (GNUNET_OK ==
GNUNET_PQ_exec_statements (pg->conn,
es))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "BUG: Preflight check committed transaction `%s'!\n",
+ "BUG: Preflight check rolled back transaction `%s'!\n",
pg->transaction_name);
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "BUG: Preflight check failed to commit transaction `%s'!\n",
+ "BUG: Preflight check failed to rollback transaction `%s'!\n",
pg->transaction_name);
}
pg->transaction_name = NULL;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Check that the database connection is still up.
+ *
+ * @param cls a `struct PostgresClosure` with connection to check
+ */
+static void
+check_connection (void *cls)
+{
+ struct PostgresClosure *pg = cls;
+
+ GNUNET_PQ_reconnect_if_down (pg->conn);
}
@@ -135,7 +359,7 @@ postgres_preflight (void *cls)
* must point to a constant
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
begin_transaction (void *cls,
const char *name)
{
@@ -164,7 +388,6 @@ begin_transaction (void *cls,
* Roll back the current transaction of a database connection.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
- * @return #GNUNET_OK on success
*/
static void
rollback (void *cls)
@@ -1025,6 +1248,30 @@ postgres_increment_lifetime (void *cls,
/**
+ * Initialize tables.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+static enum GNUNET_GenericReturnValue
+postgres_create_tables (void *cls)
+{
+ struct PostgresClosure *pc = cls;
+ struct GNUNET_PQ_Context *conn;
+
+ conn = GNUNET_PQ_connect_with_cfg (pc->cfg,
+ "syncdb-postgres",
+ "sync-",
+ NULL,
+ NULL);
+ if (NULL == conn)
+ return GNUNET_SYSERR;
+ GNUNET_PQ_disconnect (conn);
+ return GNUNET_OK;
+}
+
+
+/**
* Initialize Postgres database subsystem.
*
* @param cls a configuration instance
@@ -1036,174 +1283,18 @@ libsync_plugin_db_postgres_init (void *cls)
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
struct PostgresClosure *pg;
struct SYNC_DatabasePlugin *plugin;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- /* Orders created by the frontend, not signed or given a nonce yet.
- The contract terms will change (nonce will be added) when moved to the
- contract terms table */
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS accounts"
- "(account_pub BYTEA PRIMARY KEY CHECK (length(account_pub)=32)"
- ",expiration_date INT8 NOT NULL"
- ");"),
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS payments"
- "(account_pub BYTEA CHECK (length(account_pub)=32)"
- ",order_id VARCHAR PRIMARY KEY"
- ",token BYTEA CHECK (length(token)=16)"
- ",timestamp INT8 NOT NULL"
- ",amount_val INT8 NOT NULL" /* amount we were paid */
- ",amount_frac INT4 NOT NULL"
- ",paid BOOLEAN NOT NULL DEFAULT FALSE"
- ");"),
- GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS backups"
- "(account_pub BYTEA PRIMARY KEY REFERENCES accounts (account_pub) ON DELETE CASCADE"
- ",account_sig BYTEA NOT NULL CHECK (length(account_sig)=64)"
- ",prev_hash BYTEA NOT NULL CHECK (length(prev_hash)=64)"
- ",backup_hash BYTEA NOT NULL CHECK (length(backup_hash)=64)"
- ",data BYTEA NOT NULL"
- ");"),
- /* index for gc */
- GNUNET_PQ_make_try_execute (
- "CREATE INDEX accounts_expire ON "
- "accounts (expiration_date);"),
- GNUNET_PQ_make_try_execute (
- "CREATE INDEX payments_timestamp ON "
- "payments (paid,timestamp);"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
- struct GNUNET_PQ_PreparedStatement ps[] = {
- GNUNET_PQ_make_prepare ("account_insert",
- "INSERT INTO accounts "
- "(account_pub"
- ",expiration_date"
- ") VALUES "
- "($1,$2);",
- 2),
- GNUNET_PQ_make_prepare ("payment_insert",
- "INSERT INTO payments "
- "(account_pub"
- ",order_id"
- ",token"
- ",timestamp"
- ",amount_val"
- ",amount_frac"
- ") VALUES "
- "($1,$2,$3,$4,$5,$6);",
- 6),
- GNUNET_PQ_make_prepare ("payment_done",
- "UPDATE payments "
- "SET"
- " paid=TRUE "
- "WHERE"
- " order_id=$1"
- " AND"
- " account_pub=$2"
- " AND"
- " paid=FALSE;",
- 2),
- GNUNET_PQ_make_prepare ("account_update",
- "UPDATE accounts "
- "SET"
- " expiration_date=$1 "
- "WHERE"
- " account_pub=$2;",
- 2),
- GNUNET_PQ_make_prepare ("account_select",
- "SELECT"
- " expiration_date "
- "FROM"
- " accounts "
- "WHERE"
- " account_pub=$1;",
- 1),
- GNUNET_PQ_make_prepare ("payments_select",
- "SELECT"
- " account_pub"
- ",order_id"
- ",amount_val"
- ",amount_frac"
- " FROM payments"
- " WHERE paid=FALSE;",
- 0),
- GNUNET_PQ_make_prepare ("payments_select_by_account",
- "SELECT"
- " timestamp"
- ",order_id"
- ",token"
- ",amount_val"
- ",amount_frac"
- " FROM payments"
- " WHERE"
- " paid=FALSE"
- " AND"
- " account_pub=$1;",
- 1),
- GNUNET_PQ_make_prepare ("gc_accounts",
- "DELETE FROM accounts "
- "WHERE"
- " expiration_date < $1;",
- 1),
- GNUNET_PQ_make_prepare ("gc_pending_payments",
- "DELETE FROM payments "
- "WHERE"
- " paid=FALSE"
- " AND"
- " timestamp < $1;",
- 1),
- GNUNET_PQ_make_prepare ("backup_insert",
- "INSERT INTO backups "
- "(account_pub"
- ",account_sig"
- ",prev_hash"
- ",backup_hash"
- ",data"
- ") VALUES "
- "($1,$2,$3,$4,$5);",
- 5),
- GNUNET_PQ_make_prepare ("backup_update",
- "UPDATE backups "
- " SET"
- " backup_hash=$1"
- ",account_sig=$2"
- ",prev_hash=$3"
- ",data=$4"
- " WHERE"
- " account_pub=$5"
- " AND"
- " backup_hash=$6;",
- 6),
- GNUNET_PQ_make_prepare ("backup_select_hash",
- "SELECT "
- " backup_hash "
- "FROM"
- " backups "
- "WHERE"
- " account_pub=$1;",
- 1),
- GNUNET_PQ_make_prepare ("backup_select",
- "SELECT "
- " account_sig"
- ",prev_hash"
- ",backup_hash"
- ",data "
- "FROM"
- " backups "
- "WHERE"
- " account_pub=$1;",
- 1),
- GNUNET_PQ_make_prepare ("do_commit",
- "COMMIT",
- 0),
- GNUNET_PQ_PREPARED_STATEMENT_END
- };
pg = GNUNET_new (struct PostgresClosure);
pg->cfg = cfg;
- pg->conn = GNUNET_PQ_connect_with_cfg (cfg,
- "syncdb-postgres",
- NULL,
- es,
- ps);
- if (NULL == pg->conn)
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "syncdb-postgres",
+ "SQL_DIR",
+ &pg->sql_dir))
{
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "syncdb-postgres",
+ "SQL_DIR");
GNUNET_free (pg);
return NULL;
}
@@ -1216,13 +1307,24 @@ libsync_plugin_db_postgres_init (void *cls)
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"taler",
"CURRENCY");
- GNUNET_PQ_disconnect (pg->conn);
+ GNUNET_free (pg->sql_dir);
+ GNUNET_free (pg);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ internal_setup (pg,
+ true))
+ {
+ GNUNET_free (pg->currency);
+ GNUNET_free (pg->sql_dir);
GNUNET_free (pg);
return NULL;
}
plugin = GNUNET_new (struct SYNC_DatabasePlugin);
plugin->cls = pg;
+ plugin->create_tables = &postgres_create_tables;
plugin->drop_tables = &postgres_drop_tables;
+ plugin->preflight = &postgres_preflight;
plugin->gc = &postgres_gc;
plugin->store_payment_TR = &postgres_store_payment;
plugin->lookup_pending_payments_by_account_TR =
@@ -1249,6 +1351,7 @@ libsync_plugin_db_postgres_done (void *cls)
struct PostgresClosure *pg = plugin->cls;
GNUNET_PQ_disconnect (pg->conn);
+ GNUNET_free (pg->sql_dir);
GNUNET_free (pg);
GNUNET_free (plugin);
return NULL;
diff --git a/src/syncdb/sync-0000.sql b/src/syncdb/sync-0000.sql
new file mode 100644
index 0000000..116f409
--- /dev/null
+++ b/src/syncdb/sync-0000.sql
@@ -0,0 +1,293 @@
+-- LICENSE AND COPYRIGHT
+--
+-- Copyright (C) 2010 Hubert depesz Lubaczewski
+--
+-- This program is distributed under the (Revised) BSD License:
+-- L<http://www.opensource.org/licenses/bsd-license.php>
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- * Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+--
+-- * Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in the
+-- documentation and/or other materials provided with the distribution.
+--
+-- * Neither the name of Hubert depesz Lubaczewski's Organization
+-- nor the names of its contributors may be used to endorse or
+-- promote products derived from this software without specific
+-- prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+-- Code origin: https://gitlab.com/depesz/Versioning/blob/master/install.versioning.sql
+--
+--
+-- # NAME
+--
+-- **Versioning** - simplistic take on tracking and applying changes to databases.
+--
+-- # DESCRIPTION
+--
+-- This project strives to provide simple way to manage changes to
+-- database.
+--
+-- Instead of making changes on development server, then finding
+-- differences between production and development, deciding which ones
+-- should be installed on production, and finding a way to install them -
+-- you start with writing diffs themselves!
+--
+-- # INSTALLATION
+--
+-- To install versioning simply run install.versioning.sql in your database
+-- (all of them: production, stage, test, devel, ...).
+--
+-- # USAGE
+--
+-- In your files with patches to database, put whole logic in single
+-- transaction, and use \_v.\* functions - usually \_v.register_patch() at
+-- least to make sure everything is OK.
+--
+-- For example. Let's assume you have patch files:
+--
+-- ## 0001.sql:
+--
+-- ```
+-- create table users (id serial primary key, username text);
+-- ```
+--
+-- ## 0002.sql:
+--
+-- ```
+-- insert into users (username) values ('depesz');
+-- ```
+-- To change it to use versioning you would change the files, to this
+-- state:
+--
+-- 0000.sql:
+--
+-- ```
+-- BEGIN;
+-- select _v.register_patch('000-base', NULL, NULL);
+-- create table users (id serial primary key, username text);
+-- COMMIT;
+-- ```
+--
+-- ## 0002.sql:
+--
+-- ```
+-- BEGIN;
+-- select _v.register_patch('001-users', ARRAY['000-base'], NULL);
+-- insert into users (username) values ('depesz');
+-- COMMIT;
+-- ```
+--
+-- This will make sure that patch 001-users can only be applied after
+-- 000-base.
+--
+-- # AVAILABLE FUNCTIONS
+--
+-- ## \_v.register_patch( TEXT )
+--
+-- Registers named patch, or dies if it is already registered.
+--
+-- Returns integer which is id of patch in \_v.patches table - only if it
+-- succeeded.
+--
+-- ## \_v.register_patch( TEXT, TEXT[] )
+--
+-- Same as \_v.register_patch( TEXT ), but checks is all given patches (given as
+-- array in second argument) are already registered.
+--
+-- ## \_v.register_patch( TEXT, TEXT[], TEXT[] )
+--
+-- Same as \_v.register_patch( TEXT, TEXT[] ), but also checks if there are no conflicts with preexisting patches.
+--
+-- Third argument is array of names of patches that conflict with current one. So
+-- if any of them is installed - register_patch will error out.
+--
+-- ## \_v.unregister_patch( TEXT )
+--
+-- Removes information about given patch from the versioning data.
+--
+-- It doesn't remove objects that were created by this patch - just removes
+-- metainformation.
+--
+-- ## \_v.assert_user_is_superuser()
+--
+-- Make sure that current patch is being loaded by superuser.
+--
+-- If it's not - it will raise exception, and break transaction.
+--
+-- ## \_v.assert_user_is_not_superuser()
+--
+-- Make sure that current patch is not being loaded by superuser.
+--
+-- If it is - it will raise exception, and break transaction.
+--
+-- ## \_v.assert_user_is_one_of(TEXT, TEXT, ... )
+--
+-- Make sure that current patch is being loaded by one of listed users.
+--
+-- If ```current_user``` is not listed as one of arguments - function will raise
+-- exception and break the transaction.
+
+BEGIN;
+
+-- This file adds versioning support to database it will be loaded to.
+-- It requires that PL/pgSQL is already loaded - will raise exception otherwise.
+-- All versioning "stuff" (tables, functions) is in "_v" schema.
+
+-- All functions are defined as 'RETURNS SETOF INT4' to be able to make them to RETURN literally nothing (0 rows).
+-- >> RETURNS VOID<< IS similar, but it still outputs "empty line" in psql when calling.
+CREATE SCHEMA IF NOT EXISTS _v;
+COMMENT ON SCHEMA _v IS 'Schema for versioning data and functionality.';
+
+CREATE TABLE IF NOT EXISTS _v.patches (
+ patch_name TEXT PRIMARY KEY,
+ applied_tsz TIMESTAMPTZ NOT NULL DEFAULT now(),
+ applied_by TEXT NOT NULL,
+ requires TEXT[],
+ conflicts TEXT[]
+);
+COMMENT ON TABLE _v.patches IS 'Contains information about what patches are currently applied on database.';
+COMMENT ON COLUMN _v.patches.patch_name IS 'Name of patch, has to be unique for every patch.';
+COMMENT ON COLUMN _v.patches.applied_tsz IS 'When the patch was applied.';
+COMMENT ON COLUMN _v.patches.applied_by IS 'Who applied this patch (PostgreSQL username)';
+COMMENT ON COLUMN _v.patches.requires IS 'List of patches that are required for given patch.';
+COMMENT ON COLUMN _v.patches.conflicts IS 'List of patches that conflict with given patch.';
+
+CREATE OR REPLACE FUNCTION _v.register_patch( IN in_patch_name TEXT, IN in_requirements TEXT[], in_conflicts TEXT[], OUT versioning INT4 ) RETURNS setof INT4 AS $$
+DECLARE
+ t_text TEXT;
+ t_text_a TEXT[];
+ i INT4;
+BEGIN
+ -- Thanks to this we know only one patch will be applied at a time
+ LOCK TABLE _v.patches IN EXCLUSIVE MODE;
+
+ SELECT patch_name INTO t_text FROM _v.patches WHERE patch_name = in_patch_name;
+ IF FOUND THEN
+ RAISE EXCEPTION 'Patch % is already applied!', in_patch_name;
+ END IF;
+
+ t_text_a := ARRAY( SELECT patch_name FROM _v.patches WHERE patch_name = any( in_conflicts ) );
+ IF array_upper( t_text_a, 1 ) IS NOT NULL THEN
+ RAISE EXCEPTION 'Versioning patches conflict. Conflicting patche(s) installed: %.', array_to_string( t_text_a, ', ' );
+ END IF;
+
+ IF array_upper( in_requirements, 1 ) IS NOT NULL THEN
+ t_text_a := '{}';
+ FOR i IN array_lower( in_requirements, 1 ) .. array_upper( in_requirements, 1 ) LOOP
+ SELECT patch_name INTO t_text FROM _v.patches WHERE patch_name = in_requirements[i];
+ IF NOT FOUND THEN
+ t_text_a := t_text_a || in_requirements[i];
+ END IF;
+ END LOOP;
+ IF array_upper( t_text_a, 1 ) IS NOT NULL THEN
+ RAISE EXCEPTION 'Missing prerequisite(s): %.', array_to_string( t_text_a, ', ' );
+ END IF;
+ END IF;
+
+ INSERT INTO _v.patches (patch_name, applied_tsz, applied_by, requires, conflicts ) VALUES ( in_patch_name, now(), current_user, coalesce( in_requirements, '{}' ), coalesce( in_conflicts, '{}' ) );
+ RETURN;
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.register_patch( TEXT, TEXT[], TEXT[] ) IS 'Function to register patches in database. Raises exception if there are conflicts, prerequisites are not installed or the migration has already been installed.';
+
+CREATE OR REPLACE FUNCTION _v.register_patch( TEXT, TEXT[] ) RETURNS setof INT4 AS $$
+ SELECT _v.register_patch( $1, $2, NULL );
+$$ language sql;
+COMMENT ON FUNCTION _v.register_patch( TEXT, TEXT[] ) IS 'Wrapper to allow registration of patches without conflicts.';
+CREATE OR REPLACE FUNCTION _v.register_patch( TEXT ) RETURNS setof INT4 AS $$
+ SELECT _v.register_patch( $1, NULL, NULL );
+$$ language sql;
+COMMENT ON FUNCTION _v.register_patch( TEXT ) IS 'Wrapper to allow registration of patches without requirements and conflicts.';
+
+CREATE OR REPLACE FUNCTION _v.unregister_patch( IN in_patch_name TEXT, OUT versioning INT4 ) RETURNS setof INT4 AS $$
+DECLARE
+ i INT4;
+ t_text_a TEXT[];
+BEGIN
+ -- Thanks to this we know only one patch will be applied at a time
+ LOCK TABLE _v.patches IN EXCLUSIVE MODE;
+
+ t_text_a := ARRAY( SELECT patch_name FROM _v.patches WHERE in_patch_name = ANY( requires ) );
+ IF array_upper( t_text_a, 1 ) IS NOT NULL THEN
+ RAISE EXCEPTION 'Cannot uninstall %, as it is required by: %.', in_patch_name, array_to_string( t_text_a, ', ' );
+ END IF;
+
+ DELETE FROM _v.patches WHERE patch_name = in_patch_name;
+ GET DIAGNOSTICS i = ROW_COUNT;
+ IF i < 1 THEN
+ RAISE EXCEPTION 'Patch % is not installed, so it can''t be uninstalled!', in_patch_name;
+ END IF;
+
+ RETURN;
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.unregister_patch( TEXT ) IS 'Function to unregister patches in database. Dies if the patch is not registered, or if unregistering it would break dependencies.';
+
+CREATE OR REPLACE FUNCTION _v.assert_patch_is_applied( IN in_patch_name TEXT ) RETURNS TEXT as $$
+DECLARE
+ t_text TEXT;
+BEGIN
+ SELECT patch_name INTO t_text FROM _v.patches WHERE patch_name = in_patch_name;
+ IF NOT FOUND THEN
+ RAISE EXCEPTION 'Patch % is not applied!', in_patch_name;
+ END IF;
+ RETURN format('Patch %s is applied.', in_patch_name);
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.assert_patch_is_applied( TEXT ) IS 'Function that can be used to make sure that patch has been applied.';
+
+CREATE OR REPLACE FUNCTION _v.assert_user_is_superuser() RETURNS TEXT as $$
+DECLARE
+ v_super bool;
+BEGIN
+ SELECT usesuper INTO v_super FROM pg_user WHERE usename = current_user;
+ IF v_super THEN
+ RETURN 'assert_user_is_superuser: OK';
+ END IF;
+ RAISE EXCEPTION 'Current user is not superuser - cannot continue.';
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.assert_user_is_superuser() IS 'Function that can be used to make sure that patch is being applied using superuser account.';
+
+CREATE OR REPLACE FUNCTION _v.assert_user_is_not_superuser() RETURNS TEXT as $$
+DECLARE
+ v_super bool;
+BEGIN
+ SELECT usesuper INTO v_super FROM pg_user WHERE usename = current_user;
+ IF v_super THEN
+ RAISE EXCEPTION 'Current user is superuser - cannot continue.';
+ END IF;
+ RETURN 'assert_user_is_not_superuser: OK';
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.assert_user_is_not_superuser() IS 'Function that can be used to make sure that patch is being applied using normal (not superuser) account.';
+
+CREATE OR REPLACE FUNCTION _v.assert_user_is_one_of(VARIADIC p_acceptable_users TEXT[] ) RETURNS TEXT as $$
+DECLARE
+BEGIN
+ IF current_user = any( p_acceptable_users ) THEN
+ RETURN 'assert_user_is_one_of: OK';
+ END IF;
+ RAISE EXCEPTION 'User is not one of: % - cannot continue.', p_acceptable_users;
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.assert_user_is_one_of(TEXT[]) IS 'Function that can be used to make sure that patch is being applied by one of defined users.';
+
+COMMIT;
diff --git a/src/syncdb/sync-0001.sql b/src/syncdb/sync-0001.sql
new file mode 100644
index 0000000..a463d72
--- /dev/null
+++ b/src/syncdb/sync-0001.sql
@@ -0,0 +1,53 @@
+--
+-- This file is part of TALER
+-- Copyright (C) 2021 Taler Systems SA
+--
+-- TALER is free software; you can redistribute it and/or modify it under the
+-- terms of the GNU General Public License as published by the Free Software
+-- Foundation; either version 3, or (at your option) any later version.
+--
+-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+-- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+--
+
+-- Everything in one big transaction
+BEGIN;
+
+-- Check patch versioning is in place.
+SELECT _v.register_patch('sync-0001', NULL, NULL);
+
+CREATE TABLE IF NOT EXISTS accounts
+ (account_pub BYTEA PRIMARY KEY CHECK (length(account_pub)=32)
+ ,expiration_date INT8 NOT NULL);
+
+CREATE INDEX IF NOT EXISTS accounts_expire ON
+ accounts (expiration_date);
+
+
+CREATE TABLE IF NOT EXISTS payments
+ (account_pub BYTEA CHECK (length(account_pub)=32)
+ ,order_id VARCHAR PRIMARY KEY
+ ,token BYTEA CHECK (length(token)=16)
+ ,timestamp INT8 NOT NULL
+ ,amount_val INT8 NOT NULL
+ ,amount_frac INT4 NOT NULL
+ ,paid BOOLEAN NOT NULL DEFAULT FALSE);
+
+CREATE INDEX IF NOT EXISTS payments_timestamp ON
+ payments (paid,timestamp);
+
+
+CREATE TABLE IF NOT EXISTS backups
+ (account_pub BYTEA PRIMARY KEY REFERENCES accounts (account_pub) ON DELETE CASCADE
+ ,account_sig BYTEA NOT NULL CHECK (length(account_sig)=64)
+ ,prev_hash BYTEA NOT NULL CHECK (length(prev_hash)=64)
+ ,backup_hash BYTEA NOT NULL CHECK (length(backup_hash)=64)
+ ,data BYTEA NOT NULL);
+
+
+-- Complete transaction
+COMMIT;
diff --git a/src/syncdb/sync-dbinit.c b/src/syncdb/sync-dbinit.c
index 95aaeb6..be7b2ae 100644
--- a/src/syncdb/sync-dbinit.c
+++ b/src/syncdb/sync-dbinit.c
@@ -39,6 +39,7 @@ static int reset_db;
*/
static int gc_db;
+
/**
* Main function that will be run.
*
@@ -60,14 +61,23 @@ run (void *cls,
{
fprintf (stderr,
"Failed to initialize database plugin.\n");
- global_ret = 1;
+ global_ret = EXIT_NOTINSTALLED;
return;
}
if (reset_db)
{
- (void) plugin->drop_tables (plugin->cls);
+ if (GNUNET_OK != plugin->drop_tables (plugin->cls))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not drop tables as requested. Either database was not yet initialized, or permission denied. Consult the logs. Will still try to create new tables.\n");
+ }
+ }
+ if (GNUNET_OK !=
+ plugin->create_tables (plugin->cls))
+ {
+ global_ret = EXIT_FAILURE;
SYNC_DB_plugin_unload (plugin);
- plugin = SYNC_DB_plugin_load (cfg);
+ return;
}
if (gc_db)
{
@@ -79,9 +89,15 @@ run (void *cls,
GNUNET_TIME_relative_multiply (
GNUNET_TIME_UNIT_YEARS,
6));
- plugin->gc (plugin->cls,
- now,
- ancient);
+ if (0 >
+ plugin->gc (plugin->cls,
+ now,
+ ancient))
+ {
+ fprintf (stderr,
+ "Garbage collection failed!\n");
+ global_ret = EXIT_FAILURE;
+ }
}
SYNC_DB_plugin_unload (plugin);
}
@@ -93,7 +109,7 @@ run (void *cls,
*
* @param argc number of arguments from the command line
* @param argv command line arguments
- * @return 0 ok, 1 on error
+ * @return 0 ok, non-zero on error
*/
int
main (int argc,
@@ -110,23 +126,22 @@ main (int argc,
&gc_db),
GNUNET_GETOPT_OPTION_END
};
+ enum GNUNET_GenericReturnValue ret;
/* FIRST get the libtalerutil initialization out
of the way. Then throw that one away, and force
the SYNC defaults to be used! */
(void) TALER_project_data_default ();
GNUNET_OS_init (SYNC_project_data_default ());
- GNUNET_assert (GNUNET_OK ==
- GNUNET_log_setup ("sync-dbinit",
- "INFO",
- NULL));
- if (GNUNET_OK !=
- GNUNET_PROGRAM_run (argc, argv,
- "sync-dbinit",
- "Initialize sync database",
- options,
- &run, NULL))
- return 1;
+ ret = GNUNET_PROGRAM_run (argc, argv,
+ "sync-dbinit",
+ "Initialize sync database",
+ options,
+ &run, NULL);
+ if (GNUNET_SYSERR == ret)
+ return EXIT_INVALIDARGUMENT;
+ if (GNUNET_NO == ret)
+ return EXIT_SUCCESS;
return global_ret;
}
diff --git a/src/syncdb/sync_db_plugin.c b/src/syncdb/sync_db_plugin.c
index 6c4f8d5..2c3bd48 100644
--- a/src/syncdb/sync_db_plugin.c
+++ b/src/syncdb/sync_db_plugin.c
@@ -28,14 +28,13 @@
* Initialize the plugin.
*
* @param cfg configuration to use
- * @return #GNUNET_OK on success
+ * @return NULL on failure
*/
struct SYNC_DatabasePlugin *
SYNC_DB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg)
{
char *plugin_name;
char *lib_name;
- struct GNUNET_CONFIGURATION_Handle *cfg_dup;
struct SYNC_DatabasePlugin *plugin;
if (GNUNET_SYSERR ==
@@ -53,13 +52,12 @@ SYNC_DB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg)
"libsync_plugin_db_%s",
plugin_name);
GNUNET_free (plugin_name);
- cfg_dup = GNUNET_CONFIGURATION_dup (cfg);
- plugin = GNUNET_PLUGIN_load (lib_name, cfg_dup);
+ plugin = GNUNET_PLUGIN_load (lib_name,
+ (void *) cfg);
if (NULL != plugin)
plugin->library_name = lib_name;
else
GNUNET_free (lib_name);
- GNUNET_CONFIGURATION_destroy (cfg_dup);
return plugin;
}
diff --git a/src/syncdb/sync_db_postgres.conf b/src/syncdb/sync_db_postgres.conf
index 0460bd2..db41bd0 100644
--- a/src/syncdb/sync_db_postgres.conf
+++ b/src/syncdb/sync_db_postgres.conf
@@ -2,6 +2,10 @@
#The DB plugin to use
DB = postgres
-[anastasisdb-postgres]
+[syncdb-postgres]
#The connection string the plugin has to use for connecting to the database
-CONFIG = postgres:///anastasis
+CONFIG = postgres:///sync
+
+# Where are the SQL files to setup our tables?
+# Important: this MUST end with a "/"!
+SQL_DIR = $DATADIR/sql/
diff --git a/src/syncdb/test_sync_db.c b/src/syncdb/test_sync_db.c
index 09c7501..8bea684 100644
--- a/src/syncdb/test_sync_db.c
+++ b/src/syncdb/test_sync_db.c
@@ -24,6 +24,7 @@
#include "sync_service.h"
#include "sync_database_plugin.h"
#include "sync_database_lib.h"
+#include "sync_util.h"
#define FAILIF(cond) \
@@ -98,19 +99,20 @@ run (void *cls)
result = 77;
return;
}
- if (GNUNET_OK != plugin->drop_tables (plugin->cls))
+ if (GNUNET_OK !=
+ plugin->drop_tables (plugin->cls))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Dropping tables failed\n");
- result = 77;
- return;
}
- SYNC_DB_plugin_unload (plugin);
- if (NULL == (plugin = SYNC_DB_plugin_load (cfg)))
+ if (GNUNET_OK !=
+ plugin->create_tables (plugin->cls))
{
- result = 77;
- return;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Creating tables failed\n");
}
+ GNUNET_assert (GNUNET_OK ==
+ plugin->preflight (plugin->cls));
memset (&account_pub, 1, sizeof (account_pub));
memset (&account_sig, 2, sizeof (account_sig));
memset (&token, 3, sizeof (token));
@@ -267,13 +269,15 @@ main (int argc,
char *testname;
struct GNUNET_CONFIGURATION_Handle *cfg;
- result = -1;
+ result = EXIT_FAILURE;
if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
{
GNUNET_break (0);
- return -1;
+ return EXIT_FAILURE;
}
GNUNET_log_setup (argv[0], "DEBUG", NULL);
+ (void) TALER_project_data_default ();
+ GNUNET_OS_init (SYNC_project_data_default ());
plugin_name++;
(void) GNUNET_asprintf (&testname,
"%s",
@@ -289,7 +293,7 @@ main (int argc,
GNUNET_break (0);
GNUNET_free (config_filename);
GNUNET_free (testname);
- return 2;
+ return EXIT_NOTCONFIGURED;
}
GNUNET_SCHEDULER_run (&run, cfg);
GNUNET_CONFIGURATION_destroy (cfg);
diff --git a/src/syncdb/test_sync_db_postgres.conf b/src/syncdb/test_sync_db_postgres.conf
index 6485f69..c555c4f 100644
--- a/src/syncdb/test_sync_db_postgres.conf
+++ b/src/syncdb/test_sync_db_postgres.conf
@@ -8,3 +8,7 @@ CURRENCY = EUR
[syncdb-postgres]
#The connection string the plugin has to use for connecting to the database
CONFIG = postgres:///synccheck
+
+# Where are the SQL files to setup our tables?
+# Important: this MUST end with a "/"!
+SQL_DIR = $DATADIR/sql/
diff --git a/src/testing/test_sync_api.conf b/src/testing/test_sync_api.conf
index e94fdde..54d2af7 100644
--- a/src/testing/test_sync_api.conf
+++ b/src/testing/test_sync_api.conf
@@ -50,6 +50,10 @@ UPLOAD_LIMIT_MB = 1
[syncdb-postgres]
CONFIG = postgres:///synccheck
+# Where are the SQL files to setup our tables?
+# Important: this MUST end with a "/"!
+SQL_DIR = $DATADIR/sql/
+
##########################################
# Configuration for the merchant backend #
##########################################