1 | #include "duckdb/function/scalar/regexp.hpp" |
2 | #include "duckdb/execution/expression_executor.hpp" |
3 | |
4 | namespace duckdb { |
5 | |
6 | namespace regexp_util { |
7 | |
8 | bool TryParseConstantPattern(ClientContext &context, Expression &expr, string &constant_string) { |
9 | if (!expr.IsFoldable()) { |
10 | return false; |
11 | } |
12 | Value pattern_str = ExpressionExecutor::EvaluateScalar(context, expr); |
13 | if (!pattern_str.IsNull() && pattern_str.type().id() == LogicalTypeId::VARCHAR) { |
14 | constant_string = StringValue::Get(value: pattern_str); |
15 | return true; |
16 | } |
17 | return false; |
18 | } |
19 | |
20 | void ParseRegexOptions(const string &options, duckdb_re2::RE2::Options &result, bool *global_replace) { |
21 | for (idx_t i = 0; i < options.size(); i++) { |
22 | switch (options[i]) { |
23 | case 'c': |
24 | // case-sensitive matching |
25 | result.set_case_sensitive(true); |
26 | break; |
27 | case 'i': |
28 | // case-insensitive matching |
29 | result.set_case_sensitive(false); |
30 | break; |
31 | case 'l': |
32 | // literal matching |
33 | result.set_literal(true); |
34 | break; |
35 | case 'm': |
36 | case 'n': |
37 | case 'p': |
38 | // newline-sensitive matching |
39 | result.set_dot_nl(false); |
40 | break; |
41 | case 's': |
42 | // non-newline-sensitive matching |
43 | result.set_dot_nl(true); |
44 | break; |
45 | case 'g': |
46 | // global replace, only available for regexp_replace |
47 | if (global_replace) { |
48 | *global_replace = true; |
49 | } else { |
50 | throw InvalidInputException("Option 'g' (global replace) is only valid for regexp_replace" ); |
51 | } |
52 | break; |
53 | case ' ': |
54 | case '\t': |
55 | case '\n': |
56 | // ignore whitespace |
57 | break; |
58 | default: |
59 | throw InvalidInputException("Unrecognized Regex option %c" , options[i]); |
60 | } |
61 | } |
62 | } |
63 | |
64 | void ParseRegexOptions(ClientContext &context, Expression &expr, RE2::Options &target, bool *global_replace) { |
65 | if (expr.HasParameter()) { |
66 | throw ParameterNotResolvedException(); |
67 | } |
68 | if (!expr.IsFoldable()) { |
69 | throw InvalidInputException("Regex options field must be a constant" ); |
70 | } |
71 | Value options_str = ExpressionExecutor::EvaluateScalar(context, expr); |
72 | if (options_str.IsNull()) { |
73 | throw InvalidInputException("Regex options field must not be NULL" ); |
74 | } |
75 | if (options_str.type().id() != LogicalTypeId::VARCHAR) { |
76 | throw InvalidInputException("Regex options field must be a string" ); |
77 | } |
78 | ParseRegexOptions(options: StringValue::Get(value: options_str), result&: target, global_replace); |
79 | } |
80 | |
81 | } // namespace regexp_util |
82 | |
83 | } // namespace duckdb |
84 | |