SQL++ parser:
1. refactored asterix-aql to become asterix-lang-common and asterix-lang-aql, where the former is the common part for different languages;
2. added asterix-lang-sqlpp on top of asterix-lang-common;
3. ported parser tests, optimizer tests and runtime tests in asterix-app to their sql++ version, and added parser tests for all the queries.
Change-Id: Ie5af4e3b692ca017ec047a1ba3b404a51beb3a2e
Reviewed-on: https://asterix-gerrit.ics.uci.edu/466
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/AbstractBinaryCorrelateClause.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/AbstractBinaryCorrelateClause.java
new file mode 100644
index 0000000..b1dbba5
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/AbstractBinaryCorrelateClause.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.sqlpp.optype.JoinType;
+
+public abstract class AbstractBinaryCorrelateClause implements Clause {
+
+ private JoinType joinType;
+ private Expression rightExpr;
+ private VariableExpr rightVar;
+ private VariableExpr rightPosVar;
+
+ public AbstractBinaryCorrelateClause(JoinType joinType, Expression rightExpr, VariableExpr rightVar,
+ VariableExpr rightPosVar) {
+ this.joinType = joinType;
+ this.rightExpr = rightExpr;
+ this.rightVar = rightVar;
+ this.rightPosVar = rightPosVar;
+ }
+
+ public JoinType getJoinType() {
+ return joinType;
+ }
+
+ public Expression getRightExpression() {
+ return rightExpr;
+ }
+
+ public void setRightExpression(Expression rightExpr) {
+ this.rightExpr = rightExpr;
+ }
+
+ public VariableExpr getRightVariable() {
+ return rightVar;
+ }
+
+ public VariableExpr getPositionalVariable() {
+ return rightPosVar;
+ }
+
+ public boolean hasPositionalVariable() {
+ return rightPosVar != null;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/AbstractBinaryCorrelateWithConditionClause.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/AbstractBinaryCorrelateWithConditionClause.java
new file mode 100644
index 0000000..e1d4a7b
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/AbstractBinaryCorrelateWithConditionClause.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.sqlpp.optype.JoinType;
+
+public abstract class AbstractBinaryCorrelateWithConditionClause extends AbstractBinaryCorrelateClause {
+
+ private Expression conditionExpr;
+
+ public AbstractBinaryCorrelateWithConditionClause(JoinType joinType, Expression rightExpr, VariableExpr rightVar,
+ VariableExpr rightPosVar, Expression conditionExpr) {
+ super(joinType, rightExpr, rightVar, rightPosVar);
+ this.conditionExpr = conditionExpr;
+ }
+
+ public Expression getConditionExpression() {
+ return conditionExpr;
+ }
+
+ public void setConditionExpression(Expression conditionExpr) {
+ this.conditionExpr = conditionExpr;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/FromClause.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/FromClause.java
new file mode 100644
index 0000000..802869d
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/FromClause.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class FromClause implements Clause {
+
+ private List<FromTerm> fromTerms = new ArrayList<FromTerm>();
+
+ public FromClause(List<FromTerm> fromTerms) {
+ this.fromTerms = fromTerms;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.FROM_CLAUSE;
+ }
+
+ public List<FromTerm> getFromTerms() {
+ return fromTerms;
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/FromTerm.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/FromTerm.java
new file mode 100644
index 0000000..d7ab068
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/FromTerm.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class FromTerm implements Clause {
+ private Expression leftExpr;
+ private VariableExpr leftVar;
+ private VariableExpr posVar;
+ private List<AbstractBinaryCorrelateClause> correlateClauses;
+
+ public FromTerm(Expression leftExpr, VariableExpr leftVar, VariableExpr posVar,
+ List<AbstractBinaryCorrelateClause> correlateClauses) {
+ this.leftExpr = leftExpr;
+ this.leftVar = leftVar;
+ this.posVar = posVar;
+ this.correlateClauses = correlateClauses;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.FROM_TERM;
+ }
+
+ public Expression getLeftExpression() {
+ return leftExpr;
+ }
+
+ public void setLeftExpression(Expression expr) {
+ this.leftExpr = expr;
+ }
+
+ public VariableExpr getLeftVariable() {
+ return leftVar;
+ }
+
+ public VariableExpr getPositionalVariable() {
+ return posVar;
+ }
+
+ public boolean hasCorrelateClauses() {
+ return correlateClauses != null && correlateClauses.size() > 0;
+ }
+
+ public List<AbstractBinaryCorrelateClause> getCorrelateClauses() {
+ return correlateClauses;
+ }
+
+ public boolean hasPositionalVariable() {
+ return posVar != null;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/HavingClause.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/HavingClause.java
new file mode 100644
index 0000000..98cca9c
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/HavingClause.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.clause;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class HavingClause implements Clause {
+
+ private Expression filterExpression;
+
+ public HavingClause(Expression filterExpression) {
+ this.filterExpression = filterExpression;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.HAVING_CLAUSE;
+ }
+
+ public Expression getFilterExpression() {
+ return filterExpression;
+ }
+
+ public void setFilterExpression(Expression filterExpression) {
+ this.filterExpression = filterExpression;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/JoinClause.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/JoinClause.java
new file mode 100644
index 0000000..0da25cd
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/JoinClause.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.optype.JoinType;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class JoinClause extends AbstractBinaryCorrelateWithConditionClause {
+
+ public JoinClause(JoinType joinType, Expression rightExpr, VariableExpr rightVar, VariableExpr rightPosVar,
+ Expression conditionExpr) {
+ super(joinType, rightExpr, rightVar, rightPosVar, conditionExpr);
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.JOIN_CLAUSE;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/NestClause.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/NestClause.java
new file mode 100644
index 0000000..5719572
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/NestClause.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.optype.JoinType;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class NestClause extends AbstractBinaryCorrelateWithConditionClause {
+
+ public NestClause(JoinType joinType, Expression rightExpr, VariableExpr rightVar, VariableExpr rightPosVar,
+ Expression conditionExpr) {
+ super(joinType, rightExpr, rightVar, rightPosVar, conditionExpr);
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.NEST_CLAUSE;
+ }
+
+}
\ No newline at end of file
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/Projection.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/Projection.java
new file mode 100644
index 0000000..bfb5abf
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/Projection.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class Projection implements Clause {
+
+ private Expression expr;
+ private String name;
+ private boolean star;
+ private boolean exprStar;
+
+ public Projection(Expression expr, String name, boolean star, boolean exprStar) {
+ this.expr = expr;
+ this.name = name;
+ this.star = star;
+ this.exprStar = exprStar;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.PROJECTION;
+ }
+
+ public Expression getExpression() {
+ return expr;
+ }
+
+ public void setExpression(Expression expr) {
+ this.expr = expr;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean hasName() {
+ return name != null;
+ }
+
+ public boolean star() {
+ return star;
+ }
+
+ public boolean exprStar() {
+ return exprStar;
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectBlock.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectBlock.java
new file mode 100644
index 0000000..646e150
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectBlock.java
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.clause.GroupbyClause;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.clause.WhereClause;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class SelectBlock implements Clause {
+
+ private SelectClause selectClause;
+ private FromClause fromClause;
+ private List<LetClause> letClauses;
+ private WhereClause whereClause;
+ private GroupbyClause groupbyClause;
+ private List<LetClause> letClausesAfterGby;
+ private HavingClause havingClause;
+
+ public SelectBlock(SelectClause selectClause, FromClause fromClause, List<LetClause> letClauses,
+ WhereClause whereClause, GroupbyClause groupbyClause, List<LetClause> letClausesAfterGby,
+ HavingClause havingClause) {
+ this.selectClause = selectClause;
+ this.fromClause = fromClause;
+ this.letClauses = letClauses;
+ this.whereClause = whereClause;
+ this.groupbyClause = groupbyClause;
+ this.havingClause = havingClause;
+ this.letClausesAfterGby = letClausesAfterGby;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.SELECT_BLOCK;
+ }
+
+ public SelectClause getSelectClause() {
+ return selectClause;
+ }
+
+ public FromClause getFromClause() {
+ return fromClause;
+ }
+
+ public List<LetClause> getLetList() {
+ return letClauses;
+ }
+
+ public WhereClause getWhereClause() {
+ return whereClause;
+ }
+
+ public GroupbyClause getGroupbyClause() {
+ return groupbyClause;
+ }
+
+ public HavingClause getHavingClause() {
+ return havingClause;
+ }
+
+ public boolean hasFromClause() {
+ return fromClause != null;
+ }
+
+ public boolean hasLetClauses() {
+ return letClauses != null && letClauses.size() > 0;
+ }
+
+ public boolean hasWhereClause() {
+ return whereClause != null;
+ }
+
+ public boolean hasGroupbyClause() {
+ return groupbyClause != null;
+ }
+
+ public boolean hasLetClausesAfterGroupby() {
+ return letClausesAfterGby != null && letClausesAfterGby.size() > 0;
+ }
+
+ public List<LetClause> getLetListAfterGroupby() {
+ return letClausesAfterGby;
+ }
+
+ public boolean hasHavingClause() {
+ return havingClause != null;
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectClause.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectClause.java
new file mode 100644
index 0000000..c6b4e24
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectClause.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class SelectClause implements Clause {
+
+ private SelectElement selectElement;
+ private SelectRegular selectRegular;
+ private boolean distinct;
+
+ public SelectClause(SelectElement selectElement, SelectRegular selectRegular, boolean distinct) {
+ this.selectElement = selectElement;
+ this.selectRegular = selectRegular;
+ this.distinct = distinct;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.SELECT_CLAUSE;
+ }
+
+ public SelectElement getSelectElement() {
+ return selectElement;
+ }
+
+ public SelectRegular getSelectRegular() {
+ return selectRegular;
+ }
+
+ public boolean selectElement() {
+ return selectElement != null;
+ }
+
+ public boolean selectRegular() {
+ return selectRegular != null;
+ }
+
+ public boolean distinct() {
+ return distinct;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectElement.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectElement.java
new file mode 100644
index 0000000..e13506a
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectElement.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class SelectElement implements Clause {
+
+ private Expression expr;
+
+ public SelectElement(Expression expr) {
+ this.expr = expr;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.SELECT_ELEMENT;
+ }
+
+ public Expression getExpression() {
+ return expr;
+ }
+
+ public void setExpression(Expression expr) {
+ this.expr = expr;
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectRegular.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectRegular.java
new file mode 100644
index 0000000..e8a14ea
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectRegular.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class SelectRegular implements Clause {
+
+ private List<Projection> projections;
+
+ public SelectRegular(List<Projection> projections) {
+ this.projections = projections;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.SELECT_REGULAR;
+ }
+
+ public List<Projection> getProjections() {
+ return projections;
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectSetOperation.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectSetOperation.java
new file mode 100644
index 0000000..8e77745
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/SelectSetOperation.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationInput;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class SelectSetOperation implements Clause {
+
+ private SetOperationInput leftInput;
+ private List<SetOperationRight> rightInputs;
+
+ public SelectSetOperation(SetOperationInput leftInput, List<SetOperationRight> rightInputs) {
+ this.leftInput = leftInput;
+ this.rightInputs = rightInputs;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.SELECT_SET_OPERATION;
+ }
+
+ public SetOperationInput getLeftInput() {
+ return leftInput;
+ }
+
+ public List<SetOperationRight> getRightInputs() {
+ return rightInputs;
+ }
+
+ public boolean hasRightInputs() {
+ return rightInputs != null && rightInputs.size() > 0;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/UnnestClause.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/UnnestClause.java
new file mode 100644
index 0000000..b71838b
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/UnnestClause.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.clause;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.optype.JoinType;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class UnnestClause extends AbstractBinaryCorrelateClause {
+
+ public UnnestClause(JoinType joinType, Expression rightExpr, VariableExpr rightVar, VariableExpr rightPosVar) {
+ super(joinType, rightExpr, rightVar, rightPosVar);
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public ClauseType getClauseType() {
+ return ClauseType.UNNEST_CLAUSE;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/SelectExpression.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/SelectExpression.java
new file mode 100644
index 0000000..eb3f8d8
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/SelectExpression.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.expression;
+
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.clause.LimitClause;
+import org.apache.asterix.lang.common.clause.OrderbyClause;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class SelectExpression implements Expression {
+
+ private List<LetClause> letList;
+ private SelectSetOperation selectSetOperation;
+ private OrderbyClause orderbyClause;
+ private LimitClause limitClause;
+ private boolean subquery;
+
+ public SelectExpression(List<LetClause> letList, SelectSetOperation selectSetOperation, OrderbyClause orderbyClause,
+ LimitClause limitClause, boolean subquery) {
+ this.letList = letList;
+ this.selectSetOperation = selectSetOperation;
+ this.orderbyClause = orderbyClause;
+ this.limitClause = limitClause;
+ this.subquery = subquery;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ return ((ISqlppVisitor<R, T>) visitor).visit(this, arg);
+ }
+
+ @Override
+ public Kind getKind() {
+ return Kind.SELECT_EXPRESSION;
+ }
+
+ public List<LetClause> getLetList() {
+ return letList;
+ }
+
+ public SelectSetOperation getSelectSetOperation() {
+ return selectSetOperation;
+ }
+
+ public OrderbyClause getOrderbyClause() {
+ return orderbyClause;
+ }
+
+ public LimitClause getLimitClause() {
+ return limitClause;
+ }
+
+ public boolean hasOrderby() {
+ return orderbyClause != null;
+ }
+
+ public boolean hasLimit() {
+ return limitClause != null;
+ }
+
+ public boolean hasLetClauses() {
+ return letList != null && letList.size() > 0;
+ }
+
+ public boolean isSubquery() {
+ return subquery;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/optype/JoinType.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/optype/JoinType.java
new file mode 100644
index 0000000..f4b84f5
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/optype/JoinType.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.optype;
+
+public enum JoinType {
+
+ INNER,
+ LEFTOUTER
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/optype/SetOpType.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/optype/SetOpType.java
new file mode 100644
index 0000000..9036c89
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/optype/SetOpType.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.optype;
+
+public enum SetOpType {
+ UNION,
+ INTERSECT,
+ EXCEPT
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppRewriter.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppRewriter.java
new file mode 100644
index 0000000..4caecfe
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppRewriter.java
@@ -0,0 +1,318 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.rewrites;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
+import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.visitor.GatherFunctionCallsVisitor;
+import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
+import org.apache.asterix.lang.sqlpp.clause.FromClause;
+import org.apache.asterix.lang.sqlpp.clause.FromTerm;
+import org.apache.asterix.lang.sqlpp.clause.HavingClause;
+import org.apache.asterix.lang.sqlpp.clause.JoinClause;
+import org.apache.asterix.lang.sqlpp.clause.NestClause;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.clause.SelectClause;
+import org.apache.asterix.lang.sqlpp.clause.SelectElement;
+import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
+import org.apache.asterix.lang.sqlpp.util.FunctionUtils;
+import org.apache.asterix.lang.sqlpp.visitor.InlineColumnAliasVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.SqlppInlineUdfsVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.VariableCheckAndRewriteVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+import org.apache.asterix.metadata.MetadataManager;
+import org.apache.asterix.metadata.MetadataTransactionContext;
+import org.apache.asterix.metadata.declared.AqlMetadataProvider;
+import org.apache.asterix.metadata.entities.Function;
+import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
+
+public final class SqlppRewriter {
+
+ private Query topExpr;
+ private final List<FunctionDecl> declaredFunctions;
+ private final LangRewritingContext context;
+ private final MetadataTransactionContext mdTxnCtx;
+ private final AqlMetadataProvider metadataProvider;
+
+ public SqlppRewriter(List<FunctionDecl> declaredFunctions, Query topExpr, AqlMetadataProvider metadataProvider) {
+ this.topExpr = topExpr;
+ context = new LangRewritingContext(topExpr.getVarCounter());
+ this.declaredFunctions = declaredFunctions;
+ this.mdTxnCtx = metadataProvider.getMetadataTxnContext();
+ this.metadataProvider = metadataProvider;
+ }
+
+ public Query getExpr() {
+ return topExpr;
+ }
+
+ public int getVarCounter() {
+ return context.getVarCounter();
+ }
+
+ public void rewrite() throws AsterixException {
+ // Inlines column aliases.
+ inlineColumnAlias();
+
+ // Replace global variable access with the dataset function.
+ variableCheckAndRewrite();
+
+ // Inlines functions.
+ inlineDeclaredUdfs();
+ }
+
+ private void inlineColumnAlias() throws AsterixException {
+ if (topExpr == null) {
+ return;
+ }
+ // Inline column aliases.
+ InlineColumnAliasVisitor inlineColumnAliasVisitor = new InlineColumnAliasVisitor();
+ inlineColumnAliasVisitor.visit(topExpr, false);
+ }
+
+ private void variableCheckAndRewrite() throws AsterixException {
+ if (topExpr == null) {
+ return;
+ }
+ VariableCheckAndRewriteVisitor variableCheckAndRewriteVisitor = new VariableCheckAndRewriteVisitor();
+ variableCheckAndRewriteVisitor.visit(topExpr, null);
+ }
+
+ private void inlineDeclaredUdfs() throws AsterixException {
+ if (topExpr == null) {
+ return;
+ }
+ List<FunctionSignature> funIds = new ArrayList<FunctionSignature>();
+ for (FunctionDecl fdecl : declaredFunctions) {
+ funIds.add(fdecl.getSignature());
+ }
+
+ List<FunctionDecl> otherFDecls = new ArrayList<FunctionDecl>();
+ buildOtherUdfs(topExpr.getBody(), otherFDecls, funIds);
+ declaredFunctions.addAll(otherFDecls);
+ if (!declaredFunctions.isEmpty()) {
+ SqlppInlineUdfsVisitor visitor = new SqlppInlineUdfsVisitor(context);
+ while (topExpr.accept(visitor, declaredFunctions)) {
+ // loop until no more changes
+ }
+ }
+ declaredFunctions.removeAll(otherFDecls);
+ }
+
+ private void buildOtherUdfs(Expression expression, List<FunctionDecl> functionDecls,
+ List<FunctionSignature> declaredFunctions) throws AsterixException {
+ if (expression == null) {
+ return;
+ }
+ String value = metadataProvider.getConfig().get(FunctionUtils.IMPORT_PRIVATE_FUNCTIONS);
+ boolean includePrivateFunctions = (value != null) ? Boolean.valueOf(value.toLowerCase()) : false;
+ Set<FunctionSignature> functionCalls = getFunctionCalls(expression);
+ for (FunctionSignature signature : functionCalls) {
+
+ if (declaredFunctions != null && declaredFunctions.contains(signature)) {
+ continue;
+ }
+
+ Function function = lookupUserDefinedFunctionDecl(signature);
+ if (function == null) {
+ if (AsterixBuiltinFunctions.isBuiltinCompilerFunction(signature, includePrivateFunctions)) {
+ continue;
+ }
+ StringBuilder messageBuilder = new StringBuilder();
+ if (functionDecls.size() > 0) {
+ messageBuilder.append(" function " + functionDecls.get(functionDecls.size() - 1).getSignature()
+ + " depends upon function " + signature + " which is undefined");
+ } else {
+ messageBuilder.append(" function " + signature + " is undefined ");
+ }
+ throw new AsterixException(messageBuilder.toString());
+ }
+
+ if (function.getLanguage().equalsIgnoreCase(Function.LANGUAGE_AQL)) {
+ FunctionDecl functionDecl = FunctionUtils.getFunctionDecl(function);
+ if (functionDecl != null) {
+ if (functionDecls.contains(functionDecl)) {
+ throw new AsterixException("ERROR:Recursive invocation "
+ + functionDecls.get(functionDecls.size() - 1).getSignature() + " <==> "
+ + functionDecl.getSignature());
+ }
+ functionDecls.add(functionDecl);
+ buildOtherUdfs(functionDecl.getFuncBody(), functionDecls, declaredFunctions);
+ }
+ }
+ }
+
+ }
+
+ private Function lookupUserDefinedFunctionDecl(FunctionSignature signature) throws AsterixException {
+ if (signature.getNamespace() == null) {
+ return null;
+ }
+ return MetadataManager.INSTANCE.getFunction(mdTxnCtx, signature);
+ }
+
+ private Set<FunctionSignature> getFunctionCalls(Expression expression) throws AsterixException {
+ GatherFunctionCalls gfc = new GatherFunctionCalls();
+ expression.accept(gfc, null);
+ return gfc.getCalls();
+ }
+
+ private static class GatherFunctionCalls extends GatherFunctionCallsVisitor implements ISqlppVisitor<Void, Void> {
+
+ public GatherFunctionCalls() {
+ }
+
+ @Override
+ public Void visit(FromClause fromClause, Void arg) throws AsterixException {
+ for (FromTerm fromTerm : fromClause.getFromTerms()) {
+ fromTerm.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(FromTerm fromTerm, Void arg) throws AsterixException {
+ fromTerm.getLeftExpression().accept(this, arg);
+ for (AbstractBinaryCorrelateClause correlateClause : fromTerm.getCorrelateClauses()) {
+ correlateClause.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(JoinClause joinClause, Void arg) throws AsterixException {
+ joinClause.getRightExpression().accept(this, arg);
+ joinClause.getConditionExpression().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(NestClause nestClause, Void arg) throws AsterixException {
+ nestClause.getRightExpression().accept(this, arg);
+ nestClause.getConditionExpression().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(Projection projection, Void arg) throws AsterixException {
+ projection.getExpression().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectBlock selectBlock, Void arg) throws AsterixException {
+ if (selectBlock.hasFromClause()) {
+ selectBlock.getFromClause().accept(this, arg);
+ }
+ if (selectBlock.hasLetClauses()) {
+ for (LetClause letClause : selectBlock.getLetList()) {
+ letClause.accept(this, arg);
+ }
+ }
+ if (selectBlock.hasWhereClause()) {
+ selectBlock.getWhereClause().accept(this, arg);
+ }
+ if (selectBlock.hasGroupbyClause()) {
+ selectBlock.getGroupbyClause().accept(this, arg);
+ }
+ if (selectBlock.hasLetClausesAfterGroupby()) {
+ for (LetClause letClause : selectBlock.getLetListAfterGroupby()) {
+ letClause.accept(this, arg);
+ }
+ }
+ if (selectBlock.hasHavingClause()) {
+ selectBlock.getHavingClause().accept(this, arg);
+ }
+ selectBlock.getSelectClause().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectClause selectClause, Void arg) throws AsterixException {
+ if (selectClause.selectElement()) {
+ selectClause.getSelectElement().accept(this, arg);
+ } else {
+ selectClause.getSelectRegular().accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectElement selectElement, Void arg) throws AsterixException {
+ selectElement.getExpression().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectRegular selectRegular, Void arg) throws AsterixException {
+ for (Projection projection : selectRegular.getProjections()) {
+ projection.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectSetOperation selectSetOperation, Void arg) throws AsterixException {
+ selectSetOperation.getLeftInput().accept(this, arg);
+ for (SetOperationRight setOperationRight : selectSetOperation.getRightInputs()) {
+ setOperationRight.getSetOperationRightInput().accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectExpression selectStatement, Void arg) throws AsterixException {
+ selectStatement.getSelectSetOperation().accept(this, arg);
+ if (selectStatement.hasOrderby()) {
+ selectStatement.getOrderbyClause().accept(this, arg);
+ }
+ if (selectStatement.hasLimit()) {
+ selectStatement.getLimitClause().accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(UnnestClause unnestClause, Void arg) throws AsterixException {
+ unnestClause.getRightExpression().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(HavingClause havingClause, Void arg) throws AsterixException {
+ havingClause.getFilterExpression().accept(this, arg);
+ return null;
+ }
+
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/struct/SetOperationInput.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/struct/SetOperationInput.java
new file mode 100644
index 0000000..da89709
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/struct/SetOperationInput.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.struct;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class SetOperationInput {
+
+ private SelectBlock selectBlock;
+ private SelectExpression subquery;
+
+ public SetOperationInput(SelectBlock selectBlock, SelectExpression subquery) {
+ this.selectBlock = selectBlock;
+ this.subquery = subquery;
+ }
+
+ public SelectBlock getSelectBlock() {
+ return selectBlock;
+ }
+
+ public SelectExpression getSubquery() {
+ return subquery;
+ }
+
+ public boolean selectBlock() {
+ return selectBlock != null;
+ }
+
+ public boolean subquery() {
+ return subquery != null;
+ }
+
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws AsterixException {
+ if (selectBlock != null) {
+ return ((ISqlppVisitor<R, T>) visitor).visit(selectBlock, arg);
+ } else {
+ return ((ISqlppVisitor<R, T>) visitor).visit(subquery, arg);
+ }
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/struct/SetOperationRight.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/struct/SetOperationRight.java
new file mode 100644
index 0000000..ae0572d
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/struct/SetOperationRight.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.struct;
+
+import org.apache.asterix.lang.sqlpp.optype.SetOpType;
+
+public class SetOperationRight {
+
+ private SetOpType opType;
+ private boolean setSemantics;
+ private SetOperationInput setOperationRightInput;
+
+ public SetOperationRight(SetOpType opType, boolean setSemantics, SetOperationInput setOperationRight) {
+ this.opType = opType;
+ this.setSemantics = setSemantics;
+ this.setOperationRightInput = setOperationRight;
+ }
+
+ public SetOpType getSetOpType() {
+ return opType;
+ }
+
+ public boolean setSemantics() {
+ return setSemantics;
+ }
+
+ public SetOperationInput getSetOperationRightInput() {
+ return setOperationRightInput;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/FunctionUtils.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/FunctionUtils.java
new file mode 100644
index 0000000..9100ecd
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/FunctionUtils.java
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.lang.sqlpp.util;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.lang.common.base.Statement;
+import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
+import org.apache.asterix.lang.sqlpp.parser.SQLPPParser;
+import org.apache.asterix.metadata.entities.Function;
+import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
+
+public class FunctionUtils {
+
+ public static final String IMPORT_PRIVATE_FUNCTIONS = "import-private-functions";
+
+ public static FunctionDecl getFunctionDecl(Function function) throws AsterixException {
+ String functionBody = function.getFunctionBody();
+ List<String> params = function.getParams();
+ List<VarIdentifier> varIdentifiers = new ArrayList<VarIdentifier>();
+
+ StringBuilder builder = new StringBuilder();
+ builder.append(" use dataverse " + function.getDataverseName() + ";");
+ builder.append(" declare function " + function.getName().split("@")[0]);
+ builder.append("(");
+ for (String param : params) {
+ VarIdentifier varId = new VarIdentifier(param);
+ varIdentifiers.add(varId);
+ builder.append(param);
+ builder.append(",");
+ }
+ if (params.size() > 0) {
+ builder.delete(builder.length() - 1, builder.length());
+ }
+ builder.append(")");
+ builder.append("{");
+ builder.append("\n");
+ builder.append(functionBody);
+ builder.append("\n");
+ builder.append("}");
+
+ SQLPPParser parser = new SQLPPParser(new StringReader(new String(builder)));
+
+ List<Statement> statements = null;
+ try {
+ statements = parser.parse();
+ } catch (AsterixException pe) {
+ throw new AsterixException(pe);
+ }
+
+ FunctionDecl decl = (FunctionDecl) statements.get(1);
+ return decl;
+ }
+
+ public static IFunctionInfo getFunctionInfo(FunctionIdentifier fi) {
+ return AsterixBuiltinFunctions.getAsterixFunctionInfo(fi);
+ }
+
+ public static IFunctionInfo getFunctionInfo(FunctionSignature fs) {
+ return getFunctionInfo(new FunctionIdentifier(fs.getNamespace(), fs.getName(), fs.getArity()));
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppAstPrintUtil.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppAstPrintUtil.java
new file mode 100644
index 0000000..0f7ec4a
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppAstPrintUtil.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.ILangExpression;
+import org.apache.asterix.lang.common.base.Statement;
+import org.apache.asterix.lang.sqlpp.visitor.SqlppPrintVisitor;
+
+public class SqlppAstPrintUtil {
+
+ /**
+ * Prints the AST (abstract syntax tree) of an ILangExpression.
+ *
+ * @param expr
+ * the language expression.
+ * @param output
+ * a writer for printing strings.
+ * @throws AsterixException
+ */
+ public static void print(ILangExpression expr, PrintWriter output) throws AsterixException {
+ SqlppPrintVisitor visitor = new SqlppPrintVisitor(output);
+ expr.accept(visitor, 0);
+ }
+
+ /**
+ * Prints the AST of a list of top-level language statements.
+ *
+ * @param statements
+ * a list of statements of a query
+ * @param output
+ * a writer for printing strings.
+ * @throws AsterixException
+ */
+ public static void print(List<Statement> statements, PrintWriter output) throws AsterixException {
+ SqlppPrintVisitor visitor = new SqlppPrintVisitor(output);
+ for (Statement statement : statements) {
+ statement.accept(visitor, 0);
+ }
+ }
+
+ /**
+ * @param expr
+ * a language expression.
+ * @return the AST of a language expression.
+ * @throws AsterixException
+ */
+ public static String toString(ILangExpression expr) throws AsterixException {
+ List<ILangExpression> exprs = new ArrayList<ILangExpression>();
+ exprs.add(expr);
+ return toString(exprs);
+ }
+
+ /**
+ * @param exprs
+ * a list of language expression.
+ * @return an AST of the input language expressions.
+ * @throws AsterixException
+ */
+ public static String toString(List<ILangExpression> exprs) throws AsterixException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ PrintWriter output = new PrintWriter(bos);
+ SqlppPrintVisitor visitor = new SqlppPrintVisitor(output);
+ for (ILangExpression expr : exprs) {
+ expr.accept(visitor, 0);
+ }
+ output.close();
+ return new String(bos.toByteArray());
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppFormatPrintUtil.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppFormatPrintUtil.java
new file mode 100644
index 0000000..f10c9fc
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppFormatPrintUtil.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.ILangExpression;
+import org.apache.asterix.lang.common.base.Statement;
+import org.apache.asterix.lang.sqlpp.visitor.SqlppFormatPrintVisitor;
+
+public class SqlppFormatPrintUtil {
+
+ /**
+ * Prints the formatted output of an ILangExpression.
+ *
+ * @param expr
+ * the language expression.
+ * @param output
+ * a writer for printing strings.
+ * @throws AsterixException
+ */
+ public static void print(ILangExpression expr, PrintWriter output) throws AsterixException {
+ SqlppFormatPrintVisitor visitor = new SqlppFormatPrintVisitor(output);
+ expr.accept(visitor, 0);
+ }
+
+ /**
+ * Prints the formatted output of a list of top-level language statements.
+ *
+ * @param statements
+ * a list of statements of a query
+ * @param output
+ * a writer for printing strings.
+ * @throws AsterixException
+ */
+ public static void print(List<Statement> statements, PrintWriter output) throws AsterixException {
+ SqlppFormatPrintVisitor visitor = new SqlppFormatPrintVisitor(output);
+ for (Statement statement : statements) {
+ statement.accept(visitor, 0);
+ }
+ }
+
+ /**
+ * @param expr
+ * a language expression.
+ * @return a formatted string of a language expression.
+ * @throws AsterixException
+ */
+ public static String toString(ILangExpression expr) throws AsterixException {
+ List<ILangExpression> exprs = new ArrayList<ILangExpression>();
+ exprs.add(expr);
+ return toString(exprs);
+ }
+
+ /**
+ * @param exprs
+ * a list of language expression.
+ * @return a formatted string of the input language expressions.
+ * @throws AsterixException
+ */
+ public static String toString(List<ILangExpression> exprs) throws AsterixException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ PrintWriter output = new PrintWriter(bos);
+ SqlppFormatPrintVisitor visitor = new SqlppFormatPrintVisitor(output);
+ for (ILangExpression expr : exprs) {
+ expr.accept(visitor, 0);
+ }
+ output.close();
+ return new String(bos.toByteArray());
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableSubstitutionUtil.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableSubstitutionUtil.java
new file mode 100644
index 0000000..0a4c2c4
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableSubstitutionUtil.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.ILangExpression;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
+import org.apache.asterix.lang.common.rewrites.VariableSubstitutionEnvironment;
+import org.apache.asterix.lang.sqlpp.visitor.SqlppCloneAndSubstituteVariablesVisitor;
+import org.apache.asterix.lang.sqlpp.visitor.SqlppSubstituteVariablesVisitor;
+
+public class SqlppVariableSubstitutionUtil {
+
+ public static List<ILangExpression> substituteVariable(List<ILangExpression> expressions,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ SqlppCloneAndSubstituteVariablesVisitor visitor = new SqlppSubstituteVariablesVisitor(
+ new LangRewritingContext(0));
+ List<ILangExpression> newExprs = new ArrayList<ILangExpression>();
+ for (ILangExpression expression : expressions) {
+ newExprs.add(expression.accept(visitor, env).first);
+ }
+ return newExprs;
+ }
+
+ public static ILangExpression substituteVariable(ILangExpression expression, VariableSubstitutionEnvironment env)
+ throws AsterixException {
+ SqlppSubstituteVariablesVisitor visitor = new SqlppSubstituteVariablesVisitor(new LangRewritingContext(0));
+ return expression.accept(visitor, env).first;
+ }
+
+ public static List<ILangExpression> substituteVariable(List<ILangExpression> expressions,
+ Map<VariableExpr, Expression> varExprMap) throws AsterixException {
+ SqlppSubstituteVariablesVisitor visitor = new SqlppSubstituteVariablesVisitor(new LangRewritingContext(0));
+ VariableSubstitutionEnvironment env = new VariableSubstitutionEnvironment(varExprMap);
+ List<ILangExpression> newExprs = new ArrayList<ILangExpression>();
+ for (ILangExpression expression : expressions) {
+ newExprs.add(expression.accept(visitor, env).first);
+ }
+ return newExprs;
+ }
+
+ public static ILangExpression substituteVariable(ILangExpression expression,
+ Map<VariableExpr, Expression> varExprMap) throws AsterixException {
+ SqlppSubstituteVariablesVisitor visitor = new SqlppSubstituteVariablesVisitor(new LangRewritingContext(0));
+ VariableSubstitutionEnvironment env = new VariableSubstitutionEnvironment(varExprMap);
+ return expression.accept(visitor, env).first;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/InlineColumnAliasVisitor.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/InlineColumnAliasVisitor.java
new file mode 100644
index 0000000..d6955c0
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/InlineColumnAliasVisitor.java
@@ -0,0 +1,394 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.visitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.Expression.Kind;
+import org.apache.asterix.lang.common.base.Literal;
+import org.apache.asterix.lang.common.clause.GroupbyClause;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.clause.LimitClause;
+import org.apache.asterix.lang.common.clause.OrderbyClause;
+import org.apache.asterix.lang.common.clause.WhereClause;
+import org.apache.asterix.lang.common.expression.CallExpr;
+import org.apache.asterix.lang.common.expression.FieldAccessor;
+import org.apache.asterix.lang.common.expression.FieldBinding;
+import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair;
+import org.apache.asterix.lang.common.expression.IfExpr;
+import org.apache.asterix.lang.common.expression.IndexAccessor;
+import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.LiteralExpr;
+import org.apache.asterix.lang.common.expression.OperatorExpr;
+import org.apache.asterix.lang.common.expression.QuantifiedExpression;
+import org.apache.asterix.lang.common.expression.RecordConstructor;
+import org.apache.asterix.lang.common.expression.UnaryExpr;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.parser.ScopeChecker;
+import org.apache.asterix.lang.common.rewrites.VariableSubstitutionEnvironment;
+import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.struct.QuantifiedPair;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
+import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
+import org.apache.asterix.lang.sqlpp.clause.FromClause;
+import org.apache.asterix.lang.sqlpp.clause.FromTerm;
+import org.apache.asterix.lang.sqlpp.clause.HavingClause;
+import org.apache.asterix.lang.sqlpp.clause.JoinClause;
+import org.apache.asterix.lang.sqlpp.clause.NestClause;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.clause.SelectClause;
+import org.apache.asterix.lang.sqlpp.clause.SelectElement;
+import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
+import org.apache.asterix.lang.sqlpp.util.SqlppVariableSubstitutionUtil;
+import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppQueryExpressionVisitor;
+
+public class InlineColumnAliasVisitor extends AbstractSqlppQueryExpressionVisitor<Void, Boolean> {
+
+ private final ScopeChecker scopeChecker = new ScopeChecker();
+
+ @Override
+ public Void visit(WhereClause whereClause, Boolean arg) throws AsterixException {
+ whereClause.getWhereExpr().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(FromClause fromClause, Boolean arg) throws AsterixException {
+ for (FromTerm fromTerm : fromClause.getFromTerms()) {
+ fromTerm.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(FromTerm fromTerm, Boolean arg) throws AsterixException {
+ fromTerm.getLeftExpression().accept(this, arg);
+ // A from binding variable will override the alias to substitute.
+ scopeChecker.getCurrentScope().removeSymbolExpressionMapping(fromTerm.getLeftVariable());
+ if (fromTerm.hasPositionalVariable()) {
+ scopeChecker.getCurrentScope().removeSymbolExpressionMapping(fromTerm.getPositionalVariable());
+ }
+
+ for (AbstractBinaryCorrelateClause correlate : fromTerm.getCorrelateClauses()) {
+ correlate.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(JoinClause joinClause, Boolean arg) throws AsterixException {
+ joinClause.getRightExpression().accept(this, arg);
+ removeSubsutitions(joinClause);
+ joinClause.getConditionExpression().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(NestClause nestClause, Boolean arg) throws AsterixException {
+ nestClause.getRightExpression().accept(this, arg);
+ nestClause.getConditionExpression().accept(this, arg);
+ removeSubsutitions(nestClause);
+ return null;
+ }
+
+ @Override
+ public Void visit(UnnestClause unnestClause, Boolean arg) throws AsterixException {
+ unnestClause.getRightExpression().accept(this, arg);
+ removeSubsutitions(unnestClause);
+ return null;
+ }
+
+ @Override
+ public Void visit(Projection projection, Boolean arg) throws AsterixException {
+ projection.getExpression().accept(this, arg);
+ scopeChecker.getCurrentScope().addSymbolExpressionMappingToScope(
+ new VariableExpr(new VarIdentifier(projection.getName())), projection.getExpression());
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectBlock selectBlock, Boolean arg) throws AsterixException {
+ // Traverses the select block in the order of "select", "group-by",
+ // "group-by" lets and "having".
+ selectBlock.getSelectClause().accept(this, arg);
+
+ if (selectBlock.hasFromClause()) {
+ selectBlock.getFromClause().accept(this, arg);
+ }
+ if (selectBlock.hasLetClauses()) {
+ for (LetClause letClause : selectBlock.getLetList()) {
+ letClause.accept(this, arg);
+ }
+ }
+ if (selectBlock.hasGroupbyClause()) {
+ selectBlock.getGroupbyClause().accept(this, arg);
+ }
+ if (selectBlock.hasLetClausesAfterGroupby()) {
+ for (LetClause letClauseAfterGby : selectBlock.getLetListAfterGroupby()) {
+ letClauseAfterGby.accept(this, true);
+ }
+ }
+ if (selectBlock.hasHavingClause()) {
+ selectBlock.getHavingClause().accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectClause selectClause, Boolean arg) throws AsterixException {
+ if (selectClause.selectElement()) {
+ selectClause.getSelectElement().accept(this, arg);
+ }
+ if (selectClause.selectRegular()) {
+ selectClause.getSelectRegular().accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectElement selectElement, Boolean arg) throws AsterixException {
+ selectElement.getExpression().accept(this, true);
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectRegular selectRegular, Boolean arg) throws AsterixException {
+ for (Projection projection : selectRegular.getProjections()) {
+ projection.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectSetOperation selectSetOperation, Boolean arg) throws AsterixException {
+ selectSetOperation.getLeftInput().accept(this, arg);
+ for (SetOperationRight right : selectSetOperation.getRightInputs()) {
+ right.getSetOperationRightInput().accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectExpression selectExpression, Boolean arg) throws AsterixException {
+ scopeChecker.createNewScope();
+
+ // Visits let bindings.
+ if (selectExpression.hasLetClauses()) {
+ for (LetClause lc : selectExpression.getLetList()) {
+ lc.accept(this, arg);
+ }
+ }
+
+ // Visits selectSetOperation.
+ selectExpression.getSelectSetOperation().accept(this, arg);
+
+ // Visits order by.
+ if (selectExpression.hasOrderby()) {
+ selectExpression.getOrderbyClause().accept(this, arg);
+ }
+
+ // Visits limit.
+ if (selectExpression.hasLimit()) {
+ selectExpression.getLimitClause().accept(this, arg);
+ }
+
+ // Exits the scope that were entered within this select expression
+ scopeChecker.removeCurrentScope();
+ return null;
+ }
+
+ @Override
+ public Void visit(LetClause letClause, Boolean rewrite) throws AsterixException {
+ VariableSubstitutionEnvironment env = scopeChecker.getCurrentScope().getVarSubstitutionEnvironment();
+ if (rewrite) {
+ Expression newBindExpr = (Expression) SqlppVariableSubstitutionUtil
+ .substituteVariable(letClause.getBindingExpr(), env);
+ letClause.setBindingExpr(newBindExpr);
+ }
+ letClause.getBindingExpr().accept(this, false);
+ // A let binding variable will override the alias to substitute.
+ scopeChecker.getCurrentScope().removeSymbolExpressionMapping(letClause.getVarExpr());
+ return null;
+ }
+
+ @Override
+ public Void visit(OrderbyClause oc, Boolean arg) throws AsterixException {
+ VariableSubstitutionEnvironment env = scopeChecker.getCurrentScope().getVarSubstitutionEnvironment();
+ List<Expression> orderExprs = new ArrayList<Expression>();
+ for (Expression orderExpr : oc.getOrderbyList()) {
+ orderExprs.add((Expression) SqlppVariableSubstitutionUtil.substituteVariable(orderExpr, env));
+ orderExpr.accept(this, arg);
+ }
+ oc.setOrderbyList(orderExprs);
+ return null;
+ }
+
+ @Override
+ public Void visit(GroupbyClause gc, Boolean arg) throws AsterixException {
+ VariableSubstitutionEnvironment env = scopeChecker.getCurrentScope().getVarSubstitutionEnvironment();
+ for (GbyVariableExpressionPair gbyVarExpr : gc.getGbyPairList()) {
+ Expression newExpr = (Expression) SqlppVariableSubstitutionUtil.substituteVariable(gbyVarExpr.getExpr(),
+ env);
+ newExpr.accept(this, arg);
+ gbyVarExpr.setExpr(newExpr);
+ }
+ for (GbyVariableExpressionPair gbyVarExpr : gc.getGbyPairList()) {
+ // A group-by variable will override the alias to substitute.
+ scopeChecker.getCurrentScope().removeSymbolExpressionMapping(gbyVarExpr.getVar());
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(LimitClause limitClause, Boolean arg) throws AsterixException {
+ limitClause.getLimitExpr().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(HavingClause havingClause, Boolean arg) throws AsterixException {
+ VariableSubstitutionEnvironment env = scopeChecker.getCurrentScope().getVarSubstitutionEnvironment();
+ Expression newFilterExpr = (Expression) SqlppVariableSubstitutionUtil
+ .substituteVariable(havingClause.getFilterExpression(), env);
+ newFilterExpr.accept(this, arg);
+ havingClause.setFilterExpression(newFilterExpr);
+ return null;
+ }
+
+ @Override
+ public Void visit(Query q, Boolean arg) throws AsterixException {
+ q.getBody().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(FunctionDecl fd, Boolean arg) throws AsterixException {
+ scopeChecker.createNewScope();
+ fd.getFuncBody().accept(this, arg);
+ scopeChecker.removeCurrentScope();
+ return null;
+ }
+
+ @Override
+ public Void visit(LiteralExpr l, Boolean arg) throws AsterixException {
+ return null;
+ }
+
+ @Override
+ public Void visit(ListConstructor lc, Boolean arg) throws AsterixException {
+ for (Expression expr : lc.getExprList()) {
+ expr.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(RecordConstructor rc, Boolean rewrite) throws AsterixException {
+ for (FieldBinding binding : rc.getFbList()) {
+ Expression leftExpr = binding.getLeftExpr();
+ leftExpr.accept(this, false);
+ binding.getRightExpr().accept(this, false);
+ if (rewrite && leftExpr.getKind() == Kind.LITERAL_EXPRESSION) {
+ LiteralExpr literalExpr = (LiteralExpr) leftExpr;
+ if (literalExpr.getValue().getLiteralType() == Literal.Type.STRING) {
+ String fieldName = literalExpr.getValue().getStringValue();
+ scopeChecker.getCurrentScope().addSymbolExpressionMappingToScope(
+ new VariableExpr(new VarIdentifier(fieldName)), binding.getRightExpr());
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(OperatorExpr operatorExpr, Boolean arg) throws AsterixException {
+ for (Expression expr : operatorExpr.getExprList()) {
+ expr.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(IfExpr ifExpr, Boolean arg) throws AsterixException {
+ ifExpr.getCondExpr().accept(this, arg);
+ ifExpr.getThenExpr().accept(this, arg);
+ ifExpr.getElseExpr().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(QuantifiedExpression qe, Boolean arg) throws AsterixException {
+ for (QuantifiedPair pair : qe.getQuantifiedList()) {
+ pair.getExpr().accept(this, arg);
+ }
+ qe.getSatisfiesExpr().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(CallExpr callExpr, Boolean arg) throws AsterixException {
+ for (Expression expr : callExpr.getExprList()) {
+ expr.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(VariableExpr varExpr, Boolean arg) throws AsterixException {
+ return null;
+ }
+
+ @Override
+ public Void visit(UnaryExpr u, Boolean arg) throws AsterixException {
+ u.getExpr().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(FieldAccessor fa, Boolean arg) throws AsterixException {
+ fa.getExpr().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Void visit(IndexAccessor ia, Boolean arg) throws AsterixException {
+ ia.getExpr().accept(this, arg);
+ Expression indexExpr = ia.getExpr();
+ if (indexExpr != null) {
+ indexExpr.accept(this, arg);
+ }
+ return null;
+ }
+
+ private void removeSubsutitions(AbstractBinaryCorrelateClause unnestClause) {
+ scopeChecker.getCurrentScope().removeSymbolExpressionMapping(unnestClause.getRightVariable());
+ if (unnestClause.hasPositionalVariable()) {
+ scopeChecker.getCurrentScope().removeSymbolExpressionMapping(unnestClause.getPositionalVariable());
+ }
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java
new file mode 100644
index 0000000..3cb7b28
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java
@@ -0,0 +1,369 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.visitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Clause.ClauseType;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.ILangExpression;
+import org.apache.asterix.lang.common.clause.GroupbyClause;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.clause.LimitClause;
+import org.apache.asterix.lang.common.clause.OrderbyClause;
+import org.apache.asterix.lang.common.clause.WhereClause;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
+import org.apache.asterix.lang.common.rewrites.VariableSubstitutionEnvironment;
+import org.apache.asterix.lang.common.visitor.CloneAndSubstituteVariablesVisitor;
+import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
+import org.apache.asterix.lang.sqlpp.clause.FromClause;
+import org.apache.asterix.lang.sqlpp.clause.FromTerm;
+import org.apache.asterix.lang.sqlpp.clause.HavingClause;
+import org.apache.asterix.lang.sqlpp.clause.JoinClause;
+import org.apache.asterix.lang.sqlpp.clause.NestClause;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.clause.SelectClause;
+import org.apache.asterix.lang.sqlpp.clause.SelectElement;
+import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationInput;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+import org.apache.hyracks.algebricks.common.utils.Pair;
+
+public class SqlppCloneAndSubstituteVariablesVisitor extends CloneAndSubstituteVariablesVisitor implements
+ ISqlppVisitor<Pair<ILangExpression, VariableSubstitutionEnvironment>, VariableSubstitutionEnvironment> {
+
+ private LangRewritingContext context;
+
+ public SqlppCloneAndSubstituteVariablesVisitor(LangRewritingContext context) {
+ super(context);
+ this.context = context;
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(FromClause fromClause,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
+ List<FromTerm> newFromTerms = new ArrayList<FromTerm>();
+ for (FromTerm fromTerm : fromClause.getFromTerms()) {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> p = fromTerm.accept(this, currentEnv);
+ newFromTerms.add((FromTerm) p.first);
+ // A right from term could be correlated from a left from term,
+ // therefore we propagate the substitution environment.
+ currentEnv = p.second;
+ }
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(new FromClause(newFromTerms), currentEnv);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(FromTerm fromTerm,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ VariableExpr leftVar = fromTerm.getLeftVariable();
+ VariableExpr newLeftVar = generateNewVariable(context, leftVar);
+ VariableExpr newLeftPosVar = fromTerm.hasPositionalVariable()
+ ? generateNewVariable(context, fromTerm.getPositionalVariable()) : null;
+ Expression newLeftExpr = (Expression) fromTerm.getLeftExpression().accept(this, env).first;
+ List<AbstractBinaryCorrelateClause> newCorrelateClauses = new ArrayList<AbstractBinaryCorrelateClause>();
+
+ VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
+ currentEnv.removeSubstitution(newLeftVar);
+ if (newLeftPosVar != null) {
+ currentEnv.removeSubstitution(newLeftPosVar);
+ }
+
+ for (AbstractBinaryCorrelateClause correlateClause : fromTerm.getCorrelateClauses()) {
+ if (correlateClause.getClauseType() == ClauseType.UNNEST_CLAUSE) {
+ // The right-hand-side of unnest could be correlated with the left side,
+ // therefore we propagate the substitution environment of the left-side.
+ Pair<ILangExpression, VariableSubstitutionEnvironment> p = correlateClause.accept(this, currentEnv);
+ currentEnv = p.second;
+ newCorrelateClauses.add((AbstractBinaryCorrelateClause) p.first);
+ } else {
+ // The right-hand-side of join and nest could not be correlated with the left side,
+ // therefore we propagate the original substitution environment.
+ newCorrelateClauses.add((AbstractBinaryCorrelateClause) correlateClause.accept(this, env).first);
+ }
+ }
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(
+ new FromTerm(newLeftExpr, newLeftVar, newLeftPosVar, newCorrelateClauses), currentEnv);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(JoinClause joinClause,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ VariableExpr rightVar = joinClause.getRightVariable();
+ VariableExpr newRightVar = generateNewVariable(context, rightVar);
+ VariableExpr newRightPosVar = joinClause.hasPositionalVariable()
+ ? generateNewVariable(context, joinClause.getPositionalVariable()) : null;
+
+ // Visits the right expression.
+ Expression newRightExpr = (Expression) joinClause.getRightExpression().accept(this, env).first;
+
+ // Visits the condition.
+ VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
+ currentEnv.removeSubstitution(newRightVar);
+ if (newRightPosVar != null) {
+ currentEnv.removeSubstitution(newRightPosVar);
+ }
+ // The condition can refer to the newRightVar and newRightPosVar.
+ Expression conditionExpr = (Expression) joinClause.getConditionExpression().accept(this, currentEnv).first;
+
+ JoinClause newJoinClause = new JoinClause(joinClause.getJoinType(), newRightExpr, newRightVar, newRightPosVar,
+ conditionExpr);
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(newJoinClause, currentEnv);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(NestClause nestClause,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ VariableExpr rightVar = nestClause.getRightVariable();
+ VariableExpr newRightVar = generateNewVariable(context, rightVar);
+ VariableExpr newRightPosVar = nestClause.hasPositionalVariable()
+ ? generateNewVariable(context, nestClause.getPositionalVariable()) : null;
+
+ // Visits the right expression.
+ Expression rightExpr = (Expression) nestClause.getRightExpression().accept(this, env).first;
+
+ // Visits the condition.
+ VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
+ currentEnv.removeSubstitution(newRightVar);
+ if (newRightPosVar != null) {
+ currentEnv.removeSubstitution(newRightPosVar);
+ }
+ // The condition can refer to the newRightVar and newRightPosVar.
+ Expression conditionExpr = (Expression) nestClause.getConditionExpression().accept(this, currentEnv).first;
+
+ NestClause newJoinClause = new NestClause(nestClause.getJoinType(), rightExpr, newRightVar, newRightPosVar,
+ conditionExpr);
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(newJoinClause, currentEnv);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(UnnestClause unnestClause,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ VariableExpr rightVar = unnestClause.getRightVariable();
+ VariableExpr newRightVar = generateNewVariable(context, rightVar);
+ VariableExpr newRightPosVar = unnestClause.hasPositionalVariable()
+ ? generateNewVariable(context, unnestClause.getPositionalVariable()) : null;
+
+ // Visits the right expression.
+ Expression rightExpr = (Expression) unnestClause.getRightExpression().accept(this, env).first;
+
+ // Visits the condition.
+ VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
+ currentEnv.removeSubstitution(newRightVar);
+ if (newRightPosVar != null) {
+ currentEnv.removeSubstitution(newRightPosVar);
+ }
+ // The condition can refer to the newRightVar and newRightPosVar.
+ UnnestClause newJoinClause = new UnnestClause(unnestClause.getJoinType(), rightExpr, newRightVar,
+ newRightPosVar);
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(newJoinClause, currentEnv);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(Projection projection,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ Projection newProjection = (Projection) projection.getExpression().accept(this, env).first;
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(newProjection, env);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectBlock selectBlock,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> newFrom = null;
+ Pair<ILangExpression, VariableSubstitutionEnvironment> newLet = null;
+ Pair<ILangExpression, VariableSubstitutionEnvironment> newWhere = null;
+ Pair<ILangExpression, VariableSubstitutionEnvironment> newGroupby = null;
+ Pair<ILangExpression, VariableSubstitutionEnvironment> newHaving = null;
+ Pair<ILangExpression, VariableSubstitutionEnvironment> newSelect = null;
+ List<LetClause> newLetClauses = new ArrayList<LetClause>();
+ List<LetClause> newLetClausesAfterGby = new ArrayList<LetClause>();
+ VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
+
+ if (selectBlock.hasFromClause()) {
+ newFrom = selectBlock.getFromClause().accept(this, currentEnv);
+ currentEnv = newFrom.second;
+ }
+
+ if (selectBlock.hasLetClauses()) {
+ for (LetClause letClause : selectBlock.getLetList()) {
+ newLet = letClause.accept(this, env);
+ currentEnv = newLet.second;
+ newLetClauses.add(letClause);
+ }
+ }
+
+ if (selectBlock.hasWhereClause()) {
+ newWhere = selectBlock.getWhereClause().accept(this, currentEnv);
+ currentEnv = newWhere.second;
+ }
+
+ if (selectBlock.hasGroupbyClause()) {
+ newGroupby = selectBlock.getGroupbyClause().accept(this, currentEnv);
+ currentEnv = newGroupby.second;
+ if (selectBlock.hasLetClausesAfterGroupby()) {
+ for (LetClause letClauseAfterGby : selectBlock.getLetListAfterGroupby()) {
+ newLet = letClauseAfterGby.accept(this, env);
+ currentEnv = newLet.second;
+ newLetClausesAfterGby.add(letClauseAfterGby);
+ }
+ }
+ }
+
+ if (selectBlock.hasHavingClause()) {
+ newHaving = selectBlock.getHavingClause().accept(this, currentEnv);
+ currentEnv = newHaving.second;
+ }
+
+ newSelect = selectBlock.getSelectClause().accept(this, currentEnv);
+ currentEnv = newSelect.second;
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(
+ new SelectBlock((SelectClause) newSelect.first, newFrom == null ? null : (FromClause) newFrom.first,
+ newLetClauses, newWhere == null ? null : (WhereClause) newWhere.first,
+ newGroupby == null ? null : (GroupbyClause) newGroupby.first, newLetClausesAfterGby,
+ newHaving == null ? null : (HavingClause) newHaving.first),
+ currentEnv);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectClause selectClause,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ boolean distinct = selectClause.distinct();
+ if (selectClause.selectElement()) {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> newSelectElement = selectClause.getSelectElement()
+ .accept(this, env);
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(
+ new SelectClause((SelectElement) newSelectElement.first, null, distinct), newSelectElement.second);
+ } else {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> newSelectRegular = selectClause.getSelectRegular()
+ .accept(this, env);
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(
+ new SelectClause(null, (SelectRegular) newSelectRegular.first, distinct), newSelectRegular.second);
+ }
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectElement selectElement,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> newExpr = selectElement.getExpression().accept(this,
+ env);
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(new SelectElement((Expression) newExpr.first),
+ newExpr.second);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectRegular selectRegular,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ List<Projection> newProjections = new ArrayList<Projection>();
+ for (Projection projection : selectRegular.getProjections()) {
+ newProjections.add((Projection) projection.accept(this, env).first);
+ }
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(new SelectRegular(newProjections), env);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectSetOperation selectSetOperation,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ SetOperationInput leftInput = selectSetOperation.getLeftInput();
+ SetOperationInput newLeftInput = null;
+
+ // Sets the left input.
+ if (leftInput.selectBlock()) {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> p = leftInput.getSelectBlock().accept(this, env);
+ newLeftInput = new SetOperationInput((SelectBlock) p.first, null);
+ } else {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> p = leftInput.getSubquery().accept(this, env);
+ newLeftInput = new SetOperationInput(null, (SelectExpression) p.first);
+ }
+
+ // Sets the right input
+ List<SetOperationRight> newRightInputs = new ArrayList<SetOperationRight>();
+ for (SetOperationRight right : selectSetOperation.getRightInputs()) {
+ SetOperationInput newRightInput = null;
+ SetOperationInput rightInput = right.getSetOperationRightInput();
+ if (rightInput.selectBlock()) {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> p = rightInput.getSelectBlock().accept(this,
+ env);
+ newRightInput = new SetOperationInput((SelectBlock) p.first, null);
+ } else {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> p = rightInput.getSubquery().accept(this, env);
+ newRightInput = new SetOperationInput(null, (SelectExpression) p.first);
+ }
+ newRightInputs.add(new SetOperationRight(right.getSetOpType(), right.setSemantics(), newRightInput));
+ }
+ SelectSetOperation newSelectSetOperation = new SelectSetOperation(newLeftInput, newRightInputs);
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(newSelectSetOperation, env);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectExpression selectExpression,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ boolean subquery = selectExpression.isSubquery();
+ List<LetClause> newLetList = new ArrayList<LetClause>();
+ SelectSetOperation newSelectSetOperation = null;
+ OrderbyClause newOrderbyClause = null;
+ LimitClause newLimitClause = null;
+
+ VariableSubstitutionEnvironment currentEnv = env;
+ Pair<ILangExpression, VariableSubstitutionEnvironment> p = null;
+ if (selectExpression.hasLetClauses()) {
+ for (LetClause letClause : selectExpression.getLetList()) {
+ p = letClause.accept(this, currentEnv);
+ newLetList.add(letClause);
+ currentEnv = p.second;
+ }
+ }
+
+ p = selectExpression.getSelectSetOperation().accept(this, env);
+ newSelectSetOperation = (SelectSetOperation) p.first;
+ currentEnv = p.second;
+
+ if (selectExpression.hasOrderby()) {
+ p = selectExpression.getOrderbyClause().accept(this, env);
+ newOrderbyClause = (OrderbyClause) p.first;
+ currentEnv = p.second;
+ }
+
+ if (selectExpression.hasLimit()) {
+ p = selectExpression.getLimitClause().accept(this, env);
+ newLimitClause = (LimitClause) p.first;
+ currentEnv = p.second;
+ }
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(
+ new SelectExpression(newLetList, newSelectSetOperation, newOrderbyClause, newLimitClause, subquery),
+ currentEnv);
+ }
+
+ @Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(HavingClause havingClause,
+ VariableSubstitutionEnvironment env) throws AsterixException {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> p = havingClause.getFilterExpression().accept(this, env);
+ HavingClause newHavingClause = new HavingClause((Expression) p.first);
+ return new Pair<ILangExpression, VariableSubstitutionEnvironment>(newHavingClause, p.second);
+ }
+
+}
\ No newline at end of file
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java
new file mode 100644
index 0000000..4a583c2
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java
@@ -0,0 +1,300 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.visitor;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.clause.GroupbyClause;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair;
+import org.apache.asterix.lang.common.statement.InsertStatement;
+import org.apache.asterix.lang.common.visitor.FormatPrintVisitor;
+import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
+import org.apache.asterix.lang.sqlpp.clause.FromClause;
+import org.apache.asterix.lang.sqlpp.clause.FromTerm;
+import org.apache.asterix.lang.sqlpp.clause.HavingClause;
+import org.apache.asterix.lang.sqlpp.clause.JoinClause;
+import org.apache.asterix.lang.sqlpp.clause.NestClause;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.clause.SelectClause;
+import org.apache.asterix.lang.sqlpp.clause.SelectElement;
+import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class SqlppFormatPrintVisitor extends FormatPrintVisitor implements ISqlppVisitor<Void, Integer> {
+
+ private final PrintWriter out;
+
+ public SqlppFormatPrintVisitor() {
+ this(new PrintWriter(System.out));
+ }
+
+ public SqlppFormatPrintVisitor(PrintWriter out) {
+ super(out);
+ this.out = out;
+
+ // Initialize symbols
+ dataverseSymbol = " database ";
+ datasetSymbol = " table ";
+ assignSymbol = "=";
+ }
+
+ @Override
+ public Void visit(FromClause fromClause, Integer step) throws AsterixException {
+ out.print(skip(step) + "from ");
+ int index = 0;
+ for (FromTerm fromTerm : fromClause.getFromTerms()) {
+ if (index > 0) {
+ out.print(COMMA + "\n" + skip(step + 2));
+ }
+ fromTerm.accept(this, step + 2);
+ ++index;
+ }
+ out.println();
+ return null;
+ }
+
+ @Override
+ public Void visit(FromTerm fromTerm, Integer step) throws AsterixException {
+ fromTerm.getLeftExpression().accept(this, step + 2);
+ out.print(" as ");
+ fromTerm.getLeftVariable().accept(this, step + 2);
+ if (fromTerm.hasPositionalVariable()) {
+ out.print(" at ");
+ fromTerm.getPositionalVariable().accept(this, step + 2);
+ }
+ if (fromTerm.hasCorrelateClauses()) {
+ for (AbstractBinaryCorrelateClause correlateClause : fromTerm.getCorrelateClauses()) {
+ correlateClause.accept(this, step);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(JoinClause joinClause, Integer step) throws AsterixException {
+ out.print(joinClause.getJoinType());
+ joinClause.getRightExpression().accept(this, step + 2);
+ out.print(" as ");
+ joinClause.getRightVariable().accept(this, step + 2);
+ if (joinClause.hasPositionalVariable()) {
+ out.print(" at ");
+ joinClause.getPositionalVariable().accept(this, step + 2);
+ }
+ joinClause.getConditionExpression().accept(this, step + 2);
+ return null;
+ }
+
+ @Override
+ public Void visit(NestClause nestClause, Integer step) throws AsterixException {
+ out.print(nestClause.getJoinType());
+ nestClause.getRightExpression().accept(this, step + 2);
+ out.println(skip(step + 1) + " as ");
+ nestClause.getRightVariable().accept(this, step + 2);
+ if (nestClause.hasPositionalVariable()) {
+ out.println(skip(step + 1) + " at ");
+ nestClause.getPositionalVariable().accept(this, step + 2);
+ }
+ nestClause.getConditionExpression().accept(this, step + 2);
+ return null;
+ }
+
+ @Override
+ public Void visit(Projection projection, Integer step) throws AsterixException {
+ projection.getExpression().accept(this, step);
+ out.print(" as " + projection.getName());
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectBlock selectBlock, Integer step) throws AsterixException {
+ selectBlock.getSelectClause().accept(this, step);
+ if (selectBlock.hasFromClause()) {
+ selectBlock.getFromClause().accept(this, step);
+ }
+ if (selectBlock.hasLetClauses()) {
+ for (LetClause letClause : selectBlock.getLetList()) {
+ letClause.accept(this, step);
+ }
+ }
+ if (selectBlock.hasWhereClause()) {
+ selectBlock.getWhereClause().accept(this, step);
+ }
+ if (selectBlock.hasGroupbyClause()) {
+ selectBlock.getGroupbyClause().accept(this, step);
+ if (selectBlock.hasLetClausesAfterGroupby()) {
+ for (LetClause letClause : selectBlock.getLetListAfterGroupby()) {
+ letClause.accept(this, step);
+ }
+ }
+ }
+ if (selectBlock.hasHavingClause()) {
+ selectBlock.getHavingClause().accept(this, step);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectClause selectClause, Integer step) throws AsterixException {
+ if (selectClause.selectRegular()) {
+ selectClause.getSelectRegular().accept(this, step);
+ }
+ if (selectClause.selectElement()) {
+ selectClause.getSelectElement().accept(this, step);
+ }
+ out.println();
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectElement selectElement, Integer step) throws AsterixException {
+ out.print("select element ");
+ selectElement.getExpression().accept(this, step);
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectRegular selectRegular, Integer step) throws AsterixException {
+ out.print("select ");
+ int index = 0;
+ for (Projection projection : selectRegular.getProjections()) {
+ if (index > 0) {
+ out.print(COMMA);
+ }
+ projection.accept(this, step);
+ ++index;
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectSetOperation selectSetOperation, Integer step) throws AsterixException {
+ selectSetOperation.getLeftInput().accept(this, step);
+ if (selectSetOperation.hasRightInputs()) {
+ for (SetOperationRight right : selectSetOperation.getRightInputs()) {
+ String all = right.setSemantics() ? " " : " all ";
+ out.print(right.getSetOpType() + all);
+ right.getSetOperationRightInput().accept(this, step);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectExpression selectStatement, Integer step) throws AsterixException {
+ if (selectStatement.isSubquery()) {
+ out.print("(");
+ }
+ int selectStep = selectStatement.isSubquery() ? step + 2 : step;
+ if (selectStatement.hasLetClauses()) {
+ for (LetClause letClause : selectStatement.getLetList()) {
+ letClause.accept(this, selectStep);
+ }
+ }
+ selectStatement.getSelectSetOperation().accept(this, selectStep);
+ if (selectStatement.hasOrderby()) {
+ selectStatement.getOrderbyClause().accept(this, selectStep);
+ }
+ if (selectStatement.hasLimit()) {
+ selectStatement.getLimitClause().accept(this, selectStep);
+ }
+ if (selectStatement.isSubquery()) {
+ out.print(skip(step) + " )");
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(UnnestClause unnestClause, Integer step) throws AsterixException {
+ out.print(unnestClause.getJoinType());
+ unnestClause.getRightExpression().accept(this, step + 2);
+ out.print(" as ");
+ unnestClause.getRightVariable().accept(this, step + 2);
+ if (unnestClause.hasPositionalVariable()) {
+ out.print(" at ");
+ unnestClause.getPositionalVariable().accept(this, step + 2);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(HavingClause havingClause, Integer step) throws AsterixException {
+ out.print(skip(step) + " having ");
+ havingClause.getFilterExpression().accept(this, step + 2);
+ out.println();
+ return null;
+ }
+
+ @Override
+ public Void visit(GroupbyClause gc, Integer step) throws AsterixException {
+ if (gc.hasHashGroupByHint()) {
+ out.println(skip(step) + "/* +hash */");
+ }
+ out.print(skip(step) + "group by ");
+ printDelimitedGbyExpressions(gc.getGbyPairList(), step + 2);
+ out.println();
+ return null;
+ }
+
+ @Override
+ public Void visit(InsertStatement insert, Integer step) throws AsterixException {
+ out.print(skip(step) + "insert into " + datasetSymbol
+ + generateFullName(insert.getDataverseName(), insert.getDatasetName()) + "\n");
+ insert.getQuery().accept(this, step);
+ out.println(SEMICOLON);
+ return null;
+ }
+
+ @Override
+ public Void visit(LetClause lc, Integer step) throws AsterixException {
+ out.print(skip(step) + "with ");
+ Expression bindingExpr = lc.getBindingExpr();
+ bindingExpr.accept(this, step + 2);
+ out.print(" as ");
+ lc.getVarExpr().accept(this, step + 2);
+ out.println();
+ return null;
+ }
+
+ @Override
+ protected void printDelimitedGbyExpressions(List<GbyVariableExpressionPair> gbyList, int step)
+ throws AsterixException {
+ int gbySize = gbyList.size();
+ int gbyIndex = 0;
+ for (GbyVariableExpressionPair pair : gbyList) {
+ pair.getExpr().accept(this, step);
+ if (pair.getVar() != null) {
+ out.print(" as ");
+ pair.getVar().accept(this, step);
+ }
+ if (++gbyIndex < gbySize) {
+ out.print(COMMA);
+ }
+ }
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppInlineUdfsVisitor.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppInlineUdfsVisitor.java
new file mode 100644
index 0000000..2931d25
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppInlineUdfsVisitor.java
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.visitor;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
+import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.visitor.AbstractInlineUdfsVisitor;
+import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
+import org.apache.asterix.lang.sqlpp.clause.FromClause;
+import org.apache.asterix.lang.sqlpp.clause.FromTerm;
+import org.apache.asterix.lang.sqlpp.clause.HavingClause;
+import org.apache.asterix.lang.sqlpp.clause.JoinClause;
+import org.apache.asterix.lang.sqlpp.clause.NestClause;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.clause.SelectClause;
+import org.apache.asterix.lang.sqlpp.clause.SelectElement;
+import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
+import org.apache.asterix.lang.sqlpp.util.SqlppVariableSubstitutionUtil;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+import org.apache.hyracks.algebricks.common.utils.Pair;
+
+public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor
+ implements ISqlppVisitor<Boolean, List<FunctionDecl>> {
+
+ public SqlppInlineUdfsVisitor(LangRewritingContext context) {
+ super(context, new SqlppCloneAndSubstituteVariablesVisitor(context));
+ }
+
+ @Override
+ protected Expression generateQueryExpression(List<LetClause> letClauses, Expression returnExpr)
+ throws AsterixException {
+ Map<VariableExpr, Expression> varExprMap = extractLetBindingVariableExpressionMappings(letClauses);
+ return (Expression) SqlppVariableSubstitutionUtil.substituteVariable(returnExpr, varExprMap);
+ }
+
+ @Override
+ public Boolean visit(FromClause fromClause, List<FunctionDecl> func) throws AsterixException {
+ boolean changed = false;
+ for (FromTerm fromTerm : fromClause.getFromTerms()) {
+ changed |= fromTerm.accept(this, func);
+ }
+ return changed;
+ }
+
+ @Override
+ public Boolean visit(FromTerm fromTerm, List<FunctionDecl> func) throws AsterixException {
+ boolean changed = false;
+ changed |= fromTerm.getLeftExpression().accept(this, func);
+ for (AbstractBinaryCorrelateClause correlateClause : fromTerm.getCorrelateClauses()) {
+ changed |= correlateClause.accept(this, func);
+ }
+ return changed;
+ }
+
+ @Override
+ public Boolean visit(JoinClause joinClause, List<FunctionDecl> funcs) throws AsterixException {
+ Pair<Boolean, Expression> p1 = inlineUdfsInExpr(joinClause.getRightExpression(), funcs);
+ joinClause.setRightExpression(p1.second);
+ Pair<Boolean, Expression> p2 = inlineUdfsInExpr(joinClause.getConditionExpression(), funcs);
+ joinClause.setConditionExpression(p2.second);
+ return p1.first && p2.first;
+ }
+
+ @Override
+ public Boolean visit(NestClause nestClause, List<FunctionDecl> funcs) throws AsterixException {
+ Pair<Boolean, Expression> p1 = inlineUdfsInExpr(nestClause.getRightExpression(), funcs);
+ nestClause.setRightExpression(p1.second);
+ Pair<Boolean, Expression> p2 = inlineUdfsInExpr(nestClause.getConditionExpression(), funcs);
+ nestClause.setConditionExpression(p2.second);
+ return p1.first && p2.first;
+ }
+
+ @Override
+ public Boolean visit(Projection projection, List<FunctionDecl> funcs) throws AsterixException {
+ Pair<Boolean, Expression> p = inlineUdfsInExpr(projection.getExpression(), funcs);
+ projection.setExpression(p.second);
+ return p.first;
+ }
+
+ @Override
+ public Boolean visit(SelectBlock selectBlock, List<FunctionDecl> funcs) throws AsterixException {
+ boolean changed = false;
+ if (selectBlock.hasFromClause()) {
+ changed |= selectBlock.getFromClause().accept(this, funcs);
+ }
+ if (selectBlock.hasLetClauses()) {
+ for (LetClause letClause : selectBlock.getLetList()) {
+ changed |= letClause.accept(this, funcs);
+ }
+ }
+ if (selectBlock.hasWhereClause()) {
+ changed |= selectBlock.getWhereClause().accept(this, funcs);
+ }
+ if (selectBlock.hasGroupbyClause()) {
+ changed |= selectBlock.getGroupbyClause().accept(this, funcs);
+ }
+ if (selectBlock.hasLetClausesAfterGroupby()) {
+ for (LetClause letClause : selectBlock.getLetListAfterGroupby()) {
+ changed |= letClause.accept(this, funcs);
+ }
+ }
+ if (selectBlock.hasHavingClause()) {
+ changed |= selectBlock.getHavingClause().accept(this, funcs);
+ }
+ changed |= selectBlock.getSelectClause().accept(this, funcs);
+ return changed;
+ }
+
+ @Override
+ public Boolean visit(SelectClause selectClause, List<FunctionDecl> funcs) throws AsterixException {
+ boolean changed = false;
+ if (selectClause.selectElement()) {
+ changed |= selectClause.getSelectElement().accept(this, funcs);
+ } else {
+ changed |= selectClause.getSelectRegular().accept(this, funcs);
+ }
+ return changed;
+ }
+
+ @Override
+ public Boolean visit(SelectElement selectElement, List<FunctionDecl> funcs) throws AsterixException {
+ Pair<Boolean, Expression> p = inlineUdfsInExpr(selectElement.getExpression(), funcs);
+ selectElement.setExpression(p.second);
+ return p.first;
+ }
+
+ @Override
+ public Boolean visit(SelectRegular selectRegular, List<FunctionDecl> funcs) throws AsterixException {
+ boolean changed = false;
+ for (Projection projection : selectRegular.getProjections()) {
+ changed |= projection.accept(this, funcs);
+ }
+ return changed;
+ }
+
+ @Override
+ public Boolean visit(SelectSetOperation selectSetOperation, List<FunctionDecl> funcs) throws AsterixException {
+ boolean changed = false;
+ changed |= selectSetOperation.getLeftInput().accept(this, funcs);
+ for (SetOperationRight right : selectSetOperation.getRightInputs()) {
+ changed |= right.getSetOperationRightInput().accept(this, funcs);
+ }
+ return changed;
+ }
+
+ @Override
+ public Boolean visit(SelectExpression selectExpression, List<FunctionDecl> funcs) throws AsterixException {
+ boolean changed = false;
+ if (selectExpression.hasLetClauses()) {
+ for (LetClause letClause : selectExpression.getLetList()) {
+ changed |= letClause.accept(this, funcs);
+ }
+ }
+ changed |= selectExpression.getSelectSetOperation().accept(this, funcs);
+ if (selectExpression.hasOrderby()) {
+ changed |= selectExpression.getOrderbyClause().accept(this, funcs);
+ }
+ if (selectExpression.hasLimit()) {
+ changed |= selectExpression.getLimitClause().accept(this, funcs);
+ }
+ return changed;
+ }
+
+ @Override
+ public Boolean visit(UnnestClause unnestClause, List<FunctionDecl> funcs) throws AsterixException {
+ Pair<Boolean, Expression> p = inlineUdfsInExpr(unnestClause.getRightExpression(), funcs);
+ unnestClause.setRightExpression(p.second);
+ return p.first;
+ }
+
+ @Override
+ public Boolean visit(HavingClause havingClause, List<FunctionDecl> funcs) throws AsterixException {
+ Pair<Boolean, Expression> p = inlineUdfsInExpr(havingClause.getFilterExpression(), funcs);
+ havingClause.setFilterExpression(p.second);
+ return p.first;
+ }
+
+ private Map<VariableExpr, Expression> extractLetBindingVariableExpressionMappings(List<LetClause> letClauses)
+ throws AsterixException {
+ Map<VariableExpr, Expression> varExprMap = new HashMap<VariableExpr, Expression>();
+ for (LetClause lc : letClauses) {
+ // inline let variables one by one iteratively.
+ lc.setBindingExpr(
+ (Expression) SqlppVariableSubstitutionUtil.substituteVariable(lc.getBindingExpr(), varExprMap));
+ varExprMap.put(lc.getVarExpr(), lc.getBindingExpr());
+ }
+ return varExprMap;
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppPrintVisitor.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppPrintVisitor.java
new file mode 100644
index 0000000..9938c1e
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppPrintVisitor.java
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.visitor;
+
+import java.io.PrintWriter;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.visitor.QueryPrintVisitor;
+import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
+import org.apache.asterix.lang.sqlpp.clause.FromClause;
+import org.apache.asterix.lang.sqlpp.clause.FromTerm;
+import org.apache.asterix.lang.sqlpp.clause.HavingClause;
+import org.apache.asterix.lang.sqlpp.clause.JoinClause;
+import org.apache.asterix.lang.sqlpp.clause.NestClause;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.clause.SelectClause;
+import org.apache.asterix.lang.sqlpp.clause.SelectElement;
+import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
+import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
+
+public class SqlppPrintVisitor extends QueryPrintVisitor implements ISqlppVisitor<Void, Integer> {
+
+ private final PrintWriter out;
+
+ public SqlppPrintVisitor() {
+ super();
+ out = new PrintWriter(System.out);
+ }
+
+ public SqlppPrintVisitor(PrintWriter out) {
+ super(out);
+ this.out = out;
+ }
+
+ @Override
+ public Void visit(FromClause fromClause, Integer step) throws AsterixException {
+ out.print(skip(step) + "FROM [");
+ int index = 0;
+ for (FromTerm fromTerm : fromClause.getFromTerms()) {
+ if (index > 0) {
+ out.println(",");
+ }
+ fromTerm.accept(this, step + 1);
+ ++index;
+ }
+ out.println(skip(step) + "]");
+ return null;
+ }
+
+ @Override
+ public Void visit(FromTerm fromTerm, Integer step) throws AsterixException {
+ fromTerm.getLeftExpression().accept(this, step);
+ out.println(skip(step) + "AS");
+ fromTerm.getLeftVariable().accept(this, step);
+ if (fromTerm.hasPositionalVariable()) {
+ out.println(skip(step) + "AT");
+ fromTerm.getPositionalVariable().accept(this, step);
+ }
+ if (fromTerm.hasCorrelateClauses()) {
+ for (AbstractBinaryCorrelateClause correlateClause : fromTerm.getCorrelateClauses()) {
+ correlateClause.accept(this, step);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(JoinClause joinClause, Integer step) throws AsterixException {
+ out.println(skip(step) + joinClause.getJoinType() + " JOIN");
+ joinClause.getRightExpression().accept(this, step + 1);
+ out.println(skip(step + 1) + "AS");
+ joinClause.getRightVariable().accept(this, step + 1);
+ if (joinClause.hasPositionalVariable()) {
+ out.println(skip(step + 1) + "AT");
+ joinClause.getPositionalVariable().accept(this, step + 1);
+ }
+ joinClause.getConditionExpression().accept(this, step + 1);
+ return null;
+ }
+
+ @Override
+ public Void visit(NestClause nestClause, Integer step) throws AsterixException {
+ out.println(skip(step) + nestClause.getJoinType() + " NEST");
+ nestClause.getRightExpression().accept(this, step + 1);
+ out.println(skip(step + 1) + "AS");
+ nestClause.getRightVariable().accept(this, step + 1);
+ if (nestClause.hasPositionalVariable()) {
+ out.println(skip(step + 1) + "AT");
+ nestClause.getPositionalVariable().accept(this, step + 1);
+ }
+ nestClause.getConditionExpression().accept(this, step + 1);
+ return null;
+ }
+
+ @Override
+ public Void visit(Projection projection, Integer step) throws AsterixException {
+ projection.getExpression().accept(this, step);
+ out.println(skip(step) + projection.getName());
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectBlock selectBlock, Integer step) throws AsterixException {
+ selectBlock.getSelectClause().accept(this, step);
+ if (selectBlock.hasFromClause()) {
+ selectBlock.getFromClause().accept(this, step);
+ }
+ if (selectBlock.hasLetClauses()) {
+ for (LetClause letClause : selectBlock.getLetList()) {
+ letClause.accept(this, step);
+ }
+ }
+ if (selectBlock.hasWhereClause()) {
+ selectBlock.getWhereClause().accept(this, step);
+ }
+ if (selectBlock.hasGroupbyClause()) {
+ selectBlock.getGroupbyClause().accept(this, step);
+ if (selectBlock.hasLetClausesAfterGroupby()) {
+ for (LetClause letClause : selectBlock.getLetListAfterGroupby()) {
+ letClause.accept(this, step);
+ }
+ }
+ }
+ if (selectBlock.hasHavingClause()) {
+ selectBlock.getHavingClause().accept(this, step);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectClause selectClause, Integer step) throws AsterixException {
+ if (selectClause.selectRegular()) {
+ selectClause.getSelectRegular().accept(this, step);
+ }
+ if (selectClause.selectElement()) {
+ selectClause.getSelectElement().accept(this, step);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectElement selectElement, Integer step) throws AsterixException {
+ out.println(skip(step) + "SELECT ELEMENT [");
+ selectElement.getExpression().accept(this, step);
+ out.println(skip(step) + "]");
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectRegular selectRegular, Integer step) throws AsterixException {
+ out.println(skip(step) + "SELECT [");
+ for (Projection projection : selectRegular.getProjections()) {
+ projection.accept(this, step);
+ }
+ out.println(skip(step) + "]");
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectSetOperation selectSetOperation, Integer step) throws AsterixException {
+ selectSetOperation.getLeftInput().accept(this, step);
+ if (selectSetOperation.hasRightInputs()) {
+ for (SetOperationRight right : selectSetOperation.getRightInputs()) {
+ String all = right.setSemantics() ? " ALL " : "";
+ out.println(skip(step) + right.getSetOpType() + all);
+ right.getSetOperationRightInput().accept(this, step + 1);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(SelectExpression selectStatement, Integer step) throws AsterixException {
+ if (selectStatement.isSubquery()) {
+ out.println(skip(step) + "(");
+ }
+ int selectStep = selectStatement.isSubquery() ? step + 1 : step;
+ if (selectStatement.hasLetClauses()) {
+ for (LetClause letClause : selectStatement.getLetList()) {
+ letClause.accept(this, selectStep);
+ }
+ }
+ selectStatement.getSelectSetOperation().accept(this, selectStep);
+ if (selectStatement.hasOrderby()) {
+ selectStatement.getOrderbyClause().accept(this, selectStep);
+ }
+ if (selectStatement.hasLimit()) {
+ selectStatement.getLimitClause().accept(this, selectStep);
+ }
+ if (selectStatement.isSubquery()) {
+ out.println(skip(step) + ")");
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(UnnestClause unnestClause, Integer step) throws AsterixException {
+ out.println(skip(step) + unnestClause.getJoinType() + " UNNEST");
+ unnestClause.getRightExpression().accept(this, step + 1);
+ out.println(skip(step + 1) + " AS");
+ unnestClause.getRightVariable().accept(this, step + 1);
+ if (unnestClause.hasPositionalVariable()) {
+ out.println(skip(step + 1) + " AT");
+ unnestClause.getPositionalVariable().accept(this, step + 1);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visit(HavingClause havingClause, Integer step) throws AsterixException {
+ out.println(skip(step) + " HAVING");
+ havingClause.getFilterExpression().accept(this, step + 1);
+ return null;
+ }
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSubstituteVariablesVisitor.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSubstituteVariablesVisitor.java
new file mode 100644
index 0000000..b00afe0
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppSubstituteVariablesVisitor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.visitor;
+
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
+import org.apache.asterix.lang.common.rewrites.VariableSubstitutionEnvironment;
+
+public class SqlppSubstituteVariablesVisitor extends SqlppCloneAndSubstituteVariablesVisitor {
+
+ public SqlppSubstituteVariablesVisitor(LangRewritingContext context) {
+ super(context);
+ }
+
+ @Override
+ public Expression rewriteVariableExpr(VariableExpr expr, VariableSubstitutionEnvironment env) {
+ if (env.constainsOldVar(expr)) {
+ return env.findSubstituion(expr);
+ }
+ return expr;
+ }
+
+ @Override
+ public VariableExpr generateNewVariable(LangRewritingContext context, VariableExpr varExpr) {
+ return varExpr;
+ }
+
+}
\ No newline at end of file
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/VariableCheckAndRewriteVisitor.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/VariableCheckAndRewriteVisitor.java
new file mode 100644
index 0000000..9dd223d
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/VariableCheckAndRewriteVisitor.java
@@ -0,0 +1,481 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.visitor;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.clause.GroupbyClause;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.clause.LimitClause;
+import org.apache.asterix.lang.common.clause.OrderbyClause;
+import org.apache.asterix.lang.common.clause.WhereClause;
+import org.apache.asterix.lang.common.context.Scope;
+import org.apache.asterix.lang.common.expression.CallExpr;
+import org.apache.asterix.lang.common.expression.FieldAccessor;
+import org.apache.asterix.lang.common.expression.FieldBinding;
+import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair;
+import org.apache.asterix.lang.common.expression.IfExpr;
+import org.apache.asterix.lang.common.expression.IndexAccessor;
+import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.LiteralExpr;
+import org.apache.asterix.lang.common.expression.OperatorExpr;
+import org.apache.asterix.lang.common.expression.QuantifiedExpression;
+import org.apache.asterix.lang.common.expression.RecordConstructor;
+import org.apache.asterix.lang.common.expression.UnaryExpr;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.literal.StringLiteral;
+import org.apache.asterix.lang.common.parser.ScopeChecker;
+import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.struct.Identifier;
+import org.apache.asterix.lang.common.struct.QuantifiedPair;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
+import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
+import org.apache.asterix.lang.sqlpp.clause.FromClause;
+import org.apache.asterix.lang.sqlpp.clause.FromTerm;
+import org.apache.asterix.lang.sqlpp.clause.HavingClause;
+import org.apache.asterix.lang.sqlpp.clause.JoinClause;
+import org.apache.asterix.lang.sqlpp.clause.NestClause;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.clause.SelectClause;
+import org.apache.asterix.lang.sqlpp.clause.SelectElement;
+import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
+import org.apache.asterix.lang.sqlpp.util.SqlppFormatPrintUtil;
+import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppQueryExpressionVisitor;
+import org.apache.asterix.metadata.bootstrap.MetadataConstants;
+
+public class VariableCheckAndRewriteVisitor extends AbstractSqlppQueryExpressionVisitor<Expression, Void> {
+
+ private final ScopeChecker scopeChecker = new ScopeChecker();
+
+ @Override
+ public Expression visit(FromClause fromClause, Void arg) throws AsterixException {
+ scopeChecker.extendCurrentScope();
+ for (FromTerm fromTerm : fromClause.getFromTerms()) {
+ fromTerm.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Expression visit(FromTerm fromTerm, Void arg) throws AsterixException {
+ // Visit the left expression of a from term.
+ fromTerm.setLeftExpression(fromTerm.getLeftExpression().accept(this, arg));
+
+ // Registers the data item variable
+ VariableExpr leftVar = fromTerm.getLeftVariable();
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(leftVar.getVar());
+
+ // Registers the positional variable
+ if (fromTerm.hasPositionalVariable()) {
+ VariableExpr posVar = fromTerm.getPositionalVariable();
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(posVar.getVar());
+ }
+
+ // Visits join/unnest/nest clauses.
+ for (AbstractBinaryCorrelateClause correlateClause : fromTerm.getCorrelateClauses()) {
+ correlateClause.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Expression visit(JoinClause joinClause, Void arg) throws AsterixException {
+ // NOTE: the two join branches cannot be correlated, instead of checking
+ // the correlation here,
+ // we defer the check to the query optimizer.
+ joinClause.setRightExpression(joinClause.getRightExpression().accept(this, arg));
+
+ // Registers the data item variable.
+ VariableExpr rightVar = joinClause.getRightVariable();
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(rightVar.getVar());
+
+ if (joinClause.hasPositionalVariable()) {
+ // Registers the positional variable.
+ VariableExpr posVar = joinClause.getPositionalVariable();
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(posVar.getVar());
+ }
+
+ // The condition expression can refer to the just registered variables
+ // for the right branch.
+ joinClause.setConditionExpression(joinClause.getConditionExpression().accept(this, arg));
+ return null;
+ }
+
+ @Override
+ public Expression visit(NestClause nestClause, Void arg) throws AsterixException {
+ // NOTE: the two branches of a NEST cannot be correlated, instead of
+ // checking the correlation here, we defer the check to the query
+ // optimizer.
+ nestClause.setRightExpression(nestClause.getRightExpression().accept(this, arg));
+
+ // Registers the data item variable.
+ VariableExpr rightVar = nestClause.getRightVariable();
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(rightVar.getVar());
+
+ if (nestClause.hasPositionalVariable()) {
+ // Registers the positional variable.
+ VariableExpr posVar = nestClause.getPositionalVariable();
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(posVar.getVar());
+ }
+
+ // The condition expression can refer to the just registered variables
+ // for the right branch.
+ nestClause.setConditionExpression(nestClause.getConditionExpression().accept(this, arg));
+ return null;
+ }
+
+ @Override
+ public Expression visit(UnnestClause unnestClause, Void arg) throws AsterixException {
+ unnestClause.setRightExpression(unnestClause.getRightExpression().accept(this, arg));
+
+ // register the data item variable
+ VariableExpr rightVar = unnestClause.getRightVariable();
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(rightVar.getVar());
+
+ if (unnestClause.hasPositionalVariable()) {
+ // register the positional variable
+ VariableExpr posVar = unnestClause.getPositionalVariable();
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(posVar.getVar());
+ }
+ return null;
+ }
+
+ @Override
+ public Expression visit(Projection projection, Void arg) throws AsterixException {
+ projection.setExpression(projection.getExpression().accept(this, arg));
+ return null;
+ }
+
+ @Override
+ public Expression visit(SelectBlock selectBlock, Void arg) throws AsterixException {
+ // Traverses the select block in the order of "from", "let"s, "where",
+ // "group by", "let"s, "having" and "select".
+ if (selectBlock.hasFromClause()) {
+ selectBlock.getFromClause().accept(this, arg);
+ }
+ if (selectBlock.hasLetClauses()) {
+ List<LetClause> letList = selectBlock.getLetList();
+ for (LetClause letClause : letList) {
+ letClause.accept(this, arg);
+ }
+ }
+ if (selectBlock.hasWhereClause()) {
+ selectBlock.getWhereClause().accept(this, arg);
+ }
+ if (selectBlock.hasGroupbyClause()) {
+ selectBlock.getGroupbyClause().accept(this, arg);
+ }
+ if (selectBlock.hasLetClausesAfterGroupby()) {
+ List<LetClause> letListAfterGby = selectBlock.getLetListAfterGroupby();
+ for (LetClause letClauseAfterGby : letListAfterGby) {
+ letClauseAfterGby.accept(this, arg);
+ }
+ }
+ if (selectBlock.hasHavingClause()) {
+ selectBlock.getHavingClause().accept(this, arg);
+ }
+ selectBlock.getSelectClause().accept(this, arg);
+ return null;
+ }
+
+ @Override
+ public Expression visit(SelectClause selectClause, Void arg) throws AsterixException {
+ if (selectClause.selectElement()) {
+ selectClause.getSelectElement().accept(this, arg);
+ }
+ if (selectClause.selectRegular()) {
+ selectClause.getSelectRegular().accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Expression visit(SelectElement selectElement, Void arg) throws AsterixException {
+ selectElement.setExpression(selectElement.getExpression().accept(this, arg));
+ return null;
+ }
+
+ @Override
+ public Expression visit(SelectRegular selectRegular, Void arg) throws AsterixException {
+ for (Projection projection : selectRegular.getProjections()) {
+ projection.accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Expression visit(SelectSetOperation selectSetOperation, Void arg) throws AsterixException {
+ selectSetOperation.getLeftInput().accept(this, arg);
+ for (SetOperationRight right : selectSetOperation.getRightInputs()) {
+ scopeChecker.createNewScope();
+ right.getSetOperationRightInput().accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
+ public Expression visit(HavingClause havingClause, Void arg) throws AsterixException {
+ havingClause.setFilterExpression(havingClause.getFilterExpression().accept(this, arg));
+ return null;
+ }
+
+ @Override
+ public Expression visit(Query q, Void arg) throws AsterixException {
+ q.setBody(q.getBody().accept(this, arg));
+ return null;
+ }
+
+ @Override
+ public Expression visit(FunctionDecl fd, Void arg) throws AsterixException {
+ scopeChecker.createNewScope();
+ fd.setFuncBody(fd.getFuncBody().accept(this, arg));
+ scopeChecker.removeCurrentScope();
+ return null;
+ }
+
+ @Override
+ public Expression visit(WhereClause whereClause, Void arg) throws AsterixException {
+ whereClause.setWhereExpr(whereClause.getWhereExpr().accept(this, arg));
+ return null;
+ }
+
+ @Override
+ public Expression visit(OrderbyClause oc, Void arg) throws AsterixException {
+ List<Expression> newOrderbyList = new ArrayList<Expression>();
+ for (Expression orderExpr : oc.getOrderbyList()) {
+ newOrderbyList.add(orderExpr.accept(this, arg));
+ }
+ oc.setOrderbyList(newOrderbyList);
+ return null;
+ }
+
+ @Override
+ public Expression visit(GroupbyClause gc, Void arg) throws AsterixException {
+ Scope newScope = scopeChecker.extendCurrentScopeNoPush(true);
+ // Puts all group-by variables into the symbol set of the new scope.
+ for (GbyVariableExpressionPair gbyVarExpr : gc.getGbyPairList()) {
+ gbyVarExpr.setExpr(gbyVarExpr.getExpr().accept(this, arg));
+ VariableExpr gbyVar = gbyVarExpr.getVar();
+ if (gbyVar != null) {
+ newScope.addNewVarSymbolToScope(gbyVarExpr.getVar().getVar());
+ }
+ }
+ // Puts all live variables into withVarList.
+ List<VariableExpr> withVarList = new ArrayList<VariableExpr>();
+ Iterator<Identifier> varIterator = scopeChecker.getCurrentScope().liveSymbols();
+ while (varIterator.hasNext()) {
+ Identifier ident = varIterator.next();
+ VariableExpr varExpr = new VariableExpr();
+ if (ident instanceof VarIdentifier) {
+ varExpr.setIsNewVar(false);
+ varExpr.setVar((VarIdentifier) ident);
+ withVarList.add(varExpr);
+ newScope.addNewVarSymbolToScope((VarIdentifier) ident);
+ }
+ }
+ gc.setWithVarList(withVarList);
+ scopeChecker.replaceCurrentScope(newScope);
+ return null;
+ }
+
+ @Override
+ public Expression visit(LimitClause limitClause, Void arg) throws AsterixException {
+ scopeChecker.pushForbiddenScope(scopeChecker.getCurrentScope());
+ limitClause.setLimitExpr(limitClause.getLimitExpr().accept(this, arg));
+ scopeChecker.popForbiddenScope();
+ return null;
+ }
+
+ @Override
+ public Expression visit(LetClause letClause, Void arg) throws AsterixException {
+ scopeChecker.extendCurrentScope();
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(letClause.getVarExpr().getVar());
+ letClause.setBindingExpr(letClause.getBindingExpr().accept(this, arg));
+ return null;
+ }
+
+ @Override
+ public Expression visit(SelectExpression selectExpression, Void arg) throws AsterixException {
+ Scope scopeBeforeSelectExpression = scopeChecker.getCurrentScope();
+ scopeChecker.createNewScope();
+
+ // visit let list
+ if (selectExpression.hasLetClauses()) {
+ for (LetClause letClause : selectExpression.getLetList()) {
+ letClause.accept(this, arg);
+ }
+ }
+
+ // visit the main select.
+ selectExpression.getSelectSetOperation().accept(this, arg);
+
+ // visit order by
+ if (selectExpression.hasOrderby()) {
+ for (Expression orderExpr : selectExpression.getOrderbyClause().getOrderbyList()) {
+ orderExpr.accept(this, arg);
+ }
+ }
+
+ // visit limit
+ if (selectExpression.hasLimit()) {
+ selectExpression.getLimitClause().accept(this, arg);
+ }
+
+ // Exit scopes that were entered within this select expression
+ while (scopeChecker.getCurrentScope() != scopeBeforeSelectExpression) {
+ scopeChecker.removeCurrentScope();
+ }
+ return selectExpression;
+ }
+
+ @Override
+ public Expression visit(LiteralExpr l, Void arg) throws AsterixException {
+ return l;
+ }
+
+ @Override
+ public Expression visit(ListConstructor lc, Void arg) throws AsterixException {
+ List<Expression> newExprList = new ArrayList<Expression>();
+ for (Expression expr : lc.getExprList()) {
+ newExprList.add(expr.accept(this, arg));
+ }
+ lc.setExprList(newExprList);
+ return lc;
+ }
+
+ @Override
+ public Expression visit(RecordConstructor rc, Void arg) throws AsterixException {
+ for (FieldBinding binding : rc.getFbList()) {
+ binding.setLeftExpr(binding.getLeftExpr().accept(this, arg));
+ binding.setRightExpr(binding.getRightExpr().accept(this, arg));
+ }
+ return rc;
+ }
+
+ @Override
+ public Expression visit(OperatorExpr operatorExpr, Void arg) throws AsterixException {
+ List<Expression> newExprList = new ArrayList<Expression>();
+ for (Expression expr : operatorExpr.getExprList()) {
+ newExprList.add(expr.accept(this, arg));
+ }
+ operatorExpr.setExprList(newExprList);
+ return operatorExpr;
+ }
+
+ @Override
+ public Expression visit(IfExpr ifExpr, Void arg) throws AsterixException {
+ ifExpr.setCondExpr(ifExpr.getCondExpr().accept(this, arg));
+ ifExpr.setThenExpr(ifExpr.getThenExpr().accept(this, arg));
+ ifExpr.setElseExpr(ifExpr.getElseExpr().accept(this, arg));
+ return ifExpr;
+ }
+
+ @Override
+ public Expression visit(QuantifiedExpression qe, Void arg) throws AsterixException {
+ scopeChecker.createNewScope();
+ for (QuantifiedPair pair : qe.getQuantifiedList()) {
+ scopeChecker.getCurrentScope().addNewVarSymbolToScope(pair.getVarExpr().getVar());
+ pair.setExpr(pair.getExpr().accept(this, arg));
+ }
+ qe.setSatisfiesExpr(qe.getSatisfiesExpr().accept(this, arg));
+ scopeChecker.removeCurrentScope();
+ return qe;
+ }
+
+ @Override
+ public Expression visit(CallExpr callExpr, Void arg) throws AsterixException {
+ List<Expression> newExprList = new ArrayList<Expression>();
+ for (Expression expr : callExpr.getExprList()) {
+ newExprList.add(expr.accept(this, arg));
+ }
+ callExpr.setExprList(newExprList);
+ return callExpr;
+ }
+
+ @Override
+ public Expression visit(VariableExpr varExpr, Void arg) throws AsterixException {
+ String varName = varExpr.getVar().getValue();
+ if (scopeChecker.isInForbiddenScopes(varName)) {
+ throw new AsterixException(
+ "Inside limit clauses, it is disallowed to reference a variable having the same name as any variable bound in the same scope as the limit clause.");
+ }
+ if (rewriteNeeded(varExpr)) {
+ return datasetRewrite(varExpr);
+ } else {
+ return varExpr;
+ }
+ }
+
+ @Override
+ public Expression visit(UnaryExpr u, Void arg) throws AsterixException {
+ u.setExpr(u.getExpr().accept(this, arg));
+ return u;
+ }
+
+ @Override
+ public Expression visit(FieldAccessor fa, Void arg) throws AsterixException {
+ fa.setExpr(fa.getExpr().accept(this, arg));
+ return fa;
+ }
+
+ @Override
+ public Expression visit(IndexAccessor ia, Void arg) throws AsterixException {
+ ia.setExpr(ia.getExpr().accept(this, arg));
+ if (ia.getIndexExpr() != null) {
+ ia.setIndexExpr(ia.getExpr());
+ }
+ return ia;
+ }
+
+ // Whether a rewrite is needed for a variable reference expression.
+ private boolean rewriteNeeded(VariableExpr varExpr) throws AsterixException {
+ String varName = varExpr.getVar().getValue();
+ Identifier ident = scopeChecker.lookupSymbol(varName);
+ if (ident != null) {
+ // Exists such an identifier
+ varExpr.setIsNewVar(false);
+ varExpr.setVar((VarIdentifier) ident);
+ return false;
+ } else {
+ // Meets a undefined variable
+ return true;
+ }
+ }
+
+ // Rewrites for global variable (e.g., dataset) references.
+ private Expression datasetRewrite(Expression expr) throws AsterixException {
+ String funcName = "dataset";
+ String dataverse = MetadataConstants.METADATA_DATAVERSE_NAME;
+ FunctionSignature signature = new FunctionSignature(dataverse, funcName, 1);
+ List<Expression> argList = new ArrayList<Expression>();
+ argList.add(new LiteralExpr(new StringLiteral(SqlppFormatPrintUtil.toString(expr))));
+ return new CallExpr(signature, argList);
+ }
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppQueryExpressionVisitor.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppQueryExpressionVisitor.java
new file mode 100644
index 0000000..dda25eb
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppQueryExpressionVisitor.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.visitor.base;
+
+import org.apache.asterix.lang.common.visitor.base.AbstractQueryExpressionVisitor;
+
+public abstract class AbstractSqlppQueryExpressionVisitor<R, T> extends AbstractQueryExpressionVisitor<R, T>
+ implements ISqlppVisitor<R, T> {
+
+}
diff --git a/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/ISqlppVisitor.java b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/ISqlppVisitor.java
new file mode 100644
index 0000000..538d9c3
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/ISqlppVisitor.java
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.lang.sqlpp.visitor.base;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+import org.apache.asterix.lang.sqlpp.clause.FromClause;
+import org.apache.asterix.lang.sqlpp.clause.FromTerm;
+import org.apache.asterix.lang.sqlpp.clause.HavingClause;
+import org.apache.asterix.lang.sqlpp.clause.JoinClause;
+import org.apache.asterix.lang.sqlpp.clause.NestClause;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.clause.SelectClause;
+import org.apache.asterix.lang.sqlpp.clause.SelectElement;
+import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+
+public interface ISqlppVisitor<R, T> extends ILangVisitor<R, T> {
+
+ R visit(FromClause fromClause, T arg) throws AsterixException;
+
+ R visit(FromTerm fromTerm, T arg) throws AsterixException;
+
+ R visit(JoinClause joinClause, T arg) throws AsterixException;
+
+ R visit(NestClause nestClause, T arg) throws AsterixException;
+
+ R visit(Projection projection, T arg) throws AsterixException;
+
+ R visit(SelectBlock selectBlock, T arg) throws AsterixException;
+
+ R visit(SelectClause selectClause, T arg) throws AsterixException;
+
+ R visit(SelectElement selectElement, T arg) throws AsterixException;
+
+ R visit(SelectRegular selectRegular, T arg) throws AsterixException;
+
+ R visit(SelectSetOperation selectSetOperation, T arg) throws AsterixException;
+
+ R visit(SelectExpression selectStatement, T arg) throws AsterixException;
+
+ R visit(UnnestClause unnestClause, T arg) throws AsterixException;
+
+ R visit(HavingClause havingClause, T arg) throws AsterixException;
+}
diff --git a/asterix-lang-sqlpp/src/main/javacc/SQLPP.html b/asterix-lang-sqlpp/src/main/javacc/SQLPP.html
new file mode 100644
index 0000000..4bb64d2
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/javacc/SQLPP.html
@@ -0,0 +1,895 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+<TITLE>BNF for SQLPP.jj</TITLE>
+</HEAD>
+<BODY>
+<H1 ALIGN=CENTER>BNF for SQLPP.jj</H1>
+<H2 ALIGN=CENTER>TOKENS</H2>
+<TABLE>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN [IGNORE_CASE] : {
+<ALL: "all">
+| <AND: "and">
+| <APPLY: "apply">
+| <AS: "as">
+| <ASC: "asc">
+| <AT: "at">
+| <AUTOGENERATED: "autogenerated">
+| <BTREE: "btree">
+| <BY: "by">
+| <CASE: "case">
+| <CLOSED: "closed">
+| <CREATE: "create">
+| <COMPACTION: "compaction">
+| <COMPACT: "compact">
+| <CONNECT: "connect">
+| <CORRELATE: "correlate">
+| <DATASET: "table">
+| <DATAVERSE: "database">
+| <DECLARE: "declare">
+| <DEFINITION: "definition">
+| <DELETE: "delete">
+| <DESC: "desc">
+| <DISCONNECT: "disconnect">
+| <DISTINCT: "distinct">
+| <DROP: "drop">
+| <ELEMENT: "element">
+| <ELSE: "else">
+| <ENFORCED: "enforced">
+| <EVERY: "every">
+| <EXCEPT: "except">
+| <EXISTS: "exists">
+| <EXTERNAL: "external">
+| <FEED: "feed">
+| <FILTER: "filter">
+| <FLATTEN: "flatten">
+| <FOR: "for">
+| <FORMAT: "format">
+| <FROM: "from">
+| <FULL: "full">
+| <FUNCTION: "function">
+| <GROUP: "group">
+| <HAVING: "having">
+| <HINTS: "hints">
+| <IF: "if">
+| <INTO: "into">
+| <IN: "in">
+| <INDEX: "index">
+| <INGESTION: "ingestion">
+| <INNER: "inner">
+| <INSERT: "insert">
+| <INTERNAL: "internal">
+| <INTERSECT: "intersect">
+| <JOIN: "join">
+| <KEYWORD: "keyword">
+| <KEY: "key">
+| <LEFT: "left">
+| <LETTING: "letting">
+| <LET: "let">
+| <LIMIT: "limit">
+| <LOAD: "load">
+| <NEST: "nest">
+| <NODEGROUP: "nodegroup">
+| <NGRAM: "ngram">
+| <OFFSET: "offset">
+| <ON: "on">
+| <OPEN: "open">
+| <OR: "or">
+| <ORDER: "order">
+| <OUTER: "outer">
+| <OUTPUT: "output">
+| <PATH: "path">
+| <POLICY: "policy">
+| <PRESORTED: "pre-sorted">
+| <PRIMARY: "primary">
+| <RAW: "raw">
+| <REFRESH: "refresh">
+| <RETURN: "return">
+| <RTREE: "rtree">
+| <RUN: "run">
+| <SATISFIES: "satisfies">
+| <SECONDARY: "secondary">
+| <SELECT: "select">
+| <SET: "set">
+| <SOME: "some">
+| <TEMPORARY: "temporary">
+| <THEN: "then">
+| <TYPE: "type">
+| <TO: "to">
+| <UNION: "union">
+| <UNNEST: "unnest">
+| <VALUE: "value">
+| <WHEN: "when">
+| <WHERE: "where">
+| <WITH: "with">
+| <WRITE: "write">
+| <UPDATE: "update">
+| <USE: "use">
+| <USING: "using">
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<CARET: "^">
+| <DIV: "/">
+| <IDIV: "idiv">
+| <MINUS: "-">
+| <MOD: "%">
+| <MUL: "*">
+| <PLUS: "+">
+| <LEFTPAREN: "(">
+| <RIGHTPAREN: ")">
+| <LEFTBRACKET: "[">
+| <RIGHTBRACKET: "]">
+| <ATT: "@">
+| <COLON: ":">
+| <COMMA: ",">
+| <DOT: ".">
+| <QUES: "?">
+| <SEMICOLON: ";">
+| <SHARP: "#">
+| <LT: "<">
+| <GT: ">">
+| <LE: "<=">
+| <GE: ">=">
+| <EQ: "=">
+| <NE: "!=">
+| <SIMILAR: "~=">
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<LEFTBRACE: "{"> : DEFAULT
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT> TOKEN : {
+<RIGHTBRACE: "}"> : {
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<LEFTDBLBRACE: "{{"> : IN_DBL_BRACE
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<IN_DBL_BRACE> TOKEN : {
+<RIGHTDBLBRACE: "}}"> : {
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<INTEGER_LITERAL: (<DIGIT>)+>
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<NULL: "null">
+| <TRUE: "true">
+| <FALSE: "false">
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<#DIGIT: ["0"-"9"]>
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<DOUBLE_LITERAL: <DIGITS> | <DIGITS> ("." <DIGITS>)? | "." <DIGITS>>
+| <FLOAT_LITERAL: <DIGITS> ("f" | "F") | <DIGITS> ("." <DIGITS> ("f" | "F"))? | "." <DIGITS> ("f" | "F")>
+| <DIGITS: (<DIGIT>)+>
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<#LETTER: ["A"-"Z","a"-"z"]>
+| <SPECIALCHARS: ["$","_"]>
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<QUOTED_STRING: "\"" (<EscapeQuot> | <EscapeBslash> | <EscapeSlash> | <EscapeBspace> | <EscapeFormf> | <EscapeNl> | <EscapeCr> | <EscapeTab> | ~["\"","\\"])* "\"">
+| <STRING_LITERAL: "\'" (<EscapeQuot> | <EscapeApos> | <EscapeBslash> | <EscapeSlash> | <EscapeBspace> | <EscapeFormf> | <EscapeNl> | <EscapeCr> | <EscapeTab> | ~["\'","\\"])* "\'">
+| <#EscapeQuot: "\\\"">
+| <#EscapeApos: "\\\'">
+| <#EscapeBslash: "\\\\">
+| <#EscapeSlash: "\\/">
+| <#EscapeBspace: "\\b">
+| <#EscapeFormf: "\\f">
+| <#EscapeNl: "\\n">
+| <#EscapeCr: "\\r">
+| <#EscapeTab: "\\t">
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> TOKEN : {
+<IDENTIFIER: <LETTER> (<LETTER> | <DIGIT> | <SPECIALCHARS>)*>
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> SKIP : {
+" "
+| "\t"
+| "\r"
+| "\n"
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> SKIP : {
+<"//" (~["\n"])* "\n">
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> SKIP : {
+<"//" (~["\n","\r"])* ("\n" | "\r" | "\r\n")?>
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<DEFAULT,IN_DBL_BRACE> SKIP : {
+"/*" : INSIDE_COMMENT
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<INSIDE_COMMENT> SPECIAL : {
+<"+" (" ")* (~["*"])*>
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<INSIDE_COMMENT> SKIP : {
+"/*" : {
+}
+
+ </PRE>
+ </TD>
+ </TR>
+ <!-- Token -->
+ <TR>
+ <TD>
+ <PRE>
+<INSIDE_COMMENT> SKIP : {
+"*/" : {
+| <~[]>
+}
+
+ </PRE>
+ </TD>
+ </TR>
+</TABLE>
+<H2 ALIGN=CENTER>NON-TERMINALS</H2>
+<TABLE>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod1">Statement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod2">SingleStatement</A> ( <SEMICOLON> )* )* <EOF></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod2">SingleStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod3">DataverseDeclaration</A> | <A HREF="#prod4">FunctionDeclaration</A> | <A HREF="#prod5">CreateStatement</A> | <A HREF="#prod6">LoadStatement</A> | <A HREF="#prod7">DropStatement</A> | <A HREF="#prod8">WriteStatement</A> | <A HREF="#prod9">SetStatement</A> | <A HREF="#prod10">InsertStatement</A> | <A HREF="#prod11">DeleteStatement</A> | <A HREF="#prod12">UpdateStatement</A> | <A HREF="#prod13">FeedStatement</A> | <A HREF="#prod14">CompactStatement</A> | <A HREF="#prod15">Query</A> <SEMICOLON> | <A HREF="#prod16">RefreshExternalDatasetStatement</A> | <A HREF="#prod17">RunStatement</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod3">DataverseDeclaration</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><USE> <A HREF="#prod18">Identifier</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod5">CreateStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><CREATE> ( <A HREF="#prod19">TypeSpecification</A> | <A HREF="#prod20">NodegroupSpecification</A> | <A HREF="#prod21">DatasetSpecification</A> | <A HREF="#prod22">IndexSpecification</A> | <A HREF="#prod23">DataverseSpecification</A> | <A HREF="#prod24">FunctionSpecification</A> | <A HREF="#prod25">FeedSpecification</A> | <A HREF="#prod26">FeedPolicySpecification</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod19">TypeSpecification</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><TYPE> <A HREF="#prod27">TypeName</A> <A HREF="#prod28">IfNotExists</A> <AS> <A HREF="#prod29">TypeExpr</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod20">NodegroupSpecification</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><NODEGROUP> <A HREF="#prod18">Identifier</A> <A HREF="#prod28">IfNotExists</A> <ON> <A HREF="#prod18">Identifier</A> ( <COMMA> <A HREF="#prod18">Identifier</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod21">DatasetSpecification</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <EXTERNAL> <DATASET> <A HREF="#prod30">QualifiedName</A> <LEFTPAREN> <A HREF="#prod18">Identifier</A> <RIGHTPAREN> <A HREF="#prod28">IfNotExists</A> <USING> <A HREF="#prod31">AdapterName</A> <A HREF="#prod32">Configuration</A> ( <ON> <A HREF="#prod18">Identifier</A> )? ( <HINTS> <A HREF="#prod33">Properties</A> )? ( <USING> <COMPACTION> <POLICY> <A HREF="#prod34">CompactionPolicy</A> ( <A HREF="#prod32">Configuration</A> )? )? | ( <INTERNAL> | <TEMPORARY> )? <DATASET> <A HREF="#prod30">QualifiedName</A> <LEFTPAREN> <A HREF="#prod18">Identifier</A> <RIGHTPAREN> <A HREF="#prod28">IfNotExists</A> <A HREF="#prod35">PrimaryKey</A> ( <AUTOGENERATED> )? ( <ON> <A HREF="#prod18">Identifier</A> )? ( <HINTS> <A HREF="#prod33">Properties</A> )? ( <USING> <COMPACTION> <POLICY> <A HREF="#prod34">CompactionPolicy</A> ( <A HREF="#prod32">Configuration</A> )? )? ( <WITH> <FILTER> <ON> <A HREF="#prod36">NestedField</A> )? )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod16">RefreshExternalDatasetStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><REFRESH> <EXTERNAL> <DATASET> <A HREF="#prod30">QualifiedName</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod17">RunStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><RUN> <A HREF="#prod18">Identifier</A> <LEFTPAREN> ( <A HREF="#prod18">Identifier</A> ( <COMMA> )? )* <RIGHTPAREN> <FROM> <DATASET> <A HREF="#prod30">QualifiedName</A> <TO> <DATASET> <A HREF="#prod30">QualifiedName</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod22">IndexSpecification</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><INDEX> <A HREF="#prod18">Identifier</A> <A HREF="#prod28">IfNotExists</A> <ON> <A HREF="#prod30">QualifiedName</A> <LEFTPAREN> ( <A HREF="#prod37">OpenField</A> ) ( <COMMA> <A HREF="#prod37">OpenField</A> )* <RIGHTPAREN> ( <TYPE> <A HREF="#prod38">IndexType</A> )? ( <ENFORCED> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod34">CompactionPolicy</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod39">FilterField</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod38">IndexType</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <BTREE> | <RTREE> | <KEYWORD> | <NGRAM> <LEFTPAREN> <INTEGER_LITERAL> <RIGHTPAREN> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod23">DataverseSpecification</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><DATAVERSE> <A HREF="#prod18">Identifier</A> <A HREF="#prod28">IfNotExists</A> ( <WITH> <FORMAT> <A HREF="#prod40">QuotedString</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod24">FunctionSpecification</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><FUNCTION> <A HREF="#prod41">FunctionName</A> <A HREF="#prod28">IfNotExists</A> <A HREF="#prod42">ParameterList</A> <LEFTBRACE> <A HREF="#prod43">Expression</A> <RIGHTBRACE></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod25">FeedSpecification</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <SECONDARY> <FEED> <A HREF="#prod30">QualifiedName</A> <A HREF="#prod28">IfNotExists</A> <FROM> <FEED> <A HREF="#prod30">QualifiedName</A> ( <A HREF="#prod44">ApplyFunction</A> )? | ( <PRIMARY> )? <FEED> <A HREF="#prod30">QualifiedName</A> <A HREF="#prod28">IfNotExists</A> <USING> <A HREF="#prod31">AdapterName</A> <A HREF="#prod32">Configuration</A> ( <A HREF="#prod44">ApplyFunction</A> )? )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod26">FeedPolicySpecification</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <INGESTION> <POLICY> <A HREF="#prod18">Identifier</A> <A HREF="#prod28">IfNotExists</A> <FROM> ( <POLICY> <A HREF="#prod18">Identifier</A> <A HREF="#prod32">Configuration</A> ( <DEFINITION> <A HREF="#prod40">QuotedString</A> )? | <PATH> <A HREF="#prod18">Identifier</A> ( <DEFINITION> <A HREF="#prod40">QuotedString</A> )? ) )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod42">ParameterList</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTPAREN> ( <IDENTIFIER> ( <COMMA> <IDENTIFIER> )* )? <RIGHTPAREN></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod28">IfNotExists</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <IF> ( "not exists" | "NOT EXISTS" ) )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod44">ApplyFunction</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><APPLY> <FUNCTION> <A HREF="#prod41">FunctionName</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod45">GetPolicy</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><USING> <POLICY> <A HREF="#prod18">Identifier</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod46">FunctionSignature</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod41">FunctionName</A> <ATT> <INTEGER_LITERAL></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod35">PrimaryKey</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><PRIMARY> <KEY> <A HREF="#prod36">NestedField</A> ( <COMMA> <A HREF="#prod36">NestedField</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod7">DropStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><DROP> ( <DATASET> <A HREF="#prod30">QualifiedName</A> <A HREF="#prod47">IfExists</A> | <INDEX> <A HREF="#prod48">DoubleQualifiedName</A> <A HREF="#prod47">IfExists</A> | <NODEGROUP> <A HREF="#prod18">Identifier</A> <A HREF="#prod47">IfExists</A> | <TYPE> <A HREF="#prod27">TypeName</A> <A HREF="#prod47">IfExists</A> | <DATAVERSE> <A HREF="#prod18">Identifier</A> <A HREF="#prod47">IfExists</A> | <FUNCTION> <A HREF="#prod46">FunctionSignature</A> <A HREF="#prod47">IfExists</A> | <FEED> <A HREF="#prod30">QualifiedName</A> <A HREF="#prod47">IfExists</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod47">IfExists</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <IF> <EXISTS> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod10">InsertStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><INSERT> <INTO> <A HREF="#prod30">QualifiedName</A> <A HREF="#prod15">Query</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod11">DeleteStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><DELETE> <A HREF="#prod49">Variable</A> <FROM> <A HREF="#prod30">QualifiedName</A> ( <WHERE> <A HREF="#prod43">Expression</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod12">UpdateStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><UPDATE> <A HREF="#prod49">Variable</A> <IN> <A HREF="#prod43">Expression</A> <WHERE> <A HREF="#prod43">Expression</A> <LEFTPAREN> ( <A HREF="#prod50">UpdateClause</A> ( <COMMA> <A HREF="#prod50">UpdateClause</A> )* ) <RIGHTPAREN></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod50">UpdateClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <SET> <A HREF="#prod43">Expression</A> <EQ> <A HREF="#prod43">Expression</A> | <A HREF="#prod10">InsertStatement</A> | <A HREF="#prod11">DeleteStatement</A> | <A HREF="#prod12">UpdateStatement</A> | <IF> <LEFTPAREN> <A HREF="#prod43">Expression</A> <RIGHTPAREN> <THEN> <A HREF="#prod50">UpdateClause</A> ( <ELSE> <A HREF="#prod50">UpdateClause</A> )? )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod9">SetStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><SET> <A HREF="#prod18">Identifier</A> <A HREF="#prod40">QuotedString</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod8">WriteStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><WRITE> <OUTPUT> <TO> <A HREF="#prod18">Identifier</A> <COLON> <A HREF="#prod40">QuotedString</A> ( <USING> <A HREF="#prod40">QuotedString</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod6">LoadStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LOAD> <DATASET> <A HREF="#prod30">QualifiedName</A> <USING> <A HREF="#prod31">AdapterName</A> <A HREF="#prod32">Configuration</A> ( <PRESORTED> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod31">AdapterName</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod14">CompactStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><COMPACT> <DATASET> <A HREF="#prod30">QualifiedName</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod13">FeedStatement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <CONNECT> <FEED> <A HREF="#prod30">QualifiedName</A> <TO> <DATASET> <A HREF="#prod30">QualifiedName</A> ( <A HREF="#prod45">GetPolicy</A> )? | <DISCONNECT> <FEED> <A HREF="#prod30">QualifiedName</A> <FROM> <DATASET> <A HREF="#prod30">QualifiedName</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod32">Configuration</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTPAREN> ( <A HREF="#prod51">KeyValuePair</A> ( <COMMA> <A HREF="#prod51">KeyValuePair</A> )* )? <RIGHTPAREN></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod51">KeyValuePair</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTPAREN> <A HREF="#prod40">QuotedString</A> <EQ> <A HREF="#prod40">QuotedString</A> <RIGHTPAREN></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod33">Properties</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <LEFTPAREN> <A HREF="#prod52">Property</A> ( <COMMA> <A HREF="#prod52">Property</A> )* <RIGHTPAREN> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod52">Property</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A> <EQ> ( <A HREF="#prod40">QuotedString</A> | <INTEGER_LITERAL> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod53">IndexedTypeExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod54">TypeReference</A> | <A HREF="#prod55">OrderedListTypeDef</A> | <A HREF="#prod56">UnorderedListTypeDef</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod29">TypeExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod57">RecordTypeDef</A> | <A HREF="#prod54">TypeReference</A> | <A HREF="#prod55">OrderedListTypeDef</A> | <A HREF="#prod56">UnorderedListTypeDef</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod57">RecordTypeDef</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <CLOSED> | <OPEN> )? <LEFTBRACE> ( <A HREF="#prod58">RecordField</A> ( <COMMA> <A HREF="#prod58">RecordField</A> )* )? <RIGHTBRACE></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod58">RecordField</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A> <COLON> <A HREF="#prod29">TypeExpr</A> ( <QUES> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod54">TypeReference</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod55">OrderedListTypeDef</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTBRACKET> ( <A HREF="#prod29">TypeExpr</A> ) <RIGHTBRACKET></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod56">UnorderedListTypeDef</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTDBLBRACE> ( <A HREF="#prod29">TypeExpr</A> ) <RIGHTDBLBRACE></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod41">FunctionName</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A> ( <DOT> <A HREF="#prod18">Identifier</A> ( <SHARP> <A HREF="#prod18">Identifier</A> )? | <SHARP> <A HREF="#prod18">Identifier</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod27">TypeName</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod30">QualifiedName</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod18">Identifier</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <IDENTIFIER> | <A HREF="#prod40">QuotedString</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod37">OpenField</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod36">NestedField</A> ( <COLON> <A HREF="#prod53">IndexedTypeExpr</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod36">NestedField</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A> ( <DOT> <A HREF="#prod18">Identifier</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod40">QuotedString</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><QUOTED_STRING></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod59">StringLiteral</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><STRING_LITERAL></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod30">QualifiedName</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A> ( <DOT> <A HREF="#prod18">Identifier</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod48">DoubleQualifiedName</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod18">Identifier</A> <DOT> <A HREF="#prod18">Identifier</A> ( <DOT> <A HREF="#prod18">Identifier</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod4">FunctionDeclaration</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><DECLARE> <FUNCTION> <A HREF="#prod18">Identifier</A> <A HREF="#prod42">ParameterList</A> <LEFTBRACE> <A HREF="#prod43">Expression</A> <RIGHTBRACE></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod15">Query</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod43">Expression</A> | <A HREF="#prod60">SelectExpression</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod43">Expression</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod61">OperatorExpr</A> | <A HREF="#prod62">IfThenElse</A> | <A HREF="#prod63">QuantifiedExpression</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod61">OperatorExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod64">AndExpr</A> ( <OR> <A HREF="#prod64">AndExpr</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod64">AndExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod65">RelExpr</A> ( <AND> <A HREF="#prod65">RelExpr</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod65">RelExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod66">AddExpr</A> ( ( <LT> | <GT> | <LE> | <GE> | <EQ> | <NE> | <SIMILAR> ) <A HREF="#prod66">AddExpr</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod66">AddExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod67">MultExpr</A> ( ( <PLUS> | <MINUS> ) <A HREF="#prod67">MultExpr</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod67">MultExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod68">UnaryExpr</A> ( ( <MUL> | <DIV> | <MOD> | <CARET> | <IDIV> ) <A HREF="#prod68">UnaryExpr</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod68">UnaryExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( ( <PLUS> | <MINUS> ) )? <A HREF="#prod69">ValueExpr</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod69">ValueExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod70">PrimaryExpr</A> ( <A HREF="#prod71">Field</A> | <A HREF="#prod72">Index</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod71">Field</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><DOT> <A HREF="#prod18">Identifier</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod72">Index</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTBRACKET> ( <A HREF="#prod43">Expression</A> | <QUES> ) <RIGHTBRACKET></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod70">PrimaryExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod73">FunctionCallExpr</A> | <A HREF="#prod74">Literal</A> | <A HREF="#prod75">VariableRef</A> | <A HREF="#prod76">ListConstructor</A> | <A HREF="#prod77">RecordConstructor</A> | <A HREF="#prod78">ParenthesizedExpression</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod74">Literal</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod59">StringLiteral</A> | <INTEGER_LITERAL> | <FLOAT_LITERAL> | <DOUBLE_LITERAL> | <NULL> | <TRUE> | <FALSE> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod75">VariableRef</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <IDENTIFIER> | <A HREF="#prod40">QuotedString</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod49">Variable</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <IDENTIFIER> | <A HREF="#prod40">QuotedString</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod76">ListConstructor</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod79">OrderedListConstructor</A> | <A HREF="#prod80">UnorderedListConstructor</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod79">OrderedListConstructor</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTBRACKET> <A HREF="#prod81">ExpressionList</A> <RIGHTBRACKET></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod80">UnorderedListConstructor</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTDBLBRACE> <A HREF="#prod81">ExpressionList</A> <RIGHTDBLBRACE></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod81">ExpressionList</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod43">Expression</A> ( <COMMA> <A HREF="#prod81">ExpressionList</A> )? )? ( <A HREF="#prod82">Comma</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod82">Comma</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><COMMA></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod77">RecordConstructor</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTBRACE> ( <A HREF="#prod83">FieldBinding</A> ( <COMMA> <A HREF="#prod83">FieldBinding</A> )* )? <RIGHTBRACE></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod83">FieldBinding</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod43">Expression</A> <COLON> <A HREF="#prod43">Expression</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod73">FunctionCallExpr</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod41">FunctionName</A> <LEFTPAREN> ( <A HREF="#prod43">Expression</A> ( <COMMA> <A HREF="#prod43">Expression</A> )* )? <RIGHTPAREN></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod78">ParenthesizedExpression</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <LEFTPAREN> <A HREF="#prod43">Expression</A> <RIGHTPAREN> | <A HREF="#prod84">Subquery</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod62">IfThenElse</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><IF> <LEFTPAREN> <A HREF="#prod43">Expression</A> <RIGHTPAREN> <THEN> <A HREF="#prod43">Expression</A> <ELSE> <A HREF="#prod43">Expression</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod60">SelectExpression</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod85">LetClause</A> )? <A HREF="#prod86">SelectSetOperation</A> ( <A HREF="#prod87">OrderbyClause</A> )? ( <A HREF="#prod88">LimitClause</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod86">SelectSetOperation</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod89">SelectBlock</A> ( ( <UNION> | <INTERSECT> | <EXCEPT> ) ( <ALL> )? ( <A HREF="#prod89">SelectBlock</A> | <A HREF="#prod84">Subquery</A> ) )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod84">Subquery</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LEFTPAREN> <A HREF="#prod60">SelectExpression</A> <RIGHTPAREN></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod89">SelectBlock</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod90">SelectClause</A> ( <A HREF="#prod91">FromClause</A> ( <A HREF="#prod85">LetClause</A> )? )? ( <A HREF="#prod92">WhereClause</A> )? ( <A HREF="#prod93">GroupbyClause</A> ( <A HREF="#prod85">LetClause</A> )? ( <A HREF="#prod94">HavingClause</A> )? )? | <A HREF="#prod91">FromClause</A> ( <A HREF="#prod85">LetClause</A> )? ( <A HREF="#prod92">WhereClause</A> )? ( <A HREF="#prod93">GroupbyClause</A> ( <A HREF="#prod85">LetClause</A> )? ( <A HREF="#prod94">HavingClause</A> )? )? <A HREF="#prod90">SelectClause</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod90">SelectClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><SELECT> ( <ALL> | <DISTINCT> )? ( <A HREF="#prod95">SelectRegular</A> | <A HREF="#prod96">SelectElement</A> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod95">SelectRegular</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod97">Projection</A> ( <COMMA> <A HREF="#prod97">Projection</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod96">SelectElement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <RAW> | <ELEMENT> | <VALUE> ) <A HREF="#prod43">Expression</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod97">Projection</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <A HREF="#prod43">Expression</A> ( <AS> )? <A HREF="#prod18">Identifier</A> | <A HREF="#prod43">Expression</A> <DOT> <MUL> | <MUL> )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod91">FromClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><FROM> <A HREF="#prod98">FromTerm</A> ( <COMMA> <A HREF="#prod98">FromTerm</A> )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod98">FromTerm</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod43">Expression</A> ( <AS> )? <A HREF="#prod49">Variable</A> ( <AT> <A HREF="#prod49">Variable</A> )? ( ( <A HREF="#prod99">JoinType</A> )? ( <A HREF="#prod100">JoinClause</A> | <A HREF="#prod101">NestClause</A> | <A HREF="#prod102">UnnestClause</A> ) )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod100">JoinClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><JOIN> <A HREF="#prod43">Expression</A> ( <AS> )? <A HREF="#prod49">Variable</A> ( <AT> <A HREF="#prod49">Variable</A> )? <ON> <A HREF="#prod43">Expression</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod101">NestClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><NEST> <A HREF="#prod43">Expression</A> ( <AS> )? <A HREF="#prod49">Variable</A> ( <AT> <A HREF="#prod49">Variable</A> )? <ON> <A HREF="#prod43">Expression</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod102">UnnestClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <UNNEST> | <CORRELATE> | <FLATTEN> ) <A HREF="#prod43">Expression</A> ( <AS> )? <A HREF="#prod49">Variable</A> ( <AT> <A HREF="#prod49">Variable</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod99">JoinType</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( <INNER> | <LEFT> ( <OUTER> )? )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod85">LetClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( ( <LET> | <LETTING> ) <A HREF="#prod103">LetElement</A> ( <COMMA> <A HREF="#prod103">LetElement</A> )* | <WITH> <A HREF="#prod104">WithElement</A> ( <COMMA> <A HREF="#prod104">WithElement</A> )* )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod92">WhereClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><WHERE> <A HREF="#prod43">Expression</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod87">OrderbyClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><ORDER> <BY> <A HREF="#prod43">Expression</A> ( ( <ASC> ) | ( <DESC> ) )? ( <COMMA> <A HREF="#prod43">Expression</A> ( ( <ASC> ) | ( <DESC> ) )? )*</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod93">GroupbyClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><GROUP> <BY> ( <A HREF="#prod43">Expression</A> ( ( <AS> )? <A HREF="#prod49">Variable</A> )? ( <COMMA> <A HREF="#prod43">Expression</A> ( ( <AS> )? <A HREF="#prod49">Variable</A> )? )* )</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod94">HavingClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><HAVING> <A HREF="#prod43">Expression</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod88">LimitClause</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><LIMIT> <A HREF="#prod43">Expression</A> ( <OFFSET> <A HREF="#prod43">Expression</A> )?</TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod63">QuantifiedExpression</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE>( ( <SOME> ) | ( <EVERY> ) ) <A HREF="#prod49">Variable</A> <IN> <A HREF="#prod43">Expression</A> ( <COMMA> <A HREF="#prod49">Variable</A> <IN> <A HREF="#prod43">Expression</A> )* <SATISFIES> <A HREF="#prod43">Expression</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod103">LetElement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod49">Variable</A> <EQ> <A HREF="#prod43">Expression</A></TD>
+</TR>
+<TR>
+<TD ALIGN=RIGHT VALIGN=BASELINE><A NAME="prod104">WithElement</A></TD>
+<TD ALIGN=CENTER VALIGN=BASELINE>::=</TD>
+<TD ALIGN=LEFT VALIGN=BASELINE><A HREF="#prod49">Variable</A> <AS> <A HREF="#prod43">Expression</A></TD>
+</TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
new file mode 100644
index 0000000..62899d6
--- /dev/null
+++ b/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -0,0 +1,2910 @@
+options {
+
+
+ STATIC = false;
+
+}
+
+
+PARSER_BEGIN(SQLPPParser)
+
+package org.apache.asterix.lang.sqlpp.parser;
+
+// For SQL++ ParserTokenManager
+import org.apache.xerces.util.IntStack;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.asterix.common.annotations.AutoDataGen;
+import org.apache.asterix.common.annotations.DateBetweenYearsDataGen;
+import org.apache.asterix.common.annotations.DatetimeAddRandHoursDataGen;
+import org.apache.asterix.common.annotations.DatetimeBetweenYearsDataGen;
+import org.apache.asterix.common.annotations.FieldIntervalDataGen;
+import org.apache.asterix.common.annotations.FieldValFileDataGen;
+import org.apache.asterix.common.annotations.FieldValFileSameIndexDataGen;
+import org.apache.asterix.common.annotations.IRecordFieldDataGen;
+import org.apache.asterix.common.annotations.InsertRandIntDataGen;
+import org.apache.asterix.common.annotations.ListDataGen;
+import org.apache.asterix.common.annotations.ListValFileDataGen;
+import org.apache.asterix.common.annotations.SkipSecondaryIndexSearchExpressionAnnotation;
+import org.apache.asterix.common.annotations.TypeDataGen;
+import org.apache.asterix.common.annotations.UndeclaredFieldsDataGen;
+import org.apache.asterix.common.config.DatasetConfig.DatasetType;
+import org.apache.asterix.common.config.DatasetConfig.IndexType;
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.Literal;
+import org.apache.asterix.lang.common.base.IParser;
+import org.apache.asterix.lang.common.base.Statement;
+import org.apache.asterix.lang.common.clause.GroupbyClause;
+import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.clause.LimitClause;
+import org.apache.asterix.lang.common.clause.OrderbyClause;
+import org.apache.asterix.lang.common.clause.UpdateClause;
+import org.apache.asterix.lang.common.clause.WhereClause;
+import org.apache.asterix.lang.common.context.RootScopeFactory;
+import org.apache.asterix.lang.common.context.Scope;
+import org.apache.asterix.lang.common.expression.AbstractAccessor;
+import org.apache.asterix.lang.common.expression.CallExpr;
+import org.apache.asterix.lang.common.expression.FieldAccessor;
+import org.apache.asterix.lang.common.expression.FieldBinding;
+import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair;
+import org.apache.asterix.lang.common.expression.IfExpr;
+import org.apache.asterix.lang.common.expression.IndexAccessor;
+import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.LiteralExpr;
+import org.apache.asterix.lang.common.expression.OperatorExpr;
+import org.apache.asterix.lang.common.expression.OrderedListTypeDefinition;
+import org.apache.asterix.lang.common.expression.QuantifiedExpression;
+import org.apache.asterix.lang.common.expression.RecordConstructor;
+import org.apache.asterix.lang.common.expression.RecordTypeDefinition;
+import org.apache.asterix.lang.common.expression.TypeExpression;
+import org.apache.asterix.lang.common.expression.TypeReferenceExpression;
+import org.apache.asterix.lang.common.expression.UnaryExpr;
+import org.apache.asterix.lang.common.expression.UnaryExpr.Sign;
+import org.apache.asterix.lang.common.expression.UnorderedListTypeDefinition;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.literal.DoubleLiteral;
+import org.apache.asterix.lang.common.literal.FalseLiteral;
+import org.apache.asterix.lang.common.literal.FloatLiteral;
+import org.apache.asterix.lang.common.literal.LongIntegerLiteral;
+import org.apache.asterix.lang.common.literal.NullLiteral;
+import org.apache.asterix.lang.common.literal.StringLiteral;
+import org.apache.asterix.lang.common.literal.TrueLiteral;
+import org.apache.asterix.lang.common.parser.ScopeChecker;
+import org.apache.asterix.lang.common.statement.CompactStatement;
+import org.apache.asterix.lang.common.statement.ConnectFeedStatement;
+import org.apache.asterix.lang.common.statement.CreateDataverseStatement;
+import org.apache.asterix.lang.common.statement.CreateFeedPolicyStatement;
+import org.apache.asterix.lang.common.statement.CreateFeedStatement;
+import org.apache.asterix.lang.common.statement.CreateFunctionStatement;
+import org.apache.asterix.lang.common.statement.CreateIndexStatement;
+import org.apache.asterix.lang.common.statement.CreatePrimaryFeedStatement;
+import org.apache.asterix.lang.common.statement.CreateSecondaryFeedStatement;
+import org.apache.asterix.lang.common.statement.DatasetDecl;
+import org.apache.asterix.lang.common.statement.DataverseDecl;
+import org.apache.asterix.lang.common.statement.DataverseDropStatement;
+import org.apache.asterix.lang.common.statement.DeleteStatement;
+import org.apache.asterix.lang.common.statement.DisconnectFeedStatement;
+import org.apache.asterix.lang.common.statement.DropStatement;
+import org.apache.asterix.lang.common.statement.ExternalDetailsDecl;
+import org.apache.asterix.lang.common.statement.FeedDropStatement;
+import org.apache.asterix.lang.common.statement.FunctionDecl;
+import org.apache.asterix.lang.common.statement.FunctionDropStatement;
+import org.apache.asterix.lang.common.statement.IndexDropStatement;
+import org.apache.asterix.lang.common.statement.InsertStatement;
+import org.apache.asterix.lang.common.statement.InternalDetailsDecl;
+import org.apache.asterix.lang.common.statement.LoadStatement;
+import org.apache.asterix.lang.common.statement.NodeGroupDropStatement;
+import org.apache.asterix.lang.common.statement.NodegroupDecl;
+import org.apache.asterix.lang.common.statement.Query;
+import org.apache.asterix.lang.common.statement.RefreshExternalDatasetStatement;
+import org.apache.asterix.lang.common.statement.RunStatement;
+import org.apache.asterix.lang.common.statement.SetStatement;
+import org.apache.asterix.lang.common.statement.TypeDecl;
+import org.apache.asterix.lang.common.statement.TypeDropStatement;
+import org.apache.asterix.lang.common.statement.UpdateStatement;
+import org.apache.asterix.lang.common.statement.WriteStatement;
+import org.apache.asterix.lang.common.struct.Identifier;
+import org.apache.asterix.lang.common.struct.QuantifiedPair;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
+import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause;
+import org.apache.asterix.lang.sqlpp.clause.FromClause;
+import org.apache.asterix.lang.sqlpp.clause.FromTerm;
+import org.apache.asterix.lang.sqlpp.clause.HavingClause;
+import org.apache.asterix.lang.sqlpp.clause.JoinClause;
+import org.apache.asterix.lang.sqlpp.clause.NestClause;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.clause.SelectBlock;
+import org.apache.asterix.lang.sqlpp.clause.SelectClause;
+import org.apache.asterix.lang.sqlpp.clause.SelectElement;
+import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
+import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
+import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
+import org.apache.asterix.lang.sqlpp.optype.JoinType;
+import org.apache.asterix.lang.sqlpp.optype.SetOpType;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationInput;
+import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
+import org.apache.asterix.metadata.bootstrap.MetadataConstants;
+import org.apache.hyracks.algebricks.common.utils.Pair;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
+import org.apache.hyracks.algebricks.core.algebra.expressions.IndexedNLJoinExpressionAnnotation;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+
+
+
+public class SQLPPParser extends ScopeChecker implements IParser {
+
+ // optimizer hints
+ private static final String AUTO_HINT = "auto";
+ private static final String BROADCAST_JOIN_HINT = "bcast";
+ private static final String COMPOSE_VAL_FILES_HINT = "compose-val-files";
+ private static final String DATE_BETWEEN_YEARS_HINT = "date-between-years";
+ private static final String DATETIME_ADD_RAND_HOURS_HINT = "datetime-add-rand-hours";
+ private static final String DATETIME_BETWEEN_YEARS_HINT = "datetime-between-years";
+ private static final String HASH_GROUP_BY_HINT = "hash";
+ private static final String INDEXED_NESTED_LOOP_JOIN_HINT = "indexnl";
+ private static final String INMEMORY_HINT = "inmem";
+ private static final String INSERT_RAND_INT_HINT = "insert-rand-int";
+ private static final String INTERVAL_HINT = "interval";
+ private static final String LIST_HINT = "list";
+ private static final String LIST_VAL_FILE_HINT = "list-val-file";
+ private static final String RANGE_HINT = "range";
+ private static final String SKIP_SECONDARY_INDEX_SEARCH_HINT = "skip-index";
+ private static final String VAL_FILE_HINT = "val-files";
+ private static final String VAL_FILE_SAME_INDEX_HINT = "val-file-same-idx";
+
+ private static final String GEN_FIELDS_HINT = "gen-fields";
+
+ // data generator hints
+ private static final String DGEN_HINT = "dgen";
+
+ private static class IndexParams {
+ public IndexType type;
+ public int gramLength;
+
+ public IndexParams(IndexType type, int gramLength) {
+ this.type = type;
+ this.gramLength = gramLength;
+ }
+ };
+
+ private static class FunctionName {
+ public String dataverse = null;
+ public String library = null;
+ public String function = null;
+ public String hint = null;
+ }
+
+ private static String getHint(Token t) {
+ if (t.specialToken == null) {
+ return null;
+ }
+ String s = t.specialToken.image;
+ int n = s.length();
+ if (n < 2) {
+ return null;
+ }
+ return s.substring(1).trim();
+ }
+
+ private static IRecordFieldDataGen parseFieldDataGen(String hint) throws ParseException {
+ IRecordFieldDataGen rfdg = null;
+ String splits[] = hint.split(" +");
+ if (splits[0].equals(VAL_FILE_HINT)) {
+ File[] valFiles = new File[splits.length - 1];
+ for (int k=1; k<splits.length; k++) {
+ valFiles[k-1] = new File(splits[k]);
+ }
+ rfdg = new FieldValFileDataGen(valFiles);
+ } else if (splits[0].equals(VAL_FILE_SAME_INDEX_HINT)) {
+ rfdg = new FieldValFileSameIndexDataGen(new File(splits[1]), splits[2]);
+ } else if (splits[0].equals(LIST_VAL_FILE_HINT)) {
+ rfdg = new ListValFileDataGen(new File(splits[1]), Integer.parseInt(splits[2]), Integer.parseInt(splits[3]));
+ } else if (splits[0].equals(LIST_HINT)) {
+ rfdg = new ListDataGen(Integer.parseInt(splits[1]), Integer.parseInt(splits[2]));
+ } else if (splits[0].equals(INTERVAL_HINT)) {
+ FieldIntervalDataGen.ValueType vt;
+ if (splits[1].equals("int")) {
+ vt = FieldIntervalDataGen.ValueType.INT;
+ } else if (splits[1].equals("long")) {
+ vt = FieldIntervalDataGen.ValueType.LONG;
+ } else if (splits[1].equals("float")) {
+ vt = FieldIntervalDataGen.ValueType.FLOAT;
+ } else if (splits[1].equals("double")) {
+ vt = FieldIntervalDataGen.ValueType.DOUBLE;
+ } else {
+ throw new ParseException("Unknown type for interval data gen: " + splits[1]);
+ }
+ rfdg = new FieldIntervalDataGen(vt, splits[2], splits[3]);
+ } else if (splits[0].equals(INSERT_RAND_INT_HINT)) {
+ rfdg = new InsertRandIntDataGen(splits[1], splits[2]);
+ } else if (splits[0].equals(DATE_BETWEEN_YEARS_HINT)) {
+ rfdg = new DateBetweenYearsDataGen(Integer.parseInt(splits[1]), Integer.parseInt(splits[2]));
+ } else if (splits[0].equals(DATETIME_BETWEEN_YEARS_HINT)) {
+ rfdg = new DatetimeBetweenYearsDataGen(Integer.parseInt(splits[1]), Integer.parseInt(splits[2]));
+ } else if (splits[0].equals(DATETIME_ADD_RAND_HOURS_HINT)) {
+ rfdg = new DatetimeAddRandHoursDataGen(Integer.parseInt(splits[1]), Integer.parseInt(splits[2]), splits[3]);
+ } else if (splits[0].equals(AUTO_HINT)) {
+ rfdg = new AutoDataGen(splits[1]);
+ }
+ return rfdg;
+ }
+
+ public SQLPPParser(String s){
+ this(new StringReader(s));
+ super.setInput(s);
+ }
+
+ public static void main(String args[]) throws ParseException, TokenMgrError, IOException, FileNotFoundException, AsterixException {
+ File file = new File(args[0]);
+ Reader fis = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
+ SQLPPParser parser = new SQLPPParser(fis);
+ List<Statement> st = parser.parse();
+ //st.accept(new SQLPPPrintVisitor(), 0);
+ }
+
+ public List<Statement> parse() throws AsterixException {
+ try {
+ return Statement();
+ } catch (Error e) {
+ // this is here as the JavaCharStream that's below the lexer somtimes throws Errors that are not handled
+ // by the ANTLR-generated lexer or parser (e.g it does this for invalid backslash u + 4 hex digits escapes)
+ throw new AsterixException(new ParseException(e.getMessage()));
+ } catch (ParseException e) {
+ throw new AsterixException(e.getMessage());
+ }
+ }
+}
+
+PARSER_END(SQLPPParser)
+
+
+List<Statement> Statement() throws ParseException:
+{
+ scopeStack.push(RootScopeFactory.createRootScope(this));
+ List<Statement> decls = new ArrayList<Statement>();
+ Statement stmt = null;
+}
+{
+ ( stmt = SingleStatement() (<SEMICOLON>)*
+ {
+ decls.add(stmt);
+ }
+ )*
+ <EOF>
+ {
+ return decls;
+ }
+}
+
+Statement SingleStatement() throws ParseException:
+{
+ Statement stmt = null;
+}
+{
+ (
+ stmt = DataverseDeclaration()
+ | stmt = FunctionDeclaration()
+ | stmt = CreateStatement()
+ | stmt = LoadStatement()
+ | stmt = DropStatement()
+ | stmt = WriteStatement()
+ | stmt = SetStatement()
+ | stmt = InsertStatement()
+ | stmt = DeleteStatement()
+ | stmt = UpdateStatement()
+ | stmt = FeedStatement()
+ | stmt = CompactStatement()
+ | stmt = Query() <SEMICOLON>
+ | stmt = RefreshExternalDatasetStatement()
+ | stmt = RunStatement()
+ )
+ {
+ return stmt;
+ }
+}
+
+DataverseDecl DataverseDeclaration() throws ParseException:
+{
+ String dvName = null;
+}
+{
+ <USE> dvName = Identifier()
+ {
+ defaultDataverse = dvName;
+ return new DataverseDecl(new Identifier(dvName));
+ }
+}
+
+Statement CreateStatement() throws ParseException:
+{
+ String hint = null;
+ boolean dgen = false;
+ Statement stmt = null;
+}
+{
+ <CREATE>
+ (
+ {
+ hint = getHint(token);
+ if (hint != null && hint.startsWith(DGEN_HINT)) {
+ dgen = true;
+ }
+ }
+ stmt = TypeSpecification(hint, dgen)
+ | stmt = NodegroupSpecification()
+ | stmt = DatasetSpecification()
+ | stmt = IndexSpecification()
+ | stmt = DataverseSpecification()
+ | stmt = FunctionSpecification()
+ | stmt = FeedSpecification()
+ | stmt = FeedPolicySpecification()
+ )
+ {
+ return stmt;
+ }
+}
+
+TypeDecl TypeSpecification(String hint, boolean dgen) throws ParseException:
+{
+ Pair<Identifier,Identifier> nameComponents = null;
+ boolean ifNotExists = false;
+ TypeExpression typeExpr = null;
+}
+{
+ <TYPE> nameComponents = TypeName() ifNotExists = IfNotExists()
+ <AS> typeExpr = TypeExpr()
+ {
+ long numValues = -1;
+ String filename = null;
+ if (dgen) {
+ String splits[] = hint.split(" +");
+ if (splits.length != 3) {
+ throw new ParseException("Expecting /*+ dgen <filename> <numberOfItems> */");
+ }
+ filename = splits[1];
+ numValues = Long.parseLong(splits[2]);
+ }
+ TypeDataGen tddg = new TypeDataGen(dgen, filename, numValues);
+ return new TypeDecl(nameComponents.first, nameComponents.second, typeExpr, tddg, ifNotExists);
+ }
+}
+
+
+NodegroupDecl NodegroupSpecification() throws ParseException:
+{
+ String name = null;
+ String tmp = null;
+ boolean ifNotExists = false;
+ List<Identifier>ncNames = null;
+}
+{
+ <NODEGROUP> name = Identifier()
+ ifNotExists = IfNotExists() <ON> tmp = Identifier()
+ {
+ ncNames = new ArrayList<Identifier>();
+ ncNames.add(new Identifier(tmp));
+ }
+ ( <COMMA> tmp = Identifier()
+ {
+ ncNames.add(new Identifier(tmp));
+ }
+ )*
+ {
+ return new NodegroupDecl(new Identifier(name), ncNames, ifNotExists);
+ }
+}
+
+DatasetDecl DatasetSpecification() throws ParseException:
+{
+ Pair<Identifier,Identifier> nameComponents = null;
+ boolean ifNotExists = false;
+ String typeName = null;
+ String adapterName = null;
+ Map<String,String> properties = null;
+ Map<String,String> compactionPolicyProperties = null;
+ FunctionSignature appliedFunction = null;
+ List<List<String>> primaryKeyFields = null;
+ String nodeGroupName = null;
+ Map<String,String> hints = new HashMap<String,String>();
+ DatasetDecl dsetDecl = null;
+ boolean autogenerated = false;
+ String compactionPolicy = null;
+ boolean temp = false;
+ List<String> filterField = null;
+}
+{
+ (
+ <EXTERNAL> <DATASET> nameComponents = QualifiedName()
+ <LEFTPAREN> typeName = Identifier() <RIGHTPAREN>
+ ifNotExists = IfNotExists()
+ <USING> adapterName = AdapterName() properties = Configuration()
+ (<ON> nodeGroupName = Identifier() )?
+ ( <HINTS> hints = Properties() )?
+ ( <USING> <COMPACTION> <POLICY> compactionPolicy = CompactionPolicy() (LOOKAHEAD(1) compactionPolicyProperties = Configuration())? )?
+ {
+ ExternalDetailsDecl edd = new ExternalDetailsDecl();
+ edd.setAdapter(adapterName);
+ edd.setProperties(properties);
+ dsetDecl = new DatasetDecl(nameComponents.first,
+ nameComponents.second,
+ new Identifier(typeName),
+ nodeGroupName != null? new Identifier(nodeGroupName): null,
+ compactionPolicy,
+ compactionPolicyProperties,
+ hints,
+ DatasetType.EXTERNAL,
+ edd,
+ ifNotExists);
+ }
+
+ | (<INTERNAL> | <TEMPORARY> { temp = true; })?
+ <DATASET> nameComponents = QualifiedName()
+ <LEFTPAREN> typeName = Identifier() <RIGHTPAREN>
+ ifNotExists = IfNotExists()
+ primaryKeyFields = PrimaryKey()
+ (<AUTOGENERATED> { autogenerated = true; } )?
+ (<ON> nodeGroupName = Identifier() )?
+ ( <HINTS> hints = Properties() )?
+ ( <USING> <COMPACTION> <POLICY> compactionPolicy = CompactionPolicy() (LOOKAHEAD(1) compactionPolicyProperties = Configuration())? )?
+ ( LOOKAHEAD(2) <WITH> <FILTER> <ON> filterField = NestedField() )?
+ {
+ InternalDetailsDecl idd = new InternalDetailsDecl(primaryKeyFields,
+ autogenerated,
+ filterField,
+ temp);
+ dsetDecl = new DatasetDecl(nameComponents.first,
+ nameComponents.second,
+ new Identifier(typeName),
+ nodeGroupName != null ? new Identifier(nodeGroupName) : null,
+ compactionPolicy,
+ compactionPolicyProperties,
+ hints,
+ DatasetType.INTERNAL,
+ idd,
+ ifNotExists);
+ }
+ )
+ {
+ return dsetDecl;
+ }
+}
+
+RefreshExternalDatasetStatement RefreshExternalDatasetStatement() throws ParseException:
+{
+ RefreshExternalDatasetStatement redss = new RefreshExternalDatasetStatement();
+ Pair<Identifier,Identifier> nameComponents = null;
+ String datasetName = null;
+}
+{
+ <REFRESH> <EXTERNAL> <DATASET> nameComponents = QualifiedName()
+ {
+ redss.setDataverseName(nameComponents.first);
+ redss.setDatasetName(nameComponents.second);
+ return redss;
+ }
+}
+
+RunStatement RunStatement() throws ParseException:
+{
+ String system = null;
+ String tmp;
+ ArrayList<String> parameters = new ArrayList<String>();
+ Pair<Identifier,Identifier> nameComponentsFrom = null;
+ Pair<Identifier,Identifier> nameComponentsTo = null;
+}
+{
+ <RUN> system = Identifier()<LEFTPAREN> ( tmp = Identifier() [<COMMA>]
+ {
+ parameters.add(tmp);
+ }
+ )*<RIGHTPAREN>
+ <FROM> <DATASET> nameComponentsFrom = QualifiedName()
+ <TO> <DATASET> nameComponentsTo = QualifiedName()
+ {
+ return new RunStatement(system, parameters, nameComponentsFrom.first, nameComponentsFrom.second, nameComponentsTo.first, nameComponentsTo.second);
+ }
+}
+
+CreateIndexStatement IndexSpecification() throws ParseException:
+{
+ CreateIndexStatement cis = new CreateIndexStatement();
+ String indexName = null;
+ boolean ifNotExists = false;
+ Pair<Identifier,Identifier> nameComponents = null;
+ Pair<List<String>, TypeExpression> fieldPair = null;
+ IndexParams indexType = null;
+ boolean enforced = false;
+}
+{
+ <INDEX> indexName = Identifier()
+ ifNotExists = IfNotExists()
+ <ON> nameComponents = QualifiedName()
+ <LEFTPAREN> ( fieldPair = OpenField()
+ {
+ cis.addFieldExprPair(fieldPair);
+ }
+ ) (<COMMA> fieldPair = OpenField()
+ {
+ cis.addFieldExprPair(fieldPair);
+ }
+ )* <RIGHTPAREN> ( <TYPE> indexType = IndexType() )? ( <ENFORCED> { enforced = true; } )?
+ {
+ cis.setIndexName(new Identifier(indexName));
+ cis.setIfNotExists(ifNotExists);
+ cis.setDataverseName(nameComponents.first);
+ cis.setDatasetName(nameComponents.second);
+ if (indexType != null) {
+ cis.setIndexType(indexType.type);
+ cis.setGramLength(indexType.gramLength);
+ }
+ cis.setEnforced(enforced);
+ return cis;
+ }
+}
+
+String CompactionPolicy() throws ParseException :
+{
+ String compactionPolicy = null;
+}
+{
+ compactionPolicy = Identifier()
+ {
+ return compactionPolicy;
+ }
+}
+
+String FilterField() throws ParseException :
+{
+ String filterField = null;
+}
+{
+ filterField = Identifier()
+ {
+ return filterField;
+ }
+}
+
+IndexParams IndexType() throws ParseException:
+{
+ IndexType type = null;
+ int gramLength = 0;
+}
+{
+ (<BTREE>
+ {
+ type = IndexType.BTREE;
+ }
+ | <RTREE>
+ {
+ type = IndexType.RTREE;
+ }
+ | <KEYWORD>
+ {
+ type = IndexType.LENGTH_PARTITIONED_WORD_INVIX;
+ }
+ | <NGRAM> <LEFTPAREN> <INTEGER_LITERAL>
+ {
+ type = IndexType.LENGTH_PARTITIONED_NGRAM_INVIX;
+ gramLength = Integer.valueOf(token.image);
+ }
+ <RIGHTPAREN>)
+ {
+ return new IndexParams(type, gramLength);
+ }
+}
+
+CreateDataverseStatement DataverseSpecification() throws ParseException :
+{
+ String dvName = null;
+ boolean ifNotExists = false;
+ String format = null;
+}
+{
+ <DATAVERSE> dvName = Identifier()
+ ifNotExists = IfNotExists()
+ ( LOOKAHEAD(1) <WITH> <FORMAT> format = QuotedString() )?
+ {
+ return new CreateDataverseStatement(new Identifier(dvName), format, ifNotExists);
+ }
+}
+
+CreateFunctionStatement FunctionSpecification() throws ParseException:
+{
+ FunctionSignature signature;
+ boolean ifNotExists = false;
+ List<VarIdentifier> paramList = new ArrayList<VarIdentifier>();
+ String functionBody;
+ VarIdentifier var = null;
+ Expression functionBodyExpr;
+ Token beginPos;
+ Token endPos;
+ FunctionName fctName = null;
+
+ createNewScope();
+}
+{
+ <FUNCTION> fctName = FunctionName()
+ ifNotExists = IfNotExists()
+ paramList = ParameterList()
+ <LEFTBRACE>
+ {
+ beginPos = token;
+ }
+ functionBodyExpr = Expression() <RIGHTBRACE>
+ {
+ endPos = token;
+ functionBody = extractFragment(beginPos.beginLine, beginPos.beginColumn, endPos.beginLine, endPos.beginColumn);
+ // TODO use fctName.library
+ signature = new FunctionSignature(fctName.dataverse, fctName.function, paramList.size());
+ getCurrentScope().addFunctionDescriptor(signature, false);
+ removeCurrentScope();
+ return new CreateFunctionStatement(signature, paramList, functionBody, ifNotExists);
+ }
+}
+
+CreateFeedStatement FeedSpecification() throws ParseException:
+{
+ Pair<Identifier,Identifier> nameComponents = null;
+ boolean ifNotExists = false;
+ String adapterName = null;
+ Map<String,String> properties = null;
+ FunctionSignature appliedFunction = null;
+ CreateFeedStatement cfs = null;
+ Pair<Identifier,Identifier> sourceNameComponents = null;
+
+}
+{
+ (
+ <SECONDARY> <FEED> nameComponents = QualifiedName() ifNotExists = IfNotExists()
+ <FROM> <FEED> sourceNameComponents = QualifiedName() (appliedFunction = ApplyFunction())?
+ {
+ cfs = new CreateSecondaryFeedStatement(nameComponents,
+ sourceNameComponents, appliedFunction, ifNotExists);
+ }
+ |
+ (<PRIMARY>)? <FEED> nameComponents = QualifiedName() ifNotExists = IfNotExists()
+ <USING> adapterName = AdapterName() properties = Configuration() (appliedFunction = ApplyFunction())?
+ {
+ cfs = new CreatePrimaryFeedStatement(nameComponents,
+ adapterName, properties, appliedFunction, ifNotExists);
+ }
+ )
+ {
+ return cfs;
+ }
+}
+
+CreateFeedPolicyStatement FeedPolicySpecification() throws ParseException:
+{
+ String policyName = null;
+ String basePolicyName = null;
+ String sourcePolicyFile = null;
+ String definition = null;
+ boolean ifNotExists = false;
+ Map<String,String> properties = null;
+ CreateFeedPolicyStatement cfps = null;
+}
+{
+ (
+ <INGESTION> <POLICY> policyName = Identifier() ifNotExists = IfNotExists()
+ <FROM>
+ (<POLICY> basePolicyName = Identifier() properties = Configuration() (<DEFINITION> definition = QuotedString())?
+ {
+ cfps = new CreateFeedPolicyStatement(policyName,
+ basePolicyName, properties, definition, ifNotExists);
+ }
+ | <PATH> sourcePolicyFile = Identifier() (<DEFINITION> definition = QuotedString())?
+ {
+ cfps = new CreateFeedPolicyStatement(policyName, sourcePolicyFile, definition, ifNotExists);
+ }
+ )
+
+ )
+ {
+ return cfps;
+ }
+}
+
+
+
+List<VarIdentifier> ParameterList() throws ParseException:
+{
+ List<VarIdentifier> paramList = new ArrayList<VarIdentifier>();
+ VarIdentifier var = null;
+}
+{
+ <LEFTPAREN> (<IDENTIFIER>
+ {
+ var = new VarIdentifier();
+ var.setValue(token.image);
+ paramList.add(var);
+ getCurrentScope().addNewVarSymbolToScope(var);
+ }
+ (<COMMA> <IDENTIFIER>
+ {
+ var = new VarIdentifier();
+ var.setValue(token.image);
+ paramList.add(var);
+ getCurrentScope().addNewVarSymbolToScope(var);
+ }
+ )*)? <RIGHTPAREN>
+ {
+ return paramList;
+ }
+}
+
+boolean IfNotExists() throws ParseException:
+{
+}
+{
+ ( LOOKAHEAD(1) <IF> ("not exists"|"NOT EXISTS")
+ {
+ return true;
+ }
+ )?
+ {
+ return false;
+ }
+}
+
+FunctionSignature ApplyFunction() throws ParseException:
+{
+ FunctionName functioName = null;
+ FunctionSignature funcSig = null;
+}
+{
+ <APPLY> <FUNCTION> functioName = FunctionName()
+ {
+ String fqFunctionName = functioName.library == null ? functioName.function : functioName.library + "#" + functioName.function;
+ return new FunctionSignature(functioName.dataverse, fqFunctionName, 1);
+ }
+}
+
+String GetPolicy() throws ParseException:
+{
+ String policy = null;
+}
+{
+ <USING> <POLICY> policy = Identifier()
+ {
+ return policy;
+ }
+
+}
+
+FunctionSignature FunctionSignature() throws ParseException:
+{
+ FunctionName fctName = null;
+ int arity = 0;
+}
+{
+ fctName = FunctionName() <ATT> <INTEGER_LITERAL>
+ {
+ arity = new Integer(token.image);
+ if (arity < 0 && arity != FunctionIdentifier.VARARGS) {
+ throw new ParseException(" invalid arity:" + arity);
+ }
+
+ // TODO use fctName.library
+ String fqFunctionName = fctName.library == null ? fctName.function : fctName.library + "#" + fctName.function;
+ return new FunctionSignature(fctName.dataverse, fqFunctionName, arity);
+ }
+}
+
+List<List<String>> PrimaryKey() throws ParseException:
+{
+ List<String> tmp = null;
+ List<List<String>> primaryKeyFields = new ArrayList<List<String>>();
+}
+{
+ <PRIMARY> <KEY> tmp = NestedField()
+ {
+ primaryKeyFields.add(tmp);
+ }
+ ( <COMMA> tmp = NestedField()
+ {
+ primaryKeyFields.add(tmp);
+ }
+ )*
+ {
+ return primaryKeyFields;
+ }
+}
+
+Statement DropStatement() throws ParseException:
+{
+ String id = null;
+ Pair<Identifier,Identifier> pairId = null;
+ Triple<Identifier,Identifier,Identifier> tripleId = null;
+ FunctionSignature funcSig = null;
+ boolean ifExists = false;
+ Statement stmt = null;
+}
+{
+ <DROP>
+ (
+ <DATASET> pairId = QualifiedName() ifExists = IfExists()
+ {
+ stmt = new DropStatement(pairId.first, pairId.second, ifExists);
+ }
+ | <INDEX> tripleId = DoubleQualifiedName() ifExists = IfExists()
+ {
+ stmt = new IndexDropStatement(tripleId.first, tripleId.second, tripleId.third, ifExists);
+ }
+ | <NODEGROUP> id = Identifier() ifExists = IfExists()
+ {
+ stmt = new NodeGroupDropStatement(new Identifier(id), ifExists);
+ }
+ | <TYPE> pairId = TypeName() ifExists = IfExists()
+ {
+ stmt = new TypeDropStatement(pairId.first, pairId.second, ifExists);
+ }
+ | <DATAVERSE> id = Identifier() ifExists = IfExists()
+ {
+ stmt = new DataverseDropStatement(new Identifier(id), ifExists);
+ }
+ | <FUNCTION> funcSig = FunctionSignature() ifExists = IfExists()
+ {
+ stmt = new FunctionDropStatement(funcSig, ifExists);
+ }
+ | <FEED> pairId = QualifiedName() ifExists = IfExists()
+ {
+ stmt = new FeedDropStatement(pairId.first, pairId.second, ifExists);
+ }
+ )
+ {
+ return stmt;
+ }
+}
+
+boolean IfExists() throws ParseException :
+{
+}
+{
+ ( LOOKAHEAD(1) <IF> <EXISTS>
+ {
+ return true;
+ }
+ )?
+ {
+ return false;
+ }
+}
+
+InsertStatement InsertStatement() throws ParseException:
+{
+ Pair<Identifier,Identifier> nameComponents = null;
+ Query query;
+}
+{
+ <INSERT> <INTO> nameComponents = QualifiedName() query = Query()
+ {
+ query.setTopLevel(false);
+ return new InsertStatement(nameComponents.first, nameComponents.second, query, getVarCounter());
+ }
+}
+
+DeleteStatement DeleteStatement() throws ParseException:
+{
+ VariableExpr var = null;
+ Expression condition = null;
+ Pair<Identifier, Identifier> nameComponents;
+ // This is related to the new metadata lock management
+ setDataverses(new ArrayList<String>());
+ setDatasets(new ArrayList<String>());
+
+}
+{
+ <DELETE> var = Variable()
+ {
+ getCurrentScope().addNewVarSymbolToScope(var.getVar());
+ }
+ <FROM> nameComponents = QualifiedName()
+ (<WHERE> condition = Expression())?
+ {
+ // First we get the dataverses and datasets that we want to lock
+ List<String> dataverses = getDataverses();
+ List<String> datasets = getDatasets();
+ // we remove the pointer to the dataverses and datasets
+ setDataverses(null);
+ setDatasets(null);
+ return new DeleteStatement(var, nameComponents.first, nameComponents.second,
+ condition, getVarCounter(), dataverses, datasets);
+ }
+}
+
+UpdateStatement UpdateStatement() throws ParseException:
+{
+ VariableExpr vars;
+ Expression target;
+ Expression condition;
+ UpdateClause uc;
+ List<UpdateClause> ucs = new ArrayList<UpdateClause>();
+}
+{
+ <UPDATE> vars = Variable() <IN> target = Expression()
+ <WHERE> condition = Expression()
+ <LEFTPAREN> (uc = UpdateClause()
+ {
+ ucs.add(uc);
+ }
+ (<COMMA> uc = UpdateClause()
+ {
+ ucs.add(uc);
+ }
+ )*) <RIGHTPAREN>
+ {
+ return new UpdateStatement(vars, target, condition, ucs);
+ }
+}
+
+UpdateClause UpdateClause() throws ParseException:
+{
+ Expression target = null;
+ Expression value = null ;
+ InsertStatement is = null;
+ DeleteStatement ds = null;
+ UpdateStatement us = null;
+ Expression condition = null;
+ UpdateClause ifbranch = null;
+ UpdateClause elsebranch = null;
+}
+{
+ (<SET> target = Expression() <EQ> value = Expression()
+ | is = InsertStatement()
+ | ds = DeleteStatement()
+ | us = UpdateStatement()
+ | <IF> <LEFTPAREN> condition = Expression() <RIGHTPAREN>
+ <THEN> ifbranch = UpdateClause()
+ [LOOKAHEAD(1) <ELSE> elsebranch = UpdateClause()]
+ {
+ return new UpdateClause(target, value, is, ds, us, condition, ifbranch, elsebranch);
+ }
+ )
+}
+
+Statement SetStatement() throws ParseException:
+{
+ String pn = null;
+ String pv = null;
+}
+{
+ <SET> pn = Identifier() pv = QuotedString()
+ {
+ return new SetStatement(pn, pv);
+ }
+}
+
+Statement WriteStatement() throws ParseException:
+{
+ String nodeName = null;
+ String fileName = null;
+ Query query;
+ String writerClass = null;
+ Pair<Identifier,Identifier> nameComponents = null;
+}
+{
+ <WRITE> <OUTPUT> <TO> nodeName = Identifier() <COLON> fileName = QuotedString()
+ ( <USING> writerClass = QuotedString() )?
+ {
+ return new WriteStatement(new Identifier(nodeName), fileName, writerClass);
+ }
+}
+
+LoadStatement LoadStatement() throws ParseException:
+{
+ Identifier dataverseName = null;
+ Identifier datasetName = null;
+ boolean alreadySorted = false;
+ String adapterName;
+ Map<String,String> properties;
+ Pair<Identifier,Identifier> nameComponents = null;
+}
+{
+ <LOAD> <DATASET> nameComponents = QualifiedName()
+ {
+ dataverseName = nameComponents.first;
+ datasetName = nameComponents.second;
+ }
+ <USING> adapterName = AdapterName() properties = Configuration()
+ (<PRESORTED>
+ {
+ alreadySorted = true;
+ }
+ )?
+ {
+ return new LoadStatement(dataverseName, datasetName, adapterName, properties, alreadySorted);
+ }
+}
+
+
+String AdapterName() throws ParseException :
+{
+ String adapterName = null;
+}
+{
+ adapterName = Identifier()
+ {
+ return adapterName;
+ }
+}
+
+Statement CompactStatement() throws ParseException:
+{
+ Pair<Identifier,Identifier> nameComponents = null;
+ Statement stmt = null;
+}
+{
+ <COMPACT> <DATASET> nameComponents = QualifiedName()
+ {
+ stmt = new CompactStatement(nameComponents.first, nameComponents.second);
+ }
+ {
+ return stmt;
+ }
+}
+
+Statement FeedStatement() throws ParseException:
+{
+ Pair<Identifier,Identifier> feedNameComponents = null;
+ Pair<Identifier,Identifier> datasetNameComponents = null;
+
+ Map<String,String> configuration = null;
+ Statement stmt = null;
+ String policy = null;
+}
+{
+ (
+ <CONNECT> <FEED> feedNameComponents = QualifiedName() <TO> <DATASET> datasetNameComponents = QualifiedName() (policy = GetPolicy())?
+ {
+ stmt = new ConnectFeedStatement(feedNameComponents, datasetNameComponents, policy, getVarCounter());
+ }
+ | <DISCONNECT> <FEED> feedNameComponents = QualifiedName() <FROM> <DATASET> datasetNameComponents = QualifiedName()
+ {
+ stmt = new DisconnectFeedStatement(feedNameComponents, datasetNameComponents);
+ }
+ )
+ {
+ return stmt;
+ }
+}
+
+Map<String,String> Configuration() throws ParseException :
+{
+ Map<String,String> configuration = new LinkedHashMap<String,String>();
+ Pair<String, String> keyValuePair = null;
+}
+{
+ <LEFTPAREN> ( keyValuePair = KeyValuePair()
+ {
+ configuration.put(keyValuePair.first, keyValuePair.second);
+ }
+ ( <COMMA> keyValuePair = KeyValuePair()
+ {
+ configuration.put(keyValuePair.first, keyValuePair.second);
+ }
+ )* )? <RIGHTPAREN>
+ {
+ return configuration;
+ }
+}
+
+Pair<String, String> KeyValuePair() throws ParseException:
+{
+ String key;
+ String value;
+}
+{
+ <LEFTPAREN> key = QuotedString() <EQ> value = QuotedString() <RIGHTPAREN>
+ {
+ return new Pair<String, String>(key, value);
+ }
+}
+
+Map<String,String> Properties() throws ParseException:
+{
+ Map<String,String> properties = new HashMap<String,String>();
+ Pair<String, String> property;
+}
+{
+ (LOOKAHEAD(1) <LEFTPAREN> property = Property()
+ {
+ properties.put(property.first, property.second);
+ }
+ ( <COMMA> property = Property()
+ {
+ properties.put(property.first, property.second);
+ }
+ )* <RIGHTPAREN> )?
+ {
+ return properties;
+ }
+}
+
+Pair<String, String> Property() throws ParseException:
+{
+ String key;
+ String value;
+}
+{
+ key = Identifier() <EQ> ( value = QuotedString() | <INTEGER_LITERAL>
+ {
+ try {
+ value = "" + Long.valueOf(token.image);
+ } catch (NumberFormatException nfe) {
+ throw new ParseException("inapproriate value: " + token.image);
+ }
+ }
+ )
+ {
+ return new Pair<String, String>(key.toUpperCase(), value);
+ }
+}
+
+TypeExpression IndexedTypeExpr() throws ParseException:
+{
+ TypeExpression typeExpr = null;
+}
+{
+ (
+ typeExpr = TypeReference()
+ | typeExpr = OrderedListTypeDef()
+ | typeExpr = UnorderedListTypeDef()
+ )
+ {
+ return typeExpr;
+ }
+}
+
+TypeExpression TypeExpr() throws ParseException:
+{
+ TypeExpression typeExpr = null;
+}
+{
+ (
+ typeExpr = RecordTypeDef()
+ | typeExpr = TypeReference()
+ | typeExpr = OrderedListTypeDef()
+ | typeExpr = UnorderedListTypeDef()
+ )
+ {
+ return typeExpr;
+ }
+}
+
+RecordTypeDefinition RecordTypeDef() throws ParseException:
+{
+ RecordTypeDefinition recType = new RecordTypeDefinition();
+ RecordTypeDefinition.RecordKind recordKind = null;
+}
+{
+ ( <CLOSED> { recordKind = RecordTypeDefinition.RecordKind.CLOSED; }
+ | <OPEN> { recordKind = RecordTypeDefinition.RecordKind.OPEN; } )?
+ <LEFTBRACE>
+ {
+ String hint = getHint(token);
+ if (hint != null) {
+ String splits[] = hint.split(" +");
+ if (splits[0].equals(GEN_FIELDS_HINT)) {
+ if (splits.length != 5) {
+ throw new ParseException("Expecting: /*+ gen-fields <type> <min> <max> <prefix>*/");
+ }
+ if (!splits[1].equals("int")) {
+ throw new ParseException("The only supported type for gen-fields is int.");
+ }
+ UndeclaredFieldsDataGen ufdg = new UndeclaredFieldsDataGen(UndeclaredFieldsDataGen.Type.INT,
+ Integer.parseInt(splits[2]), Integer.parseInt(splits[3]), splits[4]);
+ recType.setUndeclaredFieldsDataGen(ufdg);
+ }
+ }
+
+ }
+ (
+ RecordField(recType)
+ ( <COMMA> RecordField(recType) )*
+ )?
+ <RIGHTBRACE>
+ {
+ if (recordKind == null) {
+ recordKind = RecordTypeDefinition.RecordKind.OPEN;
+ }
+ recType.setRecordKind(recordKind);
+ return recType;
+ }
+}
+
+void RecordField(RecordTypeDefinition recType) throws ParseException:
+{
+ String fieldName;
+ TypeExpression type = null;
+ boolean nullable = false;
+}
+{
+ fieldName = Identifier()
+ {
+ String hint = getHint(token);
+ IRecordFieldDataGen rfdg = hint != null ? parseFieldDataGen(hint) : null;
+ }
+ <COLON> type = TypeExpr() (<QUES> { nullable = true; } )?
+ {
+ recType.addField(fieldName, type, nullable, rfdg);
+ }
+}
+
+TypeReferenceExpression TypeReference() throws ParseException:
+{
+ String id = null;
+}
+{
+ id = Identifier()
+ {
+ if (id.equalsIgnoreCase("int")) {
+ id = "int64";
+ }
+
+ return new TypeReferenceExpression(new Identifier(id));
+ }
+}
+
+OrderedListTypeDefinition OrderedListTypeDef() throws ParseException:
+{
+ TypeExpression type = null;
+}
+{
+ <LEFTBRACKET>
+ ( type = TypeExpr() )
+ <RIGHTBRACKET>
+ {
+ return new OrderedListTypeDefinition(type);
+ }
+}
+
+
+UnorderedListTypeDefinition UnorderedListTypeDef() throws ParseException:
+{
+ TypeExpression type = null;
+}
+{
+ <LEFTDBLBRACE>
+ ( type = TypeExpr() )
+ <RIGHTDBLBRACE>
+ {
+ return new UnorderedListTypeDefinition(type);
+ }
+}
+
+FunctionName FunctionName() throws ParseException:
+{
+ String first = null;
+ String second = null;
+ String third = null;
+ boolean secondAfterDot = false;
+}
+{
+ first = Identifier()
+ {
+ FunctionName result = new FunctionName();
+ result.hint = getHint(token);
+ }
+ ( <DOT> second = Identifier()
+ {
+ secondAfterDot = true;
+ }
+ (<SHARP> third = Identifier())? | <SHARP> second = Identifier() )?
+ {
+ if (second == null) {
+ result.dataverse = defaultDataverse;
+ result.library = null;
+ result.function = first;
+ } else if (third == null) {
+ if (secondAfterDot) {
+ result.dataverse = first;
+ result.library = null;
+ result.function = second;
+ } else {
+ result.dataverse = defaultDataverse;
+ result.library = first;
+ result.function = second;
+ }
+ } else {
+ result.dataverse = first;
+ result.library = second;
+ result.function = third;
+ }
+
+ if (result.function.equalsIgnoreCase("int")) {
+ result.function = "int64";
+ }
+ return result;
+ }
+}
+
+Pair<Identifier,Identifier> TypeName() throws ParseException:
+{
+ Pair<Identifier,Identifier> name = null;
+}
+{
+ name = QualifiedName()
+ {
+ if (name.first == null) {
+ name.first = new Identifier(defaultDataverse);
+ }
+ return name;
+ }
+}
+
+String Identifier() throws ParseException:
+{
+ String lit = null;
+}
+{
+ (<IDENTIFIER>
+ {
+ return token.image;
+ }
+ | lit = QuotedString()
+ {
+ return lit;
+ }
+ )
+}
+
+Pair<List<String>, TypeExpression> OpenField() throws ParseException:
+{
+ TypeExpression fieldType = null;
+ List<String> fieldList = null;
+}
+{
+ fieldList = NestedField()
+ ( <COLON> fieldType = IndexedTypeExpr() )?
+ {
+ return new Pair<List<String>, TypeExpression>(fieldList, fieldType);
+ }
+}
+
+List<String> NestedField() throws ParseException:
+{
+ List<String> exprList = new ArrayList<String>();
+ String lit = null;
+}
+{
+ lit = Identifier()
+ {
+ exprList.add(lit);
+ }
+ (<DOT>
+ lit = Identifier()
+ {
+ exprList.add(lit);
+ }
+ )*
+ {
+ return exprList;
+ }
+}
+
+
+String QuotedString() throws ParseException:
+{
+}
+{
+ <QUOTED_STRING>
+ {
+ return removeQuotesAndEscapes(token.image);
+ }
+}
+
+
+String StringLiteral() throws ParseException:
+{
+}
+{
+ <STRING_LITERAL>
+ {
+ return removeQuotesAndEscapes(token.image);
+ }
+}
+
+Pair<Identifier,Identifier> QualifiedName() throws ParseException:
+{
+ String first = null;
+ String second = null;
+}
+{
+ first = Identifier() (<DOT> second = Identifier())?
+ {
+ Identifier id1 = null;
+ Identifier id2 = null;
+ if (second == null) {
+ id2 = new Identifier(first);
+ } else
+ {
+ id1 = new Identifier(first);
+ id2 = new Identifier(second);
+ }
+ return new Pair<Identifier,Identifier>(id1, id2);
+ }
+}
+
+Triple<Identifier,Identifier,Identifier> DoubleQualifiedName() throws ParseException:
+{
+ String first = null;
+ String second = null;
+ String third = null;
+}
+{
+ first = Identifier() <DOT> second = Identifier() (<DOT> third = Identifier())?
+ {
+ Identifier id1 = null;
+ Identifier id2 = null;
+ Identifier id3 = null;
+ if (third == null) {
+ id2 = new Identifier(first);
+ id3 = new Identifier(second);
+ } else {
+ id1 = new Identifier(first);
+ id2 = new Identifier(second);
+ id3 = new Identifier(third);
+ }
+ return new Triple<Identifier,Identifier,Identifier>(id1, id2, id3);
+ }
+}
+
+FunctionDecl FunctionDeclaration() throws ParseException:
+{
+ FunctionDecl funcDecl;
+ FunctionSignature signature;
+ String functionName;
+ List<VarIdentifier> paramList = new ArrayList<VarIdentifier>();
+ Expression funcBody;
+ createNewScope();
+}
+{
+ <DECLARE> <FUNCTION> functionName = Identifier()
+ paramList = ParameterList()
+ <LEFTBRACE> funcBody = Expression() <RIGHTBRACE>
+ {
+ signature = new FunctionSignature(defaultDataverse, functionName, paramList.size());
+ getCurrentScope().addFunctionDescriptor(signature, false);
+ funcDecl = new FunctionDecl(signature, paramList, funcBody);
+ removeCurrentScope();
+ return funcDecl;
+ }
+}
+
+
+Query Query() throws ParseException:
+{
+ Query query = new Query();
+ // we set the pointers to the dataverses and datasets lists to fill them with entities to be locked
+ setDataverses(query.getDataverses());
+ setDatasets(query.getDatasets());
+ Expression expr;
+}
+{
+ (
+ expr = Expression()
+ |
+ expr = SelectExpression(false)
+ )
+ {
+ query.setBody(expr);
+ query.setVarCounter(getVarCounter());
+ // we remove the pointers to the locked entities before we return the query object
+ setDataverses(null);
+ setDatasets(null);
+ return query;
+ }
+}
+
+
+
+Expression Expression():
+{
+ Expression expr = null;
+ Expression exprP = null;
+}
+{
+(
+ LOOKAHEAD(2)
+ expr = OperatorExpr()
+ | expr = IfThenElse()
+ | expr = QuantifiedExpression()
+)
+ {
+ return (exprP==null) ? expr : exprP;
+ }
+}
+
+
+
+Expression OperatorExpr()throws ParseException:
+{
+ OperatorExpr op = null;
+ Expression operand = null;
+}
+{
+ operand = AndExpr()
+ (
+
+ <OR>
+ {
+ if (op == null) {
+ op = new OperatorExpr();
+ op.addOperand(operand);
+ op.setCurrentop(true);
+ }
+ op.addOperator(token.image);
+ }
+
+ operand = AndExpr()
+ {
+ op.addOperand(operand);
+ }
+
+ )*
+
+ {
+ return op==null? operand: op;
+ }
+}
+
+Expression AndExpr()throws ParseException:
+{
+ OperatorExpr op = null;
+ Expression operand = null;
+}
+{
+ operand = RelExpr()
+ (
+
+ <AND>
+ {
+ if (op == null) {
+ op = new OperatorExpr();
+ op.addOperand(operand);
+ op.setCurrentop(true);
+ }
+ op.addOperator(token.image);
+ }
+
+ operand = RelExpr()
+ {
+ op.addOperand(operand);
+ }
+
+ )*
+
+ {
+ return op==null? operand: op;
+ }
+}
+
+
+
+Expression RelExpr()throws ParseException:
+{
+ OperatorExpr op = null;
+ Expression operand = null;
+ boolean broadcast = false;
+ IExpressionAnnotation annotation = null;
+}
+{
+ operand = AddExpr()
+ {
+ if (operand instanceof VariableExpr) {
+ String hint = getHint(token);
+ if (hint != null && hint.equals(BROADCAST_JOIN_HINT)) {
+ broadcast = true;
+ }
+ }
+ }
+
+ (
+ LOOKAHEAD(2)( <LT> | <GT> | <LE> | <GE> | <EQ> | <NE> |<SIMILAR>)
+ {
+ String mhint = getHint(token);
+ if (mhint != null) {
+ if (mhint.equals(INDEXED_NESTED_LOOP_JOIN_HINT)) {
+ annotation = IndexedNLJoinExpressionAnnotation.INSTANCE;
+ } else if (mhint.equals(SKIP_SECONDARY_INDEX_SEARCH_HINT)) {
+ annotation = SkipSecondaryIndexSearchExpressionAnnotation.INSTANCE;
+ }
+ }
+ if (op == null) {
+ op = new OperatorExpr();
+ op.addOperand(operand, broadcast);
+ op.setCurrentop(true);
+ broadcast = false;
+ }
+ op.addOperator(token.image);
+ }
+
+ operand = AddExpr()
+ {
+ broadcast = false;
+ if (operand instanceof VariableExpr) {
+ String hint = getHint(token);
+ if (hint != null && hint.equals(BROADCAST_JOIN_HINT)) {
+ broadcast = true;
+ }
+ }
+ op.addOperand(operand, broadcast);
+ }
+ )?
+
+ {
+ if (annotation != null) {
+ op.addHint(annotation);
+ }
+ return op==null? operand: op;
+ }
+}
+
+Expression AddExpr()throws ParseException:
+{
+ OperatorExpr op = null;
+ Expression operand = null;
+}
+{
+ operand = MultExpr()
+ (
+ LOOKAHEAD(1)
+ (<PLUS> | <MINUS>)
+ {
+ if (op == null) {
+ op = new OperatorExpr();
+ op.addOperand(operand);
+ op.setCurrentop(true);
+ }
+ ((OperatorExpr)op).addOperator(token.image);
+ }
+
+ operand = MultExpr()
+ {
+ op.addOperand(operand);
+ }
+ )*
+
+ {
+ return op==null? operand: op;
+ }
+}
+
+Expression MultExpr()throws ParseException:
+{
+ OperatorExpr op = null;
+ Expression operand = null;
+}
+{
+ operand = UnaryExpr()
+
+ (( <MUL> | <DIV> | <MOD> | <CARET> | <IDIV>)
+ {
+ if (op == null) {
+ op = new OperatorExpr();
+ op.addOperand(operand);
+ op.setCurrentop(true);
+ }
+ op.addOperator(token.image);
+ }
+ operand = UnaryExpr()
+ {
+ op.addOperand(operand);
+ }
+ )*
+
+ {
+ return op==null?operand:op;
+ }
+}
+
+Expression UnaryExpr() throws ParseException:
+{
+ Expression uexpr = null;
+ Expression expr = null;
+}
+{
+ ( (<PLUS> | <MINUS>)
+ {
+ uexpr = new UnaryExpr();
+ if("+".equals(token.image))
+ ((UnaryExpr)uexpr).setSign(Sign.POSITIVE);
+ else if("-".equals(token.image))
+ ((UnaryExpr)uexpr).setSign(Sign.NEGATIVE);
+ else
+ throw new ParseException();
+ }
+ )?
+
+ expr = ValueExpr()
+ {
+ if(uexpr!=null){
+ ((UnaryExpr)uexpr).setExpr(expr);
+ return uexpr;
+ }
+ else{
+ return expr;
+ }
+ }
+}
+
+Expression ValueExpr()throws ParseException:
+{
+ Expression expr = null;
+ Identifier ident = null;
+ AbstractAccessor fa = null;
+ Expression indexExpr = null;
+}
+{
+ expr = PrimaryExpr() (
+ ident = Field()
+ {
+ fa = (fa == null ? new FieldAccessor(expr, ident)
+ : new FieldAccessor(fa, ident));
+ }
+ | indexExpr = Index()
+ {
+ fa = (fa == null ? new IndexAccessor(expr, indexExpr)
+ : new IndexAccessor(fa, indexExpr));
+ }
+ )*
+ {
+ return fa == null ? expr : fa;
+ }
+}
+
+Identifier Field() throws ParseException:
+{
+ String ident = null;
+}
+{
+ <DOT> ident = Identifier()
+ {
+ return new Identifier(ident);
+ }
+}
+
+Expression Index() throws ParseException:
+{
+ Expression expr = null;
+}
+{
+ <LEFTBRACKET> ( expr = Expression()
+ {
+ if(expr.getKind() == Expression.Kind.LITERAL_EXPRESSION)
+ {
+ Literal lit = ((LiteralExpr)expr).getValue();
+ if(lit.getLiteralType() != Literal.Type.INTEGER &&
+ lit.getLiteralType() != Literal.Type.LONG) {
+ throw new ParseException("Index should be an INTEGER");
+ }
+ }
+ }
+
+ | <QUES> // ANY
+
+ )
+
+ <RIGHTBRACKET>
+ {
+ return expr;
+ }
+}
+
+
+Expression PrimaryExpr()throws ParseException:
+{
+ Expression expr = null;
+}
+{
+ ( LOOKAHEAD(4)
+ expr = FunctionCallExpr()
+ | expr = Literal()
+ | expr = VariableRef()
+ | expr = ListConstructor()
+ | expr = RecordConstructor()
+ | expr = ParenthesizedExpression()
+ )
+ {
+ return expr;
+ }
+}
+
+Expression Literal() throws ParseException:
+{
+ LiteralExpr lit = new LiteralExpr();
+ String str = null;
+}
+{
+ ( str = StringLiteral()
+ {
+ lit.setValue(new StringLiteral(str));
+ }
+ | <INTEGER_LITERAL>
+ {
+ lit.setValue(new LongIntegerLiteral(new Long(token.image)));
+ }
+ | <FLOAT_LITERAL>
+ {
+ lit.setValue(new FloatLiteral(new Float(token.image)));
+ }
+ | <DOUBLE_LITERAL>
+ {
+ lit.setValue(new DoubleLiteral(new Double(token.image)));
+ }
+ | <NULL>
+ {
+ lit.setValue(NullLiteral.INSTANCE);
+ }
+ | <TRUE>
+ {
+ lit.setValue(TrueLiteral.INSTANCE);
+ }
+ | <FALSE>
+ {
+ lit.setValue(FalseLiteral.INSTANCE);
+ }
+ )
+ {
+ return lit;
+ }
+}
+
+
+VariableExpr VariableRef() throws ParseException:
+{
+ VariableExpr varExp = new VariableExpr();
+ VarIdentifier var = new VarIdentifier();
+}
+{
+ { String id = null; }
+ (<IDENTIFIER> { id = token.image; } | id = QuotedString())
+ {
+ Identifier ident = lookupSymbol(id);
+ if (isInForbiddenScopes(id)) {
+ throw new ParseException("Inside limit clauses, it is disallowed to reference a variable having the same name as any variable bound in the same scope as the limit clause.");
+ }
+ if(ident != null) { // exist such ident
+ varExp.setIsNewVar(false);
+ varExp.setVar((VarIdentifier)ident);
+ } else {
+ varExp.setVar(var);
+ }
+ var.setValue(id);
+ return varExp;
+ }
+}
+
+
+VariableExpr Variable() throws ParseException:
+{
+ VariableExpr varExp = new VariableExpr();
+ VarIdentifier var = new VarIdentifier();
+}
+{
+ { String id = null; }
+ (<IDENTIFIER> { id = token.image; } | id = QuotedString())
+ {
+ Identifier ident = lookupSymbol(id);
+ if(ident != null) { // exist such ident
+ varExp.setIsNewVar(false);
+ }
+ varExp.setVar(var);
+ var.setValue(token.image);
+ return varExp;
+ }
+}
+
+Expression ListConstructor() throws ParseException:
+{
+ Expression expr = null;
+}
+{
+ (
+ expr = OrderedListConstructor() | expr = UnorderedListConstructor()
+ )
+
+ {
+ return expr;
+ }
+}
+
+
+ListConstructor OrderedListConstructor() throws ParseException:
+{
+ ListConstructor expr = new ListConstructor();
+ List<Expression> exprList = null;
+ expr.setType(ListConstructor.Type.ORDERED_LIST_CONSTRUCTOR);
+}
+{
+ <LEFTBRACKET> exprList = ExpressionList() <RIGHTBRACKET>
+ {
+ expr.setExprList(exprList);
+ return expr;
+ }
+}
+
+ListConstructor UnorderedListConstructor() throws ParseException:
+{
+ ListConstructor expr = new ListConstructor();
+ List<Expression> exprList = null;
+ expr.setType(ListConstructor.Type.UNORDERED_LIST_CONSTRUCTOR);
+}
+{
+ <LEFTDBLBRACE> exprList = ExpressionList() <RIGHTDBLBRACE>
+ {
+ expr.setExprList(exprList);
+ return expr;
+ }
+}
+
+List<Expression> ExpressionList() throws ParseException:
+{
+ Expression expr = null;
+ List<Expression> list = null;
+ List<Expression> exprList = new ArrayList<Expression>();
+}
+{
+ (
+ expr = Expression() { exprList.add(expr); }
+ (LOOKAHEAD(1) <COMMA> list = ExpressionList() { exprList.addAll(list); })?
+ )?
+ (LOOKAHEAD(1) Comma())?
+ {
+ return exprList;
+ }
+}
+
+void Comma():
+{}
+{
+ <COMMA>
+}
+
+RecordConstructor RecordConstructor() throws ParseException:
+{
+ RecordConstructor expr = new RecordConstructor();
+ FieldBinding tmp = null;
+ List<FieldBinding> fbList = new ArrayList<FieldBinding>();
+}
+{
+ <LEFTBRACE> (tmp = FieldBinding()
+ {
+ fbList.add(tmp);
+ }
+ (<COMMA> tmp = FieldBinding() { fbList.add(tmp); })*)? <RIGHTBRACE>
+ {
+ expr.setFbList(fbList);
+ return expr;
+ }
+}
+
+FieldBinding FieldBinding() throws ParseException:
+{
+ FieldBinding fb = new FieldBinding();
+ Expression left, right;
+}
+{
+ left = Expression() <COLON> right = Expression()
+ {
+ fb.setLeftExpr(left);
+ fb.setRightExpr(right);
+ return fb;
+ }
+}
+
+
+Expression FunctionCallExpr() throws ParseException:
+{
+ CallExpr callExpr;
+ List<Expression> argList = new ArrayList<Expression>();
+ Expression tmp;
+ int arity = 0;
+ FunctionName funcName = null;
+ String hint = null;
+}
+{
+ funcName = FunctionName()
+ {
+ hint = funcName.hint;
+ }
+ <LEFTPAREN> (tmp = Expression()
+ {
+ argList.add(tmp);
+ arity ++;
+ }
+ (<COMMA> tmp = Expression()
+ {
+ argList.add(tmp);
+ arity++;
+ }
+ )*)? <RIGHTPAREN>
+ {
+ // TODO use funcName.library
+ String fqFunctionName = funcName.library == null ? funcName.function : funcName.library + "#" + funcName.function;
+ FunctionSignature signature
+ = lookupFunctionSignature(funcName.dataverse, fqFunctionName, arity);
+ if (signature == null) {
+ signature = new FunctionSignature(funcName.dataverse, fqFunctionName, arity);
+ }
+ callExpr = new CallExpr(signature,argList);
+ if (hint != null) {
+ if (hint.startsWith(INDEXED_NESTED_LOOP_JOIN_HINT)) {
+ callExpr.addHint(IndexedNLJoinExpressionAnnotation.INSTANCE);
+ } else if (hint.startsWith(SKIP_SECONDARY_INDEX_SEARCH_HINT)) {
+ callExpr.addHint(SkipSecondaryIndexSearchExpressionAnnotation.INSTANCE);
+ }
+ }
+ return callExpr;
+ }
+}
+
+Expression ParenthesizedExpression() throws ParseException:
+{
+ Expression expr;
+}
+{
+ (
+ LOOKAHEAD(2)
+ <LEFTPAREN> expr = Expression() <RIGHTPAREN>
+ |
+ expr = Subquery()
+ )
+ {
+ return expr;
+ }
+}
+
+Expression IfThenElse() throws ParseException:
+{
+ Expression condExpr;
+ Expression thenExpr;
+ Expression elseExpr;
+ IfExpr ifExpr = new IfExpr();
+}
+{
+ <IF> <LEFTPAREN> condExpr = Expression() <RIGHTPAREN> <THEN> thenExpr = Expression() <ELSE> elseExpr = Expression()
+
+ {
+ ifExpr.setCondExpr(condExpr);
+ ifExpr.setThenExpr(thenExpr);
+ ifExpr.setElseExpr(elseExpr);
+ return ifExpr;
+ }
+}
+
+SelectExpression SelectExpression(boolean subquery) throws ParseException: {
+ List<LetClause> letClauses = new ArrayList<LetClause>();
+ SelectSetOperation selectSetOperation;
+ OrderbyClause orderbyClause = null;
+ LimitClause limitClause = null;
+ createNewScope();
+} {
+ ( letClauses = LetClause() )?
+ selectSetOperation = SelectSetOperation()
+ (orderbyClause = OrderbyClause() {})?
+ (limitClause = LimitClause() {})?
+ {
+ return new SelectExpression(letClauses, selectSetOperation, orderbyClause, limitClause, subquery);
+ }
+}
+
+SelectSetOperation SelectSetOperation() throws ParseException: {
+ SetOperationInput setOperationInputLeft;
+ List<SetOperationRight> setOperationRights = new ArrayList<SetOperationRight>();
+}
+{
+ {
+ SelectBlock selectBlockLeft = null;
+ SelectExpression subqueryLeft = null;
+ Expression expr = null;
+ }
+ selectBlockLeft = SelectBlock()
+ {
+ setOperationInputLeft = new SetOperationInput(selectBlockLeft, subqueryLeft);
+ }
+ (
+ {
+ SetOpType opType = SetOpType.UNION;
+ boolean setSemantics = true;
+ SelectBlock selectBlockRight = null;
+ SelectExpression subqueryRight = null;
+ }
+ (<UNION> {opType = SetOpType.UNION;} |<INTERSECT> {opType = SetOpType.INTERSECT;} |<EXCEPT> {opType = SetOpType.EXCEPT;}) (<ALL> {setSemantics = false;} )?
+ (selectBlockRight = SelectBlock()| subqueryRight = Subquery())
+ {
+ setOperationRights.add(new SetOperationRight(opType, setSemantics, new SetOperationInput(selectBlockRight, subqueryRight)));
+ }
+ )*
+ {
+ return new SelectSetOperation(setOperationInputLeft, setOperationRights);
+ }
+}
+
+SelectExpression Subquery() throws ParseException: {
+ SelectExpression selectExpr = null;
+}
+{
+ <LEFTPAREN> selectExpr = SelectExpression(true) {} <RIGHTPAREN>
+ {
+ return selectExpr;
+ }
+}
+
+SelectBlock SelectBlock() throws ParseException: {
+ SelectClause selectClause = null;
+ FromClause fromClause = null;
+ List<LetClause> fromLetClauses = null;
+ WhereClause whereClause = null;
+ GroupbyClause groupbyClause = null;
+ List<LetClause> gbyLetClauses = null;
+ HavingClause havingClause = null;
+}
+{
+ (
+ selectClause = SelectClause()
+ (
+ LOOKAHEAD(1)
+ fromClause = FromClause()
+ (
+ LOOKAHEAD(1)
+ fromLetClauses = LetClause()
+ )?
+ )?
+ (whereClause = WhereClause())?
+ (
+ groupbyClause = GroupbyClause()
+ (
+ LOOKAHEAD(1)
+ gbyLetClauses = LetClause()
+ )?
+ (havingClause = HavingClause())?
+ )?
+ |
+ fromClause = FromClause()
+ (
+ LOOKAHEAD(1)
+ fromLetClauses = LetClause()
+ )?
+ (whereClause = WhereClause())?
+ (
+ groupbyClause = GroupbyClause()
+ (
+ gbyLetClauses = LetClause()
+ )?
+ (havingClause = HavingClause())?
+ )?
+ selectClause = SelectClause()
+ )
+ {
+ return new SelectBlock(selectClause, fromClause, fromLetClauses, whereClause, groupbyClause, gbyLetClauses, havingClause);
+ }
+}
+
+SelectClause SelectClause() throws ParseException: {
+ SelectRegular selectRegular = null;
+ SelectElement selectElement = null;
+ boolean distinct = false;
+}
+{
+ <SELECT> (<ALL>|<DISTINCT> {distinct = true; } )?
+ (
+ selectRegular = SelectRegular()
+ |
+ selectElement = SelectElement()
+ )
+ {
+ return new SelectClause(selectElement, selectRegular, distinct);
+ }
+}
+
+SelectRegular SelectRegular() throws ParseException: {
+ List<Projection> projections = new ArrayList<Projection>();
+}
+{
+ {
+ Projection projection = null;
+ }
+ projection = Projection() { projections.add(projection); }
+ ( LOOKAHEAD(2) <COMMA>
+ projection = Projection() {projections.add(projection);}
+ )*
+ {
+ return new SelectRegular(projections);
+ }
+}
+
+SelectElement SelectElement() throws ParseException: {
+ Expression expr = null;
+ String name = null;
+}
+{
+ (<RAW>|<ELEMENT>|<VALUE>) expr = Expression()
+ {
+ return new SelectElement(expr);
+ }
+}
+
+Projection Projection() throws ParseException: {
+ Expression expr = null;
+ Identifier identifier = null;
+ String name = null;
+ boolean star = false;
+ boolean exprStar = false;
+}
+{
+ (
+ LOOKAHEAD(2)
+ expr= Expression() (<AS>)? name = Identifier()
+ | expr = Expression() <DOT> <MUL> {exprStar = true; }
+ | <MUL> {star = true; }
+ )
+ {
+ return new Projection(expr, name, star, exprStar);
+ }
+}
+
+FromClause FromClause() throws ParseException :
+{
+ List<FromTerm> fromTerms = new ArrayList<FromTerm>();
+ extendCurrentScope();
+}
+{
+ {
+ FromTerm fromTerm = null;
+ }
+ <FROM> fromTerm = FromTerm() { fromTerms.add(fromTerm); }
+ (LOOKAHEAD(2) <COMMA> fromTerm = FromTerm() { fromTerms.add(fromTerm); } )*
+ {
+ return new FromClause(fromTerms);
+ }
+}
+
+FromTerm FromTerm() throws ParseException :
+{
+ Expression leftExpr = null;
+ VariableExpr leftVar = null;
+ VariableExpr posVar = null;
+ List<AbstractBinaryCorrelateClause> correlateClauses = new ArrayList<AbstractBinaryCorrelateClause>();
+}
+{
+ leftExpr = Expression() (<AS>)? leftVar = Variable() (<AT> posVar = Variable())?
+ (
+ {JoinType joinType = JoinType.INNER; }
+ (joinType = JoinType())?
+ {
+ AbstractBinaryCorrelateClause correlateClause = null;
+ }
+ (correlateClause = JoinClause(joinType)
+ |
+ correlateClause = NestClause(joinType)
+ |
+ correlateClause = UnnestClause(joinType)
+ )
+ {
+ correlateClauses.add(correlateClause);
+ }
+ )*
+ {
+ return new FromTerm(leftExpr, leftVar, posVar, correlateClauses);
+ }
+}
+
+JoinClause JoinClause(JoinType joinType) throws ParseException :
+{
+ Expression rightExpr = null;
+ VariableExpr rightVar = null;
+ VariableExpr posVar = null;
+ Expression conditionExpr = null;
+}
+{
+ <JOIN> rightExpr = Expression() (<AS>)? rightVar = Variable() (<AT> posVar = Variable())? <ON> conditionExpr = Expression()
+ {
+ return new JoinClause(joinType, rightExpr, rightVar, posVar, conditionExpr);
+ }
+}
+
+NestClause NestClause(JoinType joinType) throws ParseException :
+{
+ Expression rightExpr = null;
+ VariableExpr rightVar = null;
+ VariableExpr posVar = null;
+ Expression conditionExpr = null;
+}
+{
+ <NEST> rightExpr = Expression() (<AS>)? rightVar = Variable() (<AT> posVar = Variable())? <ON> conditionExpr = Expression()
+ {
+ return new NestClause(joinType, rightExpr, rightVar, posVar, conditionExpr);
+ }
+}
+
+UnnestClause UnnestClause(JoinType joinType) throws ParseException :
+{
+ Expression rightExpr;
+ VariableExpr rightVar;
+ VariableExpr posVar = null;
+}
+{
+ (<UNNEST>|<CORRELATE>|<FLATTEN>) rightExpr = Expression() (<AS>)? rightVar = Variable() (<AT> posVar = Variable())?
+ {
+ return new UnnestClause(joinType, rightExpr, rightVar, posVar);
+ }
+}
+
+
+JoinType JoinType() throws ParseException :
+{
+ JoinType joinType = JoinType.INNER;
+}
+{
+ (<INNER>|<LEFT> (<OUTER>)? {joinType = JoinType.LEFTOUTER; })
+ {
+ return joinType;
+ }
+}
+
+List<LetClause> LetClause() throws ParseException:
+{
+ List<LetClause> letList = new ArrayList<LetClause>();
+ LetClause letClause;
+}
+{
+ (
+ (<LET>|<LETTING>) letClause = LetElement() { letList.add(letClause); } (LOOKAHEAD(1) <COMMA> letClause = LetElement() { letList.add(letClause); })*
+ |
+ <WITH> letClause = WithElement() { letList.add(letClause); } (LOOKAHEAD(1) <COMMA> letClause = WithElement() { letList.add(letClause); })*
+ )
+ {
+ return letList;
+ }
+}
+
+WhereClause WhereClause()throws ParseException :
+{
+ WhereClause wc = new WhereClause();
+ Expression whereExpr;
+}
+{
+ <WHERE> whereExpr = Expression()
+ {
+ wc.setWhereExpr(whereExpr);
+ return wc;
+ }
+}
+
+OrderbyClause OrderbyClause()throws ParseException :
+{
+ OrderbyClause oc = new OrderbyClause();
+ Expression orderbyExpr;
+ List<Expression> orderbyList = new ArrayList<Expression>();
+ List<OrderbyClause.OrderModifier> modifierList = new ArrayList<OrderbyClause.OrderModifier >();
+ int numOfOrderby = 0;
+}
+{
+ <ORDER>
+ {
+ String hint = getHint(token);
+ if (hint != null) {
+ if (hint.startsWith(INMEMORY_HINT)) {
+ String splits[] = hint.split(" +");
+ int numFrames = Integer.parseInt(splits[1]);
+ int numTuples = Integer.parseInt(splits[2]);
+ oc.setNumFrames(numFrames);
+ oc.setNumTuples(numTuples);
+ }
+ }
+ }
+ <BY> orderbyExpr = Expression()
+ {
+ orderbyList.add(orderbyExpr);
+ OrderbyClause.OrderModifier modif = OrderbyClause.OrderModifier.ASC;
+ }
+ ( (<ASC> { modif = OrderbyClause.OrderModifier.ASC; })
+ | (<DESC> { modif = OrderbyClause.OrderModifier.DESC; }))?
+ {
+ modifierList.add(modif);
+ }
+
+ (LOOKAHEAD(2) <COMMA> orderbyExpr = Expression()
+ {
+ orderbyList.add(orderbyExpr);
+ modif = OrderbyClause.OrderModifier.ASC;
+ }
+ ( (<ASC> { modif = OrderbyClause.OrderModifier.ASC; })
+ | (<DESC> { modif = OrderbyClause.OrderModifier.DESC; }))?
+ {
+ modifierList.add(modif);
+ }
+ )*
+
+ {
+ oc.setModifierList(modifierList);
+ oc.setOrderbyList(orderbyList);
+ return oc;
+ }
+}
+
+GroupbyClause GroupbyClause()throws ParseException :
+{
+ GroupbyClause gbc = new GroupbyClause();
+ List<GbyVariableExpressionPair> vePairList = new ArrayList<GbyVariableExpressionPair>();
+ VariableExpr var = null;
+ VariableExpr withVar = null;
+ Expression expr = null;
+ VariableExpr decorVar = null;
+ Expression decorExpr = null;
+}
+{
+ {
+ Scope newScope = extendCurrentScopeNoPush(true);
+ // extendCurrentScope(true);
+ }
+ <GROUP>
+ {
+ String hint = getHint(token);
+ if (hint != null && hint.equals(HASH_GROUP_BY_HINT)) {
+ gbc.setHashGroupByHint(true);
+ }
+ }
+ <BY> (
+ expr = Expression()
+ (LOOKAHEAD(1) (<AS>)?
+ var = Variable()
+ {
+ newScope.addNewVarSymbolToScope(var.getVar());
+ })?
+ {
+ GbyVariableExpressionPair pair1 = new GbyVariableExpressionPair(var, expr);
+ vePairList.add(pair1);
+ }
+ ( LOOKAHEAD(1) <COMMA>
+ expr = Expression()
+ (LOOKAHEAD(1) (<AS>)?
+ var = Variable()
+ {
+ newScope.addNewVarSymbolToScope(var.getVar());
+ })?
+ {
+ GbyVariableExpressionPair pair2 = new GbyVariableExpressionPair(var, expr);
+ vePairList.add(pair2);
+ }
+ )*
+ )
+ {
+ gbc.setGbyPairList(vePairList);
+ gbc.setDecorPairList(new ArrayList<GbyVariableExpressionPair>());
+ gbc.setWithVarList(new ArrayList<VariableExpr>());
+ replaceCurrentScope(newScope);
+ return gbc;
+ }
+}
+
+HavingClause HavingClause() throws ParseException:
+{
+ Expression filterExpr = null;
+}
+{
+ <HAVING> filterExpr = Expression()
+ {
+ return new HavingClause(filterExpr);
+ }
+}
+
+LimitClause LimitClause() throws ParseException:
+{
+ LimitClause lc = new LimitClause();
+ Expression expr;
+ pushForbiddenScope(getCurrentScope());
+}
+{
+ <LIMIT> expr = Expression() { lc.setLimitExpr(expr); }
+ (<OFFSET> expr = Expression() { lc.setOffset(expr); })?
+
+ {
+ popForbiddenScope();
+ return lc;
+ }
+}
+
+QuantifiedExpression QuantifiedExpression()throws ParseException:
+{
+ QuantifiedExpression qc = new QuantifiedExpression();
+ List<QuantifiedPair> quantifiedList = new ArrayList<QuantifiedPair>();
+ Expression satisfiesExpr;
+ VariableExpr var;
+ Expression inExpr;
+ QuantifiedPair pair;
+}
+{
+ {
+ createNewScope();
+ }
+
+ ( (<SOME> { qc.setQuantifier(QuantifiedExpression.Quantifier.SOME); })
+ | (<EVERY> { qc.setQuantifier(QuantifiedExpression.Quantifier.EVERY); }))
+ var = Variable() <IN> inExpr = Expression()
+ {
+ pair = new QuantifiedPair(var, inExpr);
+ getCurrentScope().addNewVarSymbolToScope(var.getVar());
+ quantifiedList.add(pair);
+ }
+ (
+ <COMMA> var = Variable() <IN> inExpr = Expression()
+ {
+ pair = new QuantifiedPair(var, inExpr);
+ getCurrentScope().addNewVarSymbolToScope(var.getVar());
+ quantifiedList.add(pair);
+ }
+ )*
+ <SATISFIES> satisfiesExpr = Expression()
+ {
+ qc.setSatisfiesExpr(satisfiesExpr);
+ qc.setQuantifiedList(quantifiedList);
+ removeCurrentScope();
+ return qc;
+ }
+}
+
+LetClause LetElement() throws ParseException:
+{
+ LetClause lc = new LetClause();
+ VariableExpr varExp;
+ Expression beExp;
+ extendCurrentScope();
+}
+{
+ varExp = Variable() <EQ> beExp = Expression()
+ {
+ getCurrentScope().addNewVarSymbolToScope(varExp.getVar());
+ lc.setVarExpr(varExp);
+ lc.setBindingExpr(beExp);
+ return lc;
+ }
+}
+
+LetClause WithElement() throws ParseException:
+{
+ LetClause lc = new LetClause();
+ VariableExpr varExp;
+ Expression beExp;
+ extendCurrentScope();
+}
+{
+ varExp = Variable() <AS> beExp = Expression()
+ {
+ getCurrentScope().addNewVarSymbolToScope(varExp.getVar());
+ lc.setVarExpr(varExp);
+ lc.setBindingExpr(beExp);
+ return lc;
+ }
+}
+
+TOKEN_MGR_DECLS:
+{
+ public int commentDepth = 0;
+ public IntStack lexerStateStack = new IntStack();
+
+ public void pushState() {
+ lexerStateStack.push( curLexState );
+ }
+
+ public void popState(String token) {
+ if (lexerStateStack.size() > 0) {
+ SwitchTo( lexerStateStack.pop() );
+ } else {
+ int errorLine = input_stream.getEndLine();
+ int errorColumn = input_stream.getEndColumn();
+ String msg = "Lexical error at line " + errorLine + ", column " + errorColumn + ". Encountered \"" + token
+ + "\" but state stack is empty.";
+ throw new TokenMgrError(msg, -1);
+ }
+ }
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN [IGNORE_CASE]:
+{
+ <ALL : "all">
+ | <AND : "and">
+ | <APPLY : "apply">
+ | <AS : "as">
+ | <ASC : "asc">
+ | <AT : "at">
+ | <AUTOGENERATED : "autogenerated">
+ | <BTREE : "btree">
+ | <BY : "by">
+ | <CASE : "case">
+ | <CLOSED : "closed">
+ | <CREATE : "create">
+ | <COMPACTION : "compaction">
+ | <COMPACT : "compact">
+ | <CONNECT : "connect">
+ | <CORRELATE : "correlate">
+ | <DATASET : "table">
+ | <DATAVERSE : "database">
+ | <DECLARE : "declare">
+ | <DEFINITION : "definition">
+ | <DELETE : "delete">
+ | <DESC : "desc">
+ | <DISCONNECT : "disconnect">
+ | <DISTINCT : "distinct">
+ | <DROP : "drop">
+ | <ELEMENT : "element">
+ | <ELSE : "else">
+ | <ENFORCED : "enforced">
+ | <EVERY : "every">
+ | <EXCEPT : "except">
+ | <EXISTS : "exists">
+ | <EXTERNAL : "external">
+ | <FEED : "feed">
+ | <FILTER : "filter">
+ | <FLATTEN : "flatten">
+ | <FOR : "for">
+ | <FORMAT : "format">
+ | <FROM : "from">
+ | <FULL : "full">
+ | <FUNCTION : "function">
+ | <GROUP : "group">
+ | <HAVING : "having">
+ | <HINTS : "hints">
+ | <IF : "if">
+ | <INTO : "into">
+ | <IN : "in">
+ | <INDEX : "index">
+ | <INGESTION : "ingestion">
+ | <INNER : "inner">
+ | <INSERT : "insert">
+ | <INTERNAL : "internal">
+ | <INTERSECT : "intersect">
+ | <JOIN : "join">
+ | <KEYWORD : "keyword">
+ | <KEY : "key">
+ | <LEFT : "left">
+ | <LETTING : "letting">
+ | <LET : "let">
+ | <LIMIT : "limit">
+ | <LOAD : "load">
+ | <NEST : "nest">
+ | <NODEGROUP : "nodegroup">
+ | <NGRAM : "ngram">
+ | <OFFSET : "offset">
+ | <ON : "on">
+ | <OPEN : "open">
+ | <OR : "or">
+ | <ORDER : "order">
+ | <OUTER : "outer">
+ | <OUTPUT : "output">
+ | <PATH : "path">
+ | <POLICY : "policy">
+ | <PRESORTED : "pre-sorted">
+ | <PRIMARY : "primary">
+ | <RAW : "raw">
+ | <REFRESH : "refresh">
+ | <RETURN : "return">
+ | <RTREE : "rtree">
+ | <RUN : "run">
+ | <SATISFIES : "satisfies">
+ | <SECONDARY : "secondary">
+ | <SELECT : "select">
+ | <SET : "set">
+ | <SOME : "some">
+ | <TEMPORARY : "temporary">
+ | <THEN : "then">
+ | <TYPE : "type">
+ | <TO : "to">
+ | <UNION : "union">
+ | <UNNEST : "unnest">
+ | <VALUE : "value">
+ | <WHEN : "when">
+ | <WHERE : "where">
+ | <WITH : "with">
+ | <WRITE : "write">
+ | <UPDATE : "update">
+ | <USE : "use">
+ | <USING : "using">
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ <CARET : "^">
+ | <DIV : "/">
+ | <IDIV : "idiv">
+ | <MINUS : "-">
+ | <MOD : "%">
+ | <MUL : "*">
+ | <PLUS : "+">
+
+ | <LEFTPAREN : "(">
+ | <RIGHTPAREN : ")">
+ | <LEFTBRACKET : "[">
+ | <RIGHTBRACKET : "]">
+
+ | <ATT : "@">
+ | <COLON : ":">
+ | <COMMA : ",">
+ | <DOT : ".">
+ | <QUES : "?">
+ | <SEMICOLON : ";">
+ | <SHARP : "#">
+
+ | <LT : "<">
+ | <GT : ">">
+ | <LE : "<=">
+ | <GE : ">=">
+ | <EQ : "=">
+ | <NE : "!=">
+ | <SIMILAR : "~=">
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ <LEFTBRACE : "{"> { pushState(); } : DEFAULT
+}
+
+<DEFAULT>
+TOKEN :
+{
+ <RIGHTBRACE : "}"> { popState("}"); }
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ <LEFTDBLBRACE : "{{"> { pushState(); } : IN_DBL_BRACE
+}
+
+<IN_DBL_BRACE>
+TOKEN :
+{
+ <RIGHTDBLBRACE : "}}"> { popState("}}"); }
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ <INTEGER_LITERAL : (<DIGIT>)+ >
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ <NULL : "null">
+ | <TRUE : "true">
+ | <FALSE : "false">
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ <#DIGIT : ["0" - "9"]>
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN:
+{
+ < DOUBLE_LITERAL: <DIGITS>
+ | <DIGITS> ( "." <DIGITS> )?
+ | "." <DIGITS>
+ >
+ | < FLOAT_LITERAL: <DIGITS> ( "f" | "F" )
+ | <DIGITS> ( "." <DIGITS> ( "f" | "F" ) )?
+ | "." <DIGITS> ( "f" | "F" )
+ >
+ | <DIGITS : (<DIGIT>)+ >
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ <#LETTER : ["A" - "Z", "a" - "z"]>
+ | <SPECIALCHARS : ["$", "_"]>
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ // backslash u + 4 hex digits escapes are handled in the underlying JavaCharStream
+ <QUOTED_STRING : "\"" (
+ <EscapeQuot>
+ | <EscapeBslash>
+ | <EscapeSlash>
+ | <EscapeBspace>
+ | <EscapeFormf>
+ | <EscapeNl>
+ | <EscapeCr>
+ | <EscapeTab>
+ | ~["\"","\\"])* "\"">
+ | <STRING_LITERAL : "\'" (
+ <EscapeQuot>
+ | <EscapeApos>
+ | <EscapeBslash>
+ | <EscapeSlash>
+ | <EscapeBspace>
+ | <EscapeFormf>
+ | <EscapeNl>
+ | <EscapeCr>
+ | <EscapeTab>
+ | ~["\'","\\"])* "\'">
+ | < #EscapeQuot: "\\\"" >
+ | < #EscapeApos: "\\\'" >
+ | < #EscapeBslash: "\\\\" >
+ | < #EscapeSlash: "\\/" >
+ | < #EscapeBspace: "\\b" >
+ | < #EscapeFormf: "\\f" >
+ | < #EscapeNl: "\\n" >
+ | < #EscapeCr: "\\r" >
+ | < #EscapeTab: "\\t" >
+}
+
+<DEFAULT,IN_DBL_BRACE>
+TOKEN :
+{
+ <IDENTIFIER : <LETTER> (<LETTER> | <DIGIT> | <SPECIALCHARS>)*>
+}
+
+<DEFAULT,IN_DBL_BRACE>
+SKIP:
+{
+ " "
+ | "\t"
+ | "\r"
+ | "\n"
+}
+
+<DEFAULT,IN_DBL_BRACE>
+SKIP:
+{
+ <"//" (~["\n"])* "\n">
+}
+
+<DEFAULT,IN_DBL_BRACE>
+SKIP:
+{
+ <"//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")?>
+}
+
+<DEFAULT,IN_DBL_BRACE>
+SKIP:
+{
+ <"/*"> { pushState(); } : INSIDE_COMMENT
+}
+
+<INSIDE_COMMENT>
+SPECIAL_TOKEN:
+{
+ <"+"(" ")*(~["*"])*>
+}
+
+<INSIDE_COMMENT>
+SKIP:
+{
+ <"/*"> { pushState(); }
+}
+
+<INSIDE_COMMENT>
+SKIP:
+{
+ <"*/"> { popState("*/"); }
+ | <~[]>
+}