diff --git a/src/main/java/org/qed/Backends/Cockroach/CockroachGenerator.java b/src/main/java/org/qed/Backends/Cockroach/CockroachGenerator.java index 4830f4c..b64e6c9 100644 --- a/src/main/java/org/qed/Backends/Cockroach/CockroachGenerator.java +++ b/src/main/java/org/qed/Backends/Cockroach/CockroachGenerator.java @@ -237,18 +237,6 @@ public Env transformJoin(Env env, RelRN.Join join) { String rightVar = env.bindings().get("right"); String onVar = env.bindings().get("on"); String privateVar = env.bindings().get("private"); - - // Check if join condition is True (JoinExtractFilter pattern) - if (join.cond() instanceof RexRN.True) { - String pattern = "(InnerJoin\n" - + " $" + leftVar + "\n" - + " $" + rightVar + "\n" - + " []\n" - + " $" + privateVar + "\n" - + ")"; - return env.setPattern(pattern).focus(pattern); - } - String pattern = "(InnerJoin\n" + " (Select $" + leftVar + " (ExtractBoundConditions $" + onVar + " (OutputCols $" + leftVar + ")))\n" + " (Select $" + rightVar + " (ExtractBoundConditions $" + onVar + " (OutputCols $" + rightVar + ")))\n" @@ -378,22 +366,6 @@ private String buildNestedIntersect(String intersectType, Seq sources, S @Override public Env onMatchMinus(Env env, RelRN.Minus minus) { - if (minus.sources().size() == 2) { - RelRN leftSource = minus.sources().get(0); - RelRN rightSource = minus.sources().get(1); - if (leftSource instanceof RelRN.Empty) { - String leftVar = env.generateVar("left"); - Env leftEnv = env.addBinding("left", leftVar); - String rightVar = leftEnv.generateVar("right"); - Env rightEnv = leftEnv.addBinding("right", rightVar); - // Still need to match the right source to get its pattern, but we'll use our variable name - Env rightSourceEnv = onMatch(rightEnv, rightSource); - String pattern = "(Except\n $" + leftVar + ":* & (HasZeroRows $" + leftVar + ")\n $" + rightVar + ":*\n)"; - return rightSourceEnv.addBinding("isPruneEmptyMinus", "true") - .addBinding("pruneEmptyLeft", leftVar) - .setPattern(pattern).focus(pattern); - } - } if (minus.sources().size() == 2 && minus.sources().get(0) instanceof RelRN.Minus inner) { String leftVar = env.generateVar("left"); Env leftEnv = env.addBinding("left", leftVar); @@ -870,11 +842,6 @@ private String buildNestedIntersectTransform(String intersectType, Seq s @Override public Env transformMinus(Env env, RelRN.Minus minus) { - if (env.bindings().containsKey("isPruneEmptyMinus")) { - String leftVar = env.bindings().get("pruneEmptyLeft"); - String pattern = "(ConstructEmptyValues (OutputCols $" + leftVar + "))"; - return env.setPattern(pattern).focus(pattern); - } String pattern = "(Except\n" + " $left\n" + " (Union\n" @@ -1024,26 +991,6 @@ private Env transformGroupSet(Env env, Seq groupSet) { @Override public Env transformEmpty(Env env, RelRN.Empty empty) { - // Check for any pruneEmpty* binding (generic, not rule-specific) - // Try common pruneEmpty binding names - String pruneVar = null; - boolean needsConstructEmptyValues = false; - if (env.bindings().containsKey("pruneEmptyLeft")) { - pruneVar = env.bindings().get("pruneEmptyLeft"); - needsConstructEmptyValues = true; - } else if (env.bindings().containsKey("pruneEmptyInput")) { - pruneVar = env.bindings().get("pruneEmptyInput"); - needsConstructEmptyValues = false; - } - if (pruneVar != null) { - if (needsConstructEmptyValues) { - String pattern = "(ConstructEmptyValues (OutputCols $" + pruneVar + "))"; - return env.setPattern(pattern).focus(pattern); - } else { - String pattern = "$" + pruneVar; - return env.setPattern(pattern).focus(pattern); - } - } if (env.bindings().containsKey("hasZeroRows")) { String inputVar = env.bindings().getOrDefault("zeroInput", "input"); String patternStr = env.pattern(); @@ -1054,6 +1001,11 @@ public Env transformEmpty(Env env, RelRN.Empty empty) { String pattern = "$" + inputVar; return env.setPattern(pattern).focus(pattern); } + if (env.bindings().containsKey("isPruneEmptyFilter")) { + String inputVar = env.bindings().get("pruneEmptyInput"); + String pattern = "$" + inputVar; + return env.setPattern(pattern).focus(pattern); + } String pattern = "(ConstructEmptyValues (OutputCols $input_0))"; return env.setPattern(pattern).focus(pattern); } @@ -1168,30 +1120,9 @@ else if (match.startsWith("(Union\n")) { match = "(" + unionType + "\n $" + leftVar + ":* & (HasZeroRows $" + leftVar + ")\n $" + rightVar + ":* & (HasZeroRows $" + rightVar + ")\n)"; } } - // Extract variable map early for potential normalization (before appending match) - java.util.Map varMapForNormalization = extractNumberedVarMap(match); - String out = transform.pattern(); - // Normalize match pattern for JoinExtractFilter before appending - if (!varMapForNormalization.isEmpty() && match.startsWith("(InnerJoin") && - varMapForNormalization.containsKey("left") && varMapForNormalization.containsKey("right") && - varMapForNormalization.containsKey("on") && varMapForNormalization.containsKey("private")) { - // Check output pattern to see if it's JoinExtractFilter - if (out.contains("(Select") && out.contains("(InnerJoin") && out.contains("[]")) { - for (java.util.Map.Entry e : varMapForNormalization.entrySet()) { - String base = e.getKey(); - String numbered = e.getValue(); - match = match.replaceAll( - "\\$" + java.util.regex.Pattern.quote(numbered.substring(1)), - java.util.regex.Matcher.quoteReplacement("$" + base) - ); - } - } - } - if (name.equals("PruneEmptyMinus")) { - match = match.replaceAll("\\$right_\\d+", java.util.regex.Matcher.quoteReplacement("$right")); - } sb.append(match).append("\n"); sb.append("=>\n"); + String out = transform.pattern(); if (out.startsWith("(ConstructEmptyValues (OutputCols $")) { int startIdx = "(ConstructEmptyValues (OutputCols $".length(); int endIdx = startIdx; @@ -1212,65 +1143,25 @@ else if (match.startsWith("(Union\n")) { out = "$" + numbered; } } - if (match.contains("HasZeroRows") && out.contains("ConstructEmptyValues")) { - // Find the first source variable (appears before HasZeroRows in the pattern) - // This handles cases where HasZeroRows is on a different source but we need the first one - int hasZeroRowsIdx = match.indexOf("(HasZeroRows $"); - if (hasZeroRowsIdx >= 0) { - // Find first variable before HasZeroRows - String beforeHasZeroRows = match.substring(0, hasZeroRowsIdx); - String firstSourceVar = findFirstVar(beforeHasZeroRows); - if (firstSourceVar != null) { - // Extract HasZeroRows variable - int start = hasZeroRowsIdx + "(HasZeroRows $".length(); - int end = start; - while (end < match.length() && (Character.isLetterOrDigit(match.charAt(end)) || match.charAt(end) == '_')) end++; - String hasZeroRowsVar = match.substring(start, end); - // If they differ, ensure output uses first source variable - if (!hasZeroRowsVar.equals(firstSourceVar)) { - out = out.replaceAll("(OutputCols \\$)[a-zA-Z_][a-zA-Z0-9_]*", "$1" + firstSourceVar); - } else if (match.contains("$left")) { - // Original logic: if HasZeroRows is on left, use left variable - int leftIdx = match.indexOf("$left"); - if (leftIdx >= 0) { - start = leftIdx + 1; - end = start; - while (end < match.length() && (Character.isLetterOrDigit(match.charAt(end)) || match.charAt(end) == '_')) end++; - String leftVar = match.substring(start, end); - out = out.replaceAll("(OutputCols \\$)[a-zA-Z_][a-zA-Z0-9_]*", "$1" + leftVar); - } - } - } + if (match.contains("HasZeroRows") && match.contains("$left") && out.contains("ConstructEmptyValues")) { + int leftIdx = match.indexOf("$left"); + if (leftIdx >= 0) { + int start = leftIdx + 1; + int end = start; + while (end < match.length() && (Character.isLetterOrDigit(match.charAt(end)) || match.charAt(end) == '_')) end++; + String leftVar = match.substring(start, end); + out = out.replaceAll("(OutputCols \\$)[a-zA-Z_][a-zA-Z0-9_]*", "$1" + leftVar); } } - java.util.Map varMap = varMapForNormalization; + java.util.Map varMap = extractNumberedVarMap(match); if (!varMap.isEmpty()) { - // Check if this is JoinExtractFilter pattern: Select wrapping InnerJoin with [] - // Distinguish from JoinCommute which has ExtractBoundConditions - boolean isJoinExtractFilterPattern = out.contains("(Select") && - out.contains("(InnerJoin") && out.contains("[]") && - match.startsWith("(InnerJoin") && - varMap.containsKey("left") && varMap.containsKey("right") && - varMap.containsKey("on") && varMap.containsKey("private"); - if (isJoinExtractFilterPattern) { - // Normalize output pattern (match already appended, so only normalize output) - for (java.util.Map.Entry e : varMap.entrySet()) { - String base = e.getKey(); - String numbered = e.getValue(); - out = out.replaceAll( - "\\$" + java.util.regex.Pattern.quote(numbered.substring(1)), - java.util.regex.Matcher.quoteReplacement("$" + base) - ); - } - } else { - for (java.util.Map.Entry e : varMap.entrySet()) { - String base = e.getKey(); - String numbered = e.getValue(); - out = out.replaceAll( - "\\$" + java.util.regex.Pattern.quote(base) + "(?![_0-9])", - java.util.regex.Matcher.quoteReplacement(numbered) - ); - } + for (java.util.Map.Entry e : varMap.entrySet()) { + String base = e.getKey(); + String numbered = e.getValue(); + out = out.replaceAll( + "\\$" + java.util.regex.Pattern.quote(base) + "(?![_0-9])", + java.util.regex.Matcher.quoteReplacement(numbered) + ); } } if (name.equals("PruneEmptyProject")) { diff --git a/src/main/java/org/qed/Backends/Cockroach/CockroachTests b/src/main/java/org/qed/Backends/Cockroach/CockroachTests index 1ca9357..cec8170 100644 --- a/src/main/java/org/qed/Backends/Cockroach/CockroachTests +++ b/src/main/java/org/qed/Backends/Cockroach/CockroachTests @@ -68,7 +68,7 @@ CREATE ROLE alice; # -------------------------------------------------- # FilterMerge # -------------------------------------------------- -norm expect=FilterMerge +norm expect=FilterMerge disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM (SELECT * FROM a WHERE k=3) WHERE s='foo' ---- select @@ -84,7 +84,7 @@ select ├── k:1 = 3 [outer=(1), constraints=(/1: [/3 - /3]; tight), fd=()-->(1)] └── s:4 = 'foo' [outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)] -norm expect=FilterMerge +norm expect=FilterMerge disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM (SELECT * FROM a WHERE k=3) WHERE s='foo' ---- select @@ -100,7 +100,7 @@ select ├── k:1 = 3 [outer=(1), constraints=(/1: [/3 - /3]; tight), fd=()-->(1)] └── s:4 = 'foo' [outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)] -norm expect=FilterMerge +norm expect=FilterMerge disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM (SELECT * FROM a WHERE i=1) WHERE False ---- values @@ -109,7 +109,7 @@ values ├── key: () └── fd: ()-->(1-5) -norm expect=FilterMerge +norm expect=FilterMerge disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM (SELECT * FROM a WHERE i<5) WHERE s='foo' ---- select @@ -124,7 +124,7 @@ select ├── i:2 < 5 [outer=(2), constraints=(/2: (/NULL - /4]; tight)] └── s:4 = 'foo' [outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)] -norm expect=FilterMerge +norm expect=FilterMerge disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM (SELECT * FROM a WHERE i>1 AND i<10) WHERE s='foo' OR k=5 ---- select @@ -139,7 +139,7 @@ select ├── (i:2 > 1) AND (i:2 < 10) [outer=(2), constraints=(/2: [/2 - /9]; tight)] └── (s:4 = 'foo') OR (k:1 = 5) [outer=(1,4)] -norm expect=FilterIntoJoin +norm expect=FilterIntoJoin disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM a INNER JOIN b ON a.k=b.x WHERE a.s='foo' ---- inner-join (hash) @@ -164,7 +164,7 @@ inner-join (hash) └── filters └── k:1 = x:8 [outer=(1,8), constraints=(/1: (/NULL - ]; /8: (/NULL - ]), fd=(1)==(8), (8)==(1)] -norm expect=FilterProjectTranspose disable=ProjectFilterTranspose +norm expect=FilterProjectTranspose disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM (SELECT i, i+1 AS r, f FROM a) a WHERE f=10.0 ---- project @@ -181,7 +181,7 @@ project └── projections └── i:2 + 1 [as=r:8, outer=(2), immutable] -norm expect=SemiJoinFilterTranspose disable=ProjectFilterTranspose +norm expect=SemiJoinFilterTranspose disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,UnionMerge) SELECT * FROM xy WHERE EXISTS (SELECT 1 FROM uv WHERE uv.u = xy.x) AND xy.y > 10 ---- semi-join (hash) @@ -204,7 +204,7 @@ semi-join (hash) └── filters └── u:5 = x:1 [outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)] -norm expect=ProjectFilterTranspose disable=FilterProjectTranspose +norm expect=ProjectFilterTranspose disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM (SELECT i FROM a WHERE i=100) a ---- select @@ -215,7 +215,7 @@ select └── filters └── i:2 = 100 [outer=(2), constraints=(/2: [/100 - /100]; tight), fd=()-->(2)] -norm expect=FilterReduceTrue +norm expect=FilterReduceTrue disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM a WHERE True ---- scan a @@ -227,7 +227,7 @@ exec-ddl CREATE INDEX partial_idx ON a (s) WHERE true ---- -norm expect=FilterReduceTrue +norm expect=FilterReduceTrue disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM a ---- scan a @@ -241,7 +241,7 @@ exec-ddl DROP INDEX partial_idx ---- -norm expect=UnionMerge disable=ConvertUnionToDistinctUnionAll +norm expect=UnionMerge disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,ConvertUnionToDistinctUnionAll) SELECT a, b, c FROM (SELECT a, b, c FROM t WHERE a < 0) UNION @@ -291,7 +291,7 @@ union └── t.b:15 > 1000 [outer=(15), constraints=(/15: [/1001 - ]; tight)] -norm expect=JoinPushTransitivePredicates disable=FilterIntoJoin +norm expect=JoinPushTransitivePredicates disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) SELECT * FROM a INNER JOIN b ON a.k = b.x WHERE a.s='foo' ---- inner-join (hash) @@ -316,3 +316,268 @@ inner-join (hash) └── filters └── k:1 = x:8 [outer=(1,8), constraints=(/1: (/NULL - ]; /8: (/NULL - ]), fd=(1)==(8), (8)==(1)] + + +exec-ddl +CREATE TABLE sales (id INT PRIMARY KEY, category1 STRING, category2 STRING, amount DECIMAL) +---- + +exec-ddl +CREATE TABLE emp (empno INT PRIMARY KEY, ename STRING, job STRING, mgr INT, hiredate DATE, sal DECIMAL, comm DECIMAL, deptno INT) +---- + +exec-ddl +CREATE TABLE dept (deptno INT PRIMARY KEY, dname STRING, loc STRING) +---- + +norm expect=AggregateFilterTranspose disable=(FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge,PushSelectIntoGroupBy) +SELECT category1, category2, SUM(amount) FROM (SELECT * FROM sales WHERE category1 = category2) GROUP BY category1, category2 +---- +select + ├── columns: category1:2!null category2:3!null sum:7 + ├── key: (3) + ├── fd: (2,3)-->(7), (2)==(3), (3)==(2) + ├── group-by (hash) + │ ├── columns: category1:2 category2:3 sum:7 + │ ├── grouping columns: category1:2 category2:3 + │ ├── key: (2,3) + │ ├── fd: (2,3)-->(7) + │ ├── scan sales + │ │ └── columns: category1:2 category2:3 amount:4 + │ └── aggregations + │ └── sum [as=sum:7, outer=(4)] + │ └── amount:4 + └── filters + └── category1:2 = category2:3 [outer=(2,3), constraints=(/2: (/NULL - ]; /3: (/NULL - ]), fd=(2)==(3), (3)==(2)] + +norm expect=FilterAggregateTranspose disable=(AggregateFilterTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) +SELECT * FROM (SELECT category1, category2, SUM(amount) FROM sales GROUP BY category1, category2) WHERE category1 = category2 +---- +group-by (hash) + ├── columns: category1:2!null category2:3!null sum:7 + ├── grouping columns: category2:3!null + ├── key: (3) + ├── fd: (3)-->(2,7), (2)==(3), (3)==(2) + ├── select + │ ├── columns: category1:2!null category2:3!null amount:4 + │ ├── fd: (2)==(3), (3)==(2) + │ ├── scan sales + │ │ └── columns: category1:2 category2:3 amount:4 + │ └── filters + │ └── category1:2 = category2:3 [outer=(2,3), constraints=(/2: (/NULL - ]; /3: (/NULL - ]), fd=(2)==(3), (3)==(2)] + └── aggregations + ├── sum [as=sum:7, outer=(4)] + │ └── amount:4 + └── const-agg [as=category1:2, outer=(2)] + └── category1:2 + +norm expect=ProjectMerge disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,SemiJoinFilterTranspose,UnionMerge,EliminateProject) +SELECT deptno, ename, sal * 2 AS doubled_sal FROM (SELECT deptno, ename, sal, comm FROM emp) +---- +project + ├── columns: deptno:8 ename:2 doubled_sal:11 + ├── immutable + ├── scan emp + │ └── columns: ename:2 sal:6 deptno:8 + └── projections + └── sal:6 * 2 [as=doubled_sal:11, outer=(6), immutable] + +# Additional test cases using emp/dept/sales tables +norm expect=FilterMerge disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) +SELECT * FROM (SELECT * FROM emp WHERE sal > 1000) WHERE deptno = 10 +---- +select + ├── columns: empno:1!null ename:2 job:3 mgr:4 hiredate:5 sal:6!null comm:7 deptno:8!null + ├── immutable + ├── key: (1) + ├── fd: ()-->(8), (1)-->(2-7) + ├── scan emp + │ ├── columns: empno:1!null ename:2 job:3 mgr:4 hiredate:5 sal:6 comm:7 deptno:8 + │ ├── key: (1) + │ └── fd: (1)-->(2-8) + └── filters + ├── sal:6 > 1000 [outer=(6), immutable, constraints=(/6: (/1000 - ]; tight)] + └── deptno:8 = 10 [outer=(8), constraints=(/8: [/10 - /10]; tight), fd=()-->(8)] + +norm expect=FilterIntoJoin disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) +SELECT * FROM emp INNER JOIN dept ON emp.deptno = dept.deptno WHERE emp.sal > 2000 +---- +inner-join (hash) + ├── columns: empno:1!null ename:2 job:3 mgr:4 hiredate:5 sal:6!null comm:7 deptno:8!null deptno:11!null dname:12 loc:13 + ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-more) + ├── immutable + ├── key: (1) + ├── fd: (1)-->(2-8), (11)-->(12,13), (8)==(11), (11)==(8) + ├── select + │ ├── columns: empno:1!null ename:2 job:3 mgr:4 hiredate:5 sal:6!null comm:7 emp.deptno:8 + │ ├── immutable + │ ├── key: (1) + │ ├── fd: (1)-->(2-8) + │ ├── scan emp + │ │ ├── columns: empno:1!null ename:2 job:3 mgr:4 hiredate:5 sal:6 comm:7 emp.deptno:8 + │ │ ├── key: (1) + │ │ └── fd: (1)-->(2-8) + │ └── filters + │ └── sal:6 > 2000 [outer=(6), immutable, constraints=(/6: (/2000 - ]; tight)] + ├── scan dept + │ ├── columns: dept.deptno:11!null dname:12 loc:13 + │ ├── key: (11) + │ └── fd: (11)-->(12,13) + └── filters + └── emp.deptno:8 = dept.deptno:11 [outer=(8,11), constraints=(/8: (/NULL - ]; /11: (/NULL - ]), fd=(8)==(11), (11)==(8)] + +norm expect=FilterProjectTranspose disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) +SELECT * FROM (SELECT empno, sal * 1.1 AS new_sal, job FROM emp) WHERE empno > 100 +---- +project + ├── columns: empno:1!null new_sal:11 job:3 + ├── immutable + ├── key: (1) + ├── fd: (1)-->(3,11) + ├── select + │ ├── columns: empno:1!null job:3 sal:6 + │ ├── key: (1) + │ ├── fd: (1)-->(3,6) + │ ├── scan emp + │ │ ├── columns: empno:1!null job:3 sal:6 + │ │ ├── key: (1) + │ │ └── fd: (1)-->(3,6) + │ └── filters + │ └── empno:1 > 100 [outer=(1), constraints=(/1: [/101 - ]; tight)] + └── projections + └── sal:6 * 1.1 [as=new_sal:11, outer=(6), immutable] + +norm expect=SemiJoinFilterTranspose disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,UnionMerge) +SELECT * FROM emp WHERE EXISTS (SELECT 1 FROM dept WHERE dept.deptno = emp.deptno) AND emp.sal > 1500 +---- +semi-join (hash) + ├── columns: empno:1!null ename:2 job:3 mgr:4 hiredate:5 sal:6!null comm:7 deptno:8 + ├── immutable + ├── key: (1) + ├── fd: (1)-->(2-8) + ├── select + │ ├── columns: empno:1!null ename:2 job:3 mgr:4 hiredate:5 sal:6!null comm:7 emp.deptno:8 + │ ├── immutable + │ ├── key: (1) + │ ├── fd: (1)-->(2-8) + │ ├── scan emp + │ │ ├── columns: empno:1!null ename:2 job:3 mgr:4 hiredate:5 sal:6 comm:7 emp.deptno:8 + │ │ ├── key: (1) + │ │ └── fd: (1)-->(2-8) + │ └── filters + │ └── sal:6 > 1500 [outer=(6), immutable, constraints=(/6: (/1500 - ]; tight)] + ├── scan dept + │ ├── columns: dept.deptno:11!null + │ └── key: (11) + └── filters + └── dept.deptno:11 = emp.deptno:8 [outer=(8,11), constraints=(/8: (/NULL - ]; /11: (/NULL - ]), fd=(8)==(11), (11)==(8)] + +norm expect=ProjectFilterTranspose disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) +SELECT * FROM (SELECT empno, job FROM emp WHERE job = 'MANAGER') WHERE empno > 100 +---- +select + ├── columns: empno:1!null job:3!null + ├── key: (1) + ├── fd: ()-->(3) + ├── scan emp + │ ├── columns: empno:1!null job:3 + │ ├── key: (1) + │ └── fd: (1)-->(3) + └── filters + ├── job:3 = 'MANAGER' [outer=(3), constraints=(/3: [/'MANAGER' - /'MANAGER']; tight), fd=()-->(3)] + └── empno:1 > 100 [outer=(1), constraints=(/1: [/101 - ]; tight)] + +norm expect=FilterReduceTrue disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) +SELECT * FROM sales WHERE True +---- +scan sales + ├── columns: id:1!null category1:2 category2:3 amount:4 + ├── key: (1) + └── fd: (1)-->(2-4) + +norm expect=UnionMerge disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,JoinPushTransitivePredicates,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,ConvertUnionToDistinctUnionAll) +SELECT deptno, dname FROM + (SELECT deptno, dname FROM dept WHERE loc = 'NEW YORK') +UNION + (SELECT deptno, dname FROM dept WHERE loc = 'CHICAGO') +UNION + (SELECT deptno, dname FROM dept WHERE loc = 'BOSTON') +---- +union + ├── columns: deptno:18 dname:19 + ├── left columns: deptno:11 dname:12 + ├── right columns: dept.deptno:13 dept.dname:14 + ├── key: (18,19) + ├── project + │ ├── columns: dept.deptno:1!null dept.dname:2 + │ ├── key: (1) + │ ├── fd: (1)-->(2) + │ └── select + │ ├── columns: dept.deptno:1!null dept.dname:2 loc:3!null + │ ├── key: (1) + │ ├── fd: ()-->(3), (1)-->(2) + │ ├── scan dept + │ │ ├── columns: dept.deptno:1!null dept.dname:2 loc:3 + │ │ ├── key: (1) + │ │ └── fd: (1)-->(2,3) + │ └── filters + │ └── loc:3 = 'NEW YORK' [outer=(3), constraints=(/3: [/'NEW YORK' - /'NEW YORK']; tight), fd=()-->(3)] + └── union + ├── columns: deptno:11 dname:12 + ├── left columns: dept.deptno:1 dept.dname:2 + ├── right columns: dept.deptno:6 dept.dname:7 + ├── key: (11,12) + ├── project + │ ├── columns: dept.deptno:6!null dept.dname:7 + │ ├── key: (6) + │ ├── fd: (6)-->(7) + │ └── select + │ ├── columns: dept.deptno:6!null dept.dname:7 loc:8!null + │ ├── key: (6) + │ ├── fd: ()-->(8), (6)-->(7) + │ ├── scan dept + │ │ ├── columns: dept.deptno:6!null dept.dname:7 loc:8 + │ │ ├── key: (6) + │ │ └── fd: (6)-->(7,8) + │ └── filters + │ └── loc:8 = 'CHICAGO' [outer=(8), constraints=(/8: [/'CHICAGO' - /'CHICAGO']; tight), fd=()-->(8)] + └── project + ├── columns: dept.deptno:13!null dept.dname:14 + ├── key: (13) + ├── fd: (13)-->(14) + └── select + ├── columns: dept.deptno:13!null dept.dname:14 loc:15!null + ├── key: (13) + ├── fd: ()-->(15), (13)-->(14) + ├── scan dept + │ ├── columns: dept.deptno:13!null dept.dname:14 loc:15 + │ ├── key: (13) + │ └── fd: (13)-->(14,15) + └── filters + └── loc:15 = 'BOSTON' [outer=(15), constraints=(/15: [/'BOSTON' - /'BOSTON']; tight), fd=()-->(15)] + +norm expect=JoinPushTransitivePredicates disable=(AggregateFilterTranspose,FilterAggregateTranspose,FilterIntoJoin,FilterMerge,FilterProjectTranspose,FilterReduceTrue,FilterSetOpTranspose,IntersectMerge,JoinAddRedundantSemiJoin,JoinCommute,ProjectFilterTranspose,ProjectMerge,SemiJoinFilterTranspose,UnionMerge) +SELECT * FROM emp INNER JOIN dept ON emp.deptno = dept.deptno WHERE emp.job = 'MANAGER' +---- +inner-join (hash) + ├── columns: empno:1!null ename:2 job:3!null mgr:4 hiredate:5 sal:6 comm:7 deptno:8!null deptno:11!null dname:12 loc:13 + ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-more) + ├── key: (1) + ├── fd: ()-->(3), (1)-->(2,4-8), (11)-->(12,13), (8)==(11), (11)==(8) + ├── select + │ ├── columns: empno:1!null ename:2 job:3!null mgr:4 hiredate:5 sal:6 comm:7 emp.deptno:8 + │ ├── key: (1) + │ ├── fd: ()-->(3), (1)-->(2,4-8) + │ ├── scan emp + │ │ ├── columns: empno:1!null ename:2 job:3 mgr:4 hiredate:5 sal:6 comm:7 emp.deptno:8 + │ │ ├── key: (1) + │ │ └── fd: (1)-->(2-8) + │ └── filters + │ └── job:3 = 'MANAGER' [outer=(3), constraints=(/3: [/'MANAGER' - /'MANAGER']; tight), fd=()-->(3)] + ├── scan dept + │ ├── columns: dept.deptno:11!null dname:12 loc:13 + │ ├── key: (11) + │ └── fd: (11)-->(12,13) + └── filters + └── emp.deptno:8 = dept.deptno:11 [outer=(8,11), constraints=(/8: (/NULL - ]; /11: (/NULL - ]), fd=(8)==(11), (11)==(8)] + diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/JoinExtractFilter.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/JoinExtractFilter.opt index 3eedbf5..cce0a04 100644 --- a/src/main/java/org/qed/Backends/Cockroach/Generated/JoinExtractFilter.opt +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/JoinExtractFilter.opt @@ -1,17 +1,17 @@ [JoinExtractFilter, Normalize] (InnerJoin - $left:* - $right:* - $on:* - $private:* + $input_0:* + $input_1:* + $cond_2:* + $private_3:* ) => (Select (InnerJoin - $left - $right - [] - $private + $input_0 + $input_1 + $true + $private_3 ) - $on + $cond_2 ) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/PruneEmptyMinus.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/PruneEmptyMinus.opt index b1b40fe..285acce 100644 --- a/src/main/java/org/qed/Backends/Cockroach/Generated/PruneEmptyMinus.opt +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/PruneEmptyMinus.opt @@ -1,7 +1,8 @@ [PruneEmptyMinus, Normalize] (Except - $left_0:* & (HasZeroRows $left_0) - $right:* + $empty_0:(Values) + $input_1:* + $private_2:* ) => -(ConstructEmptyValues (OutputCols $left_0)) +(ConstructEmptyValues (OutputCols $input_0))