19 #include <boost/algorithm/string/predicate.hpp>
20 #include <boost/algorithm/string/replace.hpp>
31 static const auto& unnest_expr = *
new boost::regex(
32 R
"((\s+|,)(unnest)\s*\()", boost::regex::extended | boost::regex::icase);
33 static_assert(std::is_trivially_destructible_v<decltype(unnest_expr)>);
35 result.replace(what.position(), what.length(), what[1] +
"PG_UNNEST(");
39 static const auto& cast_true_expr =
40 *
new boost::regex(R
"(CAST\s*\(\s*'t'\s+AS\s+boolean\s*\))",
41 boost::regex::extended | boost::regex::icase);
42 static_assert(std::is_trivially_destructible_v<decltype(cast_true_expr)>);
44 result, cast_true_expr, [](std::string& result, const boost::smatch& what) {
45 result.replace(what.position(), what.length(),
"true");
49 static const auto& cast_false_expr =
50 *
new boost::regex(R
"(CAST\s*\(\s*'f'\s+AS\s+boolean\s*\))",
51 boost::regex::extended | boost::regex::icase);
52 static_assert(std::is_trivially_destructible_v<decltype(cast_false_expr)>);
54 result, cast_false_expr, [](std::string& result, const boost::smatch& what) {
55 result.replace(what.position(), what.length(),
"false");
59 static const auto& ilike_expr = *
new boost::regex(
60 R
"((\s+|\()((?!\()[^\s]+)\s+ilike\s+('(?:[^']+|'')+')(\s+escape(\s+('[^']+')))?)",
61 boost::regex::perl | boost::regex::icase);
62 static_assert(std::is_trivially_destructible_v<decltype(ilike_expr)>);
64 std::string esc = what[6];
65 result.replace(what.position(),
67 what[1] +
"PG_ILIKE(" + what[2] +
", " + what[3] +
68 (esc.empty() ?
"" :
", " + esc) +
")");
72 static const auto& regexp_expr = *
new boost::regex(
73 R
"((\s+)([^\s]+)\s+REGEXP\s+('(?:[^']+|'')+')(\s+escape(\s+('[^']+')))?)",
74 boost::regex::perl | boost::regex::icase);
75 static_assert(std::is_trivially_destructible_v<decltype(regexp_expr)>);
77 std::string esc = what[6];
78 result.replace(what.position(),
80 what[1] +
"REGEXP_LIKE(" + what[2] +
", " + what[3] +
81 (esc.empty() ?
"" :
", " + esc) +
")");
86 static const auto& quant_expr =
87 *
new boost::regex(R
"(([<=>]\s*)(any|all)\s+([^(\s|;)]+))",
88 boost::regex::extended | boost::regex::icase);
89 static_assert(std::is_trivially_destructible_v<decltype(quant_expr)>);
91 auto const quant_fname = boost::iequals(what[2],
"any") ?
"PG_ANY(" :
"PG_ALL(";
93 what.position(), what.length(), what[1] + quant_fname + what[3] +
')');
97 static const auto& immediate_cast_expr =
98 *
new boost::regex(R
"(TIMESTAMP\(([0369])\)\s+('[^']+'))",
99 boost::regex::extended | boost::regex::icase);
100 static_assert(std::is_trivially_destructible_v<decltype(immediate_cast_expr)>);
102 result, immediate_cast_expr, [](std::string& result, const boost::smatch& what) {
103 result.replace(what.position(),
105 "CAST(" + what[2] +
" AS TIMESTAMP(" + what[1] +
"))");
109 static const auto& timestampadd_expr =
110 *
new boost::regex(R
"(DATE(ADD|DIFF|PART|_TRUNC)\s*\(\s*(\w+)\s*,)",
111 boost::regex::extended | boost::regex::icase);
112 static_assert(std::is_trivially_destructible_v<decltype(timestampadd_expr)>);
114 result, timestampadd_expr, [](std::string& result, const boost::smatch& what) {
116 what.position(), what.length(),
"DATE" + what[1] +
"('" + what[2] +
"',");
121 static const auto& pg_extract_expr = *
new boost::regex(
122 R
"(PG_EXTRACT\s*\(\s*(\w+)\s*,)", boost::regex::extended | boost::regex::icase);
123 static_assert(std::is_trivially_destructible_v<decltype(pg_extract_expr)>);
125 result, pg_extract_expr, [](std::string& result, const boost::smatch& what) {
126 result.replace(what.position(), what.length(),
"PG_EXTRACT('" + what[1] +
"',");
129 static const auto& extract_expr_quoted =
130 *
new boost::regex(R
"(extract\s*\(\s*'(\w+)'\s+from\s+(.+)\))",
131 boost::regex::extended | boost::regex::icase);
132 static_assert(std::is_trivially_destructible_v<decltype(extract_expr_quoted)>);
134 result, extract_expr_quoted, [](std::string& result, const boost::smatch& what) {
135 result.replace(what.position(),
137 "PG_EXTRACT('" + what[1] +
"', " + what[2] +
")");
140 static const auto& extract_expr =
141 *
new boost::regex(R
"(extract\s*\(\s*(\w+)\s+from\s+(.+)\))",
142 boost::regex::extended | boost::regex::icase);
143 static_assert(std::is_trivially_destructible_v<decltype(extract_expr)>);
144 apply_shim(result, extract_expr, [](std::string& result, const boost::smatch& what) {
145 result.replace(what.position(),
147 "PG_EXTRACT('" + what[1] +
"', " + what[2] +
")");
152 static const auto& date_trunc_expr = *
new boost::regex(
153 R
"(([^_])date_trunc\s*)", boost::regex::extended | boost::regex::icase);
154 static_assert(std::is_trivially_destructible_v<decltype(date_trunc_expr)>);
156 result, date_trunc_expr, [](std::string& result, const boost::smatch& what) {
157 result.replace(what.position(), what.length(), what[1] +
"PG_DATE_TRUNC");
161 static const auto& timestampadd_expr_quoted =
162 *
new boost::regex(R
"(TIMESTAMP(ADD|DIFF)\s*\(\s*'(\w+)'\s*,)",
163 boost::regex::extended | boost::regex::icase);
164 static_assert(std::is_trivially_destructible_v<decltype(timestampadd_expr_quoted)>);
166 timestampadd_expr_quoted,
167 [](std::string& result, const boost::smatch& what) {
168 result.replace(what.position(),
170 "DATE" + what[1] +
"('" + what[2] +
"',");
172 static const auto& timestampadd_expr =
173 *
new boost::regex(R
"(TIMESTAMP(ADD|DIFF)\s*\(\s*(\w+)\s*,)",
174 boost::regex::extended | boost::regex::icase);
175 static_assert(std::is_trivially_destructible_v<decltype(timestampadd_expr)>);
177 result, timestampadd_expr, [](std::string& result, const boost::smatch& what) {
179 what.position(), what.length(),
"DATE" + what[1] +
"('" + what[2] +
"',");
183 static const auto& us_timestamp_cast_expr =
184 *
new boost::regex(R
"(CAST\s*\(\s*('[^']+')\s*AS\s*TIMESTAMP\(6\)\s*\))",
185 boost::regex::extended | boost::regex::icase);
186 static_assert(std::is_trivially_destructible_v<decltype(us_timestamp_cast_expr)>);
188 us_timestamp_cast_expr,
189 [](std::string& result, const boost::smatch& what) {
191 what.position(), what.length(),
"usTIMESTAMP(" + what[1] +
")");
195 static const auto& ns_timestamp_cast_expr =
196 *
new boost::regex(R
"(CAST\s*\(\s*('[^']+')\s*AS\s*TIMESTAMP\(9\)\s*\))",
197 boost::regex::extended | boost::regex::icase);
198 static_assert(std::is_trivially_destructible_v<decltype(ns_timestamp_cast_expr)>);
200 ns_timestamp_cast_expr,
201 [](std::string& result, const boost::smatch& what) {
203 what.position(), what.length(),
"nsTIMESTAMP(" + what[1] +
")");
207 static const auto& corr_expr = *
new boost::regex(
208 R
"((\s+|,|\()(corr)\s*\()", boost::regex::extended | boost::regex::icase);
209 static_assert(std::is_trivially_destructible_v<decltype(corr_expr)>);
211 result.replace(what.position(), what.length(), what[1] +
"CORRELATION(");
218 static const auto& cast_to_geography_expr =
219 *
new boost::regex(R
"(CAST\s*\(\s*(((?!geography).)+)\s+AS\s+geography\s*\))",
220 boost::regex::perl | boost::regex::icase);
221 static_assert(std::is_trivially_destructible_v<decltype(cast_to_geography_expr)>);
223 cast_to_geography_expr,
224 [](std::string& result, const boost::smatch& what) {
225 result.replace(what.position(),
227 "CastToGeography(" + what[1] +
")");
229 }
catch (
const std::exception& e) {
230 LOG(
WARNING) <<
"Error apply geography cast shim: " << e.what()
231 <<
"\nContinuing query parse...";
235 static const auto& interval_subsecond_expr =
236 *
new boost::regex(R
"(interval\s+([0-9]+)\s+(millisecond|microsecond|nanosecond))",
237 boost::regex::extended | boost::regex::icase);
238 static_assert(std::is_trivially_destructible_v<decltype(interval_subsecond_expr)>);
241 interval_subsecond_expr,
242 [](std::string& result, const boost::smatch& what) {
243 std::string interval_str = what[1];
245 static const std::array<std::pair<std::string_view, size_t>, 3> precision_map{
246 std::make_pair(
"millisecond", 3),
247 std::make_pair(
"microsecond", 6),
248 std::make_pair(
"nanosecond", 9)};
249 static_assert(std::is_trivially_destructible_v<decltype(precision_map)>);
250 auto precision_it = std::find_if(
251 precision_map.cbegin(),
252 precision_map.cend(),
253 [&time_unit_str](
const std::pair<std::string_view, size_t>& precision) {
254 return time_unit_str.compare(precision.first) == 0;
256 if (precision_it != precision_map.end()) {
257 std::ostringstream out;
258 const auto interval_time = std::strtod(interval_str.c_str(),
nullptr);
260 out << std::fixed << interval_time / scale;
261 interval_str = out.str();
263 what.position(), what.length(),
"interval " + interval_str +
" second");
273 std::string
pg_shim(
const std::string& query) {
276 }
catch (
const std::exception& e) {
277 LOG(
WARNING) <<
"Error applying shim: " << e.what() <<
"\nContinuing query parse...";
double power10(unsigned const x)
std::string pg_shim_impl(const std::string &query)
std::string pg_shim(const std::string &query)