-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1644 from partiql/v1-udop
[V1] Adds basic strategies to compiler (see #1625)
- Loading branch information
Showing
18 changed files
with
523 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# PartiQL Compiler Guide | ||
|
||
This document is a guide to using the PartiQL compiler. | ||
|
||
## Overview | ||
|
||
The compiler is responsible for converting logical plans (an _operator_ tree) | ||
to physical plans (an _expr_ tree) by applying _strategies_. A _strategy_ is a class | ||
that has a _pattern_ and an _apply_ method. The pattern determines when to | ||
invoke the _apply_ method which converts the matched operators (logical) to expressions (physical). | ||
|
||
## Pattern Matching | ||
|
||
A pattern is a tree composed of nodes with one of the types, | ||
|
||
``` | ||
TYPE: T – match if class T, check children. | ||
ANY: ? - match any node, check children. | ||
ALL: * - match all nodes in the subtree. | ||
``` | ||
|
||
For backwards compatibility, a pattern will ignore unmatched children. | ||
If this is not the desired behavior, a pattern can be marked as "strict" | ||
which will match children exactly and error on extraneous children. | ||
|
||
### Example | ||
|
||
Let's combine a limit and offset into a single relational expression; the logical tree looks like this. | ||
|
||
``` | ||
RelLimit Pattern.match(..) | ||
\ | ||
RelOffset Pattern.match(..) | ||
``` | ||
|
||
We use the builders to create a pattern. | ||
|
||
``` | ||
Pattern.match(RelLimit::class) | ||
.child(Pattern.match(RelOffset::class)) | ||
.build() | ||
``` | ||
|
||
In practice, the compiler will be walking the tree so we must deal with the inputs which have been recursively compiled. | ||
Because these nodes have been compiled, they are part of the "physical" or "Expr" domain. To illustrate, I've enclosed | ||
the compiled children nodes with `< >` so `ExprValue -> <Value>` and `ExprRelation -> <Rel>`. | ||
|
||
Recall the definition of a `RelLimit` and a `RelOffset` | ||
|
||
``` | ||
* RelLimit(input: Rel, limit: Rex) | ||
* RelOffset(input: Rel, offset: Rex) | ||
``` | ||
|
||
I have labelled these children in the illustration so that you can see where the end up in the match. | ||
|
||
``` | ||
... | ||
\ | ||
RelLimit | ||
/ \ | ||
x:<Value> RelOffset | ||
/ \ | ||
y:<Value> z:<Rel> | ||
``` | ||
|
||
The compiler will look for this pattern in the operator tree, and produce a match like so, | ||
|
||
``` | ||
Match { | ||
matched: [ | ||
RelLimit, | ||
RelOffset, | ||
], | ||
children: [ | ||
[x:<Value>], | ||
[y:<Value>, z:<Rel> ] | ||
], | ||
} | ||
``` | ||
|
||
The matched items are the flattened (in-order traversal) matched nodes from the pattern, while the children | ||
is a nested list of corresponding compiled children. | ||
|
||
This match structure is sent to the Strategy which gives the implementor all the information they need to know | ||
to continue folding the tree. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
partiql-eval/src/main/java/org/partiql/eval/compiler/Match.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package org.partiql.eval.compiler; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
import org.partiql.eval.Expr; | ||
import org.partiql.plan.Operator; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
/** | ||
* Match represents a subtree match to be sent to the | ||
*/ | ||
public class Match { | ||
|
||
private final Operator[] operators; | ||
private final List<List<Expr>> children; | ||
|
||
/** | ||
* Single operator match with zero-or-more inputs. | ||
* | ||
* @param operator matched logical operator. | ||
* @param children compiled child operators. | ||
*/ | ||
public Match(@NotNull Operator operator, @NotNull List<Expr> children) { | ||
this.operators = new Operator[]{operator}; | ||
this.children = Collections.singletonList(children); | ||
} | ||
|
||
/** | ||
* Get the i-th operator (pre-order) matched by the pattern. | ||
* | ||
* @param i 0-indexed | ||
* @return Operator | ||
*/ | ||
@NotNull | ||
public Operator operator(int i) { | ||
return operators[i]; | ||
} | ||
|
||
/** | ||
* Get the i-th input to this pattern. | ||
* | ||
* @param i 0-indexed | ||
* @return Expr | ||
*/ | ||
@NotNull | ||
public List<Expr> children(int i) { | ||
return children.get(i); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
partiql-eval/src/main/java/org/partiql/eval/compiler/Pattern.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package org.partiql.eval.compiler; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.partiql.plan.Operator; | ||
|
||
import java.util.function.Predicate; | ||
|
||
/** | ||
* Pattern defines a tree pattern. | ||
*/ | ||
public class Pattern { | ||
|
||
@NotNull | ||
private final Class<? extends Operator> clazz; | ||
|
||
@Nullable | ||
private final Predicate<Operator> predicate; | ||
|
||
/** | ||
* The only public method to create a pattern for now is this single-node match. | ||
* | ||
* @param clazz Operator class. | ||
*/ | ||
public Pattern(@NotNull Class<? extends Operator> clazz) { | ||
this.clazz = clazz; | ||
this.predicate = null; | ||
} | ||
|
||
/** | ||
* Internal constructor for simple patterns. | ||
* | ||
* @param clazz root type. | ||
* @param predicate optional predicate. | ||
*/ | ||
protected Pattern(@NotNull Class<? extends Operator> clazz, @Nullable Predicate<Operator> predicate) { | ||
this.clazz = clazz; | ||
this.predicate = predicate; | ||
} | ||
|
||
public boolean matches(Operator operator) { | ||
if (!clazz.isInstance(operator)) { | ||
return false; | ||
} | ||
return predicate == null || predicate.test(operator); | ||
} | ||
|
||
} |
41 changes: 41 additions & 0 deletions
41
partiql-eval/src/main/java/org/partiql/eval/compiler/Strategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package org.partiql.eval.compiler; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
import org.partiql.eval.Expr; | ||
import org.partiql.plan.Operator; | ||
|
||
/** | ||
* Strategy converts a logical operator into a physical operator. The compiler uses the list of operands | ||
* to determine a subtree match, then invokes `apply` to produce an {@link Expr}. | ||
*/ | ||
public abstract class Strategy { | ||
|
||
@NotNull | ||
private final Pattern pattern; | ||
|
||
/** | ||
* Create a strategy for a given pattern. | ||
* | ||
* @param pattern strategy pattern. | ||
*/ | ||
public Strategy(@NotNull Pattern pattern) { | ||
this.pattern = pattern; | ||
} | ||
|
||
/** | ||
* @return the pattern associated with this strategy | ||
*/ | ||
@NotNull | ||
public Pattern getPattern() { | ||
return pattern; | ||
} | ||
|
||
/** | ||
* Applies the strategy to a logical plan operator and returns the physical operation (expr). | ||
* | ||
* @param match holds the matched operators | ||
* @return the physical operation | ||
*/ | ||
@NotNull | ||
public abstract Expr apply(@NotNull Match match); | ||
} |
Oops, something went wrong.