diff options
author | Iván Ávalos <avalos@disroot.org> | 2023-05-12 23:16:21 -0600 |
---|---|---|
committer | Iván Ávalos <avalos@disroot.org> | 2023-05-12 23:16:21 -0600 |
commit | 594aa4576f9ec45315c4d253356b9962d59d46c2 (patch) | |
tree | d46e63a6b4540864fd4b7b3f8da4806763bf3204 | |
parent | 1925b6e26c0f68c36cd9fb32165638624021686c (diff) | |
download | merchant-594aa4576f9ec45315c4d253356b9962d59d46c2.tar.gz merchant-594aa4576f9ec45315c4d253356b9962d59d46c2.tar.bz2 merchant-594aa4576f9ec45315c4d253356b9962d59d46c2.zip |
Factor out 13 new functions (shit job)
28 files changed, 2615 insertions, 1778 deletions
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am index 91b48223..1b400bce 100644 --- a/src/backenddb/Makefile.am +++ b/src/backenddb/Makefile.am @@ -81,6 +81,19 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \ pg_insert_product.h pg_insert_product.c \ pg_update_product.h pg_update_product.c \ pg_lock_product.h pg_lock_product.c \ + pg_expire_locks.h pg_expire_locks.c \ + pg_delete_order.h pg_delete_order.c \ + pg_lookup_order.h pg_lookup_order.c \ + pg_lookup_order_summary.h pg_lookup_order_summary.c \ + pg_lookup_orders.h pg_lookup_orders.c \ + pg_insert_order.h pg_insert_order.c \ + pg_unlock_inventory.h pg_unlock_inventory.c \ + pg_insert_order_lock.h pg_insert_order_lock.c \ + pg_lookup_contract_terms2.h pg_lookup_contract_terms2.c \ + pg_lookup_contract_terms.h pg_lookup_contract_terms.c \ + pg_insert_contract_terms.h pg_insert_contract_terms.c \ + pg_update_contract_terms.h pg_update_contract_terms.c \ + pg_delete_contract_terms.h pg_delete_contract_terms.c \ plugin_merchantdb_postgres.c pg_helper.h libtaler_plugin_merchantdb_postgres_la_LIBADD = \ $(LTLIBINTL) diff --git a/src/backenddb/pg_delete_contract_terms.c b/src/backenddb/pg_delete_contract_terms.c new file mode 100644 index 00000000..708a724a --- /dev/null +++ b/src/backenddb/pg_delete_contract_terms.c @@ -0,0 +1,59 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_delete_contract_terms.c + * @brief Implementation of the delete_contract_terms function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_delete_contract_terms.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_delete_contract_terms (void *cls, + const char *instance_id, + const char *order_id, + struct GNUNET_TIME_Relative legal_expiration) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_relative_time (&legal_expiration), + GNUNET_PQ_query_param_absolute_time (&now), + GNUNET_PQ_query_param_end + }; + + check_connection (pg); + PREPARE (pg, + "delete_contract_terms", + "DELETE FROM merchant_contract_terms" + " WHERE order_id=$2" + " AND merchant_serial=" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND ( ( (pay_deadline < $4) AND" + " (NOT paid) ) OR" + " (creation_time + $3 < $4) )"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "delete_contract_terms", + params); +} diff --git a/src/backenddb/pg_delete_contract_terms.h b/src/backenddb/pg_delete_contract_terms.h new file mode 100644 index 00000000..ce74a3c5 --- /dev/null +++ b/src/backenddb/pg_delete_contract_terms.h @@ -0,0 +1,47 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_delete_contract_terms.h + * @brief implementation of the delete_contract_terms function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_DELETE_CONTRACT_TERMS_H +#define PG_DELETE_CONTRACT_TERMS_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Delete information about a contract. Note that the transaction must + * enforce that the contract is not awaiting payment anymore AND was not + * paid, or is past the legal expiration. + * + * @param cls closure + * @param instance_id instance to delete order of + * @param order_id order to delete + * @param legal_expiration how long do we need to keep (paid) contracts on + * file for legal reasons (i.e. taxation) + * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS + * if locks prevent deletion OR order unknown + */ +enum GNUNET_DB_QueryStatus +TMH_PG_delete_contract_terms (void *cls, + const char *instance_id, + const char *order_id, + struct GNUNET_TIME_Relative legal_expiration); + +#endif diff --git a/src/backenddb/pg_delete_order.c b/src/backenddb/pg_delete_order.c new file mode 100644 index 00000000..e058be3b --- /dev/null +++ b/src/backenddb/pg_delete_order.c @@ -0,0 +1,87 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_delete_order.c + * @brief Implementation of the delete_order function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_delete_order.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_delete_order (void *cls, + const char *instance_id, + const char *order_id, + bool force) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_absolute_time (&now), + GNUNET_PQ_query_param_bool (force), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_QueryParam params2[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + PREPARE (pg, + "delete_order", + "WITH ms AS" + "(SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + ", mc AS" + "(SELECT paid" + " FROM merchant_contract_terms" + " JOIN ms USING (merchant_serial)" + " WHERE order_id=$2) " + "DELETE" + " FROM merchant_orders mo" + " WHERE order_id=$2" + " AND merchant_serial=(SELECT merchant_serial FROM ms)" + " AND ( (pay_deadline < $3)" + " OR (NOT EXISTS (SELECT paid FROM mc))" + " OR ($4 AND (FALSE=(SELECT paid FROM mc))) );"); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "delete_order", + params); + if ( (qs <= 0) || (! force)) + return qs; + PREPARE (pg, + "delete_contract", + "DELETE" + " FROM merchant_contract_terms" + " WHERE order_id=$2 AND" + " merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND NOT paid;"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "delete_contract", + params2); +} diff --git a/src/backenddb/pg_delete_order.h b/src/backenddb/pg_delete_order.h new file mode 100644 index 00000000..58f3e5bb --- /dev/null +++ b/src/backenddb/pg_delete_order.h @@ -0,0 +1,45 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_delete_order.h + * @brief implementation of the delete_order function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_DELETE_ORDER_H +#define PG_DELETE_ORDER_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Delete information about an order. Note that the transaction must + * enforce that the order is not awaiting payment anymore. + * + * @param cls closure + * @param instance_id instance to delete order of + * @param order_id order to delete + * @param force delete claimed but unpaid orders as well + * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS + * if pending payment prevents deletion OR order unknown + */ +enum GNUNET_DB_QueryStatus +TMH_PG_delete_order (void *cls, + const char *instance_id, + const char *order_id, + bool force); + +#endif diff --git a/src/backenddb/pg_expire_locks.c b/src/backenddb/pg_expire_locks.c new file mode 100644 index 00000000..4b12ba04 --- /dev/null +++ b/src/backenddb/pg_expire_locks.c @@ -0,0 +1,84 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_expire_locks.c + * @brief Implementation of the expire_locks function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_expire_locks.h" +#include "pg_helper.h" + +void +TMH_PG_expire_locks (void *cls) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_absolute_time (&now), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs1; + enum GNUNET_DB_QueryStatus qs2; + enum GNUNET_DB_QueryStatus qs3; + + check_connection (pg); + PREPARE (pg, + "unlock_products", + "DELETE FROM merchant_inventory_locks" + " WHERE expiration < $1"); + qs1 = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "unlock_products", + params); + if (qs1 < 0) + { + GNUNET_break (0); + return; + } + PREPARE (pg, + "unlock_orders", + "DELETE FROM merchant_orders" + " WHERE pay_deadline < $1"); + qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "unlock_orders", + params); + if (qs2 < 0) + { + GNUNET_break (0); + return; + } + PREPARE (pg, + "unlock_contracts", + "DELETE FROM merchant_contract_terms" + " WHERE NOT paid" + " AND pay_deadline < $1"); + qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "unlock_contracts", + params); + if (qs3 < 0) + { + GNUNET_break (0); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Released %d+%d+%d locks\n", + qs1, + qs2, + qs3); +} diff --git a/src/backenddb/pg_expire_locks.h b/src/backenddb/pg_expire_locks.h new file mode 100644 index 00000000..6eac73de --- /dev/null +++ b/src/backenddb/pg_expire_locks.h @@ -0,0 +1,38 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_expire_locks.h + * @brief implementation of the expire_locks function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_EXPIRE_LOCKS_H +#define PG_EXPIRE_LOCKS_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Release all expired product locks, including + * those from expired offers -- across all + * instances. + * + * @param cls closure + */ +void +TMH_PG_expire_locks (void *cls); + +#endif diff --git a/src/backenddb/pg_insert_contract_terms.c b/src/backenddb/pg_insert_contract_terms.c new file mode 100644 index 00000000..2bc6ab86 --- /dev/null +++ b/src/backenddb/pg_insert_contract_terms.c @@ -0,0 +1,132 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_insert_contract_terms.c + * @brief Implementation of the insert_contract_terms function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_insert_contract_terms.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_insert_contract_terms ( + void *cls, + const char *instance_id, + const char *order_id, + json_t *contract_terms, + uint64_t *order_serial) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Timestamp pay_deadline; + struct GNUNET_TIME_Timestamp refund_deadline; + const char *fulfillment_url; + struct TALER_PrivateContractHashP h_contract_terms; + + if (GNUNET_OK != + TALER_JSON_contract_hash (contract_terms, + &h_contract_terms)) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_timestamp ("pay_deadline", + &pay_deadline), + GNUNET_JSON_spec_timestamp ("refund_deadline", + &refund_deadline), + GNUNET_JSON_spec_end () + }; + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (NULL, + contract_terms, + spec); + if (GNUNET_OK != res) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + } + + fulfillment_url = + json_string_value (json_object_get (contract_terms, + "fulfillment_url")); + check_connection (pg); + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + TALER_PQ_query_param_json (contract_terms), + GNUNET_PQ_query_param_auto_from_type (&h_contract_terms), + GNUNET_PQ_query_param_timestamp (&pay_deadline), + GNUNET_PQ_query_param_timestamp (&refund_deadline), + (NULL == fulfillment_url) + ? GNUNET_PQ_query_param_null () + : GNUNET_PQ_query_param_string (fulfillment_url), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("order_serial", + order_serial), + GNUNET_PQ_result_spec_end + }; + PREPARE (pg, + "insert_contract_terms", + "INSERT INTO merchant_contract_terms" + "(order_serial" + ",merchant_serial" + ",order_id" + ",contract_terms" + ",h_contract_terms" + ",creation_time" + ",pay_deadline" + ",refund_deadline" + ",fulfillment_url" + ",claim_token" + ",pos_key" + ",pos_algorithm)" + "SELECT" + " mo.order_serial" + ",mo.merchant_serial" + ",mo.order_id" + ",$3" /* contract_terms */ + ",$4" /* h_contract_terms */ + ",mo.creation_time" + ",$5" /* pay_deadline */ + ",$6" /* refund_deadline */ + ",$7" /* fulfillment_url */ + ",mo.claim_token" + ",mo.pos_key" + ",mo.pos_algorithm" + " FROM merchant_orders mo" + " WHERE order_id=$2" + " AND merchant_serial=" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " RETURNING order_serial"); + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "insert_contract_terms", + params, + rs); + } +} diff --git a/src/backenddb/pg_insert_contract_terms.h b/src/backenddb/pg_insert_contract_terms.h new file mode 100644 index 00000000..8f22f5b8 --- /dev/null +++ b/src/backenddb/pg_insert_contract_terms.h @@ -0,0 +1,52 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_insert_contract_terms.h + * @brief implementation of the insert_contract_terms function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_INSERT_CONTRACT_TERMS_H +#define PG_INSERT_CONTRACT_TERMS_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Store contract terms given its @a order_id. Note that some attributes are + * expected to be calculated inside of the function, like the hash of the + * contract terms (to be hashed), the creation_time and pay_deadline (to be + * obtained from the merchant_orders table). The "session_id" should be + * initially set to the empty string. The "fulfillment_url" and "refund_deadline" + * must be extracted from @a contract_terms. + * + * @param cls closure + * @param instance_id instance's identifier + * @param order_id order_id used to store + * @param contract_terms contract terms to store + * @param[out] order_serial set to the serial of the order + * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a contract_terms + * is malformed + */ +enum GNUNET_DB_QueryStatus +TMH_PG_insert_contract_terms ( + void *cls, + const char *instance_id, + const char *order_id, + json_t *contract_terms, + uint64_t *order_serial); + +#endif diff --git a/src/backenddb/pg_insert_order.c b/src/backenddb/pg_insert_order.c new file mode 100644 index 00000000..7c7ad486 --- /dev/null +++ b/src/backenddb/pg_insert_order.c @@ -0,0 +1,82 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_insert_order.c + * @brief Implementation of the insert_order function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_insert_order.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_insert_order (void *cls, + const char *instance_id, + const char *order_id, + const struct TALER_MerchantPostDataHashP *h_post_data, + struct GNUNET_TIME_Timestamp pay_deadline, + const struct TALER_ClaimTokenP *claim_token, + const json_t *contract_terms, + const char *pos_key, + enum TALER_MerchantConfirmationAlgorithm pos_algorithm) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Timestamp now; + uint32_t pos32 = (uint32_t) pos_algorithm; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_timestamp (&pay_deadline), + GNUNET_PQ_query_param_auto_from_type (claim_token), + GNUNET_PQ_query_param_auto_from_type (h_post_data), + GNUNET_PQ_query_param_timestamp (&now), + TALER_PQ_query_param_json (contract_terms), + (NULL == pos_key) + ? GNUNET_PQ_query_param_null () + : GNUNET_PQ_query_param_string (pos_key), + GNUNET_PQ_query_param_uint32 (&pos32), + GNUNET_PQ_query_param_end + }; + + now = GNUNET_TIME_timestamp_get (); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "inserting order: order_id: %s, instance_id: %s.\n", + order_id, + instance_id); + check_connection (pg); + PREPARE (pg, + "insert_order", + "INSERT INTO merchant_orders" + "(merchant_serial" + ",order_id" + ",pay_deadline" + ",claim_token" + ",h_post_data" + ",creation_time" + ",contract_terms" + ",pos_key" + ",pos_algorithm)" + " SELECT merchant_serial," + " $2, $3, $4, $5, $6, $7, $8, $9" + " FROM merchant_instances" + " WHERE merchant_id=$1"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "insert_order", + params); +} diff --git a/src/backenddb/pg_insert_order.h b/src/backenddb/pg_insert_order.h new file mode 100644 index 00000000..297d9bdf --- /dev/null +++ b/src/backenddb/pg_insert_order.h @@ -0,0 +1,53 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_insert_order.h + * @brief implementation of the insert_order function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_INSERT_ORDER_H +#define PG_INSERT_ORDER_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Insert order into the DB. + * + * @param cls closure + * @param instance_id identifies the instance responsible for the order + * @param order_id alphanumeric string that uniquely identifies the proposal + * @param h_post_data hash of the POST data for idempotency checks + * @param pay_deadline how long does the customer have to pay for the order + * @param claim_token token to use for access control + * @param contract_terms proposal data to store + * @param pos_key encoded key for payment verification + * @param pos_algorithm algorithm to compute the payment verification + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +TMH_PG_insert_order (void *cls, + const char *instance_id, + const char *order_id, + const struct TALER_MerchantPostDataHashP *h_post_data, + struct GNUNET_TIME_Timestamp pay_deadline, + const struct TALER_ClaimTokenP *claim_token, + const json_t *contract_terms, + const char *pos_key, + enum TALER_MerchantConfirmationAlgorithm pos_algorithm); + +#endif diff --git a/src/backenddb/pg_insert_order_lock.c b/src/backenddb/pg_insert_order_lock.c new file mode 100644 index 00000000..862a6320 --- /dev/null +++ b/src/backenddb/pg_insert_order_lock.c @@ -0,0 +1,78 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_insert_order_lock.c + * @brief Implementation of the insert_order_lock function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_insert_order_lock.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_insert_order_lock (void *cls, + const char *instance_id, + const char *order_id, + const char *product_id, + uint64_t quantity) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_string (product_id), + GNUNET_PQ_query_param_uint64 (&quantity), + GNUNET_PQ_query_param_end + }; + + check_connection (pg); + PREPARE (pg, + "insert_order_lock", + "WITH tmp AS" + " (SELECT " + " product_serial" + " ,merchant_serial" + " ,total_stock" + " ,total_sold" + " ,total_lost" + " FROM merchant_inventory" + " WHERE product_id=$3" + " AND merchant_serial=" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1))" + " INSERT INTO merchant_order_locks" + " (product_serial" + " ,total_locked" + " ,order_serial)" + " SELECT tmp.product_serial, $4, order_serial" + " FROM merchant_orders" + " JOIN tmp USING(merchant_serial)" + " WHERE order_id=$2 AND" + " tmp.total_stock - tmp.total_sold - tmp.total_lost - $4 >= " + " (SELECT COALESCE(SUM(total_locked), 0)" + " FROM merchant_inventory_locks" + " WHERE product_serial=tmp.product_serial) + " + " (SELECT COALESCE(SUM(total_locked), 0)" + " FROM merchant_order_locks" + " WHERE product_serial=tmp.product_serial)"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "insert_order_lock", + params); +} diff --git a/src/backenddb/pg_insert_order_lock.h b/src/backenddb/pg_insert_order_lock.h new file mode 100644 index 00000000..c2cc9908 --- /dev/null +++ b/src/backenddb/pg_insert_order_lock.h @@ -0,0 +1,47 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_insert_order_lock.h + * @brief implementation of the insert_order_lock function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_INSERT_ORDER_LOCK_H +#define PG_INSERT_ORDER_LOCK_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Lock inventory stock to a particular order. + * + * @param cls closure + * @param instance_id identifies the instance responsible for the order + * @param order_id alphanumeric string that uniquely identifies the order + * @param product_id uniquely identifies the product to be locked + * @param quantity how many units should be locked to the @a order_id + * @return transaction status, + * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are insufficient stocks + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success + */ +enum GNUNET_DB_QueryStatus +TMH_PG_insert_order_lock (void *cls, + const char *instance_id, + const char *order_id, + const char *product_id, + uint64_t quantity); + +#endif diff --git a/src/backenddb/pg_lookup_contract_terms.c b/src/backenddb/pg_lookup_contract_terms.c new file mode 100644 index 00000000..e1f24ac4 --- /dev/null +++ b/src/backenddb/pg_lookup_contract_terms.c @@ -0,0 +1,82 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_contract_terms.c + * @brief Implementation of the lookup_contract_terms function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_lookup_contract_terms.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_contract_terms ( + void *cls, + const char *instance_id, + const char *order_id, + json_t **contract_terms, + uint64_t *order_serial, + bool *paid, + struct TALER_ClaimTokenP *claim_token) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + struct TALER_ClaimTokenP ct; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + /* contract_terms must be first! */ + TALER_PQ_result_spec_json ("contract_terms", + contract_terms), + GNUNET_PQ_result_spec_uint64 ("order_serial", + order_serial), + GNUNET_PQ_result_spec_bool ("paid", + paid), + GNUNET_PQ_result_spec_auto_from_type ("claim_token", + &ct), + GNUNET_PQ_result_spec_end + }; + + check_connection (pg); + PREPARE (pg, + "lookup_contract_terms", + "SELECT" + " contract_terms" + ",order_serial" + ",claim_token" + ",paid" + " FROM merchant_contract_terms" + " WHERE order_id=$2" + " AND merchant_serial=" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)"); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_contract_terms", + params, + (NULL != contract_terms) + ? rs + : &rs[1]); + if (NULL != claim_token) + *claim_token = ct; + return qs; +} diff --git a/src/backenddb/pg_lookup_contract_terms.h b/src/backenddb/pg_lookup_contract_terms.h new file mode 100644 index 00000000..2ab1bb16 --- /dev/null +++ b/src/backenddb/pg_lookup_contract_terms.h @@ -0,0 +1,50 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_contract_terms.h + * @brief implementation of the lookup_contract_terms function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_LOOKUP_CONTRACT_TERMS_H +#define PG_LOOKUP_CONTRACT_TERMS_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Retrieve contract terms given its @a order_id + * + * @param cls closure + * @param instance_id instance's identifier + * @param order_id order_id used to lookup. + * @param[out] contract_terms where to store the result, NULL to only check for existence + * @param[out] order_serial set to the order's serial number + * @param[out] paid set to true if the order is fully paid + * @param[out] claim_token set to token to use for access control + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_contract_terms ( + void *cls, + const char *instance_id, + const char *order_id, + json_t **contract_terms, + uint64_t *order_serial, + bool *paid, + struct TALER_ClaimTokenP *claim_token); + +#endif diff --git a/src/backenddb/pg_lookup_contract_terms2.c b/src/backenddb/pg_lookup_contract_terms2.c new file mode 100644 index 00000000..1fbb02ea --- /dev/null +++ b/src/backenddb/pg_lookup_contract_terms2.c @@ -0,0 +1,96 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_contract_terms2.c + * @brief Implementation of the lookup_contract_terms2 function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_lookup_contract_terms2.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_contract_terms2 ( + void *cls, + const char *instance_id, + const char *order_id, + json_t **contract_terms, + uint64_t *order_serial, + bool *paid, + struct TALER_ClaimTokenP *claim_token, + char **pos_key, + enum TALER_MerchantConfirmationAlgorithm *pos_algorithm) +{ + struct PostgresClosure *pg = cls; + enum GNUNET_DB_QueryStatus qs; + struct TALER_ClaimTokenP ct; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_end + }; + uint32_t pos32; + struct GNUNET_PQ_ResultSpec rs[] = { + /* contract_terms must be first! */ + TALER_PQ_result_spec_json ("contract_terms", + contract_terms), + GNUNET_PQ_result_spec_uint64 ("order_serial", + order_serial), + GNUNET_PQ_result_spec_bool ("paid", + paid), + GNUNET_PQ_result_spec_auto_from_type ("claim_token", + &ct), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_string ("pos_key", + pos_key), + NULL), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_uint32 ("pos_algorithm", + &pos32), + NULL), + GNUNET_PQ_result_spec_end + }; + + check_connection (pg); + PREPARE (pg, + "lookup_contract_terms2", + "SELECT" + " contract_terms" + ",order_serial" + ",claim_token" + ",paid" + ",pos_key" + ",pos_algorithm" + " FROM merchant_contract_terms" + " WHERE order_id=$2" + " AND merchant_serial=" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)"); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_contract_terms2", + params, + (NULL != contract_terms) + ? rs + : &rs[1]); + *pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos32; + if (NULL != claim_token) + *claim_token = ct; + return qs; +} diff --git a/src/backenddb/pg_lookup_contract_terms2.h b/src/backenddb/pg_lookup_contract_terms2.h new file mode 100644 index 00000000..6c1c8514 --- /dev/null +++ b/src/backenddb/pg_lookup_contract_terms2.h @@ -0,0 +1,54 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_contract_terms2.h + * @brief implementation of the lookup_contract_terms2 function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_LOOKUP_CONTRACT_TERMS2_H +#define PG_LOOKUP_CONTRACT_TERMS2_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Retrieve contract terms given its @a order_id + * + * @param cls closure + * @param instance_id instance's identifier + * @param order_id order_id used to lookup. + * @param[out] contract_terms where to store the result, NULL to only check for existence + * @param[out] order_serial set to the order's serial number + * @param[out] paid set to true if the order is fully paid + * @param[out] claim_token set to the claim token, NULL to only check for existence + * @param[out] pos_key encoded key for payment verification + * @param[out] pos_algorithm algorithm to compute the payment verification + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_contract_terms2 ( + void *cls, + const char *instance_id, + const char *order_id, + json_t **contract_terms, + uint64_t *order_serial, + bool *paid, + struct TALER_ClaimTokenP *claim_token, + char **pos_key, + enum TALER_MerchantConfirmationAlgorithm *pos_algorithm); + +#endif diff --git a/src/backenddb/pg_lookup_order.c b/src/backenddb/pg_lookup_order.c new file mode 100644 index 00000000..6df7456c --- /dev/null +++ b/src/backenddb/pg_lookup_order.c @@ -0,0 +1,96 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_order.c + * @brief Implementation of the lookup_order function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_lookup_order.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_order (void *cls, + const char *instance_id, + const char *order_id, + struct TALER_ClaimTokenP *claim_token, + struct TALER_MerchantPostDataHashP *h_post_data, + json_t **contract_terms) +{ + struct PostgresClosure *pg = cls; + json_t *j; + struct TALER_ClaimTokenP ct; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_result_spec_json ("contract_terms", + &j), + GNUNET_PQ_result_spec_auto_from_type ("claim_token", + &ct), + GNUNET_PQ_result_spec_auto_from_type ("h_post_data", + h_post_data), + GNUNET_PQ_result_spec_end + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finding contract term, order_id: '%s', instance_id: '%s'.\n", + order_id, + instance_id); + check_connection (pg); + PREPARE (pg, + "lookup_order", + "SELECT" + " contract_terms" + ",claim_token" + ",h_post_data" + ",pos_key" + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND merchant_orders.order_id=$2"); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_order", + params, + rs); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) + { + if (NULL != contract_terms) + *contract_terms = j; + else + json_decref (j); + if (NULL != claim_token) + *claim_token = ct; + } + else + { + /* just to be safe: NULL it */ + if (NULL != contract_terms) + *contract_terms = NULL; + if (NULL != claim_token) + *claim_token = (struct TALER_ClaimTokenP) { 0 } + ; + } + return qs; +} diff --git a/src/backenddb/pg_lookup_order.h b/src/backenddb/pg_lookup_order.h new file mode 100644 index 00000000..7ca60869 --- /dev/null +++ b/src/backenddb/pg_lookup_order.h @@ -0,0 +1,49 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_order.h + * @brief implementation of the lookup_order function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_LOOKUP_ORDER_H +#define PG_LOOKUP_ORDER_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Retrieve order given its @a order_id and the @a instance_id. + * + * @param cls closure + * @param instance_id instance to obtain order of + * @param order_id order id used to perform the lookup + * @param[out] claim_token the claim token generated for the order, + * NULL to only test if the order exists + * @param[out] h_post_data set to the hash of the POST data that created the order + * @param[out] contract_terms where to store the retrieved contract terms, + * NULL to only test if the order exists + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_order (void *cls, + const char *instance_id, + const char *order_id, + struct TALER_ClaimTokenP *claim_token, + struct TALER_MerchantPostDataHashP *h_post_data, + json_t **contract_terms); + +#endif diff --git a/src/backenddb/pg_lookup_order_summary.c b/src/backenddb/pg_lookup_order_summary.c new file mode 100644 index 00000000..3a2a4e16 --- /dev/null +++ b/src/backenddb/pg_lookup_order_summary.c @@ -0,0 +1,75 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_order_summary.c + * @brief Implementation of the lookup_order_summary function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_lookup_order_summary.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_order_summary (void *cls, + const char *instance_id, + const char *order_id, + struct GNUNET_TIME_Timestamp *timestamp, + uint64_t *order_serial) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint64 ("order_serial", + order_serial), + GNUNET_PQ_result_spec_timestamp ("creation_time", + timestamp), + GNUNET_PQ_result_spec_end + }; + + check_connection (pg); + PREPARE (pg, + "lookup_order_summary", + "(SELECT" + " creation_time" + ",order_serial" + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND merchant_contract_terms.order_id=$2)" + "UNION" + "(SELECT" + " creation_time" + ",order_serial" + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND merchant_orders.order_id=$2)"); + return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_order_summary", + params, + rs); +} diff --git a/src/backenddb/pg_lookup_order_summary.h b/src/backenddb/pg_lookup_order_summary.h new file mode 100644 index 00000000..5827aa66 --- /dev/null +++ b/src/backenddb/pg_lookup_order_summary.h @@ -0,0 +1,45 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_order_summary.h + * @brief implementation of the lookup_order_summary function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_LOOKUP_ORDER_SUMMARY_H +#define PG_LOOKUP_ORDER_SUMMARY_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Retrieve order summary given its @a order_id and the @a instance_id. + * + * @param cls closure + * @param instance_id instance to obtain order of + * @param order_id order id used to perform the lookup + * @param[out] timestamp when was the order created + * @param[out] order_serial under which serial do we keep this order + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_order_summary (void *cls, + const char *instance_id, + const char *order_id, + struct GNUNET_TIME_Timestamp *timestamp, + uint64_t *order_serial); + +#endif diff --git a/src/backenddb/pg_lookup_orders.c b/src/backenddb/pg_lookup_orders.c new file mode 100644 index 00000000..437ca8ca --- /dev/null +++ b/src/backenddb/pg_lookup_orders.c @@ -0,0 +1,926 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_orders.c + * @brief Implementation of the lookup_orders function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_lookup_orders.h" +#include "pg_helper.h" + +/** + * Context used for TMH_PG_lookup_orders(). + */ +struct LookupOrdersContext +{ + /** + * Function to call with the results. + */ + TALER_MERCHANTDB_OrdersCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Did database result extraction fail? + */ + bool extract_failed; +}; + + +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results about orders. + * + * @param[in,out] cls of type `struct LookupOrdersContext *` + * @param result the postgres result + * @param num_results the number of results in @a result + */ +static void +lookup_orders_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupOrdersContext *plc = cls; + + for (unsigned int i = 0; i < num_results; i++) + { + char *order_id; + uint64_t order_serial; + struct GNUNET_TIME_Timestamp ts; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_string ("order_id", + &order_id), + GNUNET_PQ_result_spec_uint64 ("order_serial", + &order_serial), + GNUNET_PQ_result_spec_timestamp ("creation_time", + &ts), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + plc->extract_failed = true; + return; + } + plc->cb (plc->cb_cls, + order_id, + order_serial, + ts); + GNUNET_PQ_cleanup_result (rs); + } +} + + +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_orders (void *cls, + const char *instance_id, + const struct TALER_MERCHANTDB_OrderFilter *of, + TALER_MERCHANTDB_OrdersCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + struct LookupOrdersContext plc = { + .cb = cb, + .cb_cls = cb_cls + }; + uint64_t limit = (of->delta > 0) ? of->delta : -of->delta; + uint8_t paid; + uint8_t refunded; + uint8_t wired; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_uint64 (&limit), + GNUNET_PQ_query_param_uint64 (&of->start_row), + GNUNET_PQ_query_param_timestamp (&of->date), + GNUNET_PQ_query_param_auto_from_type (&paid), + GNUNET_PQ_query_param_auto_from_type (&refunded), + GNUNET_PQ_query_param_auto_from_type (&wired), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + char stmt[128]; + + paid = (TALER_EXCHANGE_YNA_YES == of->paid); + refunded = (TALER_EXCHANGE_YNA_YES == of->refunded); + wired = (TALER_EXCHANGE_YNA_YES == of->wired); + /* painfully many cases..., note that "_xxx" being present in 'stmt' merely + means that we filter by that variable, the value we filter for is + computed above */ + GNUNET_snprintf (stmt, + sizeof (stmt), + "lookup_orders_%s%s%s%s", + (of->delta > 0) ? "inc" : "dec", + (TALER_EXCHANGE_YNA_ALL == of->paid) ? "" : "_paid", + (TALER_EXCHANGE_YNA_ALL == of->refunded) ? "" : + "_refunded", + (TALER_EXCHANGE_YNA_ALL == of->wired) ? "" : "_wired"); + PREPARE (pg, + "lookup_orders_inc", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " ORDER BY order_serial ASC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " ORDER BY order_serial ASC" + " LIMIT $2)" + " ORDER BY order_serial ASC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_inc_paid", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial ASC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " BOOL($5) = paid" + " ORDER BY order_serial ASC" + " LIMIT $2)" + " ORDER BY order_serial ASC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_inc_refunded", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial ASC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " CAST($6 as BOOL) = (order_serial IN" + " (SELECT order_serial " + " FROM merchant_refunds))" + " ORDER BY order_serial ASC" + " LIMIT $2)" + " ORDER BY order_serial ASC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_inc_wired", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial ASC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " BOOL($7) = wired" + " ORDER BY order_serial ASC" + " LIMIT $2)" + " ORDER BY order_serial ASC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_inc_paid_refunded", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial ASC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " BOOL($5) = paid" + " AND" + " BOOL($6) = (order_serial IN" + " (SELECT order_serial " + " FROM merchant_refunds))" + " ORDER BY order_serial ASC" + " LIMIT $2)" + " ORDER BY order_serial ASC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_inc_paid_wired", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial ASC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " BOOL($5) = paid" + " AND" + " BOOL($7) = wired" + " ORDER BY order_serial ASC" + " LIMIT $2)" + " ORDER BY order_serial ASC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_inc_refunded_wired", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial ASC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " BOOL($6) = (order_serial IN" + " (SELECT order_serial " + " FROM merchant_refunds))" + " AND" + " BOOL($7) = wired" + " ORDER BY order_serial ASC" + " LIMIT $2)" + " ORDER BY order_serial ASC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_inc_paid_refunded_wired", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial ASC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial > $3" + " AND" + " creation_time > $4" + " AND" + " BOOL($5) = paid" + " AND" + " BOOL($6) = (order_serial IN" + " (SELECT order_serial " + " FROM merchant_refunds))" + " AND" + " BOOL($7) = wired" + " ORDER BY order_serial ASC" + " LIMIT $2)" + " ORDER BY order_serial ASC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_dec", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " ORDER BY order_serial DESC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " ORDER BY order_serial DESC" + " LIMIT $2)" + " ORDER BY order_serial DESC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_dec_paid", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial DESC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " BOOL($5) = paid" + " ORDER BY order_serial DESC" + " LIMIT $2)" + " ORDER BY order_serial DESC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_dec_refunded", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial DESC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " BOOL($6) = (order_serial IN" + " (SELECT order_serial " + " FROM merchant_refunds))" + " ORDER BY order_serial DESC" + " LIMIT $2)" + " ORDER BY order_serial DESC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_dec_wired", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial DESC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " BOOL($7) = wired" + " ORDER BY order_serial DESC" + " LIMIT $2)" + " ORDER BY order_serial DESC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_dec_paid_refunded", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial DESC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " BOOL($5) = paid" + " AND" + " BOOL($6) = (order_serial IN" + " (SELECT order_serial " + " FROM merchant_refunds))" + " ORDER BY order_serial DESC" + " LIMIT $2)" + " ORDER BY order_serial DESC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_dec_paid_wired", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial DESC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " BOOL($5) = paid" + " AND" + " BOOL($7) = wired" + " ORDER BY order_serial DESC" + " LIMIT $2)" + " ORDER BY order_serial DESC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_dec_refunded_wired", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial DESC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " BOOL($6) = (order_serial IN" + " (SELECT order_serial " + " FROM merchant_refunds))" + " AND" + " BOOL($7) = wired" + " ORDER BY order_serial DESC" + " LIMIT $2)" + " ORDER BY order_serial DESC" + " LIMIT $2"); + PREPARE (pg, + "lookup_orders_dec_paid_refunded_wired", + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + " FROM merchant_orders" + " WHERE merchant_orders.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ + " ORDER BY order_serial DESC" + " LIMIT $2)" + "UNION " /* union ensures elements are distinct! */ + "(SELECT" + " order_id" + ",order_serial" + ",creation_time" + " FROM merchant_contract_terms" + " WHERE merchant_contract_terms.merchant_serial=" + " (SELECT merchant_serial " + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " AND" + " order_serial < $3" + " AND" + " creation_time < $4" + " AND" + " BOOL($5) = paid" + " AND" + " BOOL($6) = (order_serial IN" + " (SELECT order_serial " + + " FROM merchant_refunds))" + " AND" + " BOOL($7) = wired" + " ORDER BY order_serial DESC" + " LIMIT $2)" + " ORDER BY order_serial DESC" + " LIMIT $2"); + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + stmt, + params, + &lookup_orders_cb, + &plc); + if (plc.extract_failed) + return GNUNET_DB_STATUS_HARD_ERROR; + return qs; +} diff --git a/src/backenddb/pg_lookup_orders.h b/src/backenddb/pg_lookup_orders.h new file mode 100644 index 00000000..4b00f18b --- /dev/null +++ b/src/backenddb/pg_lookup_orders.h @@ -0,0 +1,45 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_lookup_orders.h + * @brief implementation of the lookup_orders function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_LOOKUP_ORDERS_H +#define PG_LOOKUP_ORDERS_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Retrieve orders given the @a instance_id. + * + * @param cls closure + * @param instance_id instance to obtain order of + * @param of filter to apply when looking up orders + * @param cb callback to pass all the orders that are found + * @param cb_cls closure for @a cb + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +TMH_PG_lookup_orders (void *cls, + const char *instance_id, + const struct TALER_MERCHANTDB_OrderFilter *of, + TALER_MERCHANTDB_OrdersCallback cb, + void *cb_cls); + +#endif diff --git a/src/backenddb/pg_unlock_inventory.c b/src/backenddb/pg_unlock_inventory.c new file mode 100644 index 00000000..5f4d8a7b --- /dev/null +++ b/src/backenddb/pg_unlock_inventory.c @@ -0,0 +1,47 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_unlock_inventory.c + * @brief Implementation of the unlock_inventory function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_unlock_inventory.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_unlock_inventory (void *cls, + const struct GNUNET_Uuid *uuid) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (uuid), + GNUNET_PQ_query_param_end + }; + + check_connection (pg); + PREPARE (pg, + "unlock_inventory", + "DELETE" + " FROM merchant_inventory_locks" + " WHERE lock_uuid=$1"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "unlock_inventory", + params); +} diff --git a/src/backenddb/pg_unlock_inventory.h b/src/backenddb/pg_unlock_inventory.h new file mode 100644 index 00000000..cec734e8 --- /dev/null +++ b/src/backenddb/pg_unlock_inventory.h @@ -0,0 +1,42 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_unlock_inventory.h + * @brief implementation of the unlock_inventory function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_UNLOCK_INVENTORY_H +#define PG_UNLOCK_INVENTORY_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Release an inventory lock by UUID. Releases ALL stocks locked under + * the given UUID. + * + * @param cls closure + * @param uuid the UUID to release locks for + * @return transaction status, + * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are no locks under @a uuid + * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success + */ +enum GNUNET_DB_QueryStatus +TMH_PG_unlock_inventory (void *cls, + const struct GNUNET_Uuid *uuid); + +#endif diff --git a/src/backenddb/pg_update_contract_terms.c b/src/backenddb/pg_update_contract_terms.c new file mode 100644 index 00000000..51e449a0 --- /dev/null +++ b/src/backenddb/pg_update_contract_terms.c @@ -0,0 +1,103 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_update_contract_terms.c + * @brief Implementation of the update_contract_terms function for Postgres + * @author Iván Ávalos + */ +#include "platform.h" +#include <taler/taler_error_codes.h> +#include <taler/taler_dbevents.h> +#include <taler/taler_pq_lib.h> +#include "pg_update_contract_terms.h" +#include "pg_helper.h" + +enum GNUNET_DB_QueryStatus +TMH_PG_update_contract_terms (void *cls, + const char *instance_id, + const char *order_id, + json_t *contract_terms) +{ + struct PostgresClosure *pg = cls; + struct GNUNET_TIME_Timestamp pay_deadline; + struct GNUNET_TIME_Timestamp refund_deadline; + const char *fulfillment_url = NULL; + struct TALER_PrivateContractHashP h_contract_terms; + + if (GNUNET_OK != + TALER_JSON_contract_hash (contract_terms, + &h_contract_terms)) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_timestamp ("pay_deadline", + &pay_deadline), + GNUNET_JSON_spec_timestamp ("refund_deadline", + &refund_deadline), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("fulfillment_url", + &fulfillment_url), + NULL), + GNUNET_JSON_spec_end () + }; + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (NULL, + contract_terms, + spec); + if (GNUNET_OK != res) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + } + + check_connection (pg); + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_string (order_id), + TALER_PQ_query_param_json (contract_terms), + GNUNET_PQ_query_param_auto_from_type (&h_contract_terms), + GNUNET_PQ_query_param_timestamp (&pay_deadline), + GNUNET_PQ_query_param_timestamp (&refund_deadline), + (NULL == fulfillment_url) + ? GNUNET_PQ_query_param_null () + : GNUNET_PQ_query_param_string (fulfillment_url), + GNUNET_PQ_query_param_end + }; + PREPARE (pg, + "update_contract_terms", + "UPDATE merchant_contract_terms SET" + " contract_terms=$3" + ",h_contract_terms=$4" + ",pay_deadline=$5" + ",refund_deadline=$6" + ",fulfillment_url=$7" + " WHERE order_id=$2" + " AND merchant_serial=" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)"); + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "update_contract_terms", + params); + } +} diff --git a/src/backenddb/pg_update_contract_terms.h b/src/backenddb/pg_update_contract_terms.h new file mode 100644 index 00000000..fe428dc0 --- /dev/null +++ b/src/backenddb/pg_update_contract_terms.h @@ -0,0 +1,49 @@ +/* + This file is part of TALER + Copyright (C) 2022 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/> + */ +/** + * @file backenddb/pg_update_contract_terms.h + * @brief implementation of the update_contract_terms function for Postgres + * @author Iván Ávalos + */ +#ifndef PG_UPDATE_CONTRACT_TERMS_H +#define PG_UPDATE_CONTRACT_TERMS_H + +#include <taler/taler_util.h> +#include <taler/taler_json_lib.h> +#include "taler_merchantdb_plugin.h" + +/** + * Update the contract terms stored for @a order_id. Note that some attributes are + * expected to be calculated inside of the function, like the hash of the + * contract terms (to be hashed), the creation_time and pay_deadline (to be + * obtained from the merchant_orders table). The "session_id" should be + * initially set to the empty string. The "fulfillment_url" and "refund_deadline" + * must be extracted from @a contract_terms. + * + * @param cls closure + * @param instance_id instance's identifier + * @param order_id order_id used to store + * @param contract_terms contract to store + * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a contract_terms + * is malformed + */ +enum GNUNET_DB_QueryStatus +TMH_PG_update_contract_terms (void *cls, + const char *instance_id, + const char *order_id, + json_t *contract_terms); + +#endif diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index 0e5f921f..757a303c 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -59,6 +59,19 @@ #include "pg_insert_product.h" #include "pg_update_product.h" #include "pg_lock_product.h" +#include "pg_expire_locks.h" +#include "pg_delete_order.h" +#include "pg_lookup_order.h" +#include "pg_lookup_order_summary.h" +#include "pg_lookup_orders.h" +#include "pg_insert_order.h" +#include "pg_unlock_inventory.h" +#include "pg_insert_order_lock.h" +#include "pg_lookup_contract_terms2.h" +#include "pg_lookup_contract_terms.h" +#include "pg_insert_contract_terms.h" +#include "pg_update_contract_terms.h" +#include "pg_delete_contract_terms.h" #include "pg_set_transfer_status_to_confirmed.h" @@ -337,797 +350,6 @@ postgres_commit (void *cls) /** - * Release all expired product locks, including - * those from expired offers -- across all - * instances. - * - * @param cls closure - */ -static void -postgres_expire_locks (void *cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_absolute_time (&now), - GNUNET_PQ_query_param_end - }; - enum GNUNET_DB_QueryStatus qs1; - enum GNUNET_DB_QueryStatus qs2; - enum GNUNET_DB_QueryStatus qs3; - - check_connection (pg); - qs1 = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "unlock_products", - params); - if (qs1 < 0) - { - GNUNET_break (0); - return; - } - qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "unlock_orders", - params); - if (qs2 < 0) - { - GNUNET_break (0); - return; - } - qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "unlock_contracts", - params); - if (qs3 < 0) - { - GNUNET_break (0); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Released %d+%d+%d locks\n", - qs1, - qs2, - qs3); -} - - -/** - * Delete information about an order. Note that the transaction must - * enforce that the order is not awaiting payment anymore. - * - * @param cls closure - * @param instance_id instance to delete order of - * @param order_id order to delete - * @param force delete claimed but unpaid orders as well - * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - * if pending payment prevents deletion OR order unknown - */ -static enum GNUNET_DB_QueryStatus -postgres_delete_order (void *cls, - const char *instance_id, - const char *order_id, - bool force) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_absolute_time (&now), - GNUNET_PQ_query_param_bool (force), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_QueryParam params2[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_end - }; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "delete_order", - params); - if ( (qs <= 0) || (! force)) - return qs; - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "delete_contract", - params2); -} - - -/** - * Retrieve order given its @a order_id and the @a instance_id. - * - * @param cls closure - * @param instance_id instance to obtain order of - * @param order_id order id used to perform the lookup - * @param[out] claim_token the claim token generated for the order, - * NULL to only test if the order exists - * @param[out] h_post_data set to the hash of the POST data that created the order - * @param[out] contract_terms where to store the retrieved contract terms, - * NULL to only test if the order exists - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_lookup_order (void *cls, - const char *instance_id, - const char *order_id, - struct TALER_ClaimTokenP *claim_token, - struct TALER_MerchantPostDataHashP *h_post_data, - json_t **contract_terms) -{ - struct PostgresClosure *pg = cls; - json_t *j; - struct TALER_ClaimTokenP ct; - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - TALER_PQ_result_spec_json ("contract_terms", - &j), - GNUNET_PQ_result_spec_auto_from_type ("claim_token", - &ct), - GNUNET_PQ_result_spec_auto_from_type ("h_post_data", - h_post_data), - GNUNET_PQ_result_spec_end - }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Finding contract term, order_id: '%s', instance_id: '%s'.\n", - order_id, - instance_id); - check_connection (pg); - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_order", - params, - rs); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) - { - if (NULL != contract_terms) - *contract_terms = j; - else - json_decref (j); - if (NULL != claim_token) - *claim_token = ct; - } - else - { - /* just to be safe: NULL it */ - if (NULL != contract_terms) - *contract_terms = NULL; - if (NULL != claim_token) - *claim_token = (struct TALER_ClaimTokenP) { 0 } - ; - } - return qs; -} - - -/** - * Retrieve order summary given its @a order_id and the @a instance_id. - * - * @param cls closure - * @param instance_id instance to obtain order of - * @param order_id order id used to perform the lookup - * @param[out] timestamp when was the order created - * @param[out] order_serial under which serial do we keep this order - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_lookup_order_summary (void *cls, - const char *instance_id, - const char *order_id, - struct GNUNET_TIME_Timestamp *timestamp, - uint64_t *order_serial) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("order_serial", - order_serial), - GNUNET_PQ_result_spec_timestamp ("creation_time", - timestamp), - GNUNET_PQ_result_spec_end - }; - - check_connection (pg); - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_order_summary", - params, - rs); -} - - -/** - * Context used for postgres_lookup_orders(). - */ -struct LookupOrdersContext -{ - /** - * Function to call with the results. - */ - TALER_MERCHANTDB_OrdersCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Did database result extraction fail? - */ - bool extract_failed; -}; - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results about orders. - * - * @param[in,out] cls of type `struct LookupOrdersContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -lookup_orders_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct LookupOrdersContext *plc = cls; - - for (unsigned int i = 0; i < num_results; i++) - { - char *order_id; - uint64_t order_serial; - struct GNUNET_TIME_Timestamp ts; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_string ("order_id", - &order_id), - GNUNET_PQ_result_spec_uint64 ("order_serial", - &order_serial), - GNUNET_PQ_result_spec_timestamp ("creation_time", - &ts), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - plc->extract_failed = true; - return; - } - plc->cb (plc->cb_cls, - order_id, - order_serial, - ts); - GNUNET_PQ_cleanup_result (rs); - } -} - - -/** - * Retrieve orders given the @a instance_id. - * - * @param cls closure - * @param instance_id instance to obtain order of - * @param of filter to apply when looking up orders - * @param cb callback to pass all the orders that are found - * @param cb_cls closure for @a cb - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_lookup_orders (void *cls, - const char *instance_id, - const struct TALER_MERCHANTDB_OrderFilter *of, - TALER_MERCHANTDB_OrdersCallback cb, - void *cb_cls) -{ - struct PostgresClosure *pg = cls; - struct LookupOrdersContext plc = { - .cb = cb, - .cb_cls = cb_cls - }; - uint64_t limit = (of->delta > 0) ? of->delta : -of->delta; - uint8_t paid; - uint8_t refunded; - uint8_t wired; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_uint64 (&limit), - GNUNET_PQ_query_param_uint64 (&of->start_row), - GNUNET_PQ_query_param_timestamp (&of->date), - GNUNET_PQ_query_param_auto_from_type (&paid), - GNUNET_PQ_query_param_auto_from_type (&refunded), - GNUNET_PQ_query_param_auto_from_type (&wired), - GNUNET_PQ_query_param_end - }; - enum GNUNET_DB_QueryStatus qs; - char stmt[128]; - - paid = (TALER_EXCHANGE_YNA_YES == of->paid); - refunded = (TALER_EXCHANGE_YNA_YES == of->refunded); - wired = (TALER_EXCHANGE_YNA_YES == of->wired); - /* painfully many cases..., note that "_xxx" being present in 'stmt' merely - means that we filter by that variable, the value we filter for is - computed above */ - GNUNET_snprintf (stmt, - sizeof (stmt), - "lookup_orders_%s%s%s%s", - (of->delta > 0) ? "inc" : "dec", - (TALER_EXCHANGE_YNA_ALL == of->paid) ? "" : "_paid", - (TALER_EXCHANGE_YNA_ALL == of->refunded) ? "" : - "_refunded", - (TALER_EXCHANGE_YNA_ALL == of->wired) ? "" : "_wired"); - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - stmt, - params, - &lookup_orders_cb, - &plc); - if (plc.extract_failed) - return GNUNET_DB_STATUS_HARD_ERROR; - return qs; -} - - -/** - * Insert order into the DB. - * - * @param cls closure - * @param instance_id identifies the instance responsible for the order - * @param order_id alphanumeric string that uniquely identifies the proposal - * @param h_post_data hash of the POST data for idempotency checks - * @param pay_deadline how long does the customer have to pay for the order - * @param claim_token token to use for access control - * @param contract_terms proposal data to store - * @param pos_key encoded key for payment verification - * @param pos_algorithm algorithm to compute the payment verification - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_insert_order (void *cls, - const char *instance_id, - const char *order_id, - const struct TALER_MerchantPostDataHashP *h_post_data, - struct GNUNET_TIME_Timestamp pay_deadline, - const struct TALER_ClaimTokenP *claim_token, - const json_t *contract_terms, - const char *pos_key, - enum TALER_MerchantConfirmationAlgorithm pos_algorithm) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Timestamp now; - uint32_t pos32 = (uint32_t) pos_algorithm; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_timestamp (&pay_deadline), - GNUNET_PQ_query_param_auto_from_type (claim_token), - GNUNET_PQ_query_param_auto_from_type (h_post_data), - GNUNET_PQ_query_param_timestamp (&now), - TALER_PQ_query_param_json (contract_terms), - (NULL == pos_key) - ? GNUNET_PQ_query_param_null () - : GNUNET_PQ_query_param_string (pos_key), - GNUNET_PQ_query_param_uint32 (&pos32), - GNUNET_PQ_query_param_end - }; - - now = GNUNET_TIME_timestamp_get (); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "inserting order: order_id: %s, instance_id: %s.\n", - order_id, - instance_id); - check_connection (pg); - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_order", - params); -} - - -/** - * Release an inventory lock by UUID. Releases ALL stocks locked under - * the given UUID. - * - * @param cls closure - * @param uuid the UUID to release locks for - * @return transaction status, - * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are no locks under @a uuid - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success - */ -static enum GNUNET_DB_QueryStatus -postgres_unlock_inventory (void *cls, - const struct GNUNET_Uuid *uuid) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (uuid), - GNUNET_PQ_query_param_end - }; - - check_connection (pg); - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "unlock_inventory", - params); -} - - -/** - * Lock inventory stock to a particular order. - * - * @param cls closure - * @param instance_id identifies the instance responsible for the order - * @param order_id alphanumeric string that uniquely identifies the order - * @param product_id uniquely identifies the product to be locked - * @param quantity how many units should be locked to the @a order_id - * @return transaction status, - * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS means there are insufficient stocks - * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT indicates success - */ -static enum GNUNET_DB_QueryStatus -postgres_insert_order_lock (void *cls, - const char *instance_id, - const char *order_id, - const char *product_id, - uint64_t quantity) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_string (product_id), - GNUNET_PQ_query_param_uint64 (&quantity), - GNUNET_PQ_query_param_end - }; - - check_connection (pg); - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_order_lock", - params); -} - - -/** - * Retrieve contract terms given its @a order_id - * - * @param cls closure - * @param instance_id instance's identifier - * @param order_id order_id used to lookup. - * @param[out] contract_terms where to store the result, NULL to only check for existence - * @param[out] order_serial set to the order's serial number - * @param[out] paid set to true if the order is fully paid - * @param[out] claim_token set to the claim token, NULL to only check for existence - * @param[out] pos_key encoded key for payment verification - * @param[out] pos_algorithm algorithm to compute the payment verification - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_lookup_contract_terms2 ( - void *cls, - const char *instance_id, - const char *order_id, - json_t **contract_terms, - uint64_t *order_serial, - bool *paid, - struct TALER_ClaimTokenP *claim_token, - char **pos_key, - enum TALER_MerchantConfirmationAlgorithm *pos_algorithm) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - struct TALER_ClaimTokenP ct; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_end - }; - uint32_t pos32; - struct GNUNET_PQ_ResultSpec rs[] = { - /* contract_terms must be first! */ - TALER_PQ_result_spec_json ("contract_terms", - contract_terms), - GNUNET_PQ_result_spec_uint64 ("order_serial", - order_serial), - GNUNET_PQ_result_spec_bool ("paid", - paid), - GNUNET_PQ_result_spec_auto_from_type ("claim_token", - &ct), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_string ("pos_key", - pos_key), - NULL), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_uint32 ("pos_algorithm", - &pos32), - NULL), - GNUNET_PQ_result_spec_end - }; - - check_connection (pg); - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_contract_terms2", - params, - (NULL != contract_terms) - ? rs - : &rs[1]); - *pos_algorithm = (enum TALER_MerchantConfirmationAlgorithm) pos32; - if (NULL != claim_token) - *claim_token = ct; - return qs; -} - - -/** - * Retrieve contract terms given its @a order_id - * - * @param cls closure - * @param instance_id instance's identifier - * @param order_id order_id used to lookup. - * @param[out] contract_terms where to store the result, NULL to only check for existence - * @param[out] order_serial set to the order's serial number - * @param[out] paid set to true if the order is fully paid - * @param[out] claim_token set to token to use for access control - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_lookup_contract_terms ( - void *cls, - const char *instance_id, - const char *order_id, - json_t **contract_terms, - uint64_t *order_serial, - bool *paid, - struct TALER_ClaimTokenP *claim_token) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - struct TALER_ClaimTokenP ct; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - /* contract_terms must be first! */ - TALER_PQ_result_spec_json ("contract_terms", - contract_terms), - GNUNET_PQ_result_spec_uint64 ("order_serial", - order_serial), - GNUNET_PQ_result_spec_bool ("paid", - paid), - GNUNET_PQ_result_spec_auto_from_type ("claim_token", - &ct), - GNUNET_PQ_result_spec_end - }; - - check_connection (pg); - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "lookup_contract_terms", - params, - (NULL != contract_terms) - ? rs - : &rs[1]); - if (NULL != claim_token) - *claim_token = ct; - return qs; -} - - -/** - * Store contract terms given its @a order_id. Note that some attributes are - * expected to be calculated inside of the function, like the hash of the - * contract terms (to be hashed), the creation_time and pay_deadline (to be - * obtained from the merchant_orders table). The "session_id" should be - * initially set to the empty string. The "fulfillment_url" and "refund_deadline" - * must be extracted from @a contract_terms. - * - * @param cls closure - * @param instance_id instance's identifier - * @param order_id order_id used to store - * @param contract_terms contract terms to store - * @param[out] order_serial set to the serial of the order - * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a contract_terms - * is malformed - */ -static enum GNUNET_DB_QueryStatus -postgres_insert_contract_terms ( - void *cls, - const char *instance_id, - const char *order_id, - json_t *contract_terms, - uint64_t *order_serial) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Timestamp pay_deadline; - struct GNUNET_TIME_Timestamp refund_deadline; - const char *fulfillment_url; - struct TALER_PrivateContractHashP h_contract_terms; - - if (GNUNET_OK != - TALER_JSON_contract_hash (contract_terms, - &h_contract_terms)) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_timestamp ("pay_deadline", - &pay_deadline), - GNUNET_JSON_spec_timestamp ("refund_deadline", - &refund_deadline), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (NULL, - contract_terms, - spec); - if (GNUNET_OK != res) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - } - - fulfillment_url = - json_string_value (json_object_get (contract_terms, - "fulfillment_url")); - check_connection (pg); - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - TALER_PQ_query_param_json (contract_terms), - GNUNET_PQ_query_param_auto_from_type (&h_contract_terms), - GNUNET_PQ_query_param_timestamp (&pay_deadline), - GNUNET_PQ_query_param_timestamp (&refund_deadline), - (NULL == fulfillment_url) - ? GNUNET_PQ_query_param_null () - : GNUNET_PQ_query_param_string (fulfillment_url), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_uint64 ("order_serial", - order_serial), - GNUNET_PQ_result_spec_end - }; - - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "insert_contract_terms", - params, - rs); - } -} - - -/** - * Update the contract terms stored for @a order_id. Note that some attributes are - * expected to be calculated inside of the function, like the hash of the - * contract terms (to be hashed), the creation_time and pay_deadline (to be - * obtained from the merchant_orders table). The "session_id" should be - * initially set to the empty string. The "fulfillment_url" and "refund_deadline" - * must be extracted from @a contract_terms. - * - * @param cls closure - * @param instance_id instance's identifier - * @param order_id order_id used to store - * @param contract_terms contract to store - * @return transaction status, #GNUNET_DB_STATUS_HARD_ERROR if @a contract_terms - * is malformed - */ -static enum GNUNET_DB_QueryStatus -postgres_update_contract_terms (void *cls, - const char *instance_id, - const char *order_id, - json_t *contract_terms) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Timestamp pay_deadline; - struct GNUNET_TIME_Timestamp refund_deadline; - const char *fulfillment_url = NULL; - struct TALER_PrivateContractHashP h_contract_terms; - - if (GNUNET_OK != - TALER_JSON_contract_hash (contract_terms, - &h_contract_terms)) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_timestamp ("pay_deadline", - &pay_deadline), - GNUNET_JSON_spec_timestamp ("refund_deadline", - &refund_deadline), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("fulfillment_url", - &fulfillment_url), - NULL), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (NULL, - contract_terms, - spec); - if (GNUNET_OK != res) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - } - - check_connection (pg); - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - TALER_PQ_query_param_json (contract_terms), - GNUNET_PQ_query_param_auto_from_type (&h_contract_terms), - GNUNET_PQ_query_param_timestamp (&pay_deadline), - GNUNET_PQ_query_param_timestamp (&refund_deadline), - (NULL == fulfillment_url) - ? GNUNET_PQ_query_param_null () - : GNUNET_PQ_query_param_string (fulfillment_url), - GNUNET_PQ_query_param_end - }; - - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "update_contract_terms", - params); - } -} - - -/** - * Delete information about a contract. Note that the transaction must - * enforce that the contract is not awaiting payment anymore AND was not - * paid, or is past the legal expiration. - * - * @param cls closure - * @param instance_id instance to delete order of - * @param order_id order to delete - * @param legal_expiration how long do we need to keep (paid) contracts on - * file for legal reasons (i.e. taxation) - * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - * if locks prevent deletion OR order unknown - */ -static enum GNUNET_DB_QueryStatus -postgres_delete_contract_terms (void *cls, - const char *instance_id, - const char *order_id, - struct GNUNET_TIME_Relative legal_expiration) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_relative_time (&legal_expiration), - GNUNET_PQ_query_param_absolute_time (&now), - GNUNET_PQ_query_param_end - }; - - check_connection (pg); - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "delete_contract_terms", - params); -} - - -/** * Closure for #lookup_deposits_cb(). */ struct LookupDepositsContext @@ -6206,980 +5428,6 @@ postgres_connect (void *cls) struct GNUNET_PQ_PreparedStatement ps[] = { GNUNET_PQ_make_prepare ("end_transaction", "COMMIT"), - /* for postgres_expire_locks() */ - GNUNET_PQ_make_prepare ("unlock_products", - "DELETE FROM merchant_inventory_locks" - " WHERE expiration < $1"), - /* for postgres_expire_locks() */ - GNUNET_PQ_make_prepare ("unlock_orders", - "DELETE FROM merchant_orders" - " WHERE pay_deadline < $1"), - /* for postgres_expire_locks() */ - GNUNET_PQ_make_prepare ("unlock_contracts", - "DELETE FROM merchant_contract_terms" - " WHERE NOT paid" - " AND pay_deadline < $1"), - - /* for postgres_delete_order() */ - GNUNET_PQ_make_prepare ("delete_order", - "WITH ms AS" - "(SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - ", mc AS" - "(SELECT paid" - " FROM merchant_contract_terms" - " JOIN ms USING (merchant_serial)" - " WHERE order_id=$2) " - "DELETE" - " FROM merchant_orders mo" - " WHERE order_id=$2" - " AND merchant_serial=(SELECT merchant_serial FROM ms)" - " AND ( (pay_deadline < $3)" - " OR (NOT EXISTS (SELECT paid FROM mc))" - " OR ($4 AND (FALSE=(SELECT paid FROM mc))) );"), - GNUNET_PQ_make_prepare ("delete_contract", - "DELETE" - " FROM merchant_contract_terms" - " WHERE order_id=$2 AND" - " merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND NOT paid;"), - /* for postgres_lookup_order() */ - GNUNET_PQ_make_prepare ("lookup_order", - "SELECT" - " contract_terms" - ",claim_token" - ",h_post_data" - ",pos_key" - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND merchant_orders.order_id=$2"), - /* for postgres_lookup_order_summary() */ - GNUNET_PQ_make_prepare ("lookup_order_summary", - "(SELECT" - " creation_time" - ",order_serial" - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND merchant_contract_terms.order_id=$2)" - "UNION" - "(SELECT" - " creation_time" - ",order_serial" - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND merchant_orders.order_id=$2)"), - /* for postgres_lookup_orders() */ - GNUNET_PQ_make_prepare ("lookup_orders_inc", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " ORDER BY order_serial ASC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " ORDER BY order_serial ASC" - " LIMIT $2)" - " ORDER BY order_serial ASC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_inc_paid", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial ASC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " BOOL($5) = paid" - " ORDER BY order_serial ASC" - " LIMIT $2)" - " ORDER BY order_serial ASC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_inc_refunded", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial ASC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " CAST($6 as BOOL) = (order_serial IN" - " (SELECT order_serial " - " FROM merchant_refunds))" - " ORDER BY order_serial ASC" - " LIMIT $2)" - " ORDER BY order_serial ASC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_inc_wired", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial ASC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " BOOL($7) = wired" - " ORDER BY order_serial ASC" - " LIMIT $2)" - " ORDER BY order_serial ASC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_refunded", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ - " AND" - " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial ASC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " BOOL($5) = paid" - " AND" - " BOOL($6) = (order_serial IN" - " (SELECT order_serial " - " FROM merchant_refunds))" - " ORDER BY order_serial ASC" - " LIMIT $2)" - " ORDER BY order_serial ASC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_wired", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ - " AND" - " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial ASC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " BOOL($5) = paid" - " AND" - " BOOL($7) = wired" - " ORDER BY order_serial ASC" - " LIMIT $2)" - " ORDER BY order_serial ASC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_inc_refunded_wired", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ - " AND" - " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial ASC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " BOOL($6) = (order_serial IN" - " (SELECT order_serial " - " FROM merchant_refunds))" - " AND" - " BOOL($7) = wired" - " ORDER BY order_serial ASC" - " LIMIT $2)" - " ORDER BY order_serial ASC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_inc_paid_refunded_wired", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ - " AND" - " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ - " AND" - " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial ASC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial > $3" - " AND" - " creation_time > $4" - " AND" - " BOOL($5) = paid" - " AND" - " BOOL($6) = (order_serial IN" - " (SELECT order_serial " - " FROM merchant_refunds))" - " AND" - " BOOL($7) = wired" - " ORDER BY order_serial ASC" - " LIMIT $2)" - " ORDER BY order_serial ASC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_dec", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " ORDER BY order_serial DESC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " ORDER BY order_serial DESC" - " LIMIT $2)" - " ORDER BY order_serial DESC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_dec_paid", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial DESC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " BOOL($5) = paid" - " ORDER BY order_serial DESC" - " LIMIT $2)" - " ORDER BY order_serial DESC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_dec_refunded", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial DESC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " BOOL($6) = (order_serial IN" - " (SELECT order_serial " - " FROM merchant_refunds))" - " ORDER BY order_serial DESC" - " LIMIT $2)" - " ORDER BY order_serial DESC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_dec_wired", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial DESC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " BOOL($7) = wired" - " ORDER BY order_serial DESC" - " LIMIT $2)" - " ORDER BY order_serial DESC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_refunded", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ - " AND" - " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial DESC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($7 as BOOL)" /* otherwise $7 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " BOOL($5) = paid" - " AND" - " BOOL($6) = (order_serial IN" - " (SELECT order_serial " - " FROM merchant_refunds))" - " ORDER BY order_serial DESC" - " LIMIT $2)" - " ORDER BY order_serial DESC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_wired", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ - " AND" - " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial DESC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($6 as BOOL)" /* otherwise $6 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " BOOL($5) = paid" - " AND" - " BOOL($7) = wired" - " ORDER BY order_serial DESC" - " LIMIT $2)" - " ORDER BY order_serial DESC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_dec_refunded_wired", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ - " AND" - " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial DESC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - ",CAST($5 as BOOL)" /* otherwise $5 is unused and Postgres unhappy */ - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " BOOL($6) = (order_serial IN" - " (SELECT order_serial " - " FROM merchant_refunds))" - " AND" - " BOOL($7) = wired" - " ORDER BY order_serial DESC" - " LIMIT $2)" - " ORDER BY order_serial DESC" - " LIMIT $2"), - GNUNET_PQ_make_prepare ("lookup_orders_dec_paid_refunded_wired", - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - " FROM merchant_orders" - " WHERE merchant_orders.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ - " AND" - " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ - " AND" - " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ - " AND" - " order_serial NOT IN" - " (SELECT order_serial" - " FROM merchant_contract_terms)" /* only select unclaimed orders */ - " ORDER BY order_serial DESC" - " LIMIT $2)" - "UNION " /* union ensures elements are distinct! */ - "(SELECT" - " order_id" - ",order_serial" - ",creation_time" - " FROM merchant_contract_terms" - " WHERE merchant_contract_terms.merchant_serial=" - " (SELECT merchant_serial " - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND" - " order_serial < $3" - " AND" - " creation_time < $4" - " AND" - " BOOL($5) = paid" - " AND" - " BOOL($6) = (order_serial IN" - " (SELECT order_serial " - " FROM merchant_refunds))" - " AND" - " BOOL($7) = wired" - " ORDER BY order_serial DESC" - " LIMIT $2)" - " ORDER BY order_serial DESC" - " LIMIT $2"), - /* for postgres_insert_order() */ - GNUNET_PQ_make_prepare ("insert_order", - "INSERT INTO merchant_orders" - "(merchant_serial" - ",order_id" - ",pay_deadline" - ",claim_token" - ",h_post_data" - ",creation_time" - ",contract_terms" - ",pos_key" - ",pos_algorithm)" - " SELECT merchant_serial," - " $2, $3, $4, $5, $6, $7, $8, $9" - " FROM merchant_instances" - " WHERE merchant_id=$1"), - /* for postgres_unlock_inventory() */ - GNUNET_PQ_make_prepare ("unlock_inventory", - "DELETE" - " FROM merchant_inventory_locks" - " WHERE lock_uuid=$1"), - /* for postgres_insert_order_lock() */ - GNUNET_PQ_make_prepare ("insert_order_lock", - "WITH tmp AS" - " (SELECT " - " product_serial" - " ,merchant_serial" - " ,total_stock" - " ,total_sold" - " ,total_lost" - " FROM merchant_inventory" - " WHERE product_id=$3" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1))" - " INSERT INTO merchant_order_locks" - " (product_serial" - " ,total_locked" - " ,order_serial)" - " SELECT tmp.product_serial, $4, order_serial" - " FROM merchant_orders" - " JOIN tmp USING(merchant_serial)" - " WHERE order_id=$2 AND" - " tmp.total_stock - tmp.total_sold - tmp.total_lost - $4 >= " - " (SELECT COALESCE(SUM(total_locked), 0)" - " FROM merchant_inventory_locks" - " WHERE product_serial=tmp.product_serial) + " - " (SELECT COALESCE(SUM(total_locked), 0)" - " FROM merchant_order_locks" - " WHERE product_serial=tmp.product_serial)"), - /* for postgres_lookup_contract_terms() */ - GNUNET_PQ_make_prepare ("lookup_contract_terms", - "SELECT" - " contract_terms" - ",order_serial" - ",claim_token" - ",paid" - " FROM merchant_contract_terms" - " WHERE order_id=$2" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"), - /* for postgres_lookup_contract_terms() */ - GNUNET_PQ_make_prepare ("lookup_contract_terms2", - "SELECT" - " contract_terms" - ",order_serial" - ",claim_token" - ",paid" - ",pos_key" - ",pos_algorithm" - " FROM merchant_contract_terms" - " WHERE order_id=$2" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"), - /* for postgres_insert_contract_terms() */ - GNUNET_PQ_make_prepare ("insert_contract_terms", - "INSERT INTO merchant_contract_terms" - "(order_serial" - ",merchant_serial" - ",order_id" - ",contract_terms" - ",h_contract_terms" - ",creation_time" - ",pay_deadline" - ",refund_deadline" - ",fulfillment_url" - ",claim_token" - ",pos_key" - ",pos_algorithm)" - "SELECT" - " mo.order_serial" - ",mo.merchant_serial" - ",mo.order_id" - ",$3" /* contract_terms */ - ",$4" /* h_contract_terms */ - ",mo.creation_time" - ",$5" /* pay_deadline */ - ",$6" /* refund_deadline */ - ",$7" /* fulfillment_url */ - ",mo.claim_token" - ",mo.pos_key" - ",mo.pos_algorithm" - " FROM merchant_orders mo" - " WHERE order_id=$2" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " RETURNING order_serial"), - /* for postgres_update_contract_terms() */ - GNUNET_PQ_make_prepare ("update_contract_terms", - "UPDATE merchant_contract_terms SET" - " contract_terms=$3" - ",h_contract_terms=$4" - ",pay_deadline=$5" - ",refund_deadline=$6" - ",fulfillment_url=$7" - " WHERE order_id=$2" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)"), - /* for postgres_delete_contract_terms() */ - GNUNET_PQ_make_prepare ("delete_contract_terms", - "DELETE FROM merchant_contract_terms" - " WHERE order_id=$2" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1)" - " AND ( ( (pay_deadline < $4) AND" - " (NOT paid) ) OR" - " (creation_time + $3 < $4) )"), /* for postgres_lookup_deposits() */ GNUNET_PQ_make_prepare ("lookup_deposits", "SELECT" @@ -8426,19 +6674,32 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) = &TMH_PG_update_product; plugin->lock_product = &TMH_PG_lock_product; - plugin->expire_locks = &postgres_expire_locks; - plugin->delete_order = &postgres_delete_order; - plugin->lookup_order = &postgres_lookup_order; - plugin->lookup_order_summary = &postgres_lookup_order_summary; - plugin->lookup_orders = &postgres_lookup_orders; - plugin->insert_order = &postgres_insert_order; - plugin->unlock_inventory = &postgres_unlock_inventory; - plugin->insert_order_lock = &postgres_insert_order_lock; - plugin->lookup_contract_terms = &postgres_lookup_contract_terms; - plugin->lookup_contract_terms2 = &postgres_lookup_contract_terms2; - plugin->insert_contract_terms = &postgres_insert_contract_terms; - plugin->update_contract_terms = &postgres_update_contract_terms; - plugin->delete_contract_terms = &postgres_delete_contract_terms; + plugin->expire_locks + = &TMH_PG_expire_locks; + plugin->delete_order + = &TMH_PG_delete_order; + plugin->lookup_order + = &TMH_PG_lookup_order; + plugin->lookup_order_summary + = &TMH_PG_lookup_order_summary; + plugin->lookup_orders + = &TMH_PG_lookup_orders; + plugin->insert_order + = &TMH_PG_insert_order; + plugin->unlock_inventory + = &TMH_PG_unlock_inventory; + plugin->insert_order_lock + = &TMH_PG_insert_order_lock; + plugin->lookup_contract_terms + = &TMH_PG_lookup_contract_terms; + plugin->lookup_contract_terms2 + = &TMH_PG_lookup_contract_terms2; + plugin->insert_contract_terms + = &TMH_PG_insert_contract_terms; + plugin->update_contract_terms + = &TMH_PG_update_contract_terms; + plugin->delete_contract_terms + = &TMH_PG_delete_contract_terms; plugin->lookup_deposits = &postgres_lookup_deposits; plugin->insert_exchange_signkey = &postgres_insert_exchange_signkey; plugin->insert_deposit = &postgres_insert_deposit; |