Botan 3.13.0
Crypto and TLS for C&
database.h
Go to the documentation of this file.
1/*
2* SQL database interface
3* (C) 2014,2026 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#ifndef BOTAN_SQL_DATABASE_H_
9#define BOTAN_SQL_DATABASE_H_
10
11#include <botan/exceptn.h>
12#include <botan/types.h>
13#include <chrono>
14#include <initializer_list>
15#include <memory>
16#include <optional>
17#include <span>
18#include <string>
19#include <vector>
20
21namespace Botan {
22
23/**
24* Abstract interface to a SQL database
25*/
26class BOTAN_PUBLIC_API(2, 0) SQL_Database /* NOLINT(*-special-member-functions) */ {
27 public:
28 /**
29 * An error occurred while interacting with the database
30 */
31 class BOTAN_PUBLIC_API(2, 0) SQL_DB_Error final : public Exception {
32 public:
33 /**
34 * Create a SQL_DB_Error
35 * @param what a description of the failure
36 */
37 explicit SQL_DB_Error(std::string_view what) : Exception("SQL database", what), m_rc(0) {}
38
39 /**
40 * Create a SQL_DB_Error
41 * @param what a description of the failure
42 * @param rc the database specific result code
43 */
44 SQL_DB_Error(std::string_view what, int rc) : Exception("SQL database", what), m_rc(rc) {}
45
46 /**
47 * Return the error type of this exception
48 * @return the error type of this exception
49 */
50 ErrorType error_type() const noexcept override { return ErrorType::DatabaseError; }
51
52 /**
53 * Return the database specific result code
54 * @return the result code passed at construction, or 0
55 */
56 int error_code() const noexcept override { return m_rc; }
57
58 private:
59 int m_rc;
60 };
61
62 /**
63 * A prepared SQL statement
64 */
65 class BOTAN_PUBLIC_API(2, 0) Statement /* NOLINT(*-special-member-functions) */ {
66 public:
67 /**
68 * Bind a string to a statement parameter
69 * @param column the 1-based index of the parameter
70 * @param str the value to bind
71 */
72 virtual void bind(int column, std::string_view str) = 0;
73
74 /**
75 * Bind an integer to a statement parameter
76 * @param column the 1-based index of the parameter
77 * @param i the value to bind
78 */
79 virtual void bind(int column, size_t i) = 0;
80
81 /**
82 * Bind a timestamp to a statement parameter
83 * @param column the 1-based index of the parameter
84 * @param time the value to bind
85 */
86 virtual void bind(int column, std::chrono::system_clock::time_point time) = 0;
87
88 /**
89 * Bind a blob to a statement parameter
90 * @param column the 1-based index of the parameter
91 * @param blob the value to bind
92 */
93 virtual void bind(int column, const std::vector<uint8_t>& blob) = 0;
94
95 /**
96 * Bind a blob to a statement parameter
97 * @param column the 1-based index of the parameter
98 * @param data the value to bind
99 * @param len length of data in bytes
100 */
101 virtual void bind(int column, const uint8_t* data, size_t len) = 0;
102
103 /**
104 * Bind SQL NULL to a statement parameter
105 * @param column the 1-based index of the parameter
106 */
107 virtual void bind_null(int column) = 0;
108
109 /**
110 * Read a blob from the current result row
111 * @param column the 0-based index of the column
112 * @return the blob value, valid until the next call to step
113 */
114 virtual std::span<const uint8_t> get_blob(int column) = 0;
115
116 /**
117 * Read a string from the current result row
118 * @param column the 0-based index of the column
119 * @return the string value, or nullopt if the column value was NULL
120 */
121 virtual std::optional<std::string> get_str(int column) = 0;
122
123 /**
124 * Read an integer from the current result row
125 * @param column the 0-based index of the column
126 * @return the integer value
127 */
128 virtual size_t get_size_t(int column) = 0;
129
130 /**
131 * Run the statement to completion
132 * @return the number of result rows which were stepped over
133 */
134 virtual size_t spin() = 0;
135
136 /**
137 * Advance to the next result row
138 * @return true if a row is available, false once the results are exhausted
139 */
140 virtual bool step() = 0;
141
142 virtual ~Statement() = default;
143 };
144
145 /**
146 * Create a new statement for execution.
147 * Use ?1, ?2, ?3, etc for parameters to set later with bind
148 *
149 * @param base_sql the SQL text of the statement
150 * @return the prepared statement
151 */
152 virtual std::shared_ptr<Statement> new_statement(std::string_view base_sql) const = 0;
153
154 /**
155 * Prepare a "SELECT <columns> FROM <table> [WHERE <where>] [LIMIT <limit>]"
156 * statement. `where` is the body of the WHERE clause (e.g.
157 * "id = ?1 AND name = ?2"); pass an empty string for no WHERE clause. Use
158 * ?1, ?2, ... for bound parameters. Virtual so backends can override if helpful.
159 *
160 * @param columns the columns to select
161 * @param table the table to select from
162 * @param where the body of the WHERE clause, or empty for no WHERE clause
163 * @param limit the maximum number of rows, or nullopt for no limit
164 * @return the prepared statement
165 */
166 virtual std::shared_ptr<Statement> select(std::string_view columns,
167 std::string_view table,
168 std::string_view where = {},
169 std::optional<size_t> limit = std::nullopt) const;
170
171 /**
172 * Prepare an upsert (insert-or-replace) statement for the given columns of
173 * the given table. The returned statement expects placeholders ?1..?N
174 * bound in the order the columns were given. The list must include every
175 * column of the table's primary key; backends that need the key/value
176 * distinction (e.g. Postgres ON CONFLICT) derive it by introspecting the
177 * schema.
178 *
179 * @param table the table to upsert into
180 * @param columns the columns to write, in placeholder order
181 * @return the prepared statement
182 */
183 virtual std::shared_ptr<Statement> upsert(std::string_view table,
184 std::initializer_list<std::string_view> columns) const = 0;
185
186 /**
187 * Count the rows of a table
188 * @param table_name the table to count
189 * @return the number of rows in the table
190 */
191 virtual size_t row_count(std::string_view table_name) = 0;
192
193 /**
194 * The supported column types
195 */
196 enum class Column_Type : uint8_t {
197 Blob,
198 String,
200 };
201
202 /**
203 * The name, type and constraints of one column of a table
204 */
205 class Column {
206 public:
207 /**
208 * Declare a column
209 * @param name the name of the column
210 * @param type the type of the column
211 */
212 Column(std::string name, Column_Type type) : m_name(std::move(name)), m_type(type) {}
213
214 /**
215 * Mark this column as part of the primary key
216 * @return reference to this
217 */
219 m_primary_key = true;
220 return *this;
221 }
222
223 /**
224 * Mark this column as NOT NULL
225 * @return reference to this
226 */
228 m_not_null = true;
229 return *this;
230 }
231
232 /**
233 * Mark this column as UNIQUE
234 * @return reference to this
235 */
237 m_unique = true;
238 return *this;
239 }
240
241 /**
242 * Query the column name
243 * @return the name of the column
244 */
245 const std::string& name() const { return m_name; }
246
247 /**
248 * Query the column type
249 * @return the type of the column
250 */
251 Column_Type type() const { return m_type; }
252
253 /**
254 * Query whether this column is part of the primary key
255 * @return true if primary_key was called
256 */
257 bool is_primary_key() const { return m_primary_key; }
258
259 /**
260 * Query whether this column is NOT NULL
261 * @return true if not_null was called
262 */
263 bool is_not_null() const { return m_not_null; }
264
265 /**
266 * Query whether this column is UNIQUE
267 * @return true if unique was called
268 */
269 bool is_unique() const { return m_unique; }
270
271 private:
272 std::string m_name;
273 Column_Type m_type;
274 bool m_primary_key = false;
275 bool m_not_null = false;
276 bool m_unique = false;
277 };
278
279 /**
280 * The name and columns of a table, used with create_table
281 */
283 public:
284 /**
285 * Declare a table
286 * @param name the name of the table
287 * @param columns the columns of the table
288 */
289 Table_Schema(std::string name, std::vector<Column> columns) :
290 m_name(std::move(name)), m_columns(std::move(columns)) {}
291
292 /**
293 * Only create the table if it does not already exist
294 * @return reference to this
295 */
297 m_if_not_exists = true;
298 return *this;
299 }
300
301 /**
302 * Query the table name
303 * @return the name of the table
304 */
305 const std::string& name() const { return m_name; }
306
307 /**
308 * Query the columns of the table
309 * @return the columns of the table
310 */
311 const std::vector<Column>& columns() const { return m_columns; }
312
313 /**
314 * Query whether creation is conditional
315 * @return true if if_not_exists was called
316 */
317 bool is_if_not_exists() const { return m_if_not_exists; }
318
319 private:
320 std::string m_name;
321 std::vector<Column> m_columns;
322 bool m_if_not_exists = false;
323 };
324
325 /**
326 * Create a table
327 * @param schema the name and columns of the table to create
328 */
329 virtual void create_table(const Table_Schema& schema) = 0;
330
331 /**
332 * Count the rows modified by the most recently executed statement
333 * @return the number of rows inserted, updated or deleted
334 */
335 virtual size_t rows_changed_by_last_statement() = 0;
336
337 /**
338 * Prepare and run a statement to completion
339 * @param sql the SQL text to execute
340 * @return the number of result rows which were stepped over
341 */
342 virtual size_t exec(std::string_view sql) { return new_statement(sql)->spin(); }
343
344 /**
345 * Query whether this database may be used from multiple threads
346 * @return true if the implementation is threadsafe
347 */
348 virtual bool is_threadsafe() const { return false; }
349
350 /**
351 * Return true if the given name seems to be valid as the name for a table
352 *
353 * Default implementation accepts non-empty [a-zA-Z0-9_]
354 *
355 * @param table the name to check
356 * @return true if the name is acceptable as a table name
357 */
358 virtual bool is_valid_table_name(std::string_view table) const;
359
360 virtual ~SQL_Database() = default;
361};
362
363} // namespace Botan
364
365#endif
#define BOTAN_PUBLIC_API(maj, min)
Definition api.h:21
const char * what() const noexcept override
Definition exceptn.h:94
Exception(std::string_view msg)
Definition exceptn.cpp:71
bool is_primary_key() const
Definition database.h:257
Column(std::string name, Column_Type type)
Definition database.h:212
Column_Type type() const
Definition database.h:251
const std::string & name() const
Definition database.h:245
SQL_DB_Error(std::string_view what, int rc)
Definition database.h:44
ErrorType error_type() const noexcept override
Definition database.h:50
int error_code() const noexcept override
Definition database.h:56
SQL_DB_Error(std::string_view what)
Definition database.h:37
virtual ~Statement()=default
virtual std::optional< std::string > get_str(int column)=0
virtual void bind_null(int column)=0
virtual void bind(int column, size_t i)=0
virtual void bind(int column, std::chrono::system_clock::time_point time)=0
virtual void bind(int column, const uint8_t *data, size_t len)=0
virtual void bind(int column, const std::vector< uint8_t > &blob)=0
virtual std::span< const uint8_t > get_blob(int column)=0
virtual void bind(int column, std::string_view str)=0
virtual size_t get_size_t(int column)=0
Table_Schema(std::string name, std::vector< Column > columns)
Definition database.h:289
const std::string & name() const
Definition database.h:305
const std::vector< Column > & columns() const
Definition database.h:311
virtual std::shared_ptr< Statement > new_statement(std::string_view base_sql) const =0
virtual bool is_threadsafe() const
Definition database.h:348
virtual std::shared_ptr< Statement > upsert(std::string_view table, std::initializer_list< std::string_view > columns) const =0
virtual size_t exec(std::string_view sql)
Definition database.h:342
virtual void create_table(const Table_Schema &schema)=0
virtual size_t rows_changed_by_last_statement()=0
virtual size_t row_count(std::string_view table_name)=0
virtual std::shared_ptr< Statement > select(std::string_view columns, std::string_view table, std::string_view where={}, std::optional< size_t > limit=std::nullopt) const
Definition database.cpp:28
virtual ~SQL_Database()=default
ErrorType
Definition exceptn.h:21