[NO ISSUE][COMP] Change format of dataverse display name
- user model changes: no
- storage format changes: no
- interface changes: no
- Dataverse display name is a concatenation of name parts,
separated with dots. This change adds back-tick wrapping around
those name parts that are not parseable as SQL++ identifiers.
E.g. the display name of a dataverse name ["a-b", "c-d"] used
to be a-b.c-d, after this change it is `a-b`.`c-d`
- Add decode_dataverse_display_name() builtin function that
converts dataverse canonical name to its display name
- Add IParser.parseExpression()
Change-Id: Iebc2598022cda55b3d2c287632c9bc75438c2266
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/7824
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/DataverseNameParserTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/DataverseNameParserTest.java
new file mode 100644
index 0000000..1cd41ae
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/DataverseNameParserTest.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.test.sqlpp;
+
+import java.util.List;
+
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.common.metadata.DataverseNameTest;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.IParser;
+import org.apache.asterix.lang.common.base.IParserFactory;
+import org.apache.asterix.lang.common.base.IRewriterFactory;
+import org.apache.asterix.lang.common.base.IStatementRewriter;
+import org.apache.asterix.lang.common.expression.FieldAccessor;
+import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.sqlpp.parser.SqlppParserFactory;
+import org.apache.asterix.lang.sqlpp.rewrites.SqlppRewriterFactory;
+import org.junit.Assert;
+
+public class DataverseNameParserTest extends DataverseNameTest {
+
+ private final IParserFactory parserFactory = new SqlppParserFactory();
+
+ private final IRewriterFactory rewriterFactory = new SqlppRewriterFactory(parserFactory);
+
+ @Override
+ protected void testDataverseNameImpl(DataverseName dataverseName, List<String> parts, String expectedCanonicalForm,
+ String expectedDisplayForm) throws Exception {
+ super.testDataverseNameImpl(dataverseName, parts, expectedCanonicalForm, expectedDisplayForm);
+
+ String displayForm = dataverseName.toString();
+
+ // check parse-ability of the display form
+ IParser parser = parserFactory.createParser(displayForm);
+ Expression expr = parser.parseExpression();
+ IStatementRewriter rewriter = rewriterFactory.createStatementRewriter();
+
+ for (int i = parts.size() - 1; i >= 0; i--) {
+ String part = parts.get(i);
+ String parsedPart;
+ if (i > 0) {
+ Assert.assertEquals(Expression.Kind.FIELD_ACCESSOR_EXPRESSION, expr.getKind());
+ FieldAccessor faExpr = (FieldAccessor) expr;
+ parsedPart = faExpr.getIdent().getValue();
+ expr = faExpr.getExpr();
+ } else {
+ Assert.assertEquals(Expression.Kind.VARIABLE_EXPRESSION, expr.getKind());
+ VariableExpr varExpr = (VariableExpr) expr;
+ parsedPart = rewriter.toFunctionParameterName(varExpr.getVar());
+ }
+ Assert.assertEquals("unexpected parsed part at position " + i + " in " + parts, part, parsedPart);
+ }
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/fj-dblp-csx.ast b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/fj-dblp-csx.ast
index 1d1899c..56c7eb1 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/fj-dblp-csx.ast
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/fj-dblp-csx.ast
@@ -1,4 +1,4 @@
-DataverseUse fj-dblp-csx
+DataverseUse `fj-dblp-csx`
TypeDecl DBLPType [
open RecordType {
id : integer,
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/join-super-key_01.ast b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/join-super-key_01.ast
index 50b2a5a..b0813fd 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/join-super-key_01.ast
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/join-super-key_01.ast
@@ -1,4 +1,4 @@
-DataverseUse join-super-key_1
+DataverseUse `join-super-key_1`
TypeDecl SupplierType [
closed RecordType {
s_suppkey : integer,
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/join-super-key_02.ast b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/join-super-key_02.ast
index 8e8cfe6..0b6b9b4 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/join-super-key_02.ast
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/join-super-key_02.ast
@@ -1,4 +1,4 @@
-DataverseUse join-super-key_01
+DataverseUse `join-super-key_01`
TypeDecl SupplierType [
closed RecordType {
s_suppkey : integer,
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/loj-super-key_01.ast b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/loj-super-key_01.ast
index 46c09a9..b012a70 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/loj-super-key_01.ast
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/loj-super-key_01.ast
@@ -1,4 +1,4 @@
-DataverseUse loj-super-key_01
+DataverseUse `loj-super-key_01`
TypeDecl SupplierType [
closed RecordType {
s_suppkey : integer,
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/loj-super-key_02.ast b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/loj-super-key_02.ast
index c0390e9..deee859 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/loj-super-key_02.ast
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/loj-super-key_02.ast
@@ -1,4 +1,4 @@
-DataverseUse loj-super-key_02
+DataverseUse `loj-super-key_02`
TypeDecl SupplierType [
closed RecordType {
s_suppkey : integer,
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/orderby-desc-using-gby.ast b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/orderby-desc-using-gby.ast
index 675ca8d..ca16111 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/orderby-desc-using-gby.ast
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/orderby-desc-using-gby.ast
@@ -1,4 +1,4 @@
-DataverseUse gby-using-orderby-desc
+DataverseUse `gby-using-orderby-desc`
TypeDecl AddressType [
closed RecordType {
number : integer,
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/orders-aggreg.ast b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/orders-aggreg.ast
index cd4bca3..4d8ace4 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/orders-aggreg.ast
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/orders-aggreg.ast
@@ -1,4 +1,4 @@
-DataverseUse orders-aggreg
+DataverseUse `orders-aggreg`
TypeDecl OrderType [
closed RecordType {
oid : integer,
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/pull_select_above_eq_join.ast b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/pull_select_above_eq_join.ast
index ca6fe07..c723a60 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/pull_select_above_eq_join.ast
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results_parser_sqlpp/pull_select_above_eq_join.ast
@@ -1,4 +1,4 @@
-DataverseUse pull-select-above-eq-join
+DataverseUse `pull-select-above-eq-join`
TypeDecl UserType [
open RecordType {
uid : integer,
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/special_chars_2/special_chars_2.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/special_chars_2/special_chars_2.1.ddl.sqlpp
new file mode 100644
index 0000000..867c91b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/special_chars_2/special_chars_2.1.ddl.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.
+ */
+/*
+ * Description: special characters in multipart dataverse name
+ */
+
+drop dataverse A if exists;
+create dataverse A;
+
+drop dataverse B.C if exists;
+create dataverse B.C;
+
+drop dataverse `C.D.E` if exists;
+create dataverse `C.D.E`;
+
+drop dataverse `a-A`.`b_B`.`c$C`.`z.Z` if exists;
+create dataverse `a-A`.`b_B`.`c$C`.`z.Z`;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/special_chars_2/special_chars_2.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/special_chars_2/special_chars_2.2.query.sqlpp
new file mode 100644
index 0000000..4dc4e3b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/multipart-dataverse/special_chars_2/special_chars_2.2.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+select DataverseName as CanonicalName,
+ decode_dataverse_display_name(DataverseName) as DisplayName,
+ decode_dataverse_name(DataverseName) as NameParts
+from Metadata.`Dataverse`
+order by DataverseName;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/multipart-dataverse/special_chars_2/special_chars_2.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/multipart-dataverse/special_chars_2/special_chars_2.2.adm
new file mode 100644
index 0000000..9abda4f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/multipart-dataverse/special_chars_2/special_chars_2.2.adm
@@ -0,0 +1,6 @@
+{ "CanonicalName": "A", "DisplayName": "A", "NameParts": [ "A" ] }
+{ "CanonicalName": "B.C", "DisplayName": "B.C", "NameParts": [ "B", "C" ] }
+{ "CanonicalName": "C@.D@.E", "DisplayName": "`C.D.E`", "NameParts": [ "C.D.E" ] }
+{ "CanonicalName": "Default", "DisplayName": "Default", "NameParts": [ "Default" ] }
+{ "CanonicalName": "Metadata", "DisplayName": "Metadata", "NameParts": [ "Metadata" ] }
+{ "CanonicalName": "a-A.b_B.c$C.z@.Z", "DisplayName": "`a-A`.b_B.c$C.`z.Z`", "NameParts": [ "a-A", "b_B", "c$C", "z.Z" ] }
\ 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 afdedff..7d4dbdd 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -6772,6 +6772,11 @@
</compilation-unit>
</test-case>
<test-case FilePath="multipart-dataverse">
+ <compilation-unit name="special_chars_2">
+ <output-dir compare="Text">special_chars_2</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="multipart-dataverse">
<compilation-unit name="udf_1">
<output-dir compare="Text">udf_1</output-dir>
</compilation-unit>
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
index ec9b87d..9ec6279 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
@@ -76,7 +76,7 @@
COMPILER_INTERNAL_SANITYCHECK(
BOOLEAN,
AlgebricksConfig.SANITYCHECK_DEFAULT,
- "Enabling/disable compiler sanity check");
+ "Enable/disable compiler sanity check");
private final IOptionType type;
private final Object defaultValue;
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/DataverseName.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/DataverseName.java
index 5ec3f1a..83bf94c 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/DataverseName.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/metadata/DataverseName.java
@@ -36,14 +36,15 @@
* <p>
* Each dataverse name can be encoded into a single string (called a canonical form) by
* {@link #getCanonicalForm()} and decoded back from it with {@link #createFromCanonicalForm(String)}.
- * The canonical form encoding concatenates name parts together with {@link #SEPARATOR_CHAR '.'} character.
- * The {@link #ESCAPE_CHAR '@'} character is used to escape {@link #SEPARATOR_CHAR '.'} and itself in each name part
- * prior to concatenation.
+ * The canonical form encoding concatenates name parts together with {@link #CANONICAL_FORM_SEPARATOR_CHAR '.'}
+ * character. The {@link #CANONICAL_FORM_ESCAPE_CHAR '@'} character is used to escape
+ * {@link #CANONICAL_FORM_SEPARATOR_CHAR '.'} and itself in each name part prior to concatenation.
* <p>
* E.g. the canonical form for a dataverse name {@code ["a", "b", "c"]} is {@code "a.b.c"}
* <p>
- * {@link #toString()} returns a display form which is a {@link #SEPARATOR_CHAR '.'} separated concatenation
- * of name parts without escaping. In general it's impossible to reconstruct a dataverse name from its display form.
+ * {@link #toString()} returns a display form which is a {@link #CANONICAL_FORM_SEPARATOR_CHAR '.'} separated
+ * concatenation of name parts without escaping. In general it's impossible to reconstruct a dataverse name from
+ * its display form.
* <p>
* Notes:
* <li>
@@ -61,11 +62,18 @@
private static final long serialVersionUID = 1L;
- public static final char SEPARATOR_CHAR = '.';
+ public static final char CANONICAL_FORM_SEPARATOR_CHAR = '.';
- private static final char ESCAPE_CHAR = '@';
+ private static final char CANONICAL_FORM_ESCAPE_CHAR = '@';
- private static final char[] SEPARATOR_AND_ESCAPE_CHARS = new char[] { SEPARATOR_CHAR, ESCAPE_CHAR };
+ public static final char DISPLAY_FORM_SEPARATOR_CHAR = '.';
+
+ private static final char DISPLAY_FORM_QUOTE_CHAR = '`';
+
+ private static final char DISPLAY_FORM_ESCAPE_CHAR = '\\';
+
+ private static final char[] CANONICAL_FORM_SEPARATOR_AND_ESCAPE_CHARS =
+ new char[] { CANONICAL_FORM_SEPARATOR_CHAR, CANONICAL_FORM_ESCAPE_CHAR };
private final boolean isMultiPart;
@@ -106,9 +114,24 @@
}
/**
- * Appends dataverse name parts into a given list
+ * Appends dataverse name parts into a given output collection
*/
public void getParts(Collection<? super String> outParts) {
+ getPartsFromCanonicalForm(canonicalForm, isMultiPart, outParts);
+ }
+
+ /**
+ * Appends dataverse name parts into a given output collection
+ */
+ public static void getPartsFromCanonicalForm(String canonicalForm, Collection<? super String> outParts) {
+ getPartsFromCanonicalForm(canonicalForm, isMultiPartCanonicalForm(canonicalForm), outParts);
+ }
+
+ /**
+ * Appends dataverse name parts into a given output collection
+ */
+ private static void getPartsFromCanonicalForm(String canonicalForm, boolean isMultiPart,
+ Collection<? super String> outParts) {
if (isMultiPart) {
decodeCanonicalForm(canonicalForm, DataverseName::addPartToCollection, outParts);
} else {
@@ -117,9 +140,7 @@
}
/**
- * Returns a display form which is a {@link #SEPARATOR_CHAR '.'} separated concatenation of name parts without
- * escaping. In general it's impossible to reconstruct a dataverse name from its display form, so this method
- * should not be used when roundtripability is required.
+ * Returns a display form which suitable for error messages, and is a valid SQL++ multi-part identifier.
*/
@Override
public String toString() {
@@ -129,19 +150,29 @@
private String getDisplayForm() {
String result = displayForm;
if (result == null) {
- displayForm = result = createDisplayForm();
+ StringBuilder sb = new StringBuilder(canonicalForm.length() + 1);
+ getDisplayForm(sb);
+ displayForm = result = sb.toString();
}
return result;
}
- private String createDisplayForm() {
+ public void getDisplayForm(StringBuilder out) {
+ getDisplayFormFromCanonicalForm(canonicalForm, isMultiPart, out);
+ }
+
+ public static void getDisplayFormFromCanonicalForm(String canonicalForm, StringBuilder out) {
+ getDisplayFormFromCanonicalForm(canonicalForm, isMultiPartCanonicalForm(canonicalForm), out);
+ }
+
+ private static void getDisplayFormFromCanonicalForm(String canonicalForm, boolean isMultiPart, StringBuilder out) {
if (isMultiPart) {
- StringBuilder displayForm = new StringBuilder(canonicalForm.length() + 1);
- decodeCanonicalForm(canonicalForm, DataverseName::addPartToDisplayForm, displayForm);
- return displayForm.substring(0, displayForm.length() - 1); // remove last separator char
+ decodeCanonicalForm(canonicalForm, DataverseName::addPartToDisplayForm, out);
} else {
- return decodeSinglePartNameFromCanonicalForm(canonicalForm);
+ String singlePart = decodeSinglePartNameFromCanonicalForm(canonicalForm);
+ addPartToDisplayForm(singlePart, out);
}
+ out.setLength(out.length() - 1); // remove last separator char
}
@Override
@@ -209,7 +240,7 @@
* Validates that the canonical form of the created dataverse name is the same as its given single name part.
*/
public static DataverseName createBuiltinDataverseName(String singlePart) {
- if (StringUtils.containsAny(singlePart, SEPARATOR_AND_ESCAPE_CHARS)) {
+ if (StringUtils.containsAny(singlePart, CANONICAL_FORM_SEPARATOR_AND_ESCAPE_CHARS)) {
throw new IllegalArgumentException(singlePart);
}
DataverseName dataverseName = createSinglePartName(singlePart); // 1-part name
@@ -234,7 +265,7 @@
StringBuilder sb = new StringBuilder(32);
for (int i = 0; i < partCount; i++) {
if (i > 0) {
- sb.append(SEPARATOR_CHAR);
+ sb.append(CANONICAL_FORM_SEPARATOR_CHAR);
}
encodePartIntoCanonicalForm(parts.get(fromIndex + i), sb);
}
@@ -242,7 +273,7 @@
}
private static String encodeSinglePartNamePartIntoCanonicalForm(String singlePart) {
- if (StringUtils.indexOfAny(singlePart, SEPARATOR_AND_ESCAPE_CHARS) < 0) {
+ if (StringUtils.indexOfAny(singlePart, CANONICAL_FORM_SEPARATOR_AND_ESCAPE_CHARS) < 0) {
// no escaping needed
return singlePart;
}
@@ -254,8 +285,8 @@
private static void encodePartIntoCanonicalForm(String part, StringBuilder out) {
for (int i = 0, ln = part.length(); i < ln; i++) {
char c = part.charAt(i);
- if (c == SEPARATOR_CHAR || c == ESCAPE_CHAR) {
- out.append(ESCAPE_CHAR);
+ if (c == CANONICAL_FORM_SEPARATOR_CHAR || c == CANONICAL_FORM_ESCAPE_CHAR) {
+ out.append(CANONICAL_FORM_ESCAPE_CHAR);
}
out.append(c);
}
@@ -268,11 +299,11 @@
for (int i = 0; i < ln; i++) {
char c = canonicalForm.charAt(i);
switch (c) {
- case SEPARATOR_CHAR:
+ case CANONICAL_FORM_SEPARATOR_CHAR:
partConsumer.accept(sb, partConsumerArg);
sb.setLength(0);
break;
- case ESCAPE_CHAR:
+ case CANONICAL_FORM_ESCAPE_CHAR:
i++;
c = canonicalForm.charAt(i);
// fall through to 'default'
@@ -287,8 +318,8 @@
}
// optimization for a single part name
- private String decodeSinglePartNameFromCanonicalForm(String canonicalForm) {
- if (canonicalForm.indexOf(ESCAPE_CHAR) < 0) {
+ private static String decodeSinglePartNameFromCanonicalForm(String canonicalForm) {
+ if (canonicalForm.indexOf(CANONICAL_FORM_ESCAPE_CHAR) < 0) {
// no escaping was done
return canonicalForm;
}
@@ -297,9 +328,9 @@
for (int i = 0, ln = canonicalForm.length(); i < ln; i++) {
char c = canonicalForm.charAt(i);
switch (c) {
- case SEPARATOR_CHAR:
+ case CANONICAL_FORM_SEPARATOR_CHAR:
throw new IllegalStateException(canonicalForm); // should never happen
- case ESCAPE_CHAR:
+ case CANONICAL_FORM_ESCAPE_CHAR:
i++;
c = canonicalForm.charAt(i);
// fall through to 'default'
@@ -315,9 +346,9 @@
for (int i = 0, ln = canonicalForm.length(); i < ln; i++) {
char c = canonicalForm.charAt(i);
switch (c) {
- case SEPARATOR_CHAR:
+ case CANONICAL_FORM_SEPARATOR_CHAR:
return true;
- case ESCAPE_CHAR:
+ case CANONICAL_FORM_ESCAPE_CHAR:
i++;
break;
}
@@ -330,6 +361,36 @@
}
private static void addPartToDisplayForm(CharSequence part, StringBuilder out) {
- out.append(part).append(SEPARATOR_CHAR);
+ boolean needQuote = false;
+ for (int i = 0, ln = part.length(); i < ln; i++) {
+ char c = part.charAt(i);
+ boolean noQuote = isLetter(c) || c == '_' || (i > 0 && (isDigit(c) || c == '$'));
+ if (!noQuote) {
+ needQuote = true;
+ break;
+ }
+ }
+ if (needQuote) {
+ out.append(DISPLAY_FORM_QUOTE_CHAR);
+ }
+ for (int i = 0, ln = part.length(); i < ln; i++) {
+ char c = part.charAt(i);
+ if (c == DISPLAY_FORM_ESCAPE_CHAR || c == DISPLAY_FORM_QUOTE_CHAR) {
+ out.append(DISPLAY_FORM_ESCAPE_CHAR);
+ }
+ out.append(c);
+ }
+ if (needQuote) {
+ out.append(DISPLAY_FORM_QUOTE_CHAR);
+ }
+ out.append(DISPLAY_FORM_SEPARATOR_CHAR);
+ }
+
+ private static boolean isLetter(char c) {
+ return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
+ }
+
+ private static boolean isDigit(char c) {
+ return '0' <= c && c <= '9';
}
}
\ No newline at end of file
diff --git a/asterixdb/asterix-common/src/test/java/org/apache/asterix/common/metadata/DataverseNameTest.java b/asterixdb/asterix-common/src/test/java/org/apache/asterix/common/metadata/DataverseNameTest.java
index 1a47a3f..2f0dff5 100644
--- a/asterixdb/asterix-common/src/test/java/org/apache/asterix/common/metadata/DataverseNameTest.java
+++ b/asterixdb/asterix-common/src/test/java/org/apache/asterix/common/metadata/DataverseNameTest.java
@@ -28,7 +28,7 @@
import java.util.function.Supplier;
import org.apache.commons.collections4.ListUtils;
-import org.apache.hyracks.algebricks.common.utils.Pair;
+import org.apache.hyracks.algebricks.common.utils.Triple;
import org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
import org.junit.Assert;
import org.junit.Test;
@@ -55,97 +55,114 @@
// escape character is not allowed
"c@d");
- private static final List<Pair<String, String>> TEST_SINGLE_PART_NAME_PARAMS = Arrays.asList(
- // <1-part-name, canonical-form>
- new Pair<>("abc", "abc"),
- // with escape character
- new Pair<>("a@b", "a@@b"),
- // with separator character
- new Pair<>("a.b", "a@.b"),
- // with both escape and separator characters
- new Pair<>("a@.b", "a@@@.b"));
+ private static final List<Triple<String, String, String>> TEST_SINGLE_PART_NAME_PARAMS = Arrays.asList(
+ // <1-part-name, canonical-form, display-form>
+ new Triple<>("abz", "abz", "abz"),
+ // upper-case letters
+ new Triple<>("ABZ", "ABZ", "ABZ"),
+ // letters and digits
+ new Triple<>("aA09", "aA09", "aA09"),
+ // with canonical form escape character
+ new Triple<>("a@b", "a@@b", "`a@b`"),
+ // with canonical form separator character
+ new Triple<>("a.b", "a@.b", "`a.b`"),
+ // with canonical form escape and separator characters
+ new Triple<>("a@.b", "a@@@.b", "`a@.b`"),
+ // with display form escape character
+ new Triple<>("a\\b", "a\\b", "`a\\\\b`"));
- private static final List<Pair<List<String>, String>> TEST_MULTI_PART_NAME_PARAMS = Arrays.asList(
- // <multi-part-name, canonical-form>
- new Pair<>(Arrays.asList("aa", "bb", "cc"), "aa.bb.cc"),
- // with escape character
- new Pair<>(Arrays.asList("a@a@", "@b@b", "@c@c"), "a@@a@@.@@b@@b.@@c@@c"),
- // with separator character
- new Pair<>(Arrays.asList("a.a.", ".b.b.", ".c.c"), "a@.a@..@.b@.b@..@.c@.c"),
- // with both escape and separator characters
- new Pair<>(Arrays.asList("a@a.", "@b.b@", ".c@c"), "a@@a@..@@b@.b@@.@.c@@c"),
- // with both escape and separator characters repeated
- new Pair<>(Arrays.asList("a@@a..", "@@b..b@@", "..c@@c"), "a@@@@a@.@..@@@@b@.@.b@@@@.@.@.c@@@@c"));
+ private static final List<Triple<List<String>, String, String>> TEST_MULTI_PART_NAME_PARAMS = Arrays.asList(
+ // <multi-part-name, canonical-form, display-form>
+ new Triple<>(Arrays.asList("aa", "bb", "cc"), "aa.bb.cc", "aa.bb.cc"),
+ // mixed case letters, digits
+ new Triple<>(Arrays.asList("az", "AZ", "a09Z"), "az.AZ.a09Z", "az.AZ.a09Z"),
+ // with canonical form escape character
+ new Triple<>(Arrays.asList("a@a@", "@b@b", "@c@c"), "a@@a@@.@@b@@b.@@c@@c", "`a@a@`.`@b@b`.`@c@c`"),
+ // with canonical form separator character
+ new Triple<>(Arrays.asList("a.a.", ".b.b.", ".c.c"), "a@.a@..@.b@.b@..@.c@.c", "`a.a.`.`.b.b.`.`.c.c`"),
+ // with canonical form escape and separator characters
+ new Triple<>(Arrays.asList("a@a.", "@b.b@", ".c@c"), "a@@a@..@@b@.b@@.@.c@@c", "`a@a.`.`@b.b@`.`.c@c`"),
+ // with canonical form escape and separator characters repeated
+ new Triple<>(Arrays.asList("a@@a..", "@@b..b@@", "..c@@c"), "a@@@@a@.@..@@@@b@.@.b@@@@.@.@.c@@@@c",
+ "`a@@a..`.`@@b..b@@`.`..c@@c`"),
+ // with display form escape character
+ new Triple<>(Arrays.asList("a\\b", "c\\d"), "a\\b.c\\d", "`a\\\\b`.`c\\\\d`"));
@Test
- public void testBuiltinDataverseName() {
+ public void testBuiltinDataverseName() throws Exception {
for (String p : TEST_BUILTIN_DATAVERSE_NAME_PARAMS) {
testBuiltinDataverseNameImpl(p);
}
}
@Test
- public void testSinglePartName() {
- for (Pair<String, String> p : TEST_SINGLE_PART_NAME_PARAMS) {
- String singlePart = p.first;
- String expectedCanonicalForm = p.second;
- testSinglePartNameImpl(singlePart, expectedCanonicalForm);
+ public void testSinglePartName() throws Exception {
+ for (Triple<String, String, String> t : TEST_SINGLE_PART_NAME_PARAMS) {
+ String singlePart = t.first;
+ String expectedCanonicalForm = t.second;
+ String expectedDisplayForm = t.third;
+ testSinglePartNameImpl(singlePart, expectedCanonicalForm, expectedDisplayForm);
}
}
@Test
- public void testMultiPartName() {
+ public void testMultiPartName() throws Exception {
// test single part names
- for (Pair<String, String> p : TEST_SINGLE_PART_NAME_PARAMS) {
- List<String> parts = Collections.singletonList(p.first);
- String expectedCanonicalForm = p.second;
- testMultiPartNameImpl(parts, expectedCanonicalForm);
+ for (Triple<String, String, String> t : TEST_SINGLE_PART_NAME_PARAMS) {
+ List<String> parts = Collections.singletonList(t.first);
+ String expectedCanonicalForm = t.second;
+ String expectedDisplayForm = t.third;
+ testMultiPartNameImpl(parts, expectedCanonicalForm, expectedDisplayForm);
}
// test multi part names
- for (Pair<List<String>, String> p : TEST_MULTI_PART_NAME_PARAMS) {
- List<String> parts = p.first;
- String expectedCanonicalForm = p.second;
- testMultiPartNameImpl(parts, expectedCanonicalForm);
+ for (Triple<List<String>, String, String> t : TEST_MULTI_PART_NAME_PARAMS) {
+ List<String> parts = t.first;
+ String expectedCanonicalForm = t.second;
+ String expectedDisplayForm = t.third;
+ testMultiPartNameImpl(parts, expectedCanonicalForm, expectedDisplayForm);
}
}
- private void testBuiltinDataverseNameImpl(String singlePart) {
+ private void testBuiltinDataverseNameImpl(String singlePart) throws Exception {
DataverseName dvBuiltin = DataverseName.createBuiltinDataverseName(singlePart);
DataverseName dv = DataverseName.createSinglePartName(singlePart);
Assert.assertEquals("same-builtin", dv, dvBuiltin);
- // part = canonical-form = persistent-form for builtins
- testSinglePartNameImpl(singlePart, singlePart);
+ // part = canonical-form = display-form for builtins
+ testSinglePartNameImpl(singlePart, singlePart, singlePart);
}
- private void testSinglePartNameImpl(String singlePart, String expectedCanonicalForm) {
+ private void testSinglePartNameImpl(String singlePart, String expectedCanonicalForm, String expectedDisplayForm)
+ throws Exception {
List<String> parts = Collections.singletonList(singlePart);
// construction using createSinglePartName()
DataverseName dvConstr1 = DataverseName.createSinglePartName(singlePart);
- testDataverseNameImpl(dvConstr1, parts, expectedCanonicalForm);
+ testDataverseNameImpl(dvConstr1, parts, expectedCanonicalForm, expectedDisplayForm);
// construction using create(list)
DataverseName dvConstr2 = DataverseName.create(Collections.singletonList(singlePart));
- testDataverseNameImpl(dvConstr2, parts, expectedCanonicalForm);
+ testDataverseNameImpl(dvConstr2, parts, expectedCanonicalForm, expectedDisplayForm);
// construction using create(list, from, to)
DataverseName dvConstr3 = DataverseName.create(Arrays.asList(null, null, singlePart, null, null), 2, 3);
- testDataverseNameImpl(dvConstr3, parts, expectedCanonicalForm);
+ testDataverseNameImpl(dvConstr3, parts, expectedCanonicalForm, expectedDisplayForm);
}
- private void testMultiPartNameImpl(List<String> parts, String expectedCanonicalForm) {
+ private void testMultiPartNameImpl(List<String> parts, String expectedCanonicalForm, String expectedDisplayForm)
+ throws Exception {
// construction using create(list)
DataverseName dvConstr1 = DataverseName.create(parts);
- testDataverseNameImpl(dvConstr1, parts, expectedCanonicalForm);
+ testDataverseNameImpl(dvConstr1, parts, expectedCanonicalForm, expectedDisplayForm);
// construction using create(list, from, to)
List<String> dv2InputParts =
ListUtils.union(ListUtils.union(Arrays.asList(null, null), parts), Arrays.asList(null, null));
DataverseName dvConstr2 = DataverseName.create(dv2InputParts, 2, 2 + parts.size());
- testDataverseNameImpl(dvConstr2, parts, expectedCanonicalForm);
+ testDataverseNameImpl(dvConstr2, parts, expectedCanonicalForm, expectedDisplayForm);
}
- private void testDataverseNameImpl(DataverseName dataverseName, List<String> parts, String expectedCanonicalForm) {
+ protected void testDataverseNameImpl(DataverseName dataverseName, List<String> parts, String expectedCanonicalForm,
+ String expectedDisplayForm) throws Exception {
boolean isMultiPart = parts.size() > 1;
Assert.assertEquals("is-multipart", isMultiPart, dataverseName.isMultiPart());
@@ -156,15 +173,16 @@
Assert.assertArrayEquals("get-parts-1", parts.toArray(), outParts.toArray());
// test canonical form
- Assert.assertEquals("canonical-form", expectedCanonicalForm, dataverseName.getCanonicalForm());
+ String canonicalForm = dataverseName.getCanonicalForm();
+ Assert.assertEquals("canonical-form", expectedCanonicalForm, canonicalForm);
DataverseName dvFromCanonical = DataverseName.createFromCanonicalForm(expectedCanonicalForm);
Assert.assertEquals("canonical-form-round-trip", dataverseName, dvFromCanonical);
Assert.assertEquals("canonical-form-round-trip-cmp", 0, dataverseName.compareTo(dvFromCanonical));
Assert.assertEquals("canonical-form-round-trip-hash", dataverseName.hashCode(), dvFromCanonical.hashCode());
// test display form
- String expectedDisplayForm = String.join(".", parts);
- Assert.assertEquals("display-form", expectedDisplayForm, dataverseName.toString());
+ String displayForm = dataverseName.toString();
+ Assert.assertEquals("display-form", expectedDisplayForm, displayForm);
}
@Test
diff --git a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
index e903977..d899632 100644
--- a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
+++ b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
@@ -291,6 +291,7 @@
//st.accept(new AQLPrintVisitor(), 0);
}
+ @Override
public List<Statement> parse() throws CompilationException {
return parseImpl(new ParseFunction<List<Statement>>() {
@Override
@@ -300,7 +301,8 @@
});
}
- private Expression parseExpression() throws CompilationException {
+ @Override
+ public Expression parseExpression() throws CompilationException {
return parseImpl(new ParseFunction<Expression>() {
@Override
public Expression parse() throws ParseException {
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java
index 3f73789..bd05f28 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java
@@ -30,6 +30,8 @@
List<Statement> parse() throws CompilationException;
+ Expression parseExpression() throws CompilationException;
+
FunctionDecl parseFunctionBody(FunctionSignature signature, List<String> paramNames) throws CompilationException;
/**
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/DataverseNameUtils.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/DataverseNameUtils.java
index 1eb3868..1a3f26a 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/DataverseNameUtils.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/DataverseNameUtils.java
@@ -76,7 +76,7 @@
dataverseName.getParts(dataverseNameParts);
for (int i = 0, ln = dataverseNameParts.size(); i < ln; i++) {
if (i > 0) {
- sb.append(DataverseName.SEPARATOR_CHAR);
+ sb.append(DataverseName.CANONICAL_FORM_SEPARATOR_CHAR);
}
sb.append(normalize(dataverseNameParts.get(i)));
}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
index f5caccf..290f9ea 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
@@ -1026,7 +1026,7 @@
dataverseName.getParts(dataverseNameParts);
for (int i = 0, ln = dataverseNameParts.size(); i < ln; i++) {
if (i > 0) {
- sb.append(DataverseName.SEPARATOR_CHAR);
+ sb.append(".");
}
sb.append(normalize(dataverseNameParts.get(i)));
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppStatementUtil.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppStatementUtil.java
index 9336c79..ba6d9e4 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppStatementUtil.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppStatementUtil.java
@@ -108,7 +108,7 @@
/**
* Encloses each part of the {@param dataverseName} in back-ticks and concatenates them with
- * {@link DataverseName#SEPARATOR_CHAR} separator
+ * {@link #DOT} separator
* @param stringBuilder where the dataverse name will be appended
* @param dataverseName a dataverse name which could be a valid one or one that needs to be delimited
* @return {@param stringBuilder} with the <i>delimited</i> dataverseName appended
@@ -117,7 +117,7 @@
List<String> parts = dataverseName.getParts();
for (int i = 0, ln = parts.size(); i < ln; i++) {
if (i > 0) {
- stringBuilder.append(DataverseName.SEPARATOR_CHAR);
+ stringBuilder.append(DOT);
}
enclose(stringBuilder, parts.get(i));
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 347dc18..b23492a 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -343,7 +343,8 @@
});
}
- private Expression parseExpression() throws CompilationException {
+ @Override
+ public Expression parseExpression() throws CompilationException {
return parseImpl(new ParseFunction<Expression>() {
@Override
public Expression parse() throws ParseException {
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
index f74e730..cf3ea0e 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
@@ -1592,6 +1592,8 @@
public static final FunctionIdentifier DECODE_DATAVERSE_NAME =
new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "decode-dataverse-name", 1);
+ public static final FunctionIdentifier DECODE_DATAVERSE_DISPLAY_NAME =
+ new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "decode-dataverse-display-name", 1);
static {
// first, take care of Algebricks builtin functions
@@ -2358,7 +2360,8 @@
addFunction(META, OpenARecordTypeComputer.INSTANCE, true);
addPrivateFunction(META_KEY, AnyTypeComputer.INSTANCE, false);
- addFunction(DECODE_DATAVERSE_NAME, OrderedListOfAStringTypeComputer.INSTANCE, true);
+ addFunction(DECODE_DATAVERSE_NAME, OrderedListOfAStringTypeComputer.INSTANCE_NULLABLE, true);
+ addFunction(DECODE_DATAVERSE_DISPLAY_NAME, AStringTypeComputer.INSTANCE_NULLABLE, true);
addPrivateFunction(COLLECTION_TO_SEQUENCE, CollectionToSequenceTypeComputer.INSTANCE, true);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/DecodeDataverseDisplayNameDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/DecodeDataverseDisplayNameDescriptor.java
new file mode 100644
index 0000000..a622fe8
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/DecodeDataverseDisplayNameDescriptor.java
@@ -0,0 +1,74 @@
+/*
+ * 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.runtime.evaluators.functions;
+
+import java.io.IOException;
+
+import org.apache.asterix.common.annotations.MissingNullInOutFunction;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
+
+@MissingNullInOutFunction
+public class DecodeDataverseDisplayNameDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+ private static final long serialVersionUID = 1L;
+
+ public static final IFunctionDescriptorFactory FACTORY = DecodeDataverseDisplayNameDescriptor::new;
+
+ @Override
+ public IScalarEvaluatorFactory createEvaluatorFactory(IScalarEvaluatorFactory[] args) {
+ return new IScalarEvaluatorFactory() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public IScalarEvaluator createScalarEvaluator(IEvaluatorContext ctx) throws HyracksDataException {
+ return new AbstractUnaryStringStringEval(ctx, args[0], getIdentifier(), sourceLoc) {
+
+ private final StringBuilder sb = new StringBuilder();
+
+ @Override
+ void process(UTF8StringPointable inputString, IPointable resultPointable) throws IOException {
+ String dataverseCanonicalName = inputString.toString();
+
+ sb.setLength(0);
+ DataverseName.getDisplayFormFromCanonicalForm(dataverseCanonicalName, sb);
+
+ resultBuilder.reset(resultArray, inputString.getUTF8Length());
+ resultBuilder.appendString(sb);
+ resultBuilder.finish();
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return BuiltinFunctions.DECODE_DATAVERSE_DISPLAY_NAME;
+ }
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/DecodeDataverseNameDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/DecodeDataverseNameDescriptor.java
index 1ec6a5a..fbbe5c5 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/DecodeDataverseNameDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/DecodeDataverseNameDescriptor.java
@@ -101,10 +101,8 @@
strPtr.set(bytes, offset + 1, len - 1);
String dataverseCanonicalName = strPtr.toString();
- DataverseName dataverseName = DataverseName.createFromCanonicalForm(dataverseCanonicalName);
-
dataverseNameParts.clear();
- dataverseName.getParts(dataverseNameParts);
+ DataverseName.getPartsFromCanonicalForm(dataverseCanonicalName, dataverseNameParts);
resultStorage.reset();
listBuilder.reset(listType);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
index e1c9164..42e27da 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
@@ -331,6 +331,7 @@
import org.apache.asterix.runtime.evaluators.functions.CreateQueryUIDDescriptor;
import org.apache.asterix.runtime.evaluators.functions.CreateRectangleDescriptor;
import org.apache.asterix.runtime.evaluators.functions.CreateUUIDDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.DecodeDataverseDisplayNameDescriptor;
import org.apache.asterix.runtime.evaluators.functions.DecodeDataverseNameDescriptor;
import org.apache.asterix.runtime.evaluators.functions.DeepEqualityDescriptor;
import org.apache.asterix.runtime.evaluators.functions.FullTextContainsDescriptor;
@@ -1214,6 +1215,7 @@
// Other functions
fc.add(DecodeDataverseNameDescriptor.FACTORY);
+ fc.add(DecodeDataverseDisplayNameDescriptor.FACTORY);
fc.add(RandomWithSeedDescriptor.FACTORY);
ServiceLoader.load(IFunctionRegistrant.class).iterator().forEachRemaining(c -> c.register(fc));
diff --git a/hyracks-fullstack/hyracks/hyracks-data/hyracks-data-std/src/main/java/org/apache/hyracks/data/std/util/UTF8StringBuilder.java b/hyracks-fullstack/hyracks/hyracks-data/hyracks-data-std/src/main/java/org/apache/hyracks/data/std/util/UTF8StringBuilder.java
index 147ac86..9913a39 100644
--- a/hyracks-fullstack/hyracks/hyracks-data/hyracks-data-std/src/main/java/org/apache/hyracks/data/std/util/UTF8StringBuilder.java
+++ b/hyracks-fullstack/hyracks/hyracks-data/hyracks-data-std/src/main/java/org/apache/hyracks/data/std/util/UTF8StringBuilder.java
@@ -36,7 +36,7 @@
}
}
- public void appendString(String string) throws IOException {
+ public void appendString(CharSequence string) throws IOException {
for (int i = 0; i < string.length(); i++) {
appendChar(string.charAt(i));
}