Merge branch 'mad-hatter' into 'master'
Change-Id: I24f42dc32931a214a27c2c88fde163f665cc83db
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java
index ce30637..bdc1bd7 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java
@@ -145,7 +145,8 @@
}
protected String resolveClusterUrl(IServletRequest request, String pathToNode) {
- final StringBuilder requestURL = new StringBuilder("http://");
+ final StringBuilder requestURL = new StringBuilder(request.getScheme().name());
+ requestURL.append("://");
requestURL.append(request.getHeader(HttpHeaderNames.HOST));
requestURL.append(request.getHttpRequest().uri());
if (requestURL.charAt(requestURL.length() - 1) != '/') {
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/function/TPCDSDataGeneratorReader.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/function/TPCDSDataGeneratorReader.java
index 3d08c01..72bf46f 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/function/TPCDSDataGeneratorReader.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/function/TPCDSDataGeneratorReader.java
@@ -47,6 +47,14 @@
private final FunctionIdentifier functionIdentifier;
+ // Table name will be added to each generated record
+ private final static String TABLE_NAME_FIELD_NAME = "table_name";
+
+ // When generating the values, a list is created, at index 0, all the values for the parent record exist, if a
+ // child record is created, it is at index 1 in the list
+ private static final int PARENT_VALUES_INDEX = 0;
+ private static final int CHILD_VALUES_INDEX = 1;
+
// Table members
private final List<Table> selectedTables;
private final StringBuilder builder = new StringBuilder();
@@ -90,6 +98,44 @@
}
}
+ /**
+ * Gets the table matching the provided string table name, throws an exception if no table is returned.
+ *
+ * @param tableName String table name to search for.
+ * @return Table if found, throws an exception otherwise.
+ */
+ private List<Table> getTableFromStringTableName(String tableName) throws HyracksDataException {
+
+ // Get all the tables
+ if (generateAllTables) {
+ // Remove the DBGEN_VERSION table and all children tables, parent tables will generate them
+ return Table.getBaseTables().stream()
+ .filter(table -> !table.equals(Table.DBGEN_VERSION) && !table.isChild())
+ .collect(Collectors.toList());
+ }
+
+ // Search for the table
+ List<Table> matchedTables = Table.getBaseTables().stream()
+ .filter(table -> tableName.equalsIgnoreCase(table.getName())).collect(Collectors.toList());
+
+ // Ensure the table was found
+ if (matchedTables.isEmpty()) {
+ throw new RuntimeDataException(ErrorCode.TPCDS_INVALID_TABLE_NAME, getFunctionIdentifier().getName(),
+ tableName);
+ }
+
+ return matchedTables;
+ }
+
+ /**
+ * Gets the function identifier
+ *
+ * @return function identifier
+ */
+ private FunctionIdentifier getFunctionIdentifier() {
+ return functionIdentifier;
+ }
+
@Override
public boolean hasNext() {
@@ -144,21 +190,8 @@
// Clear the builder (This is faster than re-creating the builder each iteration)
builder.setLength(0);
- builder.append("{\"tableName\":\"");
- builder.append(currentTable.toString());
- builder.append("\"");
-
- // Build the record data
- for (int counter = 0; counter < values.get(0).size(); counter++) {
- builder.append(",\"");
- builder.append(currentTable.getColumns()[counter].getName());
- builder.append("\":\"");
- builder.append(values.get(0).get(counter));
- builder.append("\"");
- }
-
- // Close the record
- builder.append("}");
+ // Construct the record
+ constructRecord(values.get(PARENT_VALUES_INDEX), currentTable);
// Reference to the parent row to be returned, before resetting the builder again
String parentRow = builder.toString();
@@ -168,21 +201,9 @@
// are done
if (generateAllTables && values.size() > 1) {
builder.setLength(0);
- builder.append("{\"tableName\":\"");
- builder.append(currentTable.getChild().toString());
- builder.append("\"");
- // Build the record data
- for (int counter = 0; counter < values.get(1).size(); counter++) {
- builder.append(",\"");
- builder.append(currentTable.getChild().getColumns()[counter].getName());
- builder.append("\":\"");
- builder.append(values.get(0).get(counter));
- builder.append("\"");
- }
-
- // Close the record
- builder.append("}");
+ // Construct the record
+ constructRecord(values.get(CHILD_VALUES_INDEX), currentTable.getChild());
// Add it to the children rows list
childRow = builder.toString();
@@ -193,40 +214,53 @@
}
/**
- * Gets the table matching the provided string table name, throws an exception if no table is returned.
+ * Constructs the record with the appropriate data types.
*
- * @param tableName String table name to search for.
- * @return Table if found, throws an exception otherwise.
+ * @param values list containing all the generated values for all columns in a string format.
+ * @param table Table the record is being constructed for
*/
- private List<Table> getTableFromStringTableName(String tableName) throws HyracksDataException {
+ private void constructRecord(List<String> values, Table table) {
+ // Add the table name to the record
+ builder.append("{\"").append(TABLE_NAME_FIELD_NAME).append("\":\"").append(table.getName()).append("\"");
- // Get all the tables
- if (generateAllTables) {
- // Remove the DBGEN_VERSION table and all children tables, parent tables will generate them
- return Table.getBaseTables().stream()
- .filter(table -> !table.equals(Table.DBGEN_VERSION) && !table.isChild())
- .collect(Collectors.toList());
+ // Build the record data
+ for (int counter = 0; counter < values.size(); counter++) {
+
+ // If the value is null, no need to check for the column type
+ if (values.get(counter) == null) {
+ builder.append(",\"");
+ builder.append(table.getColumns()[counter].getName());
+ builder.append("\":");
+ builder.append(values.get(counter));
+ continue;
+ }
+
+ String fieldName = table.getColumns()[counter].getName();
+ String stringValue = values.get(counter);
+
+ // Convert the value to the appropriate type based on the column type
+ switch (table.getColumns()[counter].getType().getBase()) {
+ case INTEGER:
+ builder.append(",\"").append(fieldName).append("\":").append(Integer.valueOf(stringValue));
+ break;
+ case DECIMAL:
+ builder.append(",\"").append(fieldName).append("\":").append(Double.valueOf(stringValue));
+ break;
+ // IDENTIFIER type could be any value, so we're taking it as a string
+ // DATE and TIME are not supported, they are stored as strings and can be modified with date functions
+ // CHAR and VARCHAR are handled as strings
+ // any other type (default case) is handled as a string value
+ case IDENTIFIER:
+ case DATE:
+ case TIME:
+ case CHAR:
+ case VARCHAR:
+ default:
+ builder.append(",\"").append(fieldName).append("\":\"").append(stringValue).append("\"");
+ break;
+ }
}
- // Search for the table
- List<Table> matchedTables = Table.getBaseTables().stream()
- .filter(table -> tableName.equalsIgnoreCase(table.getName())).collect(Collectors.toList());
-
- // Ensure the table was found
- if (matchedTables.size() != 1) {
- throw new RuntimeDataException(ErrorCode.TPCDS_INVALID_TABLE_NAME, getFunctionIdentifier().getName(),
- tableName);
- }
-
- return matchedTables;
- }
-
- /**
- * Gets the function identifier
- *
- * @return function identifier
- */
- private FunctionIdentifier getFunctionIdentifier() {
- return functionIdentifier;
+ builder.append("}");
}
}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.01.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.01.ddl.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.01.ddl.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.01.ddl.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.02.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.02.update.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.02.update.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.02.update.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.03.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.03.query.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.03.query.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.03.query.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.04.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.04.query.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.04.query.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.04.query.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.05.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.05.query.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.05.query.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.05.query.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.06.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.06.query.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.06.query.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.06.query.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.07.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.07.query.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.07.query.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.07.query.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.08.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.08.query.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.08.query.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.08.query.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.09.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.09.ddl.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.09.ddl.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_001/string_fun_001.09.ddl.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_02/fun_return_null_02.01.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_002/string_fun_002.01.query.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_02/fun_return_null_02.01.query.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_002/string_fun_002.01.query.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.01.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.01.ddl.sqlpp
similarity index 100%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.01.ddl.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.01.ddl.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.02.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.02.update.sqlpp
new file mode 100644
index 0000000..c81b5a9
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.02.update.sqlpp
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+use test;
+
+insert into closedDS([
+{"id": 1, "i8": int8("-2"), "i16": int16("10"), "i32": int32("21"), "i64": int64("87"), "f": float("4.2"), "d": double("5.0"), "str1": "foo", "mixed": 7},
+{"id": 2, "i8": int8("0"), "i16": int16("-10"), "i32": int32("21"), "i64": int64("87"), "f": float("4.2"), "d": double("5.3"), "str1": "foo", "mixed": "m"}
+]);
+
+insert into openDS([
+{"id": 1, "i8": int8("-2"), "i16": int16("10"), "i32": int32("21"), "i64": int64("87"), "f": float("4.2"), "d": double("5.0"), "str1": "foo", "mixed": 7},
+{"id": 2, "i8": int8("0"), "i16": int16("-10"), "i32": int32("21"), "i64": int64("87"), "f": float("4.2"), "d": double("5.3"), "str1": "foo", "mixed": "m"}
+]);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.03.query.sqlpp
similarity index 60%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.03.query.sqlpp
index 0701ce3..3c7ebf2 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.03.query.sqlpp
@@ -17,4 +17,22 @@
* under the License.
*/
-SELECT VALUE repeat(" new ", -1);
+/*
+ * Description: tests that string functions do not throw exception on type/data errors
+ */
+// requesttype=application/json
+// param max-warnings:json=1000
+
+use test;
+
+from closedDS as ds
+select
+repeat(ds.str1, ds.i8),
+repeat(ds.str1, ds.d),
+string_join(["str", "str"], ds.mixed),
+replace("hello world he", "he", "be", ds.i8),
+replace("hello world he", "he", "be", ds.d),
+regexp_replace("hello world he", "he", "be", ds.i8),
+regexp_replace("hello world he", "he", "be", ds.d),
+substring(ds.mixed, 0)
+order by ds.id;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.04.query.sqlpp
similarity index 60%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.04.query.sqlpp
index 0701ce3..92747a9 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.04.query.sqlpp
@@ -17,4 +17,22 @@
* under the License.
*/
-SELECT VALUE repeat(" new ", -1);
+/*
+ * Description: tests that string functions do not throw exception on type/data errors
+ */
+// requesttype=application/json
+// param max-warnings:json=1000
+
+use test;
+
+from openDS as ds
+select
+repeat(ds.str1, ds.i8),
+repeat(ds.str1, ds.d),
+string_join(["str", "str"], ds.mixed),
+replace("hello world he", "he", "be", ds.i8),
+replace("hello world he", "he", "be", ds.d),
+regexp_replace("hello world he", "he", "be", ds.i8),
+regexp_replace("hello world he", "he", "be", ds.d),
+substring(ds.mixed, 0)
+order by ds.id;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.05.query.sqlpp
similarity index 62%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.05.query.sqlpp
index 0701ce3..f1867fc 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.05.query.sqlpp
@@ -17,4 +17,18 @@
* under the License.
*/
-SELECT VALUE repeat(" new ", -1);
+/*
+ * Description: tests that string functions do not throw exception on type/data errors
+ */
+// requesttype=application/json
+// param max-warnings:json=1000
+
+use test;
+
+select
+repeat("str", double("INF")),
+replace("hello world he", "he", "be", double("-INF")),
+replace("hello world he", "he", "be", double("NaN")),
+regexp_replace("hello world he", "he", "be", double("NaN")),
+regexp_replace("hello world he", "he", "be", double("-INF")),
+substring("hello world", double("INF"));
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.09.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.06.ddl.sqlpp
similarity index 100%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.09.ddl.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/string_fun/string_fun_003/string_fun_003.06.ddl.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/tpcds/datagen_sf_1_all_tables_2/datagen_sf_1_all_tables_2.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/tpcds/datagen_sf_1_all_tables_2/datagen_sf_1_all_tables_2.1.query.sqlpp
index 303c1c7..99151b8 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/tpcds/datagen_sf_1_all_tables_2/datagen_sf_1_all_tables_2.1.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/tpcds/datagen_sf_1_all_tables_2/datagen_sf_1_all_tables_2.1.query.sqlpp
@@ -19,7 +19,7 @@
set `import-private-functions` `true`;
-select d.tableName, count(*) as count
+select d.table_name, count(*) as count
from tpcds_datagen(1) as d
-group by d.tableName
-order by d.tableName;
\ No newline at end of file
+group by d.table_name
+order by d.table_name;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.03.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.03.adm
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.03.adm
rename to asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.03.adm
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.04.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.04.adm
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.04.adm
rename to asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.04.adm
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.05.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.05.adm
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.05.adm
rename to asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.05.adm
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.06.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.06.adm
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.06.adm
rename to asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.06.adm
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.07.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.07.adm
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.07.adm
rename to asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.07.adm
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.08.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.08.adm
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_01/fun_return_null_01.08.adm
rename to asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_001/string_fun_001.08.adm
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_02/fun_return_null_02.01.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_002/string_fun_002.01.adm
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/fun_return_null_02/fun_return_null_02.01.adm
rename to asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_002/string_fun_002.01.adm
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_003/string_fun_003.01.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_003/string_fun_003.01.adm
new file mode 100644
index 0000000..382af83
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_003/string_fun_003.01.adm
@@ -0,0 +1,2 @@
+{ "$1": null, "$2": "foofoofoofoofoo", "$3": null, "$4": "bello world be", "$5": "bello world be", "$6": "bello world be", "$7": "bello world be", "$8": null }
+{ "$1": "", "$2": null, "$3": "strmstr", "$4": "hello world he", "$5": null, "$6": "hello world he", "$7": null, "$8": "m" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_003/string_fun_003.02.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_003/string_fun_003.02.adm
new file mode 100644
index 0000000..382af83
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_003/string_fun_003.02.adm
@@ -0,0 +1,2 @@
+{ "$1": null, "$2": "foofoofoofoofoo", "$3": null, "$4": "bello world be", "$5": "bello world be", "$6": "bello world be", "$7": "bello world be", "$8": null }
+{ "$1": "", "$2": null, "$3": "strmstr", "$4": "hello world he", "$5": null, "$6": "hello world he", "$7": null, "$8": "m" }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_003/string_fun_003.03.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_003/string_fun_003.03.adm
new file mode 100644
index 0000000..c89e546
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fun_return_null/string_fun/string_fun_003/string_fun_003.03.adm
@@ -0,0 +1 @@
+{ "$1": null, "$2": null, "$3": null, "$4": null, "$5": null, "$6": null }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/tpcds/datagen_sf_1_all_tables_2/datagen_sf_1_all_tables_2.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/tpcds/datagen_sf_1_all_tables_2/datagen_sf_1_all_tables_2.1.adm
index 4040b6b..b01e2cc 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/tpcds/datagen_sf_1_all_tables_2/datagen_sf_1_all_tables_2.1.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/tpcds/datagen_sf_1_all_tables_2/datagen_sf_1_all_tables_2.1.adm
@@ -1,24 +1,24 @@
-{ "count": 6, "tableName": "CALL_CENTER" }
-{ "count": 11718, "tableName": "CATALOG_PAGE" }
-{ "count": 144067, "tableName": "CATALOG_RETURNS" }
-{ "count": 1441548, "tableName": "CATALOG_SALES" }
-{ "count": 100000, "tableName": "CUSTOMER" }
-{ "count": 50000, "tableName": "CUSTOMER_ADDRESS" }
-{ "count": 1920800, "tableName": "CUSTOMER_DEMOGRAPHICS" }
-{ "count": 73049, "tableName": "DATE_DIM" }
-{ "count": 7200, "tableName": "HOUSEHOLD_DEMOGRAPHICS" }
-{ "count": 20, "tableName": "INCOME_BAND" }
-{ "count": 11745000, "tableName": "INVENTORY" }
-{ "count": 18000, "tableName": "ITEM" }
-{ "count": 300, "tableName": "PROMOTION" }
-{ "count": 35, "tableName": "REASON" }
-{ "count": 20, "tableName": "SHIP_MODE" }
-{ "count": 12, "tableName": "STORE" }
-{ "count": 287514, "tableName": "STORE_RETURNS" }
-{ "count": 2880404, "tableName": "STORE_SALES" }
-{ "count": 86400, "tableName": "TIME_DIM" }
-{ "count": 5, "tableName": "WAREHOUSE" }
-{ "count": 60, "tableName": "WEB_PAGE" }
-{ "count": 71763, "tableName": "WEB_RETURNS" }
-{ "count": 719384, "tableName": "WEB_SALES" }
-{ "count": 30, "tableName": "WEB_SITE" }
\ No newline at end of file
+{ "count": 6, "table_name": "call_center" }
+{ "count": 11718, "table_name": "catalog_page" }
+{ "count": 144067, "table_name": "catalog_returns" }
+{ "count": 1441548, "table_name": "catalog_sales" }
+{ "count": 100000, "table_name": "customer" }
+{ "count": 50000, "table_name": "customer_address" }
+{ "count": 1920800, "table_name": "customer_demographics" }
+{ "count": 73049, "table_name": "date_dim" }
+{ "count": 7200, "table_name": "household_demographics" }
+{ "count": 20, "table_name": "income_band" }
+{ "count": 11745000, "table_name": "inventory" }
+{ "count": 18000, "table_name": "item" }
+{ "count": 300, "table_name": "promotion" }
+{ "count": 35, "table_name": "reason" }
+{ "count": 20, "table_name": "ship_mode" }
+{ "count": 12, "table_name": "store" }
+{ "count": 287514, "table_name": "store_returns" }
+{ "count": 2880404, "table_name": "store_sales" }
+{ "count": 86400, "table_name": "time_dim" }
+{ "count": 5, "table_name": "warehouse" }
+{ "count": 60, "table_name": "web_page" }
+{ "count": 71763, "table_name": "web_returns" }
+{ "count": 719384, "table_name": "web_sales" }
+{ "count": 30, "table_name": "web_site" }
\ 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 1ca022a..abbb411 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -8722,12 +8722,6 @@
</compilation-unit>
</test-case>
<test-case FilePath="string">
- <compilation-unit name="repeat_error">
- <output-dir compare="Text">repeat</output-dir>
- <expected-error>Invalid value: function repeat expects its 1 input parameter to be a non-negative value, but gets -1</expected-error>
- </compilation-unit>
- </test-case>
- <test-case FilePath="string">
<compilation-unit name="replace">
<output-dir compare="Text">replace</output-dir>
</compilation-unit>
@@ -12513,10 +12507,10 @@
</compilation-unit>
</test-case>
</test-group>
- <test-group name="fun_return_null">
- <test-case FilePath="fun_return_null" check-warnings="true">
- <compilation-unit name="fun_return_null_01">
- <output-dir compare="Text">fun_return_null_01</output-dir>
+ <test-group name="fun_return_null/string_fun">
+ <test-case FilePath="fun_return_null/string_fun" check-warnings="true">
+ <compilation-unit name="string_fun_001">
+ <output-dir compare="Text">string_fun_001</output-dir>
<expected-warn>Type mismatch: function trim expects its 1st input parameter to be of type string, but the actual input type is bigint (in line 41, at column 1)</expected-warn>
<expected-warn>Type mismatch: function like expects its 2nd input parameter to be of type string, but the actual input type is tinyint (in line 32, at column 1)</expected-warn>
<expected-warn>Type mismatch: function uppercase expects its 1st input parameter to be of type string, but the actual input type is smallint (in line 38, at column 1)</expected-warn>
@@ -12614,9 +12608,9 @@
<expected-warn>Type mismatch: function ends-with expects its 1st input parameter to be of type string, but the actual input type is bigint (in line 33, at column 1)</expected-warn>
</compilation-unit>
</test-case>
- <test-case FilePath="fun_return_null" check-warnings="true">
- <compilation-unit name="fun_return_null_02">
- <output-dir compare="Text">fun_return_null_02</output-dir>
+ <test-case FilePath="fun_return_null/string_fun" check-warnings="true">
+ <compilation-unit name="string_fun_002">
+ <output-dir compare="Text">string_fun_002</output-dir>
<expected-warn>Type mismatch: function rtrim expects its 1st input parameter to be of type string, but the actual input type is bigint (in line 42, at column 1)</expected-warn>
<expected-warn>Type mismatch: function regexp-replace expects its 2nd input parameter to be of type string, but the actual input type is bigint (in line 52, at column 1)</expected-warn>
<expected-warn>Type mismatch: function regexp-like expects its 1st input parameter to be of type string, but the actual input type is bigint (in line 48, at column 1)</expected-warn>
@@ -12649,5 +12643,30 @@
<expected-warn>Type mismatch: function regexp-position expects its 1st input parameter to be of type string, but the actual input type is integer (in line 50, at column 1)</expected-warn>
</compilation-unit>
</test-case>
+ <test-case FilePath="fun_return_null/string_fun" check-warnings="true">
+ <compilation-unit name="string_fun_003">
+ <output-dir compare="Text">string_fun_003</output-dir>
+ <expected-warn>Invalid value: function repeat expects its 2nd input parameter to be an integer value, got 5.3 (in line 31, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function regexp-replace expects its 4th input parameter to be an integer value, got 5.3 (in line 36, at column 1)</expected-warn>
+ <expected-warn>Type mismatch: function substring expects its 1st input parameter to be of type string, but the actual input type is bigint (in line 37, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function replace expects its 4th input parameter to be an integer value, got 5.3 (in line 34, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function repeat expects its 2nd input parameter to be a non-negative value, got -2.0 (in line 30, at column 1)</expected-warn>
+ <expected-warn>Type mismatch: function string-join expects its 2nd input parameter to be of type string, but the actual input type is bigint (in line 32, at column 1)</expected-warn>
+
+ <expected-warn>Invalid value: function repeat expects its 2nd input parameter to be an integer value, got 5.3 (in line 31, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function regexp-replace expects its 4th input parameter to be an integer value, got 5.3 (in line 36, at column 1)</expected-warn>
+ <expected-warn>Type mismatch: function substring expects its 1st input parameter to be of type string, but the actual input type is bigint (in line 37, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function replace expects its 4th input parameter to be an integer value, got 5.3 (in line 34, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function repeat expects its 2nd input parameter to be a non-negative value, got -2.0 (in line 30, at column 1)</expected-warn>
+ <expected-warn>Type mismatch: function string-join expects its 2nd input parameter to be of type string, but the actual input type is bigint (in line 32, at column 1)</expected-warn>
+
+ <expected-warn>Invalid value: function repeat expects its 2nd input parameter to be an integer value, got Infinity (in line 29, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function replace expects its 4th input parameter to be an integer value, got -Infinity (in line 30, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function replace expects its 4th input parameter to be an integer value, got NaN (in line 31, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function regexp-replace expects its 4th input parameter to be an integer value, got NaN (in line 32, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function regexp-replace expects its 4th input parameter to be an integer value, got -Infinity (in line 33, at column 1)</expected-warn>
+ <expected-warn>Invalid value: function substring expects its 2nd input parameter to be an integer value, got Infinity (in line 34, at column 1)</expected-warn>
+ </compilation-unit>
+ </test-case>
</test-group>
</test-suite>
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 8803214..609e3a6 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
@@ -77,6 +77,7 @@
public static final int TPCDS_INVALID_TABLE_NAME = 42;
public static final int VALUE_OUT_OF_RANGE = 43;
public static final int PROHIBITED_STATEMENT_CATEGORY = 44;
+ public static final int INTEGER_VALUE_EXPECTED_FUNCTION = 45;
public static final int UNSUPPORTED_JRE = 100;
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 cb48e19..661a220 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -47,7 +47,7 @@
7 = Overflow in %1$s
8 = Underflow in %1$s
9 = Injected failure in %1$s
-10 = Invalid value: function %1$s expects its %2$s input parameter to be a non-negative value, but gets %3$s
+10 = Invalid value: function %1$s expects its %2$s input parameter to be a non-negative value, got %3$s
11 = Index out of bound in %1$s: %2$s
12 = Invalid implicit scalar to collection coercion in %1$s
14 = Property %1$s not set
@@ -79,6 +79,7 @@
42 = %1$s: \"%2$s\" is not a TPC-DS table name
43 = Value out of range, function %1$s expects its %2$s input parameter value to be between %3$s and %4$s, received %5$s
44 = %1$s statement is prohibited by this request
+45 = Invalid value: function %1$s expects its %2$s input parameter to be an integer value, got %3$s
100 = Unsupported JRE: %1$s
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/exceptions/ExceptionUtil.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/exceptions/ExceptionUtil.java
index 0791576..b5d599b 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/exceptions/ExceptionUtil.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/exceptions/ExceptionUtil.java
@@ -19,6 +19,8 @@
package org.apache.asterix.om.exceptions;
+import java.util.function.Supplier;
+
import org.apache.asterix.common.exceptions.ErrorCode;
import org.apache.asterix.common.exceptions.WarningUtil;
import org.apache.asterix.om.types.ATypeTag;
@@ -28,12 +30,12 @@
import org.apache.hyracks.api.exceptions.IWarningCollector;
import org.apache.hyracks.api.exceptions.SourceLocation;
-public class ExceptionUtil {
+public final class ExceptionUtil {
private ExceptionUtil() {
}
- public static String toExpectedTypeString(Object... expectedItems) {
+ public static String toExpectedTypeString(Object[] expectedItems) {
StringBuilder expectedTypes = new StringBuilder();
int numCandidateTypes = expectedItems.length;
for (int index = 0; index < numCandidateTypes; ++index) {
@@ -49,7 +51,7 @@
return expectedTypes.toString();
}
- public static String toExpectedTypeString(byte... expectedTypeTags) {
+ public static String toExpectedTypeString(byte[] expectedTypeTags) {
StringBuilder expectedTypes = new StringBuilder();
int numCandidateTypes = expectedTypeTags.length;
for (int index = 0; index < numCandidateTypes; ++index) {
@@ -88,20 +90,20 @@
public static void warnTypeMismatch(IEvaluatorContext ctx, SourceLocation srcLoc, FunctionIdentifier fid,
byte actualType, int argIdx, ATypeTag expectedType) {
- IWarningCollector warningCollector = ctx.getWarningCollector();
- if (warningCollector.shouldWarn()) {
- warningCollector.warn(WarningUtil.forAsterix(srcLoc, ErrorCode.TYPE_MISMATCH_FUNCTION, fid.getName(),
- indexToPosition(argIdx), expectedType,
- EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(actualType)));
- }
+ warnTypeMismatch(ctx, srcLoc, fid, actualType, argIdx, expectedType::toString);
}
public static void warnTypeMismatch(IEvaluatorContext ctx, SourceLocation srcLoc, FunctionIdentifier fid,
- byte actualType, int argIdx, byte... expectedTypes) {
+ byte actualType, int argIdx, byte[] expectedTypes) {
+ warnTypeMismatch(ctx, srcLoc, fid, actualType, argIdx, () -> toExpectedTypeString(expectedTypes));
+ }
+
+ private static void warnTypeMismatch(IEvaluatorContext ctx, SourceLocation srcLoc, FunctionIdentifier fid,
+ byte actualType, int argIdx, Supplier<String> expectedTypesString) {
IWarningCollector warningCollector = ctx.getWarningCollector();
if (warningCollector.shouldWarn()) {
warningCollector.warn(WarningUtil.forAsterix(srcLoc, ErrorCode.TYPE_MISMATCH_FUNCTION, fid.getName(),
- indexToPosition(argIdx), toExpectedTypeString(expectedTypes),
+ indexToPosition(argIdx), expectedTypesString.get(),
EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(actualType)));
}
}
@@ -121,4 +123,24 @@
warningCollector.warn(WarningUtil.forAsterix(srcLoc, ErrorCode.TYPE_UNSUPPORTED, funName, unsupportedType));
}
}
+
+ /** For functions that accept an integer value (no fractions) of any numeric type including double & float */
+ public static void warnNonInteger(IEvaluatorContext ctx, SourceLocation srcLoc, FunctionIdentifier fid, int argIdx,
+ double argValue) {
+ warnInvalidValue(ctx, srcLoc, fid, argIdx, argValue, ErrorCode.INTEGER_VALUE_EXPECTED_FUNCTION);
+ }
+
+ public static void warnNegativeValue(IEvaluatorContext ctx, SourceLocation srcLoc, FunctionIdentifier fid,
+ int argIdx, double argValue) {
+ warnInvalidValue(ctx, srcLoc, fid, argIdx, argValue, ErrorCode.NEGATIVE_VALUE);
+ }
+
+ private static void warnInvalidValue(IEvaluatorContext ctx, SourceLocation srcLoc, FunctionIdentifier fid,
+ int argIdx, double argValue, int errorCode) {
+ IWarningCollector warningCollector = ctx.getWarningCollector();
+ if (warningCollector.shouldWarn()) {
+ warningCollector.warn(WarningUtil.forAsterix(srcLoc, errorCode, fid.getName(), indexToPosition(argIdx),
+ Double.toString(argValue)));
+ }
+ }
}
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 eba5100..5f42dfb 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
@@ -126,7 +126,7 @@
import org.apache.asterix.om.typecomputer.impl.SleepTypeComputer;
import org.apache.asterix.om.typecomputer.impl.StringBooleanTypeComputer;
import org.apache.asterix.om.typecomputer.impl.StringInt32TypeComputer;
-import org.apache.asterix.om.typecomputer.impl.StringIntToStringTypeComputer;
+import org.apache.asterix.om.typecomputer.impl.StringJoinTypeComputer;
import org.apache.asterix.om.typecomputer.impl.StringStringTypeComputer;
import org.apache.asterix.om.typecomputer.impl.StringToInt64ListTypeComputer;
import org.apache.asterix.om.typecomputer.impl.StringToStringListTypeComputer;
@@ -1703,7 +1703,8 @@
addFunction(STRING_TO_CODEPOINT, StringToInt64ListTypeComputer.INSTANCE, true);
addFunction(CODEPOINT_TO_STRING, AStringTypeComputer.INSTANCE, true); // TODO
addFunction(STRING_CONCAT, ConcatTypeComputer.INSTANCE_STRING, true); // TODO
- addFunction(SUBSTRING2, StringIntToStringTypeComputer.INSTANCE_NULLABLE, true); // TODO
+ addFunction(SUBSTRING, SubstringTypeComputer.INSTANCE, true); // TODO
+ addFunction(SUBSTRING2, AStringTypeComputer.INSTANCE_NULLABLE, true);
addFunction(STRING_LENGTH, UnaryStringInt64TypeComputer.INSTANCE, true);
addFunction(STRING_LOWERCASE, StringStringTypeComputer.INSTANCE, true);
addFunction(STRING_UPPERCASE, StringStringTypeComputer.INSTANCE, true);
@@ -1724,16 +1725,15 @@
addFunction(STRING_REGEXP_POSITION, StringInt32TypeComputer.INSTANCE, true);
addFunction(STRING_REGEXP_POSITION_WITH_FLAG, StringInt32TypeComputer.INSTANCE, true);
addFunction(STRING_REGEXP_REPLACE, StringStringTypeComputer.INSTANCE, true);
- addFunction(STRING_REGEXP_REPLACE_WITH_FLAG,
- StringIntToStringTypeComputer.INSTANCE_STRING_REGEXP_REPLACE_WITH_FLAG, true); // TODO
+ addFunction(STRING_REGEXP_REPLACE_WITH_FLAG, AStringTypeComputer.INSTANCE_NULLABLE, true);
addFunction(STRING_REPLACE, StringStringTypeComputer.INSTANCE, true);
- addFunction(STRING_REPLACE_WITH_LIMIT, StringIntToStringTypeComputer.INSTANCE_TRIPLE_STRING, true); // TODO
+ addFunction(STRING_REPLACE_WITH_LIMIT, AStringTypeComputer.INSTANCE_NULLABLE, true);
addFunction(STRING_REVERSE, StringStringTypeComputer.INSTANCE, true);
addFunction(SUBSTRING_BEFORE, StringStringTypeComputer.INSTANCE, true);
addFunction(SUBSTRING_AFTER, StringStringTypeComputer.INSTANCE, true);
addPrivateFunction(STRING_EQUAL, StringBooleanTypeComputer.INSTANCE, true);
- addFunction(STRING_JOIN, AStringTypeComputer.INSTANCE, true); // TODO
- addFunction(STRING_REPEAT, StringIntToStringTypeComputer.INSTANCE, true); // TODO
+ addFunction(STRING_JOIN, StringJoinTypeComputer.INSTANCE, true);
+ addFunction(STRING_REPEAT, AStringTypeComputer.INSTANCE_NULLABLE, true);
addFunction(STRING_SPLIT, StringToStringListTypeComputer.INSTANCE, true);
addPrivateFunction(ORDERED_LIST_CONSTRUCTOR, OrderedListConstructorTypeComputer.INSTANCE, true);
@@ -2147,7 +2147,6 @@
addFunction(BINARY_BASE64_CONSTRUCTOR, ABinaryTypeComputer.INSTANCE, true);
addPrivateFunction(SUBSET_COLLECTION, SubsetCollectionTypeComputer.INSTANCE, true);
- addFunction(SUBSTRING, SubstringTypeComputer.INSTANCE, true);
addFunction(SWITCH_CASE, SwitchCaseComputer.INSTANCE, true);
addFunction(SLEEP, SleepTypeComputer.INSTANCE, false);
addPrivateFunction(INJECT_FAILURE, InjectFailureTypeComputer.INSTANCE, true);
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AStringTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AStringTypeComputer.java
index 3537fb7..4de96b8 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AStringTypeComputer.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AStringTypeComputer.java
@@ -19,6 +19,7 @@
package org.apache.asterix.om.typecomputer.impl;
import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer;
+import org.apache.asterix.om.types.AUnionType;
import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.om.types.IAType;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -26,14 +27,17 @@
public class AStringTypeComputer extends AbstractResultTypeComputer {
- public static final AStringTypeComputer INSTANCE = new AStringTypeComputer();
+ public static final AStringTypeComputer INSTANCE = new AStringTypeComputer(false);
+ public static final AStringTypeComputer INSTANCE_NULLABLE = new AStringTypeComputer(true);
- private AStringTypeComputer() {
+ private final boolean nullable;
+
+ private AStringTypeComputer(boolean nullable) {
+ this.nullable = nullable;
}
@Override
protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
- return BuiltinType.ASTRING;
+ return nullable ? AUnionType.createNullableType(BuiltinType.ASTRING) : BuiltinType.ASTRING;
}
-
}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractStringTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractStringTypeComputer.java
index d888958..ba7fc65 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractStringTypeComputer.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractStringTypeComputer.java
@@ -23,9 +23,12 @@
import org.apache.asterix.om.types.AUnionType;
import org.apache.asterix.om.types.IAType;
-abstract public class AbstractStringTypeComputer extends AbstractResultTypeComputer {
+/**
+ * For function signature: nullable_return_type fun(string...)
+ */
+public abstract class AbstractStringTypeComputer extends AbstractResultTypeComputer {
- protected IAType getType(IAType returnType, IAType... argsTypes) {
+ protected static IAType getType(IAType returnType, IAType... argsTypes) {
// all args are expected to be strings. If any arg is not string (ANY or mismatched-type), return nullable
for (IAType actualType : argsTypes) {
if (actualType.getTypeTag() != ATypeTag.STRING) {
@@ -34,11 +37,4 @@
}
return returnType;
}
-
- protected IAType getType(IAType returnType, IAType argType) {
- if (argType.getTypeTag() != ATypeTag.STRING) {
- return AUnionType.createNullableType(returnType);
- }
- return returnType;
- }
}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/StringIntToStringTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/StringIntToStringTypeComputer.java
deleted file mode 100644
index 4499e31..0000000
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/StringIntToStringTypeComputer.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.om.typecomputer.impl;
-
-import java.util.EnumSet;
-import java.util.Set;
-
-import org.apache.asterix.om.exceptions.TypeMismatchException;
-import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer;
-import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.AUnionType;
-import org.apache.asterix.om.types.BuiltinType;
-import org.apache.asterix.om.types.IAType;
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
-import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
-import org.apache.hyracks.api.exceptions.SourceLocation;
-
-public class StringIntToStringTypeComputer extends AbstractResultTypeComputer {
- public static final StringIntToStringTypeComputer INSTANCE = new StringIntToStringTypeComputer(0, 0, 1, 1, false);
-
- public static final StringIntToStringTypeComputer INSTANCE_NULLABLE =
- new StringIntToStringTypeComputer(0, 0, 1, 1, true);
-
- public static final StringIntToStringTypeComputer INSTANCE_TRIPLE_STRING =
- new StringIntToStringTypeComputer(0, 2, 3, 3, false);
-
- public static final StringIntToStringTypeComputer INSTANCE_STRING_REGEXP_REPLACE_WITH_FLAG =
- new StringIntToStringTypeComputer(0, 3, 3, 3, false);
-
- private final int stringArgIdxMin;
-
- private final int stringArgIdxMax;
-
- private final int intArgIdxMin;
-
- private final int intArgIdxMax;
-
- private final boolean nullable;
-
- public StringIntToStringTypeComputer(int stringArgIdxMin, int stringArgIdxMax, int intArgIdxMin, int intArgIdxMax,
- boolean nullable) {
- this.stringArgIdxMin = stringArgIdxMin;
- this.stringArgIdxMax = stringArgIdxMax;
- this.intArgIdxMin = intArgIdxMin;
- this.intArgIdxMax = intArgIdxMax;
- this.nullable = nullable;
- }
-
- @Override
- public void checkArgType(FunctionIdentifier funcId, int argIndex, IAType type, SourceLocation sourceLoc)
- throws AlgebricksException {
- ATypeTag tag = type.getTypeTag();
- boolean expectedStringType = false;
- if (stringArgIdxMin <= argIndex && argIndex <= stringArgIdxMax) {
- if (tag == ATypeTag.STRING) {
- return;
- }
- expectedStringType = true;
- }
-
- boolean expectedIntType = false;
- if (intArgIdxMin <= argIndex && argIndex <= intArgIdxMax) {
- switch (tag) {
- case TINYINT:
- case SMALLINT:
- case INTEGER:
- case BIGINT:
- return;
- }
- expectedIntType = true;
- }
-
- throw new TypeMismatchException(sourceLoc, funcId, argIndex, tag,
- getExpectedTypes(expectedStringType, expectedIntType));
- }
-
- @Override
- public IAType getResultType(ILogicalExpression expr, IAType... types) throws AlgebricksException {
- IAType resultType = BuiltinType.ASTRING;
- if (nullable) {
- resultType = AUnionType.createNullableType(resultType);
- }
- return resultType;
- }
-
- private ATypeTag[] getExpectedTypes(boolean expectedStringType, boolean expectedIntType) {
- Set<ATypeTag> expectedTypes = EnumSet.noneOf(ATypeTag.class);
- if (expectedStringType) {
- expectedTypes.add(ATypeTag.STRING);
- }
- if (expectedIntType) {
- expectedTypes.add(ATypeTag.TINYINT);
- expectedTypes.add(ATypeTag.SMALLINT);
- expectedTypes.add(ATypeTag.INTEGER);
- expectedTypes.add(ATypeTag.BIGINT);
- }
- return expectedTypes.toArray(new ATypeTag[0]);
- }
-}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/StringJoinTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/StringJoinTypeComputer.java
new file mode 100644
index 0000000..407a991
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/StringJoinTypeComputer.java
@@ -0,0 +1,52 @@
+/*
+ * 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.om.typecomputer.impl;
+
+import static org.apache.asterix.om.types.BuiltinType.ASTRING;
+
+import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.AbstractCollectionType;
+import org.apache.asterix.om.types.IAType;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+
+/**
+ * For function signature: nullable_string fun([string], string)
+ */
+public class StringJoinTypeComputer extends AbstractResultTypeComputer {
+
+ public static final StringJoinTypeComputer INSTANCE = new StringJoinTypeComputer();
+
+ private StringJoinTypeComputer() {
+ }
+
+ @Override
+ protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
+ return validArgs(strippedInputTypes) ? ASTRING : AUnionType.createNullableType(ASTRING);
+ }
+
+ private static boolean validArgs(IAType... strippedInputTypes) {
+ IAType firstArg = strippedInputTypes[0];
+ return firstArg.getTypeTag().isListType()
+ && ((AbstractCollectionType) firstArg).getItemType().getTypeTag() == ATypeTag.STRING
+ && strippedInputTypes[1].getTypeTag() == ATypeTag.STRING;
+ }
+}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/UnaryStringInt64TypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/UnaryStringInt64TypeComputer.java
index 37c2230..13079e2 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/UnaryStringInt64TypeComputer.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/UnaryStringInt64TypeComputer.java
@@ -35,6 +35,6 @@
@Override
public IAType getResultType(ILogicalExpression expr, IAType... types) throws AlgebricksException {
- return getType(BuiltinType.AINT64, types[0]);
+ return getType(BuiltinType.AINT64, types);
}
}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/DoubleToInt32TypeConvertComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/DoubleToInt32TypeConvertComputer.java
index 8bd9f3e..5653731 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/DoubleToInt32TypeConvertComputer.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/hierachy/DoubleToInt32TypeConvertComputer.java
@@ -66,7 +66,7 @@
return new AInt32(targetValue);
}
- private int convert(double sourceValue) throws HyracksDataException {
+ public int convert(double sourceValue) throws HyracksDataException {
// Boundary check
if (Double.isNaN(sourceValue)) {
if (strict) {
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/aggregates/std/AbstractMinMaxAggregateFunction.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/aggregates/std/AbstractMinMaxAggregateFunction.java
index 022e0f5..534d10a 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/aggregates/std/AbstractMinMaxAggregateFunction.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/aggregates/std/AbstractMinMaxAggregateFunction.java
@@ -43,7 +43,7 @@
import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
public abstract class AbstractMinMaxAggregateFunction extends AbstractAggregateFunction {
- private final String FUN_NAME = "min/max";
+ private static final String FUN_NAME = "min/max";
private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
private final IPointable inputVal = new VoidPointable();
private final ArrayBackedValueStorage outputVal = new ArrayBackedValueStorage();
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/ArgumentUtils.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/ArgumentUtils.java
new file mode 100644
index 0000000..7c27e0e
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/ArgumentUtils.java
@@ -0,0 +1,76 @@
+/*
+ * 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.common;
+
+import static org.apache.asterix.om.types.ATypeTag.VALUE_TYPE_MAPPING;
+
+import org.apache.asterix.om.base.AMutableInt32;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
+import org.apache.asterix.om.types.hierachy.DoubleToInt32TypeConvertComputer;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+
+import com.google.common.math.DoubleMath;
+
+/**
+ * Utility methods for argument handling
+ */
+public final class ArgumentUtils {
+
+ public static final byte[] EXPECTED_NUMERIC = { ATypeTag.SERIALIZED_INT8_TYPE_TAG,
+ ATypeTag.SERIALIZED_INT16_TYPE_TAG, ATypeTag.SERIALIZED_INT32_TYPE_TAG, ATypeTag.SERIALIZED_INT64_TYPE_TAG,
+ ATypeTag.SERIALIZED_FLOAT_TYPE_TAG, ATypeTag.SERIALIZED_DOUBLE_TYPE_TAG };
+ private static final DoubleToInt32TypeConvertComputer LAX_DOUBLE_TO_INT32 =
+ DoubleToInt32TypeConvertComputer.getInstance(false);
+
+ private ArgumentUtils() {
+ }
+
+ /**
+ * Checks that {@code value} is of numeric type and a finite mathematical integer (i.e. no fractions) returning
+ * true if it is and storing the integer value in {@code outInteger}. Otherwise, returns false and issues a
+ * warning. If the integer value of {@code value} cannot fit in an int32, then {@link Integer#MAX_VALUE} or
+ * {@link Integer#MIN_VALUE} is stored.
+ *
+ * @param value data to be checked
+ * @param outInteger where the integer read from {@code value} will be stored
+ */
+ public static boolean checkWarnOrSetInteger(IEvaluatorContext ctx, SourceLocation sourceLoc,
+ FunctionIdentifier funcID, int argIdx, byte[] value, int offset, AMutableInt32 outInteger)
+ throws HyracksDataException {
+ byte type = value[offset];
+ if (ATypeHierarchy.getTypeDomain(VALUE_TYPE_MAPPING[type]) != ATypeHierarchy.Domain.NUMERIC) {
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funcID, type, argIdx, EXPECTED_NUMERIC);
+ return false;
+ }
+ // deal with NaN, +/-INF
+ double doubleValue = ATypeHierarchy.getDoubleValue(funcID.getName(), argIdx, value, offset);
+ if (!DoubleMath.isMathematicalInteger(doubleValue)) {
+ ExceptionUtil.warnNonInteger(ctx, sourceLoc, funcID, argIdx, doubleValue);
+ return false;
+ }
+ outInteger.setValue(LAX_DOUBLE_TO_INT32.convert(doubleValue));
+ return true;
+ }
+}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractQuadStringStringEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractQuadStringStringEval.java
index 17db0fe..ba17616 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractQuadStringStringEval.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractQuadStringStringEval.java
@@ -27,9 +27,9 @@
import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
import org.apache.asterix.om.base.AMutableString;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.BuiltinType;
-import org.apache.asterix.runtime.exceptions.TypeMismatchException;
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;
@@ -64,6 +64,7 @@
private ISerializerDeserializer strSerde =
SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ASTRING);
+ private final IEvaluatorContext ctx;
private final UTF8StringPointable strPtr0 = new UTF8StringPointable();
private final UTF8StringPointable strPtr1 = new UTF8StringPointable();
private final UTF8StringPointable strPtr2 = new UTF8StringPointable();
@@ -72,6 +73,7 @@
public AbstractQuadStringStringEval(IEvaluatorContext context, IScalarEvaluatorFactory eval0,
IScalarEvaluatorFactory eval1, IScalarEvaluatorFactory eval2, IScalarEvaluatorFactory eval3,
FunctionIdentifier funcID, SourceLocation sourceLoc) throws HyracksDataException {
+ this.ctx = context;
this.eval0 = eval0.createScalarEvaluator(context);
this.eval1 = eval1.createScalarEvaluator(context);
this.eval2 = eval2.createScalarEvaluator(context);
@@ -92,10 +94,11 @@
return;
}
- processArgument(0, ptr0, strPtr0);
- processArgument(1, ptr1, strPtr1);
- processArgument(2, ptr2, strPtr2);
- processArgument(3, ptr3, strPtr3);
+ if (!processArgument(0, ptr0, strPtr0) || !processArgument(1, ptr1, strPtr1)
+ || !processArgument(2, ptr2, strPtr2) || !processArgument(3, ptr3, strPtr3)) {
+ PointableHelper.setNull(result);
+ return;
+ }
resultStorage.reset();
try {
@@ -108,17 +111,18 @@
result.set(resultStorage);
}
- protected void processArgument(int argIdx, IPointable argPtr, UTF8StringPointable outStrPtr)
+ protected boolean processArgument(int argIdx, IPointable argPtr, UTF8StringPointable outStrPtr)
throws HyracksDataException {
byte[] bytes = argPtr.getByteArray();
int start = argPtr.getStartOffset();
// Type check.
if (bytes[start] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, funcID, argIdx, bytes[start],
- ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funcID, bytes[start], argIdx, ATypeTag.STRING);
+ return false;
}
int len = argPtr.getLength();
outStrPtr.set(bytes, start + 1, len);
+ return true;
}
protected abstract String compute(UTF8StringPointable strPtr1st, UTF8StringPointable strPtr2nd,
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractStringStringStringIntEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractStringStringStringIntEval.java
index ea282d9..4aae469 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractStringStringStringIntEval.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractStringStringStringIntEval.java
@@ -21,9 +21,10 @@
import java.io.DataOutput;
+import org.apache.asterix.om.base.AMutableInt32;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
-import org.apache.asterix.runtime.exceptions.TypeMismatchException;
+import org.apache.asterix.runtime.evaluators.common.ArgumentUtils;
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;
@@ -37,11 +38,13 @@
import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
public abstract class AbstractStringStringStringIntEval implements IScalarEvaluator {
+
+ private final IEvaluatorContext ctx;
// Argument evaluators.
- private IScalarEvaluator eval0;
- private IScalarEvaluator eval1;
- private IScalarEvaluator eval2;
- private IScalarEvaluator eval3;
+ private final IScalarEvaluator eval0;
+ private final IScalarEvaluator eval1;
+ private final IScalarEvaluator eval2;
+ private final IScalarEvaluator eval3;
// Argument pointables.
final IPointable argPtrFirst = new VoidPointable();
@@ -51,6 +54,7 @@
private final UTF8StringPointable strPtr1st = new UTF8StringPointable();
private final UTF8StringPointable strPtr2nd = new UTF8StringPointable();
private final UTF8StringPointable strPtr3rd = new UTF8StringPointable();
+ private final AMutableInt32 mutableInt = new AMutableInt32(0);
// For outputting results.
ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
@@ -63,6 +67,7 @@
AbstractStringStringStringIntEval(IEvaluatorContext context, IScalarEvaluatorFactory eval0,
IScalarEvaluatorFactory eval1, IScalarEvaluatorFactory eval2, IScalarEvaluatorFactory eval3,
FunctionIdentifier funcID, SourceLocation sourceLoc) throws HyracksDataException {
+ this.ctx = context;
this.sourceLoc = sourceLoc;
this.eval0 = eval0.createScalarEvaluator(context);
this.eval1 = eval1.createScalarEvaluator(context);
@@ -100,30 +105,21 @@
int start3 = argPtrFourth.getStartOffset();
// Type check.
- if (bytes0[start0] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, funcID, 0, bytes0[start0], ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+ if (!checkStringsAndWarn(bytes0[start0], bytes1[start1], bytes2[start2])) {
+ PointableHelper.setNull(result);
+ return;
}
- if (bytes1[start1] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, funcID, 1, bytes1[start1], ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+ // check that the int argument is numeric without fractions (in case arg is double or float)
+ if (!ArgumentUtils.checkWarnOrSetInteger(ctx, sourceLoc, funcID, 3, bytes3, start3, mutableInt)) {
+ PointableHelper.setNull(result);
+ return;
}
- if (bytes2[start2] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, funcID, 2, bytes2[start2], ATypeTag.SERIALIZED_STRING_TYPE_TAG);
- }
- if (bytes3[start3] != ATypeTag.SERIALIZED_INT8_TYPE_TAG && bytes3[start3] != ATypeTag.SERIALIZED_INT16_TYPE_TAG
- && bytes3[start3] != ATypeTag.SERIALIZED_INT32_TYPE_TAG
- && bytes3[start3] != ATypeTag.SERIALIZED_INT64_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, funcID, 3, bytes3[start3], ATypeTag.SERIALIZED_INT8_TYPE_TAG,
- ATypeTag.SERIALIZED_INT16_TYPE_TAG, ATypeTag.SERIALIZED_INT32_TYPE_TAG,
- ATypeTag.SERIALIZED_INT64_TYPE_TAG);
- }
-
+ int int4th = mutableInt.getIntegerValue();
// Sets argument UTF8Pointables.
strPtr1st.set(bytes0, start0 + 1, len0 - 1);
strPtr2nd.set(bytes1, start1 + 1, len1 - 1);
strPtr3rd.set(bytes2, start2 + 1, len2 - 1);
- long int4th = ATypeHierarchy.getLongValue(funcID.getName(), 3, bytes3, start3);
-
// Resets the output storage.
resultStorage.reset();
// The actual processing.
@@ -146,5 +142,18 @@
* @throws HyracksDataException
*/
protected abstract void process(UTF8StringPointable first, UTF8StringPointable second, UTF8StringPointable third,
- long fourth, IPointable resultPointable) throws HyracksDataException;
+ int fourth, IPointable resultPointable) throws HyracksDataException;
+
+ /** Checks the arguments expected to be strings returning {@code false} if they are not and issuing a warning */
+ private boolean checkStringsAndWarn(byte actualType0, byte actualType1, byte actualType2) {
+ return checkAndWarn(0, actualType0) && checkAndWarn(1, actualType1) && checkAndWarn(2, actualType2);
+ }
+
+ private boolean checkAndWarn(int argIdx, byte actualType) {
+ if (actualType != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funcID, actualType, argIdx, ATypeTag.STRING);
+ return false;
+ }
+ return true;
+ }
}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringJoinDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringJoinDescriptor.java
index 6037a79..0c39fae 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringJoinDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringJoinDescriptor.java
@@ -22,23 +22,16 @@
import java.io.IOException;
import org.apache.asterix.common.annotations.MissingNullInOutFunction;
-import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
-import org.apache.asterix.om.base.AMissing;
-import org.apache.asterix.om.base.ANull;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
import org.apache.asterix.om.functions.BuiltinFunctions;
-import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
import org.apache.asterix.runtime.evaluators.common.ListAccessor;
-import org.apache.asterix.runtime.exceptions.TypeMismatchException;
-import org.apache.asterix.runtime.exceptions.UnsupportedItemTypeException;
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.dataflow.value.ISerializerDeserializer;
import org.apache.hyracks.api.exceptions.HyracksDataException;
import org.apache.hyracks.data.std.api.IPointable;
import org.apache.hyracks.data.std.primitive.VoidPointable;
@@ -50,12 +43,7 @@
public class StringJoinDescriptor extends AbstractScalarFunctionDynamicDescriptor {
private static final long serialVersionUID = 1L;
- public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
- @Override
- public IFunctionDescriptor createFunctionDescriptor() {
- return new StringJoinDescriptor();
- }
- };
+ public static final IFunctionDescriptorFactory FACTORY = StringJoinDescriptor::new;
@Override
public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) {
@@ -74,13 +62,9 @@
private final IPointable inputArgSep = new VoidPointable();
private final IScalarEvaluator evalList = listEvalFactory.createScalarEvaluator(ctx);
private final IScalarEvaluator evalSep = sepEvalFactory.createScalarEvaluator(ctx);
- @SuppressWarnings("unchecked")
- private ISerializerDeserializer<ANull> nullSerde =
- SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ANULL);
- @SuppressWarnings("unchecked")
- private ISerializerDeserializer<AMissing> missingSerde =
- SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AMISSING);
private final byte[] tempLengthArray = new byte[5];
+ private final byte[] expectedTypeList =
+ { ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG, ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG };
@Override
public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
@@ -96,15 +80,18 @@
int listOffset = inputArgList.getStartOffset();
if (listBytes[listOffset] != ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG
&& listBytes[listOffset] != ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, listBytes[listOffset],
- ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG,
- ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG);
+ PointableHelper.setNull(result);
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, getIdentifier(), listBytes[listOffset], 0,
+ expectedTypeList);
+ return;
}
byte[] sepBytes = inputArgSep.getByteArray();
int sepOffset = inputArgSep.getStartOffset();
if (sepBytes[sepOffset] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, getIdentifier(), 1, sepBytes[sepOffset],
- ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+ PointableHelper.setNull(result);
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, getIdentifier(), sepBytes[sepOffset], 1,
+ ATypeTag.STRING);
+ return;
}
int sepLen = UTF8StringUtil.getUTFLength(sepBytes, sepOffset + 1);
int sepMetaLen = UTF8StringUtil.getNumBytesToStoreLength(sepLen);
@@ -123,18 +110,17 @@
itemOffset += 1;
}
if (itemType != ATypeTag.STRING) {
- if (itemType == ATypeTag.NULL) {
- nullSerde.serialize(ANull.NULL, out);
- result.set(resultStorage);
- return;
- }
if (itemType == ATypeTag.MISSING) {
- missingSerde.serialize(AMissing.MISSING, out);
- result.set(resultStorage);
+ PointableHelper.setMissing(result);
return;
}
- throw new UnsupportedItemTypeException(sourceLoc, getIdentifier(),
- itemType.serialize());
+ PointableHelper.setNull(result);
+ if (itemType != ATypeTag.NULL) {
+ // warn only if the call is: string_join([1,3], "/") where elements are non-null
+ ExceptionUtil.warnUnsupportedType(ctx, sourceLoc, getIdentifier().getName(),
+ itemType);
+ }
+ return;
}
int currentSize = UTF8StringUtil.getUTFLength(listBytes, itemOffset);
if (i != size - 1 && currentSize != 0) {
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringRegExpReplaceWithFlagDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringRegExpReplaceWithFlagDescriptor.java
index cb18f5a..f43fedc 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringRegExpReplaceWithFlagDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringRegExpReplaceWithFlagDescriptor.java
@@ -19,14 +19,17 @@
package org.apache.asterix.runtime.evaluators.functions;
import java.io.IOException;
+import java.util.Arrays;
import org.apache.asterix.common.annotations.MissingNullInOutFunction;
+import org.apache.asterix.om.base.AMutableInt32;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
import org.apache.asterix.om.functions.BuiltinFunctions;
-import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.asterix.runtime.evaluators.common.ArgumentUtils;
import org.apache.asterix.runtime.evaluators.functions.utils.RegExpMatcher;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
@@ -40,12 +43,7 @@
public class StringRegExpReplaceWithFlagDescriptor extends AbstractScalarFunctionDynamicDescriptor {
private static final long serialVersionUID = 1L;
- public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
- @Override
- public IFunctionDescriptor createFunctionDescriptor() {
- return new StringRegExpReplaceWithFlagDescriptor();
- }
- };
+ public static final IFunctionDescriptorFactory FACTORY = StringRegExpReplaceWithFlagDescriptor::new;
@Override
public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) {
@@ -58,30 +56,43 @@
StringRegExpReplaceWithFlagDescriptor.this.getIdentifier(), sourceLoc) {
private final UTF8StringPointable emptyFlags = UTF8StringPointable.generateUTF8Pointable("");
private final RegExpMatcher matcher = new RegExpMatcher();
+ private final AMutableInt32 mutableInt = new AMutableInt32(0);
+ private byte[] expectedTypes;
private int limit;
@Override
- protected void processArgument(int argIdx, IPointable argPtr, UTF8StringPointable outStrPtr)
+ protected boolean processArgument(int argIdx, IPointable argPtr, UTF8StringPointable outStrPtr)
throws HyracksDataException {
if (argIdx == 3) {
byte[] bytes = argPtr.getByteArray();
int start = argPtr.getStartOffset();
ATypeTag tt = ATypeTag.VALUE_TYPE_MAPPING[bytes[start]];
+ if (ATypeHierarchy.getTypeDomain(tt) != ATypeHierarchy.Domain.NUMERIC
+ && tt != ATypeTag.STRING) {
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funcID, bytes[start], argIdx,
+ getExpectedTypes());
+ return false;
+ }
switch (tt) {
case TINYINT:
case SMALLINT:
case INTEGER:
case BIGINT:
- limit = ATypeHierarchy.getIntegerValue(funcID.getName(), argIdx, bytes, start,
- true);
+ case FLOAT:
+ case DOUBLE:
+ if (!ArgumentUtils.checkWarnOrSetInteger(ctx, sourceLoc, funcID, argIdx, bytes,
+ start, mutableInt)) {
+ return false;
+ }
+ limit = mutableInt.getIntegerValue();
outStrPtr.set(emptyFlags);
- return;
+ return true;
default:
limit = Integer.MAX_VALUE;
break;
}
}
- super.processArgument(argIdx, argPtr, outStrPtr);
+ return super.processArgument(argIdx, argPtr, outStrPtr);
}
@Override
@@ -90,6 +101,15 @@
matcher.build(srcPtr, patternPtr, flagsPtr);
return matcher.replace(replacePtr, limit);
}
+
+ private byte[] getExpectedTypes() {
+ if (expectedTypes == null) {
+ expectedTypes = Arrays.copyOf(ArgumentUtils.EXPECTED_NUMERIC,
+ ArgumentUtils.EXPECTED_NUMERIC.length + 1);
+ expectedTypes[expectedTypes.length - 1] = ATypeTag.SERIALIZED_STRING_TYPE_TAG;
+ }
+ return expectedTypes;
+ }
};
}
};
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringRepeatDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringRepeatDescriptor.java
index b30f3ee..83e3f8e 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringRepeatDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringRepeatDescriptor.java
@@ -23,15 +23,13 @@
import java.io.IOException;
import org.apache.asterix.common.annotations.MissingNullInOutFunction;
-import org.apache.asterix.common.exceptions.ErrorCode;
-import org.apache.asterix.common.exceptions.RuntimeDataException;
+import org.apache.asterix.om.base.AMutableInt32;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
import org.apache.asterix.om.functions.BuiltinFunctions;
-import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
-import org.apache.asterix.runtime.exceptions.TypeMismatchException;
+import org.apache.asterix.runtime.evaluators.common.ArgumentUtils;
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;
@@ -46,12 +44,7 @@
@MissingNullInOutFunction
public class StringRepeatDescriptor extends AbstractScalarFunctionDynamicDescriptor {
private static final long serialVersionUID = 1L;
- public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
- @Override
- public IFunctionDescriptor createFunctionDescriptor() {
- return new StringRepeatDescriptor();
- }
- };
+ public static final IFunctionDescriptorFactory FACTORY = StringRepeatDescriptor::new;
@Override
public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) {
@@ -68,6 +61,7 @@
// Argument pointers.
private IPointable argString = new VoidPointable();
private IPointable argNumber = new VoidPointable();
+ private final AMutableInt32 mutableInt = new AMutableInt32(0);
// For outputting the result.
private ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
@@ -89,12 +83,17 @@
// Gets the repeating times.
byte[] bytes = argNumber.getByteArray();
int offset = argNumber.getStartOffset();
- int repeatingTimes =
- ATypeHierarchy.getIntegerValue(getIdentifier().getName(), 1, bytes, offset);
+ if (!ArgumentUtils.checkWarnOrSetInteger(ctx, sourceLoc, getIdentifier(), 1, bytes, offset,
+ mutableInt)) {
+ PointableHelper.setNull(result);
+ return;
+ }
+ int repeatingTimes = mutableInt.getIntegerValue();
// Checks repeatingTimes. It should be a non-negative value.
if (repeatingTimes < 0) {
- throw new RuntimeDataException(ErrorCode.NEGATIVE_VALUE, sourceLoc,
- getIdentifier().getName(), 1, repeatingTimes);
+ PointableHelper.setNull(result);
+ ExceptionUtil.warnNegativeValue(ctx, sourceLoc, getIdentifier(), 1, repeatingTimes);
+ return;
}
// Gets the input string.
@@ -102,8 +101,10 @@
offset = argString.getStartOffset();
// Checks the type of the string argument.
if (bytes[offset] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, bytes[offset],
- ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+ PointableHelper.setNull(result);
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, getIdentifier(), bytes[offset], 0,
+ ATypeTag.STRING);
+ return;
}
// Calculates the result string length.
@@ -133,5 +134,4 @@
public FunctionIdentifier getIdentifier() {
return BuiltinFunctions.STRING_REPEAT;
}
-
}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringReplaceWithLimitDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringReplaceWithLimitDescriptor.java
index c84d791..4bb3bb5 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringReplaceWithLimitDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/StringReplaceWithLimitDescriptor.java
@@ -21,7 +21,6 @@
import org.apache.asterix.common.annotations.MissingNullInOutFunction;
import org.apache.asterix.om.functions.BuiltinFunctions;
-import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
import org.apache.asterix.runtime.evaluators.functions.utils.StringReplacer;
@@ -36,12 +35,7 @@
@MissingNullInOutFunction
public class StringReplaceWithLimitDescriptor extends AbstractScalarFunctionDynamicDescriptor {
private static final long serialVersionUID = 1L;
- public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
- @Override
- public IFunctionDescriptor createFunctionDescriptor() {
- return new StringReplaceWithLimitDescriptor();
- }
- };
+ public static final IFunctionDescriptorFactory FACTORY = StringReplaceWithLimitDescriptor::new;
@Override
public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) {
@@ -57,9 +51,9 @@
@Override
protected void process(UTF8StringPointable first, UTF8StringPointable second,
- UTF8StringPointable third, long fourth, IPointable resultPointable)
+ UTF8StringPointable third, int fourth, IPointable resultPointable)
throws HyracksDataException {
- if (replacer.findAndReplace(first, second, third, (int) fourth)) {
+ if (replacer.findAndReplace(first, second, third, fourth)) {
replacer.assignResult(resultPointable);
} else {
resultPointable.set(argPtrFirst);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/Substring2Descriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/Substring2Descriptor.java
index 63cc9d3..41ae0c3 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/Substring2Descriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/Substring2Descriptor.java
@@ -22,14 +22,14 @@
import java.io.IOException;
import org.apache.asterix.common.annotations.MissingNullInOutFunction;
+import org.apache.asterix.om.base.AMutableInt32;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
import org.apache.asterix.om.functions.BuiltinFunctions;
-import org.apache.asterix.om.functions.IFunctionDescriptor;
import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
-import org.apache.asterix.om.functions.IFunctionTypeInferer;
import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
-import org.apache.asterix.runtime.exceptions.TypeMismatchException;
+import org.apache.asterix.runtime.evaluators.common.ArgumentUtils;
import org.apache.asterix.runtime.functions.FunctionTypeInferers;
+import org.apache.asterix.runtime.utils.DescriptorFactoryUtil;
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;
@@ -46,17 +46,8 @@
@MissingNullInOutFunction
public class Substring2Descriptor extends AbstractStringOffsetConfigurableDescriptor {
private static final long serialVersionUID = 1L;
- public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
- @Override
- public IFunctionDescriptor createFunctionDescriptor() {
- return new Substring2Descriptor();
- }
-
- @Override
- public IFunctionTypeInferer createFunctionTypeInferer() {
- return FunctionTypeInferers.SET_STRING_OFFSET;
- }
- };
+ public static final IFunctionDescriptorFactory FACTORY =
+ DescriptorFactoryUtil.createFactory(Substring2Descriptor::new, FunctionTypeInferers.SET_STRING_OFFSET);
@Override
public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) {
@@ -68,15 +59,17 @@
@Override
public IScalarEvaluator createScalarEvaluator(final IEvaluatorContext ctx) throws HyracksDataException {
return new IScalarEvaluator() {
- private ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
- private DataOutput out = resultStorage.getDataOutput();
- private IPointable argString = new VoidPointable();
- private IPointable argStart = new VoidPointable();
- private IScalarEvaluator evalString = args[0].createScalarEvaluator(ctx);
- private IScalarEvaluator evalStart = args[1].createScalarEvaluator(ctx);
+ private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
+ private final DataOutput out = resultStorage.getDataOutput();
+ private final IPointable argString = new VoidPointable();
+ private final IPointable argStart = new VoidPointable();
+ private final IScalarEvaluator evalString = args[0].createScalarEvaluator(ctx);
+ private final IScalarEvaluator evalStart = args[1].createScalarEvaluator(ctx);
private final GrowableArray array = new GrowableArray();
private final UTF8StringBuilder builder = new UTF8StringBuilder();
private final UTF8StringPointable string = new UTF8StringPointable();
+ private final FunctionIdentifier funID = getIdentifier();
+ private final AMutableInt32 mutableInt = new AMutableInt32(0);
@Override
public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
@@ -90,13 +83,19 @@
byte[] bytes = argStart.getByteArray();
int offset = argStart.getStartOffset();
- int start = ATypeHierarchy.getIntegerValue(getIdentifier().getName(), 1, bytes, offset);
+ // check that the int argument is numeric without fractions (in case arg is double or float)
+ if (!ArgumentUtils.checkWarnOrSetInteger(ctx, sourceLoc, funID, 1, bytes, offset, mutableInt)) {
+ PointableHelper.setNull(result);
+ return;
+ }
+ int start = mutableInt.getIntegerValue();
bytes = argString.getByteArray();
offset = argString.getStartOffset();
int len = argString.getLength();
if (bytes[offset] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
- throw new TypeMismatchException(sourceLoc, getIdentifier(), 0, bytes[offset],
- ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+ PointableHelper.setNull(result);
+ ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, funID, bytes[offset], 0, ATypeTag.STRING);
+ return;
}
string.set(bytes, offset + 1, len - 1);
array.reset();
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java
index 7dae0b5..8af9f23 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java
@@ -23,6 +23,7 @@
import java.util.Set;
import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
/**
* An Http Request instance
@@ -81,4 +82,9 @@
* @return the remote address
*/
InetSocketAddress getRemoteAddress();
+
+ /**
+ * Indicates which scheme the client used making this request
+ */
+ HttpScheme getScheme();
}
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java
index d681d81..69f7c5f 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java
@@ -18,7 +18,6 @@
*/
package org.apache.hyracks.http.server;
-import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.HashMap;
@@ -31,25 +30,28 @@
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.codec.http.QueryStringDecoder;
public class BaseRequest implements IServletRequest {
protected final FullHttpRequest request;
protected final Map<String, List<String>> parameters;
protected final InetSocketAddress remoteAddress;
+ protected final HttpScheme scheme;
- public static IServletRequest create(ChannelHandlerContext ctx, FullHttpRequest request) throws IOException {
+ public static IServletRequest create(ChannelHandlerContext ctx, FullHttpRequest request, HttpScheme scheme) {
QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
Map<String, List<String>> param = decoder.parameters();
InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
- return new BaseRequest(request, remoteAddress, param);
+ return new BaseRequest(request, remoteAddress, param, scheme);
}
protected BaseRequest(FullHttpRequest request, InetSocketAddress remoteAddress,
- Map<String, List<String>> parameters) {
+ Map<String, List<String>> parameters, HttpScheme scheme) {
this.request = request;
this.remoteAddress = remoteAddress;
this.parameters = parameters;
+ this.scheme = scheme;
}
@Override
@@ -86,4 +88,9 @@
public InetSocketAddress getRemoteAddress() {
return remoteAddress;
}
+
+ @Override
+ public HttpScheme getScheme() {
+ return scheme;
+ }
}
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java
index 81cd04e..0e57d8d 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java
@@ -31,11 +31,12 @@
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.codec.http.QueryStringDecoder;
public class FormUrlEncodedRequest extends BaseRequest implements IServletRequest {
- public static IServletRequest create(ChannelHandlerContext ctx, FullHttpRequest request) {
+ public static IServletRequest create(ChannelHandlerContext ctx, FullHttpRequest request, HttpScheme scheme) {
Charset charset = HttpUtil.getRequestCharset(request);
Map<String, List<String>> parameters = new LinkedHashMap<>();
URLEncodedUtils.parse(request.content().toString(charset), charset).forEach(
@@ -43,11 +44,11 @@
new QueryStringDecoder(request.uri()).parameters()
.forEach((name, value) -> parameters.computeIfAbsent(name, a -> new ArrayList<>()).addAll(value));
InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
- return new FormUrlEncodedRequest(request, remoteAddress, parameters);
+ return new FormUrlEncodedRequest(request, remoteAddress, parameters, scheme);
}
private FormUrlEncodedRequest(FullHttpRequest request, InetSocketAddress remoteAddress,
- Map<String, List<String>> parameters) {
- super(request, remoteAddress, parameters);
+ Map<String, List<String>> parameters, HttpScheme scheme) {
+ super(request, remoteAddress, parameters, scheme);
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
index d9902da..2a7b47e 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
@@ -48,6 +48,7 @@
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
@@ -404,6 +405,10 @@
return closedHandler;
}
+ public HttpScheme getScheme() {
+ return HttpScheme.HTTP;
+ }
+
@Override
public String toString() {
return "{\"class\":\"" + getClass().getSimpleName() + "\",\"address\":" + address + ",\"state\":\"" + getState()
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
index fe6a431..4882572 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
@@ -18,6 +18,8 @@
*/
package org.apache.hyracks.http.server;
+import static org.apache.hyracks.http.server.utils.HttpUtil.X_FORWARDED_PROTO;
+
import java.io.IOException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
@@ -42,6 +44,7 @@
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpScheme;
public class HttpServerHandler<T extends HttpServer> extends SimpleChannelInboundHandler<Object>
implements ChannelFutureListener {
@@ -130,7 +133,10 @@
private void submit(ChannelHandlerContext ctx, IServlet servlet, FullHttpRequest request) throws IOException {
IServletRequest servletRequest;
try {
- servletRequest = HttpUtil.toServletRequest(ctx, request);
+ HttpScheme scheme =
+ server.getScheme() == HttpScheme.HTTPS || "https".equals(request.headers().get(X_FORWARDED_PROTO))
+ ? HttpScheme.HTTPS : HttpScheme.HTTP;
+ servletRequest = HttpUtil.toServletRequest(ctx, request, scheme);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.WARN, "Failure Decoding Request", e);
respond(ctx, request, HttpResponseStatus.BAD_REQUEST);
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
index 34ca2c4..0f857bd 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
@@ -44,6 +44,7 @@
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
import io.netty.util.AsciiString;
public class HttpUtil {
@@ -51,6 +52,8 @@
private static final Pattern PARENT_DIR = Pattern.compile("/[^./]+/\\.\\./");
private static final Charset DEFAULT_RESPONSE_CHARSET = StandardCharsets.UTF_8;
+ public static final AsciiString X_FORWARDED_PROTO = AsciiString.cached("x-forwarded-proto");
+
private HttpUtil() {
}
@@ -80,10 +83,10 @@
return parameter == null ? null : String.join(",", parameter);
}
- public static IServletRequest toServletRequest(ChannelHandlerContext ctx, FullHttpRequest request)
- throws IOException {
+ public static IServletRequest toServletRequest(ChannelHandlerContext ctx, FullHttpRequest request,
+ HttpScheme scheme) {
return ContentType.APPLICATION_X_WWW_FORM_URLENCODED.equals(getContentTypeOnly(request))
- ? FormUrlEncodedRequest.create(ctx, request) : BaseRequest.create(ctx, request);
+ ? FormUrlEncodedRequest.create(ctx, request, scheme) : BaseRequest.create(ctx, request, scheme);
}
public static String getContentTypeOnly(IServletRequest request) {