Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Statement.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2023, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "data/cassandra/Types.hpp"
23#include "data/cassandra/impl/Collection.hpp"
24#include "data/cassandra/impl/ManagedObject.hpp"
25#include "data/cassandra/impl/Tuple.hpp"
26#include "util/UnsupportedType.hpp"
27
28#include <cassandra.h>
29#include <fmt/core.h>
30#include <xrpl/basics/base_uint.h>
31#include <xrpl/protocol/AccountID.h>
32#include <xrpl/protocol/STAccount.h>
33
34#include <cstddef>
35#include <cstdint>
36#include <stdexcept>
37#include <string>
38#include <string_view>
39#include <tuple>
40#include <type_traits>
41#include <vector>
42
43namespace data::cassandra::impl {
44
45class Statement : public ManagedObject<CassStatement> {
46 static constexpr auto kDELETER = [](CassStatement* ptr) { cass_statement_free(ptr); };
47
48public:
55 template <typename... Args>
56 explicit Statement(std::string_view query, Args&&... args)
57 : ManagedObject{cass_statement_new_n(query.data(), query.size(), sizeof...(args)), kDELETER}
58 {
59 cass_statement_set_consistency(*this, CASS_CONSISTENCY_QUORUM);
60 cass_statement_set_is_idempotent(*this, cass_true);
61 bind<Args...>(std::forward<Args>(args)...);
62 }
63
64 /* implicit */ Statement(CassStatement* ptr) : ManagedObject{ptr, kDELETER}
65 {
66 cass_statement_set_consistency(*this, CASS_CONSISTENCY_QUORUM);
67 cass_statement_set_is_idempotent(*this, cass_true);
68 }
69
75 template <typename... Args>
76 void
77 bind(Args&&... args) const
78 {
79 std::size_t idx = 0; // NOLINT(misc-const-correctness)
80 (this->bindAt<Args>(idx++, std::forward<Args>(args)), ...);
81 }
82
89 template <typename Type>
90 void
91 bindAt(std::size_t const idx, Type&& value) const
92 {
93 using std::to_string;
94 auto throwErrorIfNeeded = [idx](CassError rc, std::string_view label) {
95 if (rc != CASS_OK)
96 throw std::logic_error(fmt::format("[{}] at idx {}: {}", label, idx, cass_error_desc(rc)));
97 };
98
99 auto bindBytes = [this, idx](auto const* data, size_t size) {
100 return cass_statement_bind_bytes(*this, idx, static_cast<cass_byte_t const*>(data), size);
101 };
102
103 using DecayedType = std::decay_t<Type>;
104 using UCharVectorType = std::vector<unsigned char>;
105 using UintTupleType = std::tuple<uint32_t, uint32_t>;
106 using UintByteTupleType = std::tuple<uint32_t, ripple::uint256>;
107 using ByteVectorType = std::vector<ripple::uint256>;
108
109 if constexpr (std::is_same_v<DecayedType, ripple::uint256> || std::is_same_v<DecayedType, ripple::uint192>) {
110 auto const rc = bindBytes(value.data(), value.size());
111 throwErrorIfNeeded(rc, "Bind ripple::base_uint");
112 } else if constexpr (std::is_same_v<DecayedType, ripple::AccountID>) {
113 auto const rc = bindBytes(value.data(), value.size());
114 throwErrorIfNeeded(rc, "Bind ripple::AccountID");
115 } else if constexpr (std::is_same_v<DecayedType, UCharVectorType>) {
116 auto const rc = bindBytes(value.data(), value.size());
117 throwErrorIfNeeded(rc, "Bind vector<unsigned char>");
118 } else if constexpr (std::is_convertible_v<DecayedType, std::string>) {
119 // reinterpret_cast is needed here :'(
120 auto const rc = bindBytes(reinterpret_cast<unsigned char const*>(value.data()), value.size());
121 throwErrorIfNeeded(rc, "Bind string (as bytes)");
122 } else if constexpr (std::is_convertible_v<DecayedType, Text>) {
123 auto const rc = cass_statement_bind_string_n(*this, idx, value.text.c_str(), value.text.size());
124 throwErrorIfNeeded(rc, "Bind string (as TEXT)");
125 } else if constexpr (std::is_same_v<DecayedType, UintTupleType> ||
126 std::is_same_v<DecayedType, UintByteTupleType>) {
127 auto const rc = cass_statement_bind_tuple(*this, idx, Tuple{std::forward<Type>(value)});
128 throwErrorIfNeeded(rc, "Bind tuple<uint32, uint32> or <uint32_t, ripple::uint256>");
129 } else if constexpr (std::is_same_v<DecayedType, ByteVectorType>) {
130 auto const rc = cass_statement_bind_collection(*this, idx, Collection{std::forward<Type>(value)});
131 throwErrorIfNeeded(rc, "Bind collection");
132 } else if constexpr (std::is_same_v<DecayedType, bool>) {
133 auto const rc = cass_statement_bind_bool(*this, idx, value ? cass_true : cass_false);
134 throwErrorIfNeeded(rc, "Bind bool");
135 } else if constexpr (std::is_same_v<DecayedType, Limit>) {
136 auto const rc = cass_statement_bind_int32(*this, idx, value.limit);
137 throwErrorIfNeeded(rc, "Bind limit (int32)");
138 }
139 // clio only uses bigint (int64_t) so we convert any incoming type
140 else if constexpr (std::is_convertible_v<DecayedType, int64_t>) {
141 auto const rc = cass_statement_bind_int64(*this, idx, value);
142 throwErrorIfNeeded(rc, "Bind int64");
143 } else {
144 // type not supported for binding
145 static_assert(util::Unsupported<DecayedType>);
146 }
147 }
148};
149
155class PreparedStatement : public ManagedObject<CassPrepared const> {
156 static constexpr auto kDELETER = [](CassPrepared const* ptr) { cass_prepared_free(ptr); };
157
158public:
159 /* implicit */ PreparedStatement(CassPrepared const* ptr) : ManagedObject{ptr, kDELETER}
160 {
161 }
162
169 template <typename... Args>
171 bind(Args&&... args) const
172 {
173 Statement statement = cass_prepared_bind(*this);
174 statement.bind<Args...>(std::forward<Args>(args)...);
175 return statement;
176 }
177};
178
179} // namespace data::cassandra::impl
Definition Collection.hpp:35
Definition ManagedObject.hpp:28
Represents a prepared statement on the DB side.
Definition Statement.hpp:155
Statement bind(Args &&... args) const
Bind the given arguments and produce a ready to execute Statement.
Definition Statement.hpp:171
Definition Statement.hpp:45
Statement(std::string_view query, Args &&... args)
Construct a new statement with optionally provided arguments.
Definition Statement.hpp:56
void bind(Args &&... args) const
Binds the given arguments to the statement.
Definition Statement.hpp:77
void bindAt(std::size_t const idx, Type &&value) const
Binds an argument to a specific index.
Definition Statement.hpp:91
Definition Tuple.hpp:39
This namespace implements the data access layer and related components.
Definition AmendmentCenter.cpp:70
static constexpr bool Unsupported
used for compile time checking of unsupported types
Definition UnsupportedType.hpp:26