forked from duckdb/duckdb-postgres
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpostgres_filter_pushdown.cpp
137 lines (127 loc) · 4.33 KB
/
postgres_filter_pushdown.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "postgres_filter_pushdown.hpp"
#include "duckdb/parser/keyword_helper.hpp"
#include "duckdb/planner/filter/in_filter.hpp"
#include "duckdb/planner/filter/optional_filter.hpp"
#include "duckdb/planner/filter/struct_filter.hpp"
#include "duckdb/common/enum_util.hpp"
namespace duckdb {
string PostgresFilterPushdown::CreateExpression(string &column_name, vector<unique_ptr<TableFilter>> &filters,
string op) {
vector<string> filter_entries;
for (auto &filter : filters) {
auto filter_str = TransformFilter(column_name, *filter);
if (!filter_str.empty()) {
filter_entries.push_back(std::move(filter_str));
}
}
if (filter_entries.empty()) {
return string();
}
return "(" + StringUtil::Join(filter_entries, " " + op + " ") + ")";
}
string PostgresFilterPushdown::TransformComparision(ExpressionType type) {
switch (type) {
case ExpressionType::COMPARE_EQUAL:
return "=";
case ExpressionType::COMPARE_NOTEQUAL:
return "<>";
case ExpressionType::COMPARE_LESSTHAN:
return "<";
case ExpressionType::COMPARE_GREATERTHAN:
return ">";
case ExpressionType::COMPARE_LESSTHANOREQUALTO:
return "<=";
case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
return ">=";
default:
throw NotImplementedException("Unsupported expression type");
}
}
string TransformBlob(const string &val) {
char const HEX_DIGITS[] = "0123456789ABCDEF";
string result = "'\\x";
for(idx_t i = 0; i < val.size(); i++) {
uint8_t byte_val = static_cast<uint8_t>(val[i]);
result += HEX_DIGITS[(byte_val >> 4) & 0xf];
result += HEX_DIGITS[byte_val & 0xf];
}
result += "'::BYTEA";
return result;
}
string TransformLiteral(const Value &val) {
switch (val.type().id()) {
case LogicalTypeId::BLOB:
return TransformBlob(StringValue::Get(val));
default:
return KeywordHelper::WriteQuoted(val.ToString());
}
}
string PostgresFilterPushdown::TransformFilter(string &column_name, TableFilter &filter) {
switch (filter.filter_type) {
case TableFilterType::IS_NULL:
return column_name + " IS NULL";
case TableFilterType::IS_NOT_NULL:
return column_name + " IS NOT NULL";
case TableFilterType::CONJUNCTION_AND: {
auto &conjunction_filter = filter.Cast<ConjunctionAndFilter>();
return CreateExpression(column_name, conjunction_filter.child_filters, "AND");
}
case TableFilterType::CONJUNCTION_OR: {
auto &conjunction_filter = filter.Cast<ConjunctionOrFilter>();
return CreateExpression(column_name, conjunction_filter.child_filters, "OR");
}
case TableFilterType::CONSTANT_COMPARISON: {
auto &constant_filter = filter.Cast<ConstantFilter>();
auto constant_string = TransformLiteral(constant_filter.constant);
auto operator_string = TransformComparision(constant_filter.comparison_type);
return StringUtil::Format("%s %s %s", column_name, operator_string, constant_string);
}
case TableFilterType::STRUCT_EXTRACT: {
auto &struct_filter = filter.Cast<StructFilter>();
auto child_name = KeywordHelper::WriteQuoted(struct_filter.child_name, '\"');
auto new_name = "(" + column_name + ")." + child_name;
return TransformFilter(new_name, *struct_filter.child_filter);
}
case TableFilterType::OPTIONAL_FILTER: {
auto &optional_filter = filter.Cast<OptionalFilter>();
return TransformFilter(column_name, *optional_filter.child_filter);
}
case TableFilterType::IN_FILTER: {
auto &in_filter = filter.Cast<InFilter>();
string in_list;
for(auto &val : in_filter.values) {
if (!in_list.empty()) {
in_list += ", ";
}
in_list += TransformLiteral(val);
}
return column_name + " IN (" + in_list + ")";
}
case TableFilterType::DYNAMIC_FILTER:
return string();
default:
throw InternalException("Unsupported table filter type");
}
}
string PostgresFilterPushdown::TransformFilters(const vector<column_t> &column_ids,
optional_ptr<TableFilterSet> filters, const vector<string> &names) {
if (!filters || filters->filters.empty()) {
// no filters
return string();
}
string result;
for (auto &entry : filters->filters) {
auto column_name = KeywordHelper::WriteQuoted(names[column_ids[entry.first]], '"');
auto &filter = *entry.second;
auto filter_text = TransformFilter(column_name, filter);
if (filter_text.empty()) {
continue;
}
if (!result.empty()) {
result += " AND ";
}
result += filter_text;
}
return result;
}
} // namespace duckdb