[NO-ISSUE][GRAPHIX] Large Graphix update.
Large commit for the following:
- Using AbstractClauseExtension.
- LEFT-MATCH now defaults to a non-foldable-action.
- Refactor of some docstrings to use HTML lists.
- Starting work towards adding using SWITCH and CYCLE at Graphix.
- Adding support for implicit correlated vertex JOINs.
- Adding support for graphs with duplicate schema edge labels.
- Adding support for unconditional schema decoration.
- Adding support for negated edge labels.
- Total revamp for schema resolution: we now take an exhaustive approach.
- Adding support for specifying Graphix compiler options in the config file.
Change-Id: I120362128a5557f7de8904b86bacde3b606760db
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb-graph/+/17235
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Glenn Galvizo <ggalvizo@uci.edu>
diff --git a/asterix-graphix/src/main/resources/lang-extension/lang.txt b/asterix-graphix/src/main/resources/lang-extension/lang.txt
index 99952bf..ca7aa66 100644
--- a/asterix-graphix/src/main/resources/lang-extension/lang.txt
+++ b/asterix-graphix/src/main/resources/lang-extension/lang.txt
@@ -18,17 +18,19 @@
//
import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
-import org.apache.asterix.graphix.common.metadata.GraphElementIdentifier;
+import org.apache.asterix.graphix.common.metadata.IElementIdentifier;
+import org.apache.asterix.graphix.lang.annotation.ElementEvaluationAnnotation;
import org.apache.asterix.graphix.lang.clause.FromGraphClause;
-import org.apache.asterix.graphix.lang.clause.GraphSelectBlock;
import org.apache.asterix.graphix.lang.clause.MatchClause;
import org.apache.asterix.graphix.lang.expression.EdgePatternExpr;
import org.apache.asterix.graphix.lang.expression.GraphConstructor;
import org.apache.asterix.graphix.lang.expression.PathPatternExpr;
import org.apache.asterix.graphix.lang.expression.VertexPatternExpr;
import org.apache.asterix.graphix.lang.optype.MatchType;
+import org.apache.asterix.graphix.lang.parser.GraphixParserHint;
import org.apache.asterix.graphix.lang.statement.CreateGraphStatement;
import org.apache.asterix.graphix.lang.statement.DeclareGraphStatement;
import org.apache.asterix.graphix.lang.statement.GraphDropStatement;
@@ -40,7 +42,7 @@
import org.apache.asterix.lang.sqlpp.parser.Token;
@new_at_the_class_def
-public GraphElementDeclaration parseGraphElementBody(GraphElementIdentifier identifier) throws CompilationException {
+public GraphElementDeclaration parseGraphElementBody(IElementIdentifier identifier) throws CompilationException {
return parseImpl(new ParseFunction<GraphElementDeclaration>() {
@Override
public GraphElementDeclaration parse() throws ParseException {
@@ -58,6 +60,35 @@
});
}
+@new_at_the_class_def
+public GraphixParserHint fetchGraphixHint(Token token, GraphixParserHint[] expectedHints) {
+ if (token == null) {
+ return null;
+ }
+ Token hintToken = token.specialToken;
+
+ // We have a hint. Pull this from our collector.
+ if (hintToken == null) {
+ return null;
+ }
+ SourceLocation sourceLoc = getSourceLocation(hintToken);
+ hintCollector.remove(sourceLoc);
+
+ // Check for Graphix hints.
+ if (hintToken.hint != null) {
+ // A Graphix hint is not a SQLPP hint, so we shouldn't get anything in the "hint" field.
+ warnUnexpectedHint(hintToken.hint.getIdentifier(), sourceLoc, StringUtil.join(expectedHints, ", ", "\""));
+
+ } else if (hintToken.hintParams != null) {
+ for (GraphixParserHint graphixHint : expectedHints) {
+ if (graphixHint.getId().equals(hintToken.hintParams)) {
+ return graphixHint;
+ }
+ }
+ }
+ return null;
+}
+
@override
SelectBlock SelectBlock() throws ParseException:
{
@@ -146,8 +177,8 @@
return selectBlock;
} else {
- GraphSelectBlock selectBlock = new GraphSelectBlock(selectClause, fromGraphClause,
- fromLetWhereClauses, groupbyClause, gbyLetHavingClauses);
+ SelectBlock selectBlock = new SelectBlock(selectClause, fromGraphClause, fromLetWhereClauses,
+ groupbyClause, gbyLetHavingClauses);
selectBlock.setSourceLocation(startSrcLoc);
return selectBlock;
}
@@ -389,11 +420,11 @@
Token beginPos = null, endPos = null;
int positionOffset = 0;
Expression vertexDefinitionExpr;
- ElementLabel vertexLabel;
+ ElementLabel elementLabel;
}
{
<VERTEX>
- vertexLabel = GraphVertexDefinitionPattern()
+ elementLabel = GraphVertexDefinitionPattern()
<PRIMARY> <KEY> <LEFTPAREN> primaryKeyFields = KeyFields() <RIGHTPAREN>
<AS>
{
@@ -408,7 +439,7 @@
String vDef = extractFragment(beginPos.beginLine, beginPos.beginColumn + positionOffset, endPos.endLine,
endPos.endColumn + 1);
removeCurrentScope();
- GraphConstructor.VertexConstructor vertexConstructor = new GraphConstructor.VertexConstructor(vertexLabel,
+ GraphConstructor.VertexConstructor vertexConstructor = new GraphConstructor.VertexConstructor(elementLabel,
primaryKeyFields.second, primaryKeyFields.first, vertexDefinitionExpr, vDef);
return addSourceLocation(vertexConstructor, startStmtToken);
}
@@ -422,7 +453,7 @@
{
<LEFTPAREN> <COLON> vertexName = Identifier() <RIGHTPAREN>
{
- return new ElementLabel(vertexName);
+ return new ElementLabel(vertexName, false);
}
}
@@ -494,18 +525,18 @@
@new
Pair<Triple<ElementLabel, ElementLabel, ElementLabel>, Boolean> GraphEdgeDefinitionPattern() throws ParseException:
{
- ElementLabel leftVertexLabel, rightVertexLabel;
+ ElementLabel leftElementLabel, rightElementLabel;
boolean isDirectedLeft;
String edgeName;
}
{
- leftVertexLabel = GraphVertexDefinitionPattern()
+ leftElementLabel = GraphVertexDefinitionPattern()
( <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> <GT> { isDirectedLeft = false; }
| <LT> <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> { isDirectedLeft = true; } )
- rightVertexLabel = GraphVertexDefinitionPattern()
+ rightElementLabel = GraphVertexDefinitionPattern()
{
Triple<ElementLabel, ElementLabel, ElementLabel> t = new Triple<ElementLabel, ElementLabel, ElementLabel>(
- leftVertexLabel, new ElementLabel(edgeName), rightVertexLabel);
+ leftElementLabel, new ElementLabel(edgeName, false), rightElementLabel);
return new Pair<Triple<ElementLabel, ElementLabel, ElementLabel>, Boolean>(t, isDirectedLeft);
}
}
@@ -603,7 +634,7 @@
Token startToken = null, edgeStartToken = null;
VertexPatternExpr vertexExpr = null;
- EdgeDescriptor edgeDescriptor = null;
+ Pair<EdgeDescriptor, List<IExpressionAnnotation>> edgeDescriptorPair = null;
}
{
vertexExpr = VertexPatternExpression()
@@ -612,11 +643,16 @@
orderedVertexExpressions.add(vertexExpr);
}
(
- edgeDescriptor = EdgeDescriptor() { edgeStartToken = token; }
+ edgeDescriptorPair = EdgeDescriptorPair() { edgeStartToken = token; }
vertexExpr = VertexPatternExpression()
{
VertexPatternExpr leftVertex = orderedVertexExpressions.get(orderedVertexExpressions.size() - 1);
- EdgePatternExpr edgePattern = new EdgePatternExpr(leftVertex, vertexExpr, edgeDescriptor);
+ EdgePatternExpr edgePattern = new EdgePatternExpr(leftVertex, vertexExpr, edgeDescriptorPair.first);
+ if (!edgeDescriptorPair.second.isEmpty()) {
+ for (IExpressionAnnotation annotation : edgeDescriptorPair.second) {
+ edgePattern.addHint(annotation);
+ }
+ }
orderedEdgeExpressions.add(addSourceLocation(edgePattern, edgeStartToken));
orderedVertexExpressions.add(vertexExpr);
}
@@ -630,33 +666,44 @@
@new
VertexPatternExpr VertexPatternExpression() throws ParseException:
{
- Set<ElementLabel> vertexLabels = new HashSet<ElementLabel>();
+ Set<String> vertexLabels = new HashSet<String>();
VariableExpr variableExpr = null;
+ Expression filterExpr = null;
+ boolean isNegatedLabelSet = false;
Token startToken = null;
String vertexLabelName;
}
{
<LEFTPAREN> { startToken = token; }
+ ( variableExpr = Variable() )?
(
- variableExpr = Variable()
+ <COLON>
+ ( <CARET> { isNegatedLabelSet = true; } )?
+ vertexLabels = ParenthesizedLabelValueSet()
)?
- (
- <COLON> vertexLabelName = Identifier() { vertexLabels.add(new ElementLabel(vertexLabelName)); }
- ( <BAR> vertexLabelName = Identifier() { vertexLabels.add(new ElementLabel(vertexLabelName)); } )*
- )?
+ ( <WHERE> filterExpr = Expression() )?
<RIGHTPAREN>
{
- VertexPatternExpr vertexExpression = new VertexPatternExpr(variableExpr, vertexLabels);
+ // Construct our label set.
+ Set<ElementLabel> labels = new HashSet<ElementLabel>();
+ for (String vertexLabelValue : vertexLabels) {
+ labels.add(new ElementLabel(vertexLabelValue, isNegatedLabelSet));
+ }
+ VertexPatternExpr vertexExpression = new VertexPatternExpr(variableExpr, filterExpr, labels);
return addSourceLocation(vertexExpression, startToken);
}
}
@new
-EdgeDescriptor EdgeDescriptor() throws ParseException:
+Pair<EdgeDescriptor, List<IExpressionAnnotation>> EdgeDescriptorPair() throws ParseException:
{
- Pair<Set<ElementLabel>, Pair<Integer, Integer>> edgeDetail = null;
- Token startToken = null;
+ GraphixParserHint[] expectedHints = { GraphixParserHint.EXPAND_AND_UNION_HINT,
+ GraphixParserHint.SWITCH_AND_CYCLE_HINT };
+ List<IExpressionAnnotation> hintList = new ArrayList<IExpressionAnnotation>();
+ Triple<Set<ElementLabel>, Pair<Integer, Integer>, Expression> edgeDetail = null;
+ Token startToken = null, hintToken = null;
VariableExpr edgeVariable = null;
+ Expression filterExpr = null;
// We default to undirected edges.
EdgeDescriptor.EdgeDirection edgeDirection = EdgeDescriptor.EdgeDirection.UNDIRECTED;
@@ -666,11 +713,9 @@
<MINUS> { startToken = token; }
(
<LEFTBRACKET>
- (
- edgeVariable = Variable()
- )?
- ( <COLON> edgeDetail = EdgeDetail() )?
- <RIGHTBRACKET> <MINUS>
+ ( edgeVariable = Variable() )?
+ ( edgeDetail = EdgeDetail() )?
+ <RIGHTBRACKET> { hintToken = token; } <MINUS>
)?
( <GT> { edgeDirection = EdgeDescriptor.EdgeDirection.LEFT_TO_RIGHT; } )?
|
@@ -681,14 +726,21 @@
<MINUS>
(
<LEFTBRACKET>
- (
- edgeVariable = Variable()
- )?
- ( <COLON> edgeDetail = EdgeDetail() )?
- <RIGHTBRACKET> <MINUS>
+ ( edgeVariable = Variable() )?
+ ( edgeDetail = EdgeDetail() )?
+ <RIGHTBRACKET> { hintToken = token; } <MINUS>
)?
)
{
+ // See if we have an evaluation hint.
+ GraphixParserHint evalHint = fetchGraphixHint(hintToken, expectedHints);
+ if (Objects.equals(evalHint, GraphixParserHint.EXPAND_AND_UNION_HINT)) {
+ hintList.add(new ElementEvaluationAnnotation(ElementEvaluationAnnotation.Kind.EXPAND_AND_UNION));
+
+ } else if (Objects.equals(evalHint, GraphixParserHint.SWITCH_AND_CYCLE_HINT)) {
+ hintList.add(new ElementEvaluationAnnotation(ElementEvaluationAnnotation.Kind.SWITCH_AND_CYCLE));
+ }
+
// Edges (by default) are of pattern type EDGE and are not sub-paths.
EdgeDescriptor.PatternType patternType = EdgeDescriptor.PatternType.EDGE;
Integer hopCountMin = 1;
@@ -697,6 +749,7 @@
Set<ElementLabel> labels = new HashSet<ElementLabel>();
if (edgeDetail != null) {
labels = edgeDetail.first;
+ filterExpr = edgeDetail.third;
// We have explicitly specified "{" and "}". Use sub-path semantics.
if (edgeDetail.second != null) {
@@ -705,42 +758,71 @@
hopCountMax = edgeDetail.second.second;
}
}
-
- return new EdgeDescriptor(edgeDirection, patternType, labels, edgeVariable, hopCountMin, hopCountMax);
+ EdgeDescriptor edgeDescriptor =
+ new EdgeDescriptor(edgeDirection, patternType, labels, filterExpr, edgeVariable, hopCountMin, hopCountMax);
+ return new Pair<EdgeDescriptor, List<IExpressionAnnotation>>(edgeDescriptor, hintList);
}
}
@new
-Pair<Set<ElementLabel>, Pair<Integer, Integer>> EdgeDetail() throws ParseException:
+Triple<Set<ElementLabel>, Pair<Integer, Integer>, Expression> EdgeDetail() throws ParseException:
{
- Set<ElementLabel> edgeLabels = new HashSet<ElementLabel>();
+ Set<String> edgeLabels = new HashSet<String>();
Pair<Integer, Integer> repetitionQuantifier = null;
+ Expression filterExpr = null;
+ boolean isNegatedLabelSet = false;
String labelName = null;
}
{
(
- // Note: we want to forbid LABEL_1|LABEL_2{...}.
- LOOKAHEAD(2, <BAR>)
- (
- labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); }
- <BAR> labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); }
- ( <BAR> labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); } )*
- )
- |
- (
- labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); }
- |
- <LEFTPAREN>
- labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); }
- ( <BAR> labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); } )*
- <RIGHTPAREN>
- )
- ( repetitionQuantifier = EdgeRepetitionQuantifier() )?
- |
( repetitionQuantifier = EdgeRepetitionQuantifier() )
+ |
+ (
+ <COLON>
+ ( <CARET> { isNegatedLabelSet = true; } )?
+ edgeLabels = ParenthesizedLabelValueSet()
+ ( LOOKAHEAD(2)
+ ( <WHERE> filterExpr = Expression() )
+ |
+ ( repetitionQuantifier = EdgeRepetitionQuantifier() )
+ )?
+ )
+ |
+ ( <WHERE> filterExpr = Expression() )
)
{
- return new Pair<Set<ElementLabel>, Pair<Integer, Integer>> (edgeLabels, repetitionQuantifier);
+ // Construct our label set.
+ Set<ElementLabel> labels = new HashSet<ElementLabel>();
+ for (String edgeLabelValue : edgeLabels) {
+ labels.add(new ElementLabel(edgeLabelValue, isNegatedLabelSet));
+ }
+ return new Triple<Set<ElementLabel>, Pair<Integer, Integer>, Expression> (labels, repetitionQuantifier, filterExpr);
+ }
+}
+
+@new
+Set<String> ParenthesizedLabelValueSet() throws ParseException:
+{
+ Set<String> labelSet = new HashSet<String>();
+ Set<String> innerLabelSet = null;
+ String labelName = null;
+}
+{
+ (
+ ( labelName = Identifier() { labelSet.add(labelName); } )
+ |
+ (
+ <LEFTPAREN>
+ innerLabelSet = ParenthesizedLabelValueSet() { labelSet.addAll(innerLabelSet); }
+ (
+ <BAR>
+ innerLabelSet = ParenthesizedLabelValueSet() { labelSet.addAll(innerLabelSet); }
+ )*
+ <RIGHTPAREN>
+ )
+ )
+ {
+ return labelSet;
}
}
@@ -751,12 +833,17 @@
Integer hopCountMax = null;
}
{
- <LEFTBRACE>
- ( // Note: we forbid unbounded edge repetition.
- ( <INTEGER_LITERAL> { hopCountMin = Integer.valueOf(token.image); } )?
- <COMMA> <INTEGER_LITERAL> { hopCountMax = Integer.valueOf(token.image); }
+ (
+ <PLUS>
+ |
+ (
+ <LEFTBRACE>
+ ( <INTEGER_LITERAL> { hopCountMin = Integer.valueOf(token.image); } )?
+ <COMMA>
+ ( <INTEGER_LITERAL> { hopCountMax = Integer.valueOf(token.image); } )?
+ <RIGHTBRACE>
+ )
)
- <RIGHTBRACE>
{
return new Pair<Integer, Integer>(hopCountMin, hopCountMax);
}