SQLon test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 9 / 0 / 9
Functions: 100.0% 4 / 0 / 4
Branches: -% 0 / 0 / 0

include/sqlon/sql_options.h
Line Branch Exec Source
1 /******************************************************************************
2 **
3 ** Copyright (C) 2026 Ivan Pinezhaninov <ivan.pinezhaninov@gmail.com>
4 **
5 ** This file is part of the SQLon - which can be found at
6 ** https://github.com/IvanPinezhaninov/sqlon/.
7 **
8 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
11 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
12 ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
13 ** OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
14 ** THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 **
16 ******************************************************************************/
17
18 #ifndef SQLON_SQL_OPTIONS_H
19 #define SQLON_SQL_OPTIONS_H
20
21 #include <sqlon/export.h>
22
23 #include <cstdint>
24 #include <optional>
25 #include <string>
26 #include <vector>
27
28 namespace sqlon {
29
30 /** @brief Parameter placeholder syntax. */
31 enum class placeholder_style : std::uint8_t {
32 question_mark, ///< Question-mark placeholders such as `?`.
33 numbered, ///< Numbered placeholders such as `$1`.
34 named ///< Named placeholders such as `:name`.
35 };
36
37 /** @brief Identifier quoting syntax. */
38 enum class identifier_quote_style : std::uint8_t {
39 double_quote, ///< Double-quoted identifiers.
40 backtick, ///< Backtick-quoted identifiers.
41 brackets ///< Bracket-quoted identifiers.
42 };
43
44 /** @brief Rendering strategy for SELECT row limiting. */
45 enum class row_limit_style : std::uint8_t {
46 limit_offset, ///< Render LIMIT followed by OFFSET.
47 offset_fetch, ///< Render OFFSET followed by FETCH.
48 top_offset_fetch ///< Render TOP, or OFFSET and FETCH when an offset is present.
49 };
50
51 /** @brief Rendering strategy for recursive common table expressions. */
52 enum class recursive_cte_style : std::uint8_t {
53 recursive_keyword, ///< Render WITH RECURSIVE.
54 plain_with ///< Render WITH without a RECURSIVE keyword.
55 };
56
57 /** @brief SQL keyword used for the EXCEPT set operation. */
58 enum class except_style : std::uint8_t {
59 except_keyword, ///< Render EXCEPT.
60 minus_keyword ///< Render MINUS.
61 };
62
63 /** @brief Rendering strategy for Boolean SQL literals. */
64 enum class boolean_literal_style : std::uint8_t {
65 keywords, ///< Render TRUE and FALSE.
66 integers ///< Render 1 and 0.
67 };
68
69 /** @brief Rendering strategy for relation aliases. */
70 enum class relation_alias_style : std::uint8_t {
71 with_as, ///< Render the AS keyword before an alias.
72 without_as ///< Render an alias without AS.
73 };
74
75 /** @brief Rendering strategy for a targeted INSERT conflict action. */
76 enum class conflict_update_style : std::uint8_t {
77 on_conflict_clause, ///< Append an ON CONFLICT clause to INSERT.
78 merge_statement, ///< Render the INSERT and conflict action as MERGE.
79 update_or_insert ///< Render UPDATE OR INSERT syntax.
80 };
81
82 /** @brief Row-source syntax used by a generated MERGE statement. */
83 enum class merge_source_style : std::uint8_t {
84 values_table, ///< Use a derived VALUES table.
85 union_all_select ///< Use SELECT rows joined with UNION ALL.
86 };
87
88 /** @brief Rendering strategy for nested set-operation operands. */
89 enum class set_operand_style : std::uint8_t {
90 parenthesized, ///< Parenthesize the operand directly.
91 derived_table ///< Wrap the operand in a derived table.
92 };
93
94 /** @brief Rendering strategy for an INSERT without explicit values. */
95 enum class default_values_style : std::uint8_t {
96 unsupported, ///< DEFAULT VALUES is unavailable.
97 standard, ///< Render standard DEFAULT VALUES syntax.
98 empty_parenthesized_values ///< Render an empty parenthesized VALUES list.
99 };
100
101 /** @brief Rendering strategy for OFFSET without LIMIT. */
102 enum class offset_without_limit_style : std::uint8_t {
103 standalone, ///< Render OFFSET without a preceding LIMIT.
104 negative_one_limit, ///< Render LIMIT -1 before OFFSET.
105 maximum_unsigned_limit ///< Render the maximum unsigned 64-bit LIMIT before OFFSET.
106 };
107
108 /** @brief Escaping rules for explicit SQL string literals. */
109 enum class string_literal_style : std::uint8_t {
110 standard, ///< Escape quotes by doubling them.
111 backslash_escaped, ///< Escape quotes, backslashes, and control bytes with backslashes.
112 mode_independent ///< Double quotes and reject backslashes whose interpretation depends on SQL mode.
113 };
114
115 /** @brief Rendering strategy for references to values proposed by an INSERT. */
116 enum class inserted_row_reference_style : std::uint8_t {
117 unsupported, ///< Proposed-row references are unavailable.
118 excluded_table, ///< Use the special EXCLUDED relation.
119 values_row_alias, ///< Alias the VALUES row and reference that alias.
120 merge_source ///< Reference a column of the generated MERGE source.
121 };
122
123 /** @brief Configures a relation supplied to SELECT when FROM is omitted. */
124 struct implicit_relation_source final {
125 /** @brief Ordered components of the qualified relation identifier. */
126 std::vector<std::string> identifier_parts;
127
128 /** @brief Whether to quote each identifier component. */
129 bool quote_identifier{true};
130 };
131
132 /** @brief Optional SQL syntax capabilities supported by a rendering profile. */
133 enum class sql_capability : std::uint32_t {
134 none = 0, ///< No optional capabilities.
135 returning = 1U << 0U, ///< RETURNING clauses.
136 on_conflict = 1U << 1U, ///< ON CONFLICT clauses.
137 on_duplicate_key_update = 1U << 2U, ///< ON DUPLICATE KEY UPDATE clauses.
138 full_join = 1U << 3U, ///< FULL JOIN relations.
139 reusable_numbered_parameters = 1U << 4U, ///< Reuse numbered placeholders.
140 reusable_named_parameters = 1U << 5U, ///< Reuse named placeholders.
141 conflict_update_requires_target = 1U << 6U, ///< Require a conflict target for updates.
142 right_join = 1U << 7U, ///< RIGHT JOIN relations.
143 nulls_ordering = 1U << 8U, ///< NULLS FIRST and NULLS LAST.
144 recursive_cte = 1U << 9U, ///< Recursive common table expressions.
145 intersect = 1U << 10U, ///< INTERSECT set operations.
146 except = 1U << 11U, ///< EXCEPT set operations.
147 window_functions = 1U << 12U, ///< Window functions.
148 groups_window_frame = 1U << 13U, ///< GROUPS window frames.
149 default_values = 1U << 14U, ///< Statement-level DEFAULT VALUES.
150 default_value = 1U << 15U, ///< Per-value DEFAULT expressions.
151 insert_select = 1U << 16U, ///< INSERT from SELECT.
152 update_from = 1U << 17U, ///< UPDATE FROM clauses.
153 delete_using = 1U << 18U, ///< DELETE USING clauses.
154 default_values_with_conflict = 1U << 19U, ///< Conflict clauses with DEFAULT VALUES.
155 insert_select_conflict_requires_where = 1U << 20U, ///< WHERE before INSERT SELECT conflict clauses.
156 distinct_window_aggregates = 1U << 21U, ///< DISTINCT window aggregates.
157 data_modifying_cte = 1U << 22U, ///< INSERT, UPDATE, or DELETE statements in CTE bodies.
158 multi_row_values = 1U << 23U, ///< Multiple rows in an INSERT VALUES source.
159 merge = 1U << 24U ///< MERGE statements generated for targeted conflicts.
160 };
161
162 /** @brief Combines SQL capability flags. */
163 3972 constexpr sql_capability operator|(sql_capability left, sql_capability right) noexcept
164 {
165 3972 return static_cast<sql_capability>(static_cast<std::uint32_t>(left) | static_cast<std::uint32_t>(right));
166 }
167
168 /** @brief Intersects SQL capability flags. */
169 305 constexpr sql_capability operator&(sql_capability left, sql_capability right) noexcept
170 {
171 305 return static_cast<sql_capability>(static_cast<std::uint32_t>(left) & static_cast<std::uint32_t>(right));
172 }
173
174 /** @brief Adds a SQL capability flag. */
175 3 constexpr sql_capability& operator|=(sql_capability& left, sql_capability right) noexcept
176 {
177 3 left = left | right;
178 3 return left;
179 }
180
181 /** @brief Returns whether a capability set contains a flag. */
182 305 constexpr bool has_capability(sql_capability capabilities, sql_capability capability) noexcept
183 {
184 305 return (capabilities & capability) != sql_capability::none;
185 }
186
187 /** @brief Database-agnostic SQL rendering configuration. */
188 struct sql_options final {
189 /** @brief Parameter placeholder syntax. */
190 placeholder_style placeholders{placeholder_style::question_mark};
191
192 /** @brief Identifier quoting syntax. */
193 identifier_quote_style identifier_quotes{identifier_quote_style::double_quote};
194
195 /** @brief SELECT row-limiting syntax. */
196 row_limit_style row_limits{row_limit_style::limit_offset};
197
198 /** @brief Optional relation added to a SELECT without an explicit FROM clause. */
199 std::optional<implicit_relation_source> implicit_select_source;
200
201 /** @brief Recursive CTE rendering strategy. */
202 recursive_cte_style recursive_ctes{recursive_cte_style::recursive_keyword};
203
204 /** @brief EXCEPT set-operation keyword. */
205 except_style except_operator{except_style::except_keyword};
206
207 /** @brief Boolean literal rendering strategy. */
208 boolean_literal_style boolean_literals{boolean_literal_style::keywords};
209
210 /** @brief Relation-alias rendering strategy. */
211 relation_alias_style relation_aliases{relation_alias_style::with_as};
212
213 /** @brief Targeted INSERT conflict rendering strategy. */
214 conflict_update_style conflict_updates{conflict_update_style::on_conflict_clause};
215
216 /** @brief Row-source syntax used by generated MERGE statements. */
217 merge_source_style merge_sources{merge_source_style::values_table};
218
219 /** @brief Optional trusted SQL hint appended to a generated MERGE target. */
220 std::optional<std::string> merge_target_hint;
221
222 /** @brief Whether a generated MERGE must end with a semicolon. */
223 bool terminate_merge{};
224
225 /** @brief Nested set-operand rendering strategy. */
226 set_operand_style set_operands{set_operand_style::parenthesized};
227
228 /** @brief DEFAULT VALUES rendering strategy. */
229 default_values_style default_values{default_values_style::unsupported};
230
231 /** @brief OFFSET rendering strategy when LIMIT is absent. */
232 offset_without_limit_style offset_without_limit{offset_without_limit_style::standalone};
233
234 /** @brief Explicit SQL string-literal escaping rules. */
235 string_literal_style string_literals{string_literal_style::standard};
236
237 /** @brief Proposed INSERT-row reference strategy. */
238 inserted_row_reference_style inserted_row_references{inserted_row_reference_style::unsupported};
239
240 /** @brief Supported optional SQL syntax. */
241 sql_capability capabilities{sql_capability::none};
242
243 /** @brief Prefix used before numbered placeholder indices. */
244 std::string numbered_parameter_prefix{"$"};
245
246 /** @brief Prefix used before named placeholders. */
247 std::string named_parameter_prefix{":"};
248 };
249
250 namespace presets {
251
252 /** @brief Returns the PostgreSQL compatibility profile. */
253 SQLON_API sql_options postgresql();
254
255 /** @brief Returns the MySQL compatibility profile. */
256 SQLON_API sql_options mysql();
257
258 /** @brief Returns the SQLite compatibility profile. */
259 SQLON_API sql_options sqlite();
260
261 /** @brief Returns the Oracle Database 19c compatibility profile. */
262 SQLON_API sql_options oracle();
263
264 /** @brief Returns the SQL Server 2019+ compatibility profile. */
265 SQLON_API sql_options sql_server();
266
267 /** @brief Returns the Firebird 5.0 compatibility profile. */
268 SQLON_API sql_options firebird();
269
270 } // namespace presets
271 } // namespace sqlon
272
273 #endif // SQLON_SQL_OPTIONS_H
274