Line data Source code
1 : /*
2 : This file is part of Challenger
3 : Copyright (C) 2024 Taler Systems SA
4 :
5 : Challenger is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : Challenger is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : Challenger; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file src/challengerdb/update_client.c
18 : * @brief Implementation of the update_client function for Postgres
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <taler/taler_error_codes.h>
23 : #include <taler/taler_dbevents.h>
24 : #include <taler/taler_pq_lib.h>
25 : #include "update_client.h"
26 : #include "pg_helper.h"
27 :
28 : enum GNUNET_DB_QueryStatus
29 4 : CHALLENGERDB_update_client (struct CHALLENGERDB_PostgresContext *ctx,
30 : uint64_t client_id,
31 : const char *client_redirect_uri,
32 : const char *client_secret,
33 : bool *uri_conflict)
34 : {
35 4 : struct GNUNET_PQ_QueryParam params[] = {
36 4 : GNUNET_PQ_query_param_uint64 (&client_id),
37 4 : GNUNET_PQ_query_param_string (client_redirect_uri),
38 : NULL == client_secret
39 4 : ? GNUNET_PQ_query_param_null ()
40 4 : : GNUNET_PQ_query_param_string (client_secret),
41 : GNUNET_PQ_query_param_end
42 : };
43 : bool updated;
44 : bool conflict;
45 4 : struct GNUNET_PQ_ResultSpec rs[] = {
46 4 : GNUNET_PQ_result_spec_bool ("updated",
47 : &updated),
48 4 : GNUNET_PQ_result_spec_bool ("uri_conflict",
49 : &conflict),
50 : GNUNET_PQ_result_spec_end
51 : };
52 : enum GNUNET_DB_QueryStatus qs;
53 :
54 4 : *uri_conflict = false;
55 : /* "No rows updated" has two very different causes here: the client does
56 : not exist, or another client already uses @a client_redirect_uri (which
57 : violates clients_uri_key, and GNUnet maps a unique violation to
58 : NO_RESULTS -- indistinguishable from "not found" at the API). So detect
59 : the collision ourselves and refuse the UPDATE in that case, and report
60 : which of the two happened. */
61 4 : PREPARE (ctx,
62 : "update_client",
63 : "WITH target AS ("
64 : " SELECT client_serial_id"
65 : " FROM clients"
66 : " WHERE client_serial_id=$1"
67 : "), taken AS ("
68 : " SELECT client_serial_id"
69 : " FROM clients"
70 : " WHERE uri=$2"
71 : " AND client_serial_id<>$1"
72 : "), upd AS ("
73 : " UPDATE clients"
74 : " SET uri=$2"
75 : " ,client_secret=COALESCE($3,client_secret)"
76 : " WHERE client_serial_id=$1"
77 : " AND NOT EXISTS (SELECT 1 FROM taken)"
78 : " RETURNING client_serial_id"
79 : ") SELECT"
80 : " EXISTS (SELECT 1 FROM upd) AS updated"
81 : " ,( EXISTS (SELECT 1 FROM target)"
82 : " AND EXISTS (SELECT 1 FROM taken) ) AS uri_conflict;");
83 4 : qs = GNUNET_PQ_eval_prepared_singleton_select (ctx->conn,
84 : "update_client",
85 : params,
86 : rs);
87 4 : if (0 > qs)
88 0 : return qs;
89 4 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
90 : {
91 : /* Our SELECT always yields exactly one row, so zero rows can only be a
92 : unique violation on clients.uri: another transaction inserted the URI
93 : after our snapshot was taken. */
94 0 : *uri_conflict = true;
95 0 : return qs;
96 : }
97 4 : *uri_conflict = conflict;
98 : return updated
99 : ? GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
100 4 : : GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
101 : }
|