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) {