3
3
#include " storage/postgres_transaction.hpp"
4
4
#include " storage/postgres_optimizer.hpp"
5
5
#include " duckdb/planner/operator/logical_get.hpp"
6
+ #include " duckdb/planner/operator/logical_limit.hpp"
6
7
#include " storage/postgres_catalog.hpp"
7
8
#include " postgres_scanner.hpp"
8
9
10
+
9
11
namespace duckdb {
10
12
11
13
struct PostgresOperators {
12
14
reference_map_t <PostgresCatalog, vector<reference<LogicalGet>>> scans;
13
15
};
14
16
17
+ static void OptimizePostgresScanLimitPushdown (unique_ptr<LogicalOperator> &op) {
18
+ if (op->type == LogicalOperatorType::LOGICAL_LIMIT) {
19
+ auto &limit = op->Cast <LogicalLimit>();
20
+ reference<LogicalOperator> child = *op->children [0 ];
21
+
22
+ while (child.get ().type == LogicalOperatorType::LOGICAL_PROJECTION) {
23
+ child = *child.get ().children [0 ];
24
+ }
25
+
26
+ if (child.get ().type != LogicalOperatorType::LOGICAL_GET) {
27
+ OptimizePostgresScanLimitPushdown (op->children [0 ]);
28
+ return ;
29
+ }
30
+
31
+ auto &get = child.get ().Cast <LogicalGet>();
32
+ if (!PostgresCatalog::IsPostgresScan (get.function .name )) {
33
+ OptimizePostgresScanLimitPushdown (op->children [0 ]);
34
+ return ;
35
+ }
36
+
37
+ switch (limit.limit_val .Type ()) {
38
+ case LimitNodeType::CONSTANT_VALUE:
39
+ case LimitNodeType::UNSET:
40
+ break ;
41
+ default :
42
+ // not a constant or unset limit
43
+ OptimizePostgresScanLimitPushdown (op->children [0 ]);
44
+ return ;
45
+ }
46
+ switch (limit.offset_val .Type ()) {
47
+ case LimitNodeType::CONSTANT_VALUE:
48
+ case LimitNodeType::UNSET:
49
+ break ;
50
+ default :
51
+ // not a constant or unset offset
52
+ OptimizePostgresScanLimitPushdown (op->children [0 ]);
53
+ return ;
54
+ }
55
+
56
+ auto &bind_data = get.bind_data ->Cast <PostgresBindData>();
57
+
58
+ string generated_limit_clause = " " ;
59
+ if (limit.limit_val .Type () != LimitNodeType::UNSET) {
60
+ generated_limit_clause += " LIMIT " + to_string (limit.limit_val .GetConstantValue ());
61
+ }
62
+ if (limit.offset_val .Type () != LimitNodeType::UNSET) {
63
+ generated_limit_clause += " OFFSET " + to_string (limit.offset_val .GetConstantValue ());
64
+ }
65
+
66
+ if (!generated_limit_clause.empty ()) {
67
+ bind_data.limit = generated_limit_clause;
68
+
69
+ op = std::move (op->children [0 ]);
70
+ return ;
71
+ }
72
+ }
73
+
74
+ for (auto &child : op->children ) {
75
+ OptimizePostgresScanLimitPushdown (child);
76
+ }
77
+ }
78
+
15
79
void GatherPostgresScans (LogicalOperator &op, PostgresOperators &result) {
16
80
if (op.type == LogicalOperatorType::LOGICAL_GET) {
17
81
auto &get = op.Cast <LogicalGet>();
@@ -35,6 +99,8 @@ void GatherPostgresScans(LogicalOperator &op, PostgresOperators &result) {
35
99
}
36
100
37
101
void PostgresOptimizer::Optimize (OptimizerExtensionInput &input, unique_ptr<LogicalOperator> &plan) {
102
+ // look at query plan and check if we can find LIMIT/OFFSET to pushdown
103
+ OptimizePostgresScanLimitPushdown (plan);
38
104
// look at the query plan and check if we can enable streaming query scans
39
105
PostgresOperators operators;
40
106
GatherPostgresScans (*plan, operators);
0 commit comments