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 |