[NO ISSUE][COMP] Rewrite SELECT * in sql-compat mode
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- In sql-compat mode rewrite SELECT * into SELECT v.*
if there's a single variable defined in FROM clause
- Fail if FROM clause has two or more variables
Change-Id: I871398d60a328271e89842abcd95631a61dcc001
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/13647
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
index 48a8f4b..2dd4f96 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
@@ -778,45 +778,78 @@
Set<String> fieldNames = new HashSet<>();
for (Projection projection : selectRegular.getProjections()) {
- if (projection.varStar()) {
- if (!fieldBindings.isEmpty()) {
- RecordConstructor recordConstr = new RecordConstructor(new ArrayList<>(fieldBindings));
- recordConstr.setSourceLocation(selectRegular.getSourceLocation());
- recordExprs.add(recordConstr);
- fieldBindings.clear();
- }
- Expression projectionExpr = projection.getExpression();
- SourceLocation sourceLoc = projection.getSourceLocation();
- CallExpr toObjectExpr = new CallExpr(new FunctionSignature(BuiltinFunctions.TO_OBJECT),
- Collections.singletonList(projectionExpr));
- toObjectExpr.setSourceLocation(sourceLoc);
- CallExpr ifMissingOrNullExpr = new CallExpr(new FunctionSignature(BuiltinFunctions.IF_MISSING_OR_NULL),
- Arrays.asList(toObjectExpr, new RecordConstructor(Collections.emptyList())));
- ifMissingOrNullExpr.setSourceLocation(sourceLoc);
- recordExprs.add(ifMissingOrNullExpr);
- } else if (projection.star()) {
- if (selectBlock.hasGroupbyClause()) {
- getGroupBindings(selectBlock.getGroupbyClause(), fieldBindings, fieldNames,
- SqlppExpressionToPlanTranslator::includeInSelectStar);
- if (selectBlock.hasLetHavingClausesAfterGroupby()) {
- getLetBindings(selectBlock.getLetHavingListAfterGroupby(), fieldBindings, fieldNames,
+ boolean everyVarStar = false;
+ switch (projection.getKind()) {
+ case VAR_STAR:
+ if (!fieldBindings.isEmpty()) {
+ RecordConstructor recordConstr = new RecordConstructor(new ArrayList<>(fieldBindings));
+ recordConstr.setSourceLocation(selectRegular.getSourceLocation());
+ recordExprs.add(recordConstr);
+ fieldBindings.clear();
+ }
+ Expression expr =
+ translateProjectVarStar(projection.getExpression(), projection.getSourceLocation());
+ recordExprs.add(expr);
+ break;
+ case EVERY_VAR_STAR:
+ everyVarStar = true;
+ // fall thru to STAR
+ case STAR:
+ List<FieldBinding> fieldBindingsForStar;
+ Set<String> fieldNamesForStar;
+ if (everyVarStar) {
+ fieldBindingsForStar = new ArrayList<>();
+ fieldNamesForStar = new HashSet<>();
+ } else {
+ fieldBindingsForStar = fieldBindings;
+ fieldNamesForStar = fieldNames;
+ }
+ if (selectBlock.hasGroupbyClause()) {
+ getGroupBindings(selectBlock.getGroupbyClause(), fieldBindingsForStar, fieldNamesForStar,
+ SqlppExpressionToPlanTranslator::includeInSelectStar);
+ if (selectBlock.hasLetHavingClausesAfterGroupby()) {
+ getLetBindings(selectBlock.getLetHavingListAfterGroupby(), fieldBindingsForStar,
+ fieldNamesForStar, SqlppExpressionToPlanTranslator::includeInSelectStar);
+ }
+ } else if (selectBlock.hasFromClause()) {
+ getFromBindings(selectBlock.getFromClause(), fieldBindingsForStar, fieldNamesForStar,
+ SqlppExpressionToPlanTranslator::includeInSelectStar);
+ if (selectBlock.hasLetWhereClauses()) {
+ getLetBindings(selectBlock.getLetWhereList(), fieldBindingsForStar, fieldNamesForStar,
+ SqlppExpressionToPlanTranslator::includeInSelectStar);
+ }
+ } else if (selectBlock.hasLetWhereClauses()) {
+ getLetBindings(selectBlock.getLetWhereList(), fieldBindingsForStar, fieldNamesForStar,
SqlppExpressionToPlanTranslator::includeInSelectStar);
}
- } else if (selectBlock.hasFromClause()) {
- getFromBindings(selectBlock.getFromClause(), fieldBindings, fieldNames,
- SqlppExpressionToPlanTranslator::includeInSelectStar);
- if (selectBlock.hasLetWhereClauses()) {
- getLetBindings(selectBlock.getLetWhereList(), fieldBindings, fieldNames,
- SqlppExpressionToPlanTranslator::includeInSelectStar);
+ if (everyVarStar) {
+ if (!fieldBindings.isEmpty()) {
+ RecordConstructor recordConstr = new RecordConstructor(new ArrayList<>(fieldBindings));
+ recordConstr.setSourceLocation(selectRegular.getSourceLocation());
+ recordExprs.add(recordConstr);
+ fieldBindings.clear();
+ }
+ // We currently only support EVERY_VAR_STAR over a single variable
+ if (fieldBindingsForStar.size() > 1) {
+ throw new CompilationException(ErrorCode.AMBIGUOUS_PROJECTION,
+ projection.getSourceLocation());
+ }
+ for (FieldBinding fieldBinding : fieldBindingsForStar) {
+ expr = translateProjectVarStar(fieldBinding.getRightExpr(), projection.getSourceLocation());
+ recordExprs.add(expr);
+ }
}
- } else if (selectBlock.hasLetWhereClauses()) {
- getLetBindings(selectBlock.getLetWhereList(), fieldBindings, fieldNames,
- SqlppExpressionToPlanTranslator::includeInSelectStar);
- }
- } else if (projection.hasName()) {
- fieldBindings.add(getFieldBinding(projection, fieldNames));
- } else {
- throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, projection.getSourceLocation(), "");
+ break;
+ case NAMED_EXPR:
+ if (!projection.hasName()) {
+ throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE,
+ projection.getSourceLocation(), "");
+ }
+ fieldBindings.add(getFieldBinding(projection, fieldNames));
+ break;
+ default:
+ throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, projection.getSourceLocation(),
+ "");
}
}
if (!fieldBindings.isEmpty()) {
@@ -835,6 +868,17 @@
}
}
+ private Expression translateProjectVarStar(Expression projectionExpr, SourceLocation sourceLoc) {
+ // var.* -> if_missing_or_null(to_object(var), {})
+ CallExpr toObjectExpr = new CallExpr(new FunctionSignature(BuiltinFunctions.TO_OBJECT),
+ Collections.singletonList(projectionExpr));
+ toObjectExpr.setSourceLocation(sourceLoc);
+ CallExpr ifMissingOrNullExpr = new CallExpr(new FunctionSignature(BuiltinFunctions.IF_MISSING_OR_NULL),
+ Arrays.asList(toObjectExpr, new RecordConstructor(Collections.emptyList())));
+ ifMissingOrNullExpr.setSourceLocation(sourceLoc);
+ return ifMissingOrNullExpr;
+ }
+
private static boolean includeInSelectStar(VariableExpr varExpr) {
boolean excludeFromSelectStar =
varExpr.hasHints() && varExpr.getHints().contains(ExcludeFromSelectStarAnnotation.INSTANCE);
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/sql-compat/select_star_01/select_star_01.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/sql-compat/select_star_01/select_star_01.1.query.sqlpp
new file mode 100644
index 0000000..87d2207
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/sql-compat/select_star_01/select_star_01.1.query.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+/*
+ * Test SELECT * in sql-compat mode
+ */
+
+// requesttype=application/json
+// param sql-compat:json=true
+
+with T as (
+ select r x, -r y
+ from range(1, 2) r
+)
+
+select *
+from T t
+order by x;
+
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/sql-compat/select_star_02_negative/select_star_02_negative.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/sql-compat/select_star_02_negative/select_star_02_negative.1.query.sqlpp
new file mode 100644
index 0000000..c1b4824
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/sql-compat/select_star_02_negative/select_star_02_negative.1.query.sqlpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+/*
+ * Test that SELECT * fails in sql-compat mode if
+ * FROM clause has more than one variable
+ */
+
+// requesttype=application/json
+// param sql-compat:json=true
+
+with T as (
+ select r x, -r y
+ from range(1, 2) r
+)
+
+select *
+from T t1, T t2;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/sql-compat/select_star_01/select_star_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/sql-compat/select_star_01/select_star_01.1.adm
new file mode 100644
index 0000000..7c1ec37
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/sql-compat/select_star_01/select_star_01.1.adm
@@ -0,0 +1,2 @@
+{ "x": 1, "y": -1 }
+{ "x": 2, "y": -2 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index 6450a1c..facf00f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -10130,6 +10130,19 @@
</compilation-unit>
</test-case>
</test-group>
+ <test-group name="sql-compat">
+ <test-case FilePath="sql-compat">
+ <compilation-unit name="select_star_01">
+ <output-dir compare="Text">select_star_01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="sql-compat">
+ <compilation-unit name="select_star_02_negative">
+ <output-dir compare="Text">none</output-dir>
+ <expected-error>ASX1168: Ambiguous projection in SELECT clause (in line 32, at column 8)</expected-error>
+ </compilation-unit>
+ </test-case>
+ </test-group>
<test-group name="statement-params">
<test-case FilePath="statement-params">
<compilation-unit name="index_01">
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index 1f96cc8..d49dffc 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -252,6 +252,7 @@
INVALID_FOREIGN_KEY_DEFINITION_REF_PK_NOT_FOUND(1165),
INVALID_FOREIGN_KEY_DEFINITION_REF_PK_MISMATCH(1166),
CANNOT_CHANGE_PRIMARY_KEY(1167),
+ AMBIGUOUS_PROJECTION(1168),
// Feed errors
DATAFLOW_ILLEGAL_STATE(3001),
diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index f40fdcf..136e169 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -254,6 +254,7 @@
1165 = Invalid foreign key definition: %1$s %2$s does not have a primary key
1166 = Invalid foreign key definition: foreign key does not match primary key of %1$s %2$s
1167 = Cannot change primary key of %1$s %2$s
+1168 = Ambiguous projection in SELECT clause
# Feed Errors
3001 = Illegal state.
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/Projection.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/Projection.java
index 7aa3cec..fbfc5a2 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/Projection.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/clause/Projection.java
@@ -32,7 +32,8 @@
public enum Kind {
NAMED_EXPR, // expr AS name
STAR, // *
- VAR_STAR // variable.*
+ VAR_STAR, // variable.*
+ EVERY_VAR_STAR // *.* (currently only used in SQL-compatible mode)
}
private Kind kind;
@@ -54,6 +55,7 @@
}
break;
case STAR:
+ case EVERY_VAR_STAR:
if (expr != null || name != null) {
throw new IllegalArgumentException();
}
@@ -142,6 +144,8 @@
return "*";
case VAR_STAR:
return expr + ".*";
+ case EVERY_VAR_STAR:
+ return "*.*";
default:
throw new IllegalStateException();
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
index b6fd9da..b28f4b9 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
@@ -59,6 +59,7 @@
import org.apache.asterix.lang.sqlpp.rewrites.visitor.InlineWithExpressionVisitor;
import org.apache.asterix.lang.sqlpp.rewrites.visitor.OperatorExpressionVisitor;
import org.apache.asterix.lang.sqlpp.rewrites.visitor.SetOperationVisitor;
+import org.apache.asterix.lang.sqlpp.rewrites.visitor.SqlCompatRewriteVisitor;
import org.apache.asterix.lang.sqlpp.rewrites.visitor.SqlppCaseAggregateExtractionVisitor;
import org.apache.asterix.lang.sqlpp.rewrites.visitor.SqlppCaseExpressionVisitor;
import org.apache.asterix.lang.sqlpp.rewrites.visitor.SqlppFunctionCallResolverVisitor;
@@ -138,6 +139,9 @@
// Sets up parameters.
setup(context, topStatement, externalVars, allowNonStoredUdfCalls, inlineUdfsAndViews);
+ // Initial SQL-compat mode rewrites
+ rewriteSqlCompat();
+
// Resolves function calls
resolveFunctionCalls();
@@ -218,6 +222,15 @@
rewriteTopExpr(listInputFunctionVisitor, null);
}
+ protected void rewriteSqlCompat() throws CompilationException {
+ boolean sqlCompatMode = metadataProvider.getBooleanProperty(SQL_COMPAT_OPTION, SQL_COMPAT_OPTION_DEFAULT);
+ if (!sqlCompatMode) {
+ return;
+ }
+ SqlCompatRewriteVisitor visitor = new SqlCompatRewriteVisitor();
+ rewriteTopExpr(visitor, null);
+ }
+
protected void resolveFunctionCalls() throws CompilationException {
SqlppFunctionCallResolverVisitor visitor =
new SqlppFunctionCallResolverVisitor(context, allowNonStoredUdfCalls);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlCompatRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlCompatRewriteVisitor.java
new file mode 100644
index 0000000..69eb156
--- /dev/null
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlCompatRewriteVisitor.java
@@ -0,0 +1,43 @@
+/*
+ * 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.visitor;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.ILangExpression;
+import org.apache.asterix.lang.sqlpp.clause.Projection;
+import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppSimpleExpressionVisitor;
+
+/**
+ * Applies initial rewritings for "SQL-compatible" evaluation mode
+ * <ol>
+ * <li>Rewrites "SELECT *" into "SELECT *.*".
+ * </ol>
+ */
+public final class SqlCompatRewriteVisitor extends AbstractSqlppSimpleExpressionVisitor {
+
+ @Override
+ public Expression visit(Projection projection, ILangExpression arg) throws CompilationException {
+ if (projection.getKind() == Projection.Kind.STAR) {
+ projection.setKind(Projection.Kind.EVERY_VAR_STAR);
+ }
+ return super.visit(projection, arg);
+ }
+}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupingSetsVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupingSetsVisitor.java
index 9aca37a..1259b64 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupingSetsVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupingSetsVisitor.java
@@ -165,7 +165,7 @@
// For regular SELECT we need to add ORDERBY/LIMIT free variables to the projection list of the SELECT clause,
// so they can be accessed using field-access-by-name after SELECT.
// Some of these variables might be already projected by SELECT, so we need to account for that.
- // We currently do not support (fail) SELECT v.* because in this case we cannot statically compute
+ // We currently do not support (fail) SELECT v.* and *.* because in this case we cannot statically compute
// the schema of the record produced by the SELECT and therefore cannot guarantee that the field
// names we generate will not conflict with the existing fields in the SELECT output.
// The added projections will be later removed by the outer query.
@@ -181,6 +181,7 @@
Projection projection = projectionList.get(i);
switch (projection.getKind()) {
case VAR_STAR:
+ case EVERY_VAR_STAR:
throw new CompilationException(ErrorCode.UNSUPPORTED_GBY_OBY_SELECT_COMBO,
selectBlock.getSourceLocation());
case STAR:
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java
index 27c3952..db663cd 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java
@@ -135,6 +135,9 @@
case STAR:
out.println(skip(step) + "*");
break;
+ case EVERY_VAR_STAR:
+ out.println(skip(step) + "*.*");
+ break;
case VAR_STAR:
projection.getExpression().accept(this, step);
out.println(skip(step) + ".*");
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java
index 34ca727..975379d 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppFormatPrintVisitor.java
@@ -127,6 +127,9 @@
case STAR:
out.print(" * ");
break;
+ case EVERY_VAR_STAR:
+ out.print(" *.* ");
+ break;
case VAR_STAR:
projection.getExpression().accept(this, step);
out.print(".* ");