[ASTERIXDB-2979][MTD][GRAPH] Implement CREATE / DROP GRAPH
Initial commit. This supports CREATE GRAPH, DROP GRAPH, and prevents
dropping views / functions / datasets / synonyms / dataverses that a
graph depends on.
Change-Id: Ibaf4dc7066b85d8ea3b58c6b90fd83af3a700506
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb-graph/+/14644
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Ian Maxon <imaxon@uci.edu>
diff --git a/asterix-graphix/src/main/resources/lang-extension/lang.txt b/asterix-graphix/src/main/resources/lang-extension/lang.txt
new file mode 100644
index 0000000..6d215f0
--- /dev/null
+++ b/asterix-graphix/src/main/resources/lang-extension/lang.txt
@@ -0,0 +1,354 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+import org.apache.asterix.graphix.common.metadata.GraphElementIdentifier;
+import org.apache.asterix.graphix.lang.expression.GraphConstructor;
+import org.apache.asterix.graphix.lang.statement.CreateGraphStatement;
+import org.apache.asterix.graphix.lang.statement.GraphDropStatement;
+import org.apache.asterix.graphix.lang.statement.GraphElementDecl;
+import org.apache.asterix.lang.sqlpp.parser.ParseException;
+import org.apache.asterix.lang.sqlpp.parser.SqlppParseException;
+import org.apache.asterix.lang.sqlpp.parser.Token;
+
+@new_at_the_class_def
+public GraphElementDecl parseGraphElementBody(GraphElementIdentifier identifier) throws CompilationException {
+ return parseImpl(new ParseFunction<GraphElementDecl>() {
+ @Override
+ public GraphElementDecl parse() throws ParseException {
+ DataverseName dataverse = defaultDataverse;
+ defaultDataverse = identifier.getGraphIdentifier().getDataverseName();
+
+ // We borrow the ViewBody production, where we have a SelectExpression or a VariableRef.
+ createNewScope();
+ Expression elementBodyExpr = GraphixParser.this.ViewBody();
+ removeCurrentScope();
+
+ defaultDataverse = dataverse;
+ return new GraphElementDecl(identifier, elementBodyExpr);
+ }
+ });
+}
+
+@merge
+Statement CreateStatement() throws ParseException:
+{
+ // merge area 1
+ before:
+ after:
+}
+{
+ (
+ // merge area 2
+ before:
+ after: | stmt = CreateGraphStatement(startToken, false)
+ )
+ {
+ // merge area 3
+ }
+}
+
+@merge
+Statement CreateOrReplaceStatement(Token startStmtToken) throws ParseException:
+{
+ // merge area 1
+ before:
+ after:
+}
+{
+ (
+ // merge area 2
+ before:
+ after: | stmt = CreateGraphStatement(startStmtToken, true)
+ )
+ {
+ // merge area 3
+ }
+}
+
+@merge
+Statement DropStatement() throws ParseException:
+{
+ // merge area 1
+ before:
+ after:
+}
+{
+ (
+ // merge area 2
+ before:
+ after: | stmt = DropGraphStatement(startToken)
+ )
+ {
+ // merge area 3
+ }
+}
+
+@new
+CreateGraphStatement CreateGraphStatement(Token startStmtToken, boolean orReplace) throws ParseException:
+{
+ CreateGraphStatement stmt = null;
+}
+{
+ <GRAPH> stmt = CreateGraphSpecification(startStmtToken, orReplace)
+ {
+ return stmt;
+ }
+}
+
+@new
+CreateGraphStatement CreateGraphSpecification(Token startStmtToken, boolean orReplace) throws ParseException:
+{
+ Pair<DataverseName, Identifier> nameComponents = null;
+ GraphConstructor graphConstructor = null;
+ boolean ifNotExists = false;
+}
+{
+ nameComponents = QualifiedName()
+ ifNotExists = IfNotExists()
+ {
+ if (orReplace && ifNotExists) {
+ throw new SqlppParseException(getSourceLocation(startStmtToken), "Unexpected IF NOT EXISTS");
+ }
+ }
+ <AS> graphConstructor = GraphConstructor(token)
+ {
+ CreateGraphStatement stmt = new CreateGraphStatement(nameComponents.first, nameComponents.second.getValue(),
+ orReplace, ifNotExists, graphConstructor);
+ return addSourceLocation(stmt, startStmtToken);
+ }
+}
+
+@new
+GraphDropStatement DropGraphStatement(Token startStmtToken) throws ParseException:
+{
+ GraphDropStatement stmt = null;
+}
+{
+ <GRAPH> stmt = DropGraphSpecification(startStmtToken)
+ {
+ return stmt;
+ }
+}
+
+@new
+GraphDropStatement DropGraphSpecification(Token startStmtToken) throws ParseException:
+{
+ Pair<DataverseName, Identifier> pairId = null;
+ boolean ifExists = false;
+}
+{
+ pairId = QualifiedName() ifExists = IfExists()
+ {
+ GraphDropStatement stmt = new GraphDropStatement(pairId.first, pairId.second.getValue(), ifExists);
+ return addSourceLocation(stmt, startStmtToken);
+ }
+}
+
+@new
+Pair<List<Integer>, List<List<String>>> KeyFields() throws ParseException:
+{
+ Pair<List<Integer>, List<List<String>>> keyFields = null;
+}
+{
+ // This is essentially an alias for the production PrimaryKeyFields.
+ keyFields = PrimaryKeyFields()
+ {
+ return keyFields;
+ }
+}
+
+@new
+GraphConstructor GraphConstructor(Token startStmtToken) throws ParseException:
+{
+ List<GraphConstructor.VertexElement> vertexElements = new ArrayList<GraphConstructor.VertexElement>();
+ List<GraphConstructor.EdgeElement> edgeElements = new ArrayList<GraphConstructor.EdgeElement>();
+ GraphConstructor.VertexElement vertexElement = null;
+ GraphConstructor.EdgeElement edgeElement = null;
+}
+{
+ vertexElement = GraphVertexSpecification(startStmtToken) { vertexElements.add(vertexElement); }
+ ( <COMMA>
+ (
+ ( vertexElement = GraphVertexSpecification(token) { vertexElements.add(vertexElement); } )
+ | ( edgeElement = GraphEdgeSpecification(token) { edgeElements.add(edgeElement); } )
+ )
+ )*
+ {
+ GraphConstructor graphConstructor = new GraphConstructor(vertexElements, edgeElements);
+ return addSourceLocation(graphConstructor, startStmtToken);
+ }
+}
+
+@new
+GraphConstructor.VertexElement GraphVertexSpecification(Token startStmtToken) throws ParseException:
+{
+ Pair<List<Integer>, List<List<String>>> primaryKeyFields;
+ Token beginPos = null, endPos = null;
+ Expression vertexDefinitionExpr;
+ String vertexName;
+}
+{
+ <VERTEX>
+ vertexName = GraphVertexDefinitionPattern()
+ <PRIMARY> <KEY> <LEFTPAREN> primaryKeyFields = KeyFields() <RIGHTPAREN>
+ <AS>
+ {
+ beginPos = token;
+ createNewScope();
+ }
+ (
+ vertexDefinitionExpr = ViewBody()
+ | <LEFTPAREN> vertexDefinitionExpr = ViewBody() <RIGHTPAREN>
+ )
+ {
+ endPos = token;
+ String vDef = extractFragment(beginPos.beginLine, beginPos.beginColumn + 1, endPos.endLine, endPos.endColumn + 1);
+ removeCurrentScope();
+ GraphConstructor.VertexElement vertexElement = new GraphConstructor.VertexElement(vertexName,
+ primaryKeyFields.second, primaryKeyFields.first, vertexDefinitionExpr, vDef);
+ return addSourceLocation(vertexElement, startStmtToken);
+ }
+}
+
+@new
+String GraphVertexDefinitionPattern() throws ParseException:
+{
+ String vertexName;
+}
+{
+ <LEFTPAREN> <COLON> vertexName = Identifier() <RIGHTPAREN>
+ {
+ return vertexName;
+ }
+}
+
+@new
+GraphConstructor.EdgeElement GraphEdgeSpecification(Token startStmtToken) throws ParseException:
+{
+ Pair<Triple<String, String, String>, Boolean> edgeDefinitionPattern;
+ Pair<List<Integer>, List<List<String>>> keyFields;
+ Token beginPos = null, endPos = null;
+ Expression edgeDefinitionExpr = null;
+
+ List<Integer> destinationKeySourceIndicators = null;
+ List<Integer> sourceKeySourceIndicators = null;
+ List<Integer> primaryKeySourceIndicators = null;
+ List<List<String>> destinationKeyFields = null;
+ List<List<String>> sourceKeyFields = null;
+ List<List<String>> primaryKeyFields = null;
+}
+{
+ <EDGE>
+ edgeDefinitionPattern = GraphEdgeDefinitionPattern()
+ (
+ (
+ <PRIMARY> <KEY> <LEFTPAREN> keyFields = KeyFields() <RIGHTPAREN>
+ {
+ primaryKeyFields = keyFields.second;
+ primaryKeySourceIndicators = keyFields.first;
+ }
+ <SOURCE> <KEY> <LEFTPAREN> keyFields = KeyFields() <RIGHTPAREN>
+ {
+ sourceKeyFields = keyFields.second;
+ sourceKeySourceIndicators = keyFields.first;
+ }
+ <DESTINATION> <KEY> <LEFTPAREN> keyFields = KeyFields() <RIGHTPAREN>
+ {
+ destinationKeyFields = keyFields.second;
+ destinationKeySourceIndicators = keyFields.first;
+ }
+ <AS>
+ {
+ beginPos = token;
+ createNewScope();
+ }
+ (
+ edgeDefinitionExpr = ViewBody()
+ | <LEFTPAREN> edgeDefinitionExpr = ViewBody() <RIGHTPAREN>
+ )
+ )
+ |
+ (
+ <DESTINATION> <KEY> <LEFTPAREN> keyFields = KeyFields() <RIGHTPAREN>
+ {
+ destinationKeyFields = keyFields.second;
+ destinationKeySourceIndicators = keyFields.first;
+ }
+ )
+ )
+ {
+ String destinationLabel, edgeLabel, sourceLabel;
+ if (edgeDefinitionPattern.second) { // isDirectedLeft
+ sourceLabel = edgeDefinitionPattern.first.third;
+ edgeLabel = edgeDefinitionPattern.first.second;
+ destinationLabel = edgeDefinitionPattern.first.first;
+ } else {
+ sourceLabel = edgeDefinitionPattern.first.first;
+ edgeLabel = edgeDefinitionPattern.first.second;
+ destinationLabel = edgeDefinitionPattern.first.third;
+ }
+
+ String eDef = null;
+ if (edgeDefinitionExpr != null) {
+ endPos = token;
+ eDef = extractFragment(beginPos.beginLine, beginPos.beginColumn + 1, endPos.endLine, endPos.endColumn + 1);
+ removeCurrentScope();
+ }
+
+ GraphConstructor.EdgeElement edgeElement = new GraphConstructor.EdgeElement(edgeLabel, destinationLabel,
+ sourceLabel, primaryKeyFields, primaryKeySourceIndicators, destinationKeyFields, destinationKeySourceIndicators,
+ sourceKeyFields, sourceKeySourceIndicators, edgeDefinitionExpr, eDef);
+ return addSourceLocation(edgeElement, startStmtToken);
+ }
+}
+
+@new
+Pair<Triple<String, String, String>, Boolean> GraphEdgeDefinitionPattern() throws ParseException:
+{
+ String leftVertexName, edgeName, rightVertexName;
+ boolean isDirectedLeft;
+}
+{
+ leftVertexName = GraphVertexDefinitionPattern()
+ ( <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> <GT> { isDirectedLeft = false; }
+ | <LT> <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> { isDirectedLeft = true; } )
+ rightVertexName = GraphVertexDefinitionPattern()
+ {
+ Triple<String, String, String> t = new Triple<String, String, String>(leftVertexName, edgeName, rightVertexName);
+ return new Pair<Triple<String, String, String>, Boolean>(t, isDirectedLeft);
+ }
+}
+
+@new
+<DEFAULT,IN_DBL_BRACE>
+TOKEN [IGNORE_CASE]:
+{
+ <DESTINATION: "destination">
+ | <EDGE: "edge">
+ | <GRAPH: "graph">
+ | <SOURCE: "source">
+ | <VERTEX: "vertex">
+}
+
+@new_at_the_end
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ <BAR: "|">
+}
\ No newline at end of file