Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,20 @@ public String visit(Property property, List<String> children) {
FilterEncoderSql.this);
if (!join.isEmpty()) join += " ";

// When the predicate needs no sub-table join, its operand is a column reachable directly from
// the main table (aliased A). Emit it as a direct conjunct instead of a redundant
// self-semi-join (A.id IN (SELECT A.id FROM <main> WHERE ...)): that subquery scans the whole
// main table and the planner does not flatten it, so it is O(table) per predicate regardless
// of how few rows are selected. The semi-join form is kept whenever a join, junction, or
// array
// traversal is genuinely required (join non-empty) — there it is load-bearing for
// cardinality.
if (join.isEmpty() && !Objects.equals(table.getParentPath(), ImmutableList.of("_route_"))) {
return String.format(
"%%1$s%1$s%%2$s",
getQualifiedColumn(table, propertyName, "A", allowColumnFallback).first());
}

return String.format(
"A.%3$s IN (SELECT %2$s.%3$s FROM %1$s %2$s %4$sWHERE %%1$s%5$s%%2$s)",
rootSchema.getName(),
Expand Down Expand Up @@ -832,7 +846,8 @@ public String visit(de.ii.xtraplatform.cql.domain.Interval interval, List<String
+ startColumn
+ ", "
+ endColumn
+ ")%2$s)";
+ ")%2$s"
+ start.substring(start.indexOf("%2$s") + 4);
} else if (arg1 instanceof Property && arg2 instanceof TemporalLiteral) {
String startColumn = reduceToColumn(start);
startColumn =
Expand All @@ -844,7 +859,8 @@ public String visit(de.ii.xtraplatform.cql.domain.Interval interval, List<String
+ startColumn
+ ", "
+ end
+ ")%2$s)";
+ ")%2$s"
+ start.substring(start.indexOf("%2$s") + 4);
} else if (arg1 instanceof TemporalLiteral && arg2 instanceof Property) {
String endColumn = reduceToColumn(end);
endColumn =
Expand All @@ -856,7 +872,8 @@ public String visit(de.ii.xtraplatform.cql.domain.Interval interval, List<String
+ start
+ ", "
+ endColumn
+ ")%2$s)";
+ ")%2$s"
+ end.substring(end.indexOf("%2$s") + 4);
}
throw new IllegalStateException("unsupported interval: " + interval);
}
Expand Down Expand Up @@ -1776,6 +1793,23 @@ public String visit(Property property, List<String> children) {
FilterEncoderSql.this);
if (!join.isEmpty()) join += " ";

// When the predicate needs no sub-table join, its operand is a column reachable directly from
// the main table (aliased A). Emit it as a direct conjunct instead of a redundant
// self-semi-join (A.id IN (SELECT A.id FROM <main> WHERE ...)): that subquery scans the whole
// main table and the planner does not flatten it, so it is O(table) per predicate regardless
// of how few rows are selected. The semi-join form is kept whenever a join, junction, or
// array
// traversal is genuinely required (join non-empty) — there it is load-bearing for
// cardinality.
if (join.isEmpty()
&& !Objects.equals(table.first().getParentPath(), ImmutableList.of("_route_"))) {
return String.format(
"%%1$s%1$s%%2$s",
getQualifiedColumn(
table.first(), table.second(), propertyName, "A", allowColumnFallback)
.first());
}

return String.format(
"A.%3$s IN (SELECT %2$s.%3$s FROM %1$s %2$s %4$sWHERE %%1$s%5$s%%2$s)",
mapping.getMainTable().getName(),
Expand Down Expand Up @@ -1840,7 +1874,8 @@ public String visit(de.ii.xtraplatform.cql.domain.Interval interval, List<String
+ startColumn
+ ", "
+ endColumn
+ ")%2$s)";
+ ")%2$s"
+ start.substring(start.indexOf("%2$s") + 4);
} else if (arg1 instanceof Property && arg2 instanceof TemporalLiteral) {
String startColumn = reduceToColumn(start);
startColumn =
Expand All @@ -1852,7 +1887,8 @@ public String visit(de.ii.xtraplatform.cql.domain.Interval interval, List<String
+ startColumn
+ ", "
+ end
+ ")%2$s)";
+ ")%2$s"
+ start.substring(start.indexOf("%2$s") + 4);
} else if (arg1 instanceof TemporalLiteral && arg2 instanceof Property) {
String endColumn = reduceToColumn(end);
endColumn =
Expand All @@ -1864,7 +1900,8 @@ public String visit(de.ii.xtraplatform.cql.domain.Interval interval, List<String
+ start
+ ", "
+ endColumn
+ ")%2$s)";
+ ")%2$s"
+ end.substring(end.indexOf("%2$s") + 4);
}
throw new IllegalStateException("unsupported interval: " + interval);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class FilterEncoderSqlInResultSetSpec extends Specification {
def sql = filterEncoder.encode(filter, mappings["value_array"])

then:
sql == "A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id = 'foo')) SELECT rs_value FROM _rs_0_s1))"
sql == "A.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.id = 'foo') SELECT rs_value FROM _rs_0_s1)"
}

def 'plain id set without a producer filter'() {
Expand All @@ -90,7 +90,7 @@ class FilterEncoderSqlInResultSetSpec extends Specification {
def sql = filterEncoder.encode(filter, mappings["value_array"])

then:
sql == "A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A) SELECT rs_value FROM _rs_0_s1))"
sql == "A.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A) SELECT rs_value FROM _rs_0_s1)"
}

def 'plain id set, consumer matches an array property in a junction table'() {
Expand All @@ -102,7 +102,7 @@ class FilterEncoderSqlInResultSetSpec extends Specification {
def sql = filterEncoder.encode(filter, mappings["value_array"])

then:
sql == "A.id IN (SELECT AA.id FROM externalprovider AA JOIN externalprovider_externalprovidername AB ON (AA.id=AB.externalprovider_fk) WHERE AB.externalprovidername IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id = 'foo')) SELECT rs_value FROM _rs_0_s1))"
sql == "A.id IN (SELECT AA.id FROM externalprovider AA JOIN externalprovider_externalprovidername AB ON (AA.id=AB.externalprovider_fk) WHERE AB.externalprovidername IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.id = 'foo') SELECT rs_value FROM _rs_0_s1))"
}

def 'chained result sets nest recursively'() {
Expand All @@ -115,7 +115,7 @@ class FilterEncoderSqlInResultSetSpec extends Specification {
def sql = filterEncoder.encode(outer, mappings["value_array"])

then:
sql == "A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id IN (WITH _rs_1_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id = 'foo')), _rs_0_s2 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id IN (SELECT rs_value FROM _rs_1_s1))) SELECT rs_value FROM _rs_0_s2))"
sql == "A.id IN (WITH _rs_1_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.id = 'foo'), _rs_0_s2 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.id IN (SELECT rs_value FROM _rs_1_s1)) SELECT rs_value FROM _rs_0_s2)"
}

def 'an unresolved result set reference is rejected'() {
Expand Down Expand Up @@ -145,7 +145,7 @@ class FilterEncoderSqlInResultSetSpec extends Specification {
def sql = filterEncoder.encode(filter, mappings["simple"])

then:
sql == "A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT B.externalprovidername AS rs_value FROM externalprovider A JOIN externalprovider_externalprovidername B ON (A.id=B.externalprovider_fk) WHERE A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id = 'foo')) SELECT rs_value FROM _rs_0_s1))"
sql == "A.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT B.externalprovidername AS rs_value FROM externalprovider A JOIN externalprovider_externalprovidername B ON (A.id=B.externalprovider_fk) WHERE A.id = 'foo') SELECT rs_value FROM _rs_0_s1)"
}

def 'projected result set over a column of the main table'() {
Expand All @@ -156,7 +156,7 @@ class FilterEncoderSqlInResultSetSpec extends Specification {
def sql = filterEncoder.encode(filter, mappings["value_array"])

then:
sql == "A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A) SELECT rs_value FROM _rs_0_s1))"
sql == "A.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A) SELECT rs_value FROM _rs_0_s1)"
}

def 'the filter of the producer main table is applied to the result set'() {
Expand All @@ -167,7 +167,7 @@ class FilterEncoderSqlInResultSetSpec extends Specification {
def sql = filterEncoder.encode(filter, mappings["simple"])

then:
sql == "A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.type = 1)) SELECT rs_value FROM _rs_0_s1))"
sql == "A.id IN (WITH _rs_0_s1 AS MATERIALIZED (SELECT A.id AS rs_value FROM externalprovider A WHERE A.type = 1) SELECT rs_value FROM _rs_0_s1)"
}

def 'a materialized result set is inlined as a literal IN list'() {
Expand All @@ -182,7 +182,7 @@ class FilterEncoderSqlInResultSetSpec extends Specification {
def sql = filterEncoder.encode(filter, mappings["value_array"])

then:
sql == "A.id IN (SELECT AA.id FROM externalprovider AA WHERE AA.id IN ('foo', 'bar'))"
sql == "A.id IN ('foo', 'bar')"
}

def 'an empty materialized result set yields a false predicate'() {
Expand Down
Loading
Loading