Skip to content

Commit 59638af

Browse files
committed
Introduce verbatim_clause
This replaces verbatim if used as a clause in a custom query. This is a breaking change. It allows custom queries with verbatim components to be used as tables. Inspired by: rbock/sqlpp11#631
1 parent 1842de0 commit 59638af

12 files changed

Lines changed: 97 additions & 32 deletions

File tree

docs/change_log.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Breaking changes:
88

99
- Added log_category parameter to log function, #86
10+
- verbatim_clause replaces verbatim if used as a clause in a custom query
1011

1112
Other changes:
1213

docs/custom_statements.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@ for (const auto& row :
2626
}
2727
```
2828
29-
`verbatim` can also be used as a custom clause:
29+
## `verbatim_clause`
30+
`verbatim_clause` can also be used as a custom clause:
3031
3132
```c++
3233
// components of a statement can be combined into custom statement using
3334
// the `<<` operator.
3435
for (const auto& row :
3536
db(select(all_of(t)).from(t)
36-
<< sqlpp::verbatim("WINDOW window_name AS (window_definition)")
37+
<< sqlpp::verbatim_clause("WINDOW window_name AS (window_definition)")
3738
<< order_by(t.id))) {
3839
// ...
3940
}
@@ -51,7 +52,7 @@ It won't serialize its arguments, but change the return type of the statement, e
5152
// We can tell the library to treat this like a select of a single column
5253
// with the correct type.
5354
for (const auto& row :
54-
db(sqlpp::statement_t{} << sqlpp::verbatim("PRAGMA user_version")
55+
db(sqlpp::statement_t{} << sqlpp::verbatim_clause("PRAGMA user_version")
5556
<< with_result_type_of(select(t.id)))) {
5657
user_version = row.id;
5758
}
@@ -62,7 +63,7 @@ for (const auto& row :
6263
// Not recommended, though, as it is clearly more prone to errors than the
6364
// canonical way.
6465
for (const auto& row :
65-
db(sqlpp::statement_t{} << sqlpp::verbatim("SELECT *") << from(t)
66+
db(sqlpp::statement_t{} << sqlpp::verbatim_clause("SELECT *") << from(t)
6667
<< where(t.id > 17)
6768
<< with_result_type_of(select(all_of(t))))) {
6869
(void)row.id;

include/sqlpp23/core/basic/verbatim.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,6 @@ struct verbatim_t : public enable_as, enable_comparison {
4747
std::string _verbatim;
4848
};
4949

50-
template <typename DataType>
51-
struct is_clause<verbatim_t<DataType>> : public std::true_type {};
52-
53-
template <typename Statement, typename DataType>
54-
struct consistency_check<Statement, verbatim_t<DataType>> {
55-
using type = consistent_t;
56-
constexpr auto operator()() {
57-
return type{};
58-
}
59-
};
6050
template <typename DataType>
6151
struct data_type_of<verbatim_t<DataType>> {
6252
// Since we do not know what's going on inside the verbatim, we assume it can
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#pragma once
2+
3+
/*
4+
* Copyright (c) 2026, Roland Bock
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* Redistributions of source code must retain the above copyright notice, this
11+
* list of conditions and the following disclaimer.
12+
*
13+
* Redistributions in binary form must reproduce the above copyright notice,
14+
* this list of conditions and the following disclaimer in the documentation
15+
* and/or other materials provided with the distribution.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+
* POSSIBILITY OF SUCH DAMAGE.
28+
*/
29+
30+
#include <utility>
31+
32+
#include <sqlpp23/core/to_sql_string.h>
33+
#include <sqlpp23/core/type_traits.h>
34+
35+
namespace sqlpp {
36+
struct verbatim_clause_t {
37+
verbatim_clause_t(std::string verbatim_clause) : _verbatim_clause(std::move(verbatim_clause)) {}
38+
verbatim_clause_t(const verbatim_clause_t&) = default;
39+
verbatim_clause_t(verbatim_clause_t&&) = default;
40+
verbatim_clause_t& operator=(const verbatim_clause_t&) = default;
41+
verbatim_clause_t& operator=(verbatim_clause_t&&) = default;
42+
~verbatim_clause_t() = default;
43+
44+
std::string _verbatim_clause;
45+
};
46+
47+
template <>
48+
struct is_clause<verbatim_clause_t> : public std::true_type {};
49+
50+
template <typename Statement>
51+
struct consistency_check<Statement, verbatim_clause_t> {
52+
using type = consistent_t;
53+
constexpr auto operator()() {
54+
return type{};
55+
}
56+
};
57+
58+
template <typename Context>
59+
auto to_sql_string(Context&, const verbatim_clause_t& t) -> std::string {
60+
return t._verbatim_clause;
61+
}
62+
63+
inline auto verbatim_clause(std::string s) -> verbatim_clause_t {
64+
return {std::move(s)};
65+
}
66+
} // namespace sqlpp

include/sqlpp23/sqlpp23.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <sqlpp23/core/clause/returning.h>
3838
#include <sqlpp23/core/clause/on_conflict.h>
3939
#include <sqlpp23/core/clause/using.h>
40+
#include <sqlpp23/core/clause/verbatim_clause.h>
4041
#include <sqlpp23/core/database/transaction.h>
4142
#include <sqlpp23/core/debug_logger.h>
4243
#include <sqlpp23/core/function.h>

modules/sqlpp23.core.cppm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ export namespace sqlpp {
3737
using ::sqlpp::column_t;
3838
using ::sqlpp::table_t;
3939
using ::sqlpp::table_as_t;
40+
using ::sqlpp::verbatim_clause_t;
4041
using ::sqlpp::verbatim_t;
41-
using ::sqlpp::verbatim_table;
42+
using ::sqlpp::verbatim_table_t;
4243
using ::sqlpp::table_columns;
4344
using ::sqlpp::all_of;
4445
using ::sqlpp::enable_join;
@@ -51,6 +52,8 @@ using ::sqlpp::cross_join;
5152
using ::sqlpp::parameter;
5253
using ::sqlpp::parameter_t; // TODO remove?
5354
using ::sqlpp::verbatim;
55+
using ::sqlpp::verbatim_clause;
56+
using ::sqlpp::verbatim_table;
5457
using ::sqlpp::parameterized_verbatim;
5558
using ::sqlpp::schema;
5659
using ::sqlpp::schema_qualified_table;

tests/core/serialize/query/custom_query.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ int main() {
6767

6868
// A pragma query for sqlite
6969
SQLPP_COMPARE(sqlpp::statement_t<>{}
70-
<< sqlpp::verbatim("PRAGMA user_version")
70+
<< sqlpp::verbatim_clause("PRAGMA user_version")
7171
<< with_result_type_of(select(sqlpp::value(1).as(pragma))),
7272
"PRAGMA user_version");
7373

@@ -90,7 +90,7 @@ int main() {
9090
batch.add_values(bar.textN = "sample", bar.boolNn = true);
9191
batch.add_values(bar.textN = "ample", bar.boolNn = false);
9292
SQLPP_COMPARE(sqlpp::insert()
93-
<< sqlpp::verbatim(" OR IGNORE") << into(bar) << batch,
93+
<< sqlpp::verbatim_clause(" OR IGNORE") << into(bar) << batch,
9494
"INSERT OR IGNORE INTO tab_bar (text_n, bool_nn) VALUES "
9595
"('sample', 1), ('ample', 0)");
9696

tests/core/usage/CustomQuery.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ struct on_duplicate_key_update {
4242
return *this;
4343
}
4444

45-
auto get() const -> sqlpp::verbatim_t<::sqlpp::no_value_t> {
46-
return ::sqlpp::verbatim(_serialized);
45+
auto get() const -> sqlpp::verbatim_clause_t {
46+
return ::sqlpp::verbatim_clause(_serialized);
4747
}
4848
};
4949
} // namespace
@@ -57,7 +57,7 @@ int CustomQuery(int, char*[]) {
5757

5858
// A void custom query
5959
auto x = sqlpp::statement_t{}
60-
<< sqlpp::verbatim("PRAGMA writeable_schema = 1");
60+
<< sqlpp::verbatim_clause("PRAGMA writeable_schema = 1");
6161
std::cerr << to_sql_string(printer, x) << std::endl;
6262
db(x);
6363

@@ -76,14 +76,14 @@ int CustomQuery(int, char*[]) {
7676
}
7777

7878
// Create a custom "insert or ignore"
79-
db(sqlpp::insert() << sqlpp::verbatim(" OR IGNORE") << into(t)
79+
db(sqlpp::insert() << sqlpp::verbatim_clause(" OR IGNORE") << into(t)
8080
<< insert_set(t.textN = "sample", t.boolNn = true));
8181

8282
// Create a custom multi-row "insert or ignore"
8383
auto batch = insert_columns(t.textN, t.boolNn);
8484
batch.add_values(t.textN = "sample", t.boolNn = true);
8585
batch.add_values(t.textN = "ample", t.boolNn = false);
86-
db(sqlpp::insert() << sqlpp::verbatim(" OR IGNORE") << into(t) << batch);
86+
db(sqlpp::insert() << sqlpp::verbatim_clause(" OR IGNORE") << into(t) << batch);
8787

8888
// Create a MYSQL style custom "insert on duplicate update"
8989
db(sqlpp::insert_into(t).set(t.textN = "sample", t.boolNn = true)
@@ -102,22 +102,24 @@ int CustomQuery(int, char*[]) {
102102
"insert yields an integral value");
103103

104104
auto d = sqlpp::statement_t{}
105-
<< sqlpp::verbatim("INSERT INTO tab_sample VALUES()")
105+
<< sqlpp::verbatim_clause("INSERT INTO tab_sample VALUES()")
106106
<< with_result_type_of(sqlpp::insert());
107107
auto j = db(d).last_insert_id;
108108
static_assert(std::is_integral<decltype(j)>::value,
109109
"insert yields an integral value");
110110

111111
for (const auto& row :
112-
db(sqlpp::statement_t{} << sqlpp::verbatim("PRAGMA user_version")
112+
db(sqlpp::statement_t{} << sqlpp::verbatim_clause("PRAGMA user_version")
113113
<< with_result_type_of(select(all_of(t))))) {
114114
(void)row.id;
115115
}
116116

117+
(select(all_of(t)).from(t) << sqlpp::verbatim_clause("something")).as(sqlpp::alias::a);
118+
117119
// If you really want the statement to contain "SELECT *" instead of every
118120
// column explicitly (maybe you are running into size limits?)
119121
for (const auto& row :
120-
db(sqlpp::statement_t{} << sqlpp::verbatim("SELECT *") << from(t)
122+
db(sqlpp::statement_t{} << sqlpp::verbatim_clause("SELECT *") << from(t)
121123
<< where(t.id > 17)
122124
<< with_result_type_of(select(all_of(t))))) {
123125
(void)row.id;

tests/mysql/usage/CustomQuery.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ struct on_duplicate_key_update {
4444
return *this;
4545
}
4646

47-
auto get() const -> sqlpp::verbatim_t<::sqlpp::no_value_t> {
48-
return ::sqlpp::verbatim(_serialized);
47+
auto get() const -> sqlpp::verbatim_clause_t {
48+
return ::sqlpp::verbatim_clause(_serialized);
4949
}
5050
};
5151
} // namespace

tests/postgresql/usage/Transaction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ int Transaction(int, char*[]) {
3838
require_equal(__LINE__, db.is_transaction_active(), false);
3939
auto current_level = std::string(
4040
db(sqlpp::statement_t{}
41-
<< sqlpp::verbatim("show transaction_isolation;")
41+
<< sqlpp::verbatim_clause("show transaction_isolation;")
4242
<< with_result_type_of(select(sqlpp::value("").as(level))))
4343
.front()
4444
.level);
@@ -50,7 +50,7 @@ int Transaction(int, char*[]) {
5050
require_equal(__LINE__, db.is_transaction_active(), true);
5151
current_level =
5252
db(sqlpp::statement_t{}
53-
<< sqlpp::verbatim("show transaction_isolation;")
53+
<< sqlpp::verbatim_clause("show transaction_isolation;")
5454
<< with_result_type_of(select(sqlpp::value("").as(level))))
5555
.front()
5656
.level;

0 commit comments

Comments
 (0)