diff options
Diffstat (limited to 'src/backenddb/plugin_merchantdb_postgres.c')
-rw-r--r-- | src/backenddb/plugin_merchantdb_postgres.c | 548 |
1 files changed, 422 insertions, 126 deletions
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index 8e402d31..8c1646a7 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -3457,6 +3457,219 @@ postgres_lookup_transfer_details ( } +/** + * Closure for #lookup_transfers_cb(). + */ +struct LookupTransfersContext +{ + /** + * Function to call on results. + */ + TALER_MERCHANTDB_TransferCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Postgres context. + */ + struct PostgresClosure *pg; + + /** + * Transaction status (set). + */ + enum GNUNET_DB_QueryStatus qs; + + /** + * Filter to apply by verification status. + */ + enum TALER_MERCHANTDB_YesNoAll verified; +}; + + +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls of type `struct LookupTransfersContext *` + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +lookup_transfers_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LookupTransfersContext *ltc = cls; + struct PostgresClosure *pg = ltc->pg; + + for (unsigned int i = 0; i<num_results; i++) + { + struct TALER_Amount credit_amount; + struct TALER_WireTransferIdentifierRawP wtid; + char *payto_uri; + char *exchange_url; + uint64_t transfer_serial_id; + struct GNUNET_TIME_Absolute execution_time; + enum TALER_MERCHANTDB_YesNoAll verified; + uint8_t verified8; + uint8_t confirmed8; + struct GNUNET_PQ_ResultSpec rs[] = { + TALER_PQ_RESULT_SPEC_AMOUNT ("credit_amount", + &credit_amount), + GNUNET_PQ_result_spec_auto_from_type ("wtid", + &wtid), + GNUNET_PQ_result_spec_string ("payto_uri", + &payto_uri), + GNUNET_PQ_result_spec_string ("exchange_url", + &exchange_url), + GNUNET_PQ_result_spec_uint64 ("credit_serial", + &transfer_serial_id), + GNUNET_PQ_result_spec_absolute_time ("execution_time", + &execution_time), + GNUNET_PQ_result_spec_auto_from_type ("verified", + &verified8), + GNUNET_PQ_result_spec_auto_from_type ("confirmed", + &confirmed8), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ltc->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } + if (0 == verified8) + verified = TALER_MERCHANTDB_YNA_NO; + else + verified = TALER_MERCHANTDB_YNA_YES; + if ( (ltc->verified == TALER_MERCHANTDB_YNA_ALL) || + (ltc->verified == verified) ) + { + ltc->qs = i + 1; + ltc->cb (ltc->cb_cls, + &credit_amount, + &wtid, + payto_uri, + exchange_url, + transfer_serial_id, + execution_time, + TALER_MERCHANTDB_YNA_YES == verified, + 0 != confirmed8); + } + GNUNET_PQ_cleanup_result (rs); + } +} + + +/** + * Lookup transfers. Note that filtering by @a verified status is done + * outside of SQL, as we already have 8 prepared statements and adding + * a filter on verified would further double the number of statements for + * a likely rather ineffective filter. So we apply that filter in + * #lookup_transfers_cb(). + * + * @param cls closure + * @param instance_id instance to lookup payments for + * @param payto_uri account that we are interested in transfers to + * @param before timestamp for the earliest transfer we care about + * @param after timestamp for the last transfer we care about + * @param limit number of entries to return, negative for descending in execution time, + * positive for ascending in execution time + * @param offset transfer_serial number of the transfer we want to offset from + * @param verified filter transfers by verification status + * @param cb function to call with detailed transfer data + * @param cb_cls closure for @a cb + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_lookup_transfers (void *cls, + const char *instance_id, + const char *payto_uri, + struct GNUNET_TIME_Absolute before, + struct GNUNET_TIME_Absolute after, + int64_t limit, + uint64_t offset, + enum TALER_MERCHANTDB_YesNoAll verified, + TALER_MERCHANTDB_TransferCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + uint64_t plimit = (uint64_t) ((limit < 0) ? -limit : limit); + struct GNUNET_PQ_QueryParam params_payto_et[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_absolute_time (&before), + GNUNET_PQ_query_param_absolute_time (&after), + GNUNET_PQ_query_param_uint64 (&offset), + GNUNET_PQ_query_param_uint64 (&plimit), + GNUNET_PQ_query_param_string (payto_uri), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_QueryParam params_et[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_absolute_time (&before), + GNUNET_PQ_query_param_absolute_time (&after), + GNUNET_PQ_query_param_uint64 (&offset), + GNUNET_PQ_query_param_uint64 (&plimit), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_QueryParam params_payto[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_uint64 (&offset), + GNUNET_PQ_query_param_uint64 (&plimit), + GNUNET_PQ_query_param_string (payto_uri), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_QueryParam params_none[] = { + GNUNET_PQ_query_param_string (instance_id), + GNUNET_PQ_query_param_uint64 (&offset), + GNUNET_PQ_query_param_uint64 (&plimit), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_QueryParam *params; + struct LookupTransfersContext ltc = { + .cb = cb, + .cb_cls = cb_cls, + .pg = pg, + .verified = verified + }; + enum GNUNET_DB_QueryStatus qs; + char stmt[128]; + bool by_time; + + by_time = ( (before.abs_value_us != + GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) || + (after.abs_value_us != GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us) ); + + check_connection (pg); + GNUNET_snprintf (stmt, + sizeof (stmt), + "lookup_transfers%s%s%s", + (by_time) ? "_time" : "", + (NULL != payto_uri) ? "_payto" : "", + (limit > 0) ? "_asc" : "_desc"); + params = (by_time) + ? ( (NULL != payto_uri) ? params_payto_et : params_et) + : ( (NULL != payto_uri) ? params_payto : params_none); + + // FIXME: write SQL (_desc-variant!) + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + stmt, + params, + &lookup_transfers_cb, + <c); + if (0 >= qs) + return qs; + return ltc.qs; +} + + /* ********************* OLD API ************************** */ /** @@ -3672,131 +3885,6 @@ postgres_get_authorized_tip_amount (void *cls, /** - * Closure for #find_transfers_cb(). - */ -struct FindTransfersContext -{ - /** - * Function to call on results. - */ - TALER_MERCHANTDB_TransferCallback cb; - - /** - * Closure for @e cb. - */ - void *cb_cls; - - /** - * Hash of the contract we are looking under. - */ - const struct GNUNET_HashCode *h_contract_terms; - - /** - * Transaction status (set). - */ - enum GNUNET_DB_QueryStatus qs; -}; - - -/** - * Function to be called with the results of a SELECT statement - * that has returned @a num_results results. - * - * @param cls of type `struct FindTransfersContext *` - * @param result the postgres result - * @param num_result the number of results in @a result - */ -static void -find_transfers_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct FindTransfersContext *ftc = cls; - - for (unsigned int i = 0; i<num_results; i++) - { - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_WireTransferIdentifierRawP wtid; - struct GNUNET_TIME_Absolute execution_time; - json_t *proof; - - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("coin_pub", - &coin_pub), - GNUNET_PQ_result_spec_auto_from_type ("wtid", - &wtid), - GNUNET_PQ_result_spec_absolute_time ("execution_time", - &execution_time), - TALER_PQ_result_spec_json ("proof", - &proof), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - ftc->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } - ftc->qs = i + 1; - ftc->cb (ftc->cb_cls, - ftc->h_contract_terms, - &coin_pub, - &wtid, - execution_time, - proof); - GNUNET_PQ_cleanup_result (rs); - } -} - - -/** - * Lookup information about a transfer by @a h_contract_terms. Note - * that in theory there could be multiple wire transfers for a - * single @a h_contract_terms, as the transaction may have involved - * multiple coins and the coins may be spread over different wire - * transfers. - * - * @param cls closure - * @param h_contract_terms key for the search - * @param cb function to call with transfer data - * @param cb_cls closure for @a cb - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_find_transfers_by_hash (void *cls, - const struct GNUNET_HashCode *h_contract_terms, - TALER_MERCHANTDB_TransferCallback cb, - void *cb_cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (h_contract_terms), - GNUNET_PQ_query_param_end - }; - struct FindTransfersContext ftc = { - .h_contract_terms = h_contract_terms, - .cb = cb, - .cb_cls = cb_cls - }; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "find_transfers_by_hash", - params, - &find_transfers_cb, - &ftc); - if (0 >= qs) - return qs; - return ftc.qs; -} - - -/** * Store information about wire fees charged by an exchange, * including signature (so we have proof). * @@ -6007,6 +6095,214 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " WHERE merchant_transfers.wtid=$2" " AND merchant_transfers.exchange_url=$1", 2), + /* for postgres_lookup_transfers() */ + GNUNET_PQ_make_prepare ("lookup_transfers_time_payto_asc", + "SELECT" + " credit_amount_val" + ",credit_amount_frac" + ",wtid" + ",merchant_accounts.payto_uri" + ",exchange_url" + ",credit_serial" + ",merchant_transfer_signatures.execution_time" + ",verified" + ",confirmed" + " FROM merchant_transfers" + " JOIN merchant_accounts USING (account_serial)" + " JOIN merchant_transfer_signatures USING (credit_serial)" + " WHERE execution_time < $2" + " AND execution_time >= $3" + " AND credit_serial > $4" + " AND payto_uri = $6" + " AND merchant_serial =" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " ORDER BY credit_serial ASC" + " LIMIT $5", + 6), + /* for postgres_lookup_transfers() */ + GNUNET_PQ_make_prepare ("lookup_transfers_time_asc", + "SELECT" + " credit_amount_val" + ",credit_amount_frac" + ",wtid" + ",merchant_accounts.payto_uri" + ",exchange_url" + ",credit_serial" + ",merchant_transfer_signatures.execution_time" + ",verified" + ",confirmed" + " FROM merchant_transfers" + " JOIN merchant_accounts USING (account_serial)" + " JOIN merchant_transfer_signatures USING (credit_serial)" + " WHERE execution_time < $2" + " AND execution_time >= $3" + " AND credit_serial > $4" + " AND merchant_serial =" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " ORDER BY credit_serial ASC" + " LIMIT $5", + 5), + /* for postgres_lookup_transfers() */ + GNUNET_PQ_make_prepare ("lookup_transfers_payto_asc", + "SELECT" + " credit_amount_val" + ",credit_amount_frac" + ",wtid" + ",merchant_accounts.payto_uri" + ",exchange_url" + ",credit_serial" + ",CASE WHEN (merchant_transfer_signatures.execution_time) IS NULL" + " THEN 9223372036854775807" /* largest BIGINT possible */ + " ELSE merchant_transfer_signatures.execution_time" + " END AS execution_time" + ",verified" + ",confirmed" + " FROM merchant_transfers" + " JOIN merchant_accounts USING (account_serial)" + " LEFT JOIN merchant_transfer_signatures USING (credit_serial)" + " WHERE credit_serial > $2" + " AND payto_uri = $4" + " AND merchant_serial =" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " ORDER BY credit_serial ASC" + " LIMIT $3", + 4), + /* for postgres_lookup_transfers() */ + GNUNET_PQ_make_prepare ("lookup_transfers_asc", + "SELECT" + " credit_amount_val" + ",credit_amount_frac" + ",wtid" + ",merchant_accounts.payto_uri" + ",exchange_url" + ",credit_serial" + ",CASE WHEN (merchant_transfer_signatures.execution_time) IS NULL" + " THEN 9223372036854775807" /* largest BIGINT possible */ + " ELSE merchant_transfer_signatures.execution_time" + " END AS execution_time" + ",verified" + ",confirmed" + " FROM merchant_transfers" + " JOIN merchant_accounts USING (account_serial)" + " LEFT JOIN merchant_transfer_signatures USING (credit_serial)" + " WHERE credit_serial > $2" + " AND merchant_serial =" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " ORDER BY credit_serial ASC" + " LIMIT $3", + 3), + /* for postgres_lookup_transfers() */ + GNUNET_PQ_make_prepare ("lookup_transfers_time_payto_desc", + "SELECT" + " credit_amount_val" + ",credit_amount_frac" + ",wtid" + ",merchant_accounts.payto_uri" + ",exchange_url" + ",credit_serial" + ",merchant_transfer_signatures.execution_time" + ",verified" + ",confirmed" + " FROM merchant_transfers" + " JOIN merchant_accounts USING (account_serial)" + " JOIN merchant_transfer_signatures USING (credit_serial)" + " WHERE execution_time < $2" + " AND execution_time >= $3" + " AND credit_serial < $4" + " AND payto_uri = $6" + " AND merchant_serial =" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " ORDER BY credit_serial DESC" + " LIMIT $5", + 6), + /* for postgres_lookup_transfers() */ + GNUNET_PQ_make_prepare ("lookup_transfers_time_desc", + "SELECT" + " credit_amount_val" + ",credit_amount_frac" + ",wtid" + ",merchant_accounts.payto_uri" + ",exchange_url" + ",credit_serial" + ",merchant_transfer_signatures.execution_time" + ",verified" + ",confirmed" + " FROM merchant_transfers" + " JOIN merchant_accounts USING (account_serial)" + " JOIN merchant_transfer_signatures USING (credit_serial)" + " WHERE execution_time < $2" + " AND execution_time >= $3" + " AND credit_serial < $4" + " AND merchant_serial =" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " ORDER BY credit_serial DESC" + " LIMIT $5", + 5), + /* for postgres_lookup_transfers() */ + GNUNET_PQ_make_prepare ("lookup_transfers_payto_desc", + "SELECT" + " credit_amount_val" + ",credit_amount_frac" + ",wtid" + ",merchant_accounts.payto_uri" + ",exchange_url" + ",credit_serial" + ",CASE WHEN (merchant_transfer_signatures.execution_time) IS NULL" + " THEN 9223372036854775807" /* largest BIGINT possible */ + " ELSE merchant_transfer_signatures.execution_time" + " END AS execution_time" + ",verified" + ",confirmed" + " FROM merchant_transfers" + " JOIN merchant_accounts USING (account_serial)" + " LEFT JOIN merchant_transfer_signatures USING (credit_serial)" + " WHERE credit_serial < $2" + " AND payto_uri = $4" + " AND merchant_serial =" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " ORDER BY credit_serial DESC" + " LIMIT $3", + 4), + /* for postgres_lookup_transfers() */ + GNUNET_PQ_make_prepare ("lookup_transfers_desc", + "SELECT" + " credit_amount_val" + ",credit_amount_frac" + ",wtid" + ",merchant_accounts.payto_uri" + ",exchange_url" + ",credit_serial" + ",CASE WHEN (merchant_transfer_signatures.execution_time) IS NULL" + " THEN 9223372036854775807" /* largest BIGINT possible */ + " ELSE merchant_transfer_signatures.execution_time" + " END AS execution_time" + ",verified" + ",confirmed" + " FROM merchant_transfers" + " JOIN merchant_accounts USING (account_serial)" + " LEFT JOIN merchant_transfer_signatures USING (credit_serial)" + " WHERE credit_serial < $2" + " AND merchant_serial =" + " (SELECT merchant_serial" + " FROM merchant_instances" + " WHERE merchant_id=$1)" + " ORDER BY credit_serial DESC" + " LIMIT $3", + 3), /* OLD API: */ #if 0 @@ -6333,12 +6629,12 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) &postgres_set_transfer_status_to_verified; plugin->lookup_transfer_summary = &postgres_lookup_transfer_summary; plugin->lookup_transfer_details = &postgres_lookup_transfer_details; + plugin->lookup_transfers = &postgres_lookup_transfers; /* OLD API: */ plugin->store_coin_to_transfer = &postgres_store_coin_to_transfer; plugin->store_transfer_to_proof = &postgres_store_transfer_to_proof; plugin->store_wire_fee_by_exchange = &postgres_store_wire_fee_by_exchange; - plugin->find_transfers_by_hash = &postgres_find_transfers_by_hash; plugin->find_proof_by_wtid = &postgres_find_proof_by_wtid; plugin->get_authorized_tip_amount = &postgres_get_authorized_tip_amount; plugin->enable_tip_reserve_TR = &postgres_enable_tip_reserve_TR; |