You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by mb...@apache.org on 2019/10/07 16:29:22 UTC

[asterixdb] 01/04: [ASTERIXDB-2634][COMP] String functions return null on data/type errors

This is an automated email from the ASF dual-hosted git repository.

mblow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git

commit e54e4178fec325e8812f5f042c3cdba81ed49fb1
Author: Ali Alsuliman <al...@gmail.com>
AuthorDate: Thu Oct 3 15:50:17 2019 -0700

    [ASTERIXDB-2634][COMP] String functions return null on data/type errors
    
    - user model changes: no
    - storage format changes: no
    - interface changes: no
    
    Details:
    Functions changed:
      substring(string, start_idx),
      repeat(string, num_times),
      string_join([string], string_separator),
      replace(string, search_string, string_replacement, num_times),
      regexp_replace(string, string_pattern, string_replacement, num_times)
    
    Those functions (except string_join) can return NULL even if the
    arguments types are valid since the argument values could be not
    valid at runtime. Their type computer is always nullable.
    
    - int argument can be double/float on the condition that its value
      is integer
    - clean-ups:
      UnaryStringInt64TypeComputer & AbstractStringTypeComputer.
      ExceptionUtil:
      - changed signature of toExpectedTypeString(). Overloading
        with varargs with Object made it confusing.
      - changed some args to Supplier to allow code sharing.
    - removed StringIntToStringTypeComputer since now the instances
      are not being used by the above functions.
    - reorganized/renamed test cases
    
    Change-Id: Ia85a0d08888021ae439a1d9f2f5858bcd52c79f3
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/3605
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Ali Alsuliman <al...@gmail.com>
    Reviewed-by: Michael Blow <mb...@apache.org>
---
 .../string_fun_001/string_fun_001.01.ddl.sqlpp}    |   0
 .../string_fun_001/string_fun_001.02.update.sqlpp} |   0
 .../string_fun_001/string_fun_001.03.query.sqlpp}  |   0
 .../string_fun_001/string_fun_001.04.query.sqlpp}  |   0
 .../string_fun_001/string_fun_001.05.query.sqlpp}  |   0
 .../string_fun_001/string_fun_001.06.query.sqlpp}  |   0
 .../string_fun_001/string_fun_001.07.query.sqlpp}  |   0
 .../string_fun_001/string_fun_001.08.query.sqlpp}  |   0
 .../string_fun_001/string_fun_001.09.ddl.sqlpp}    |   0
 .../string_fun_002/string_fun_002.01.query.sqlpp}  |   0
 .../string_fun_003/string_fun_003.01.ddl.sqlpp}    |   0
 .../string_fun_003/string_fun_003.02.update.sqlpp} |   8 +-
 .../string_fun_003/string_fun_003.03.query.sqlpp}  |  27 ++---
 .../string_fun_003/string_fun_003.04.query.sqlpp}  |  27 ++---
 .../string_fun_003/string_fun_003.05.query.sqlpp}  |  27 ++---
 .../string_fun_003/string_fun_003.06.ddl.sqlpp}    |   0
 .../string/repeat_error/repeat_error.1.query.sqlpp |  20 ----
 .../string_fun_001/string_fun_001.03.adm}          |   0
 .../string_fun_001/string_fun_001.04.adm}          |   0
 .../string_fun_001/string_fun_001.05.adm}          |   0
 .../string_fun_001/string_fun_001.06.adm}          |   0
 .../string_fun_001/string_fun_001.07.adm}          |   0
 .../string_fun_001/string_fun_001.08.adm}          |   0
 .../string_fun_002/string_fun_002.01.adm}          |   0
 .../string_fun_003/string_fun_003.01.adm           |   2 +
 .../string_fun_003/string_fun_003.02.adm           |   2 +
 .../string_fun_003/string_fun_003.03.adm           |   1 +
 .../test/resources/runtimets/testsuite_sqlpp.xml   |  45 +++++---
 .../asterix/common/exceptions/ErrorCode.java       |   1 +
 .../src/main/resources/asx_errormsg/en.properties  |   3 +-
 .../asterix/om/exceptions/ExceptionUtil.java       |  44 ++++++--
 .../asterix/om/functions/BuiltinFunctions.java     |  15 ++-
 .../om/typecomputer/impl/AStringTypeComputer.java  |  12 ++-
 .../impl/AbstractStringTypeComputer.java           |  14 +--
 .../impl/StringIntToStringTypeComputer.java        | 116 ---------------------
 ...peComputer.java => StringJoinTypeComputer.java} |  23 +++-
 .../impl/UnaryStringInt64TypeComputer.java         |   2 +-
 .../hierachy/DoubleToInt32TypeConvertComputer.java |   2 +-
 .../std/AbstractMinMaxAggregateFunction.java       |   2 +-
 .../runtime/evaluators/common/ArgumentUtils.java   |  76 ++++++++++++++
 .../functions/AbstractQuadStringStringEval.java    |  20 ++--
 .../AbstractStringStringStringIntEval.java         |  57 +++++-----
 .../evaluators/functions/StringJoinDescriptor.java |  54 ++++------
 .../StringRegExpReplaceWithFlagDescriptor.java     |  44 +++++---
 .../functions/StringRepeatDescriptor.java          |  36 +++----
 .../StringReplaceWithLimitDescriptor.java          |  12 +--
 .../evaluators/functions/Substring2Descriptor.java |  47 ++++-----
 47 files changed, 360 insertions(+), 379 deletions(-)

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%
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_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%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.02.update.sqlpp
copy 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%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.03.query.sqlpp
copy 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%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.04.query.sqlpp
copy 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%
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_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%
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_003/string_fun_003.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_003/string_fun_003.02.update.sqlpp
similarity index 58%
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_003/string_fun_003.02.update.sqlpp
index b0caa32..c81b5a9 100644
--- 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_003/string_fun_003.02.update.sqlpp
@@ -20,11 +20,11 @@
 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.3"), "str1": "foo", "mixed": 7},
-{"id": 2, "i8": int8("2"), "i16": int16("10"), "i32": int32("21"), "i64": int64("87"), "f": float("4.2"), "d": double("5.3"), "str1": "foo", "mixed": "m"}
+{"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.3"), "str1": "foo", "mixed": 7},
-{"id": 2, "i8": int8("2"), "i16": int16("10"), "i32": int32("21"), "i64": int64("87"), "f": float("4.2"), "d": double("5.3"), "str1": "foo", "mixed": "m"}
+{"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/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_003/string_fun_003.03.query.sqlpp
similarity index 67%
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_003/string_fun_003.03.query.sqlpp
index 6dec119..3c7ebf2 100644
--- 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_003/string_fun_003.03.query.sqlpp
@@ -18,30 +18,21 @@
  */
 
 /*
- *  Description: tests reporting type mismatch for string functions
+ *  Description: tests that string functions do not throw exception on type/data errors
  */
 // requesttype=application/json
 // param max-warnings:json=1000
 
 use test;
 
-set `import-private-functions` "true";
-
 from closedDS as ds
 select
-`LIKE`(ds.str1, ds.i8),
-`LIKE`(ds.i8, ds.str1),
-contains(ds.str1, ds.i8),
-string_to_codepoint(ds.i64),
-length(ds.i32),
-lowercase(ds.i16),
-uppercase(ds.i16),
-initcap(ds.i64),
-trim(ds.i32),
-trim(ds.i64, ds.str1),
-ltrim(ds.i16),
-ltrim(ds.str1, ds.i8),
-rtrim(ds.i32),
-rtrim(ds.i64, ds.str1),
-position(ds.i8, ds.str1)
+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/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_003/string_fun_003.04.query.sqlpp
similarity index 67%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fun_return_null/fun_return_null_01/fun_return_null_01.04.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 bbfb127..92747a9 100644
--- 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_003/string_fun_003.04.query.sqlpp
@@ -18,30 +18,21 @@
  */
 
 /*
- *  Description: tests reporting type mismatch for string functions
+ *  Description: tests that string functions do not throw exception on type/data errors
  */
 // requesttype=application/json
 // param max-warnings:json=1000
 
 use test;
 
-set `import-private-functions` "true";
-
 from openDS as ds
 select
-`LIKE`(ds.str1, ds.i8),
-`LIKE`(ds.i8, ds.str1),
-contains(ds.str1, ds.i8),
-string_to_codepoint(ds.i64),
-length(ds.i32),
-lowercase(ds.i16),
-uppercase(ds.i16),
-initcap(ds.i64),
-trim(ds.i32),
-trim(ds.i64, ds.str1),
-ltrim(ds.i16),
-ltrim(ds.str1, ds.i8),
-rtrim(ds.i32),
-rtrim(ds.i64, ds.str1),
-position(ds.i8, ds.str1)
+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/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_003/string_fun_003.05.query.sqlpp
similarity index 66%
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_003/string_fun_003.05.query.sqlpp
index bbfb127..f1867fc 100644
--- 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_003/string_fun_003.05.query.sqlpp
@@ -18,30 +18,17 @@
  */
 
 /*
- *  Description: tests reporting type mismatch for string functions
+ *  Description: tests that string functions do not throw exception on type/data errors
  */
 // requesttype=application/json
 // param max-warnings:json=1000
 
 use test;
 
-set `import-private-functions` "true";
-
-from openDS as ds
 select
-`LIKE`(ds.str1, ds.i8),
-`LIKE`(ds.i8, ds.str1),
-contains(ds.str1, ds.i8),
-string_to_codepoint(ds.i64),
-length(ds.i32),
-lowercase(ds.i16),
-uppercase(ds.i16),
-initcap(ds.i64),
-trim(ds.i32),
-trim(ds.i64, ds.str1),
-ltrim(ds.i16),
-ltrim(ds.str1, ds.i8),
-rtrim(ds.i32),
-rtrim(ds.i64, ds.str1),
-position(ds.i8, ds.str1)
-order by ds.id;
\ No newline at end of file
+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%
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_003/string_fun_003.06.ddl.sqlpp
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/string/repeat_error/repeat_error.1.query.sqlpp
deleted file mode 100644
index 0701ce3..0000000
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/string/repeat_error/repeat_error.1.query.sqlpp
+++ /dev/null
@@ -1,20 +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.
- */
-
-SELECT VALUE repeat(" new ", -1);
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.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.07.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.06.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.06.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.04.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.04.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.03.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.03.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/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 class ErrorCode {
     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.algebricks.runtime.base.IEvaluatorContext;
 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 @@ public class ExceptionUtil {
         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 class ExceptionUtil {
 
     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 @@ public class ExceptionUtil {
             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.ScalarVersionOfAggregateResultTyp
 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 @@ public class BuiltinFunctions {
         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 @@ public class BuiltinFunctions {
         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 @@ public class BuiltinFunctions {
         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 @@ import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 
 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.ATypeTag;
 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 @@ abstract public class AbstractStringTypeComputer extends AbstractResultTypeCompu
         }
         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/AStringTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/StringJoinTypeComputer.java
similarity index 57%
copy from asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AStringTypeComputer.java
copy to asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/StringJoinTypeComputer.java
index 3537fb7..407a991 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/StringJoinTypeComputer.java
@@ -18,22 +18,35 @@
  */
 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.BuiltinType;
+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;
 
-public class AStringTypeComputer extends AbstractResultTypeComputer {
+/**
+ * For function signature: nullable_string fun([string], string)
+ */
+public class StringJoinTypeComputer extends AbstractResultTypeComputer {
 
-    public static final AStringTypeComputer INSTANCE = new AStringTypeComputer();
+    public static final StringJoinTypeComputer INSTANCE = new StringJoinTypeComputer();
 
-    private AStringTypeComputer() {
+    private StringJoinTypeComputer() {
     }
 
     @Override
     protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
-        return BuiltinType.ASTRING;
+        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 @@ public class UnaryStringInt64TypeComputer extends AbstractStringTypeComputer {
 
     @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 @@ public class DoubleToInt32TypeConvertComputer implements ITypeConvertComputer {
         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.data.std.util.ArrayBackedValueStorage;
 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 java.io.IOException;
 
 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 @@ public abstract class AbstractQuadStringStringEval implements IScalarEvaluator {
     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 abstract class AbstractQuadStringStringEval implements IScalarEvaluator {
     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 @@ public abstract class AbstractQuadStringStringEval implements IScalarEvaluator {
             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 @@ public abstract class AbstractQuadStringStringEval implements IScalarEvaluator {
         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 @@ package org.apache.asterix.runtime.evaluators.functions;
 
 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.data.std.util.ArrayBackedValueStorage;
 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 @@ public abstract class AbstractStringStringStringIntEval implements IScalarEvalua
     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 @@ public abstract class AbstractStringStringStringIntEval implements IScalarEvalua
     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 @@ public abstract class AbstractStringStringStringIntEval implements IScalarEvalua
         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 (bytes1[start1] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
-            throw new TypeMismatchException(sourceLoc, funcID, 1, bytes1[start1], ATypeTag.SERIALIZED_STRING_TYPE_TAG);
-        }
-        if (bytes2[start2] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
-            throw new TypeMismatchException(sourceLoc, funcID, 2, bytes2[start2], ATypeTag.SERIALIZED_STRING_TYPE_TAG);
+        if (!checkStringsAndWarn(bytes0[start0], bytes1[start1], bytes2[start2])) {
+            PointableHelper.setNull(result);
+            return;
         }
-        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);
+        // 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;
         }
-
+        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 @@ public abstract class AbstractStringStringStringIntEval implements IScalarEvalua
      * @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.DataOutput;
 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 @@ import org.apache.hyracks.util.string.UTF8StringUtil;
 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 @@ public class StringJoinDescriptor extends AbstractScalarFunctionDynamicDescripto
                     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 @@ public class StringJoinDescriptor extends AbstractScalarFunctionDynamicDescripto
                         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 @@ public class StringJoinDescriptor extends AbstractScalarFunctionDynamicDescripto
                                     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 @@ import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
 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 @@ public class StringRegExpReplaceWithFlagDescriptor extends AbstractScalarFunctio
                         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 @@ public class StringRegExpReplaceWithFlagDescriptor extends AbstractScalarFunctio
                         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.DataOutput;
 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 @@ import org.apache.hyracks.util.string.UTF8StringUtil;
 @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 @@ public class StringRepeatDescriptor extends AbstractScalarFunctionDynamicDescrip
                     // 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 @@ public class StringRepeatDescriptor extends AbstractScalarFunctionDynamicDescrip
                         // 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 @@ public class StringRepeatDescriptor extends AbstractScalarFunctionDynamicDescrip
                         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 class StringRepeatDescriptor extends AbstractScalarFunctionDynamicDescrip
     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 @@ package org.apache.asterix.runtime.evaluators.functions;
 
 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 @@ import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
 @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 @@ public class StringReplaceWithLimitDescriptor extends AbstractScalarFunctionDyna
 
                     @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.DataOutput;
 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 @@ import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
 @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 @@ public class Substring2Descriptor extends AbstractStringOffsetConfigurableDescri
             @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 @@ public class Substring2Descriptor extends AbstractStringOffsetConfigurableDescri
 
                         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();