You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by hv...@apache.org on 2023/02/17 12:19:21 UTC

[spark] branch master updated: [SPARK-42461][CONNECT] Scala Client implement first batch of functions

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

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


The following commit(s) were added to refs/heads/master by this push:
     new e6a84fef2fa [SPARK-42461][CONNECT] Scala Client implement first batch of functions
e6a84fef2fa is described below

commit e6a84fef2fa43b880c89f2f54a5fa78033021fb1
Author: Herman van Hovell <he...@databricks.com>
AuthorDate: Fri Feb 17 08:19:04 2023 -0400

    [SPARK-42461][CONNECT] Scala Client implement first batch of functions
    
    ### What changes were proposed in this pull request?
    This PR adds the following functions to Spark Connect Scala Client:
    - Sort Functions
    - Aggregate Functions
    - Misc Functions
    - Math Functions
    
    ### Why are the changes needed?
    We want to the Spark Connect Scala Client to reach parity with the original functions API.
    
    ### Does this PR introduce _any_ user-facing change?
    Yes, it adds a lot of functions.
    
    ### How was this patch tested?
    Added test for all functions and their significant variations.
    
    Closes #40050 from hvanhovell/SPARK-42461.
    
    Authored-by: Herman van Hovell <he...@databricks.com>
    Signed-off-by: Herman van Hovell <he...@databricks.com>
---
 .../main/scala/org/apache/spark/sql/Column.scala   |   14 +-
 .../scala/org/apache/spark/sql/functions.scala     | 2158 +++++++++++++++++++-
 .../org/apache/spark/sql/FunctionTestSuite.scala   |  168 ++
 .../apache/spark/sql/PlanGenerationTestSuite.scala |  409 +++-
 .../explain-results/function_abs.explain           |    2 +
 .../explain-results/function_acos.explain          |    2 +
 .../explain-results/function_acosh.explain         |    2 +
 .../function_approx_count_distinct.explain         |    2 +
 .../function_approx_count_distinct_rsd.explain     |    2 +
 .../explain-results/function_array.explain         |    2 +
 .../explain-results/function_asc.explain           |    2 +
 .../function_asc_nulls_first.explain               |    2 +
 .../function_asc_nulls_last.explain                |    2 +
 .../explain-results/function_asin.explain          |    2 +
 .../explain-results/function_asinh.explain         |    2 +
 .../explain-results/function_atan.explain          |    2 +
 .../explain-results/function_atan2.explain         |    2 +
 .../explain-results/function_atanh.explain         |    2 +
 .../explain-results/function_avg.explain           |    2 +
 .../explain-results/function_bin.explain           |    2 +
 .../explain-results/function_bitwise_not.explain   |    2 +
 .../explain-results/function_bround.explain        |    2 +
 .../explain-results/function_ceil.explain          |    2 +
 .../explain-results/function_ceil_scale.explain    |    2 +
 .../explain-results/function_coalesce.explain      |    2 +
 .../explain-results/function_col.explain           |    2 +-
 .../explain-results/function_collect_list.explain  |    2 +
 .../explain-results/function_collect_set.explain   |    2 +
 .../explain-results/function_conv.explain          |    2 +
 .../explain-results/function_corr.explain          |    2 +
 .../explain-results/function_cos.explain           |    2 +
 .../explain-results/function_cosh.explain          |    2 +
 .../explain-results/function_cot.explain           |    2 +
 .../explain-results/function_count.explain         |    2 +
 .../explain-results/function_countDistinct.explain |    2 +
 .../explain-results/function_covar_pop.explain     |    2 +
 .../explain-results/function_covar_samp.explain    |    2 +
 .../explain-results/function_csc.explain           |    2 +
 .../explain-results/function_degrees.explain       |    2 +
 .../explain-results/function_desc.explain          |    2 +
 .../function_desc_nulls_first.explain              |    2 +
 .../function_desc_nulls_last.explain               |    2 +
 .../explain-results/function_exp.explain           |    2 +
 .../explain-results/function_expm1.explain         |    2 +
 .../explain-results/function_expr.explain          |    2 +
 .../explain-results/function_factorial.explain     |    2 +
 .../explain-results/function_first.explain         |    2 +
 .../explain-results/function_floor.explain         |    2 +
 .../explain-results/function_floor_scale.explain   |    2 +
 .../explain-results/function_greatest.explain      |    2 +
 .../explain-results/function_hex.explain           |    2 +
 .../explain-results/function_hypot.explain         |    2 +
 .../function_input_file_name.explain               |    2 +
 .../explain-results/function_isnan.explain         |    2 +
 .../explain-results/function_isnull.explain        |    2 +
 .../explain-results/function_kurtosis.explain      |    2 +
 .../explain-results/function_last.explain          |    2 +
 .../explain-results/function_least.explain         |    2 +
 .../explain-results/function_log.explain           |    2 +
 .../explain-results/function_log10.explain         |    2 +
 .../explain-results/function_log1p.explain         |    2 +
 .../explain-results/function_log2.explain          |    2 +
 .../explain-results/function_log_with_base.explain |    2 +
 .../explain-results/function_map.explain           |    2 +
 .../function_map_from_arrays.explain               |    2 +
 .../explain-results/function_max_by.explain        |    2 +
 .../explain-results/function_median.explain        |    2 +
 .../explain-results/function_min.explain           |    2 +
 .../explain-results/function_min_by.explain        |    2 +
 .../explain-results/function_mode.explain          |    2 +
 .../function_monotonically_increasing_id.explain   |    2 +
 .../explain-results/function_nanvl.explain         |    2 +
 .../explain-results/function_negate.explain        |    2 +
 .../function_percentile_approx.explain             |    2 +
 .../explain-results/function_pmod.explain          |    2 +
 .../explain-results/function_pow.explain           |    2 +
 .../explain-results/function_product.explain       |    2 +
 .../explain-results/function_radians.explain       |    2 +
 .../function_rand_with_seed.explain                |    2 +
 .../function_randn_with_seed.explain               |    2 +
 .../explain-results/function_rint.explain          |    2 +
 .../explain-results/function_round.explain         |    2 +
 .../explain-results/function_sec.explain           |    2 +
 .../explain-results/function_shiftleft.explain     |    2 +
 .../explain-results/function_shiftright.explain    |    2 +
 .../function_shiftrightunsigned.explain            |    2 +
 .../explain-results/function_signum.explain        |    2 +
 .../explain-results/function_sin.explain           |    2 +
 .../explain-results/function_sinh.explain          |    2 +
 .../explain-results/function_skewness.explain      |    2 +
 .../function_spark_partition_id.explain            |    2 +
 .../explain-results/function_sqrt.explain          |    2 +
 .../explain-results/function_stddev.explain        |    2 +
 .../explain-results/function_stddev_pop.explain    |    2 +
 .../explain-results/function_stddev_samp.explain   |    2 +
 .../explain-results/function_struct.explain        |    2 +
 .../explain-results/function_sum.explain           |    2 +
 .../explain-results/function_sum_distinct.explain  |    2 +
 .../explain-results/function_tan.explain           |    2 +
 .../explain-results/function_tanh.explain          |    2 +
 .../explain-results/function_unhex.explain         |    2 +
 .../explain-results/function_var_pop.explain       |    2 +
 .../explain-results/function_var_samp.explain      |    2 +
 .../explain-results/function_variance.explain      |    2 +
 .../query-tests/queries/function_abs.json          |   19 +
 .../query-tests/queries/function_abs.proto.bin     |    4 +
 .../query-tests/queries/function_acos.json         |   19 +
 .../query-tests/queries/function_acos.proto.bin    |    4 +
 .../query-tests/queries/function_acosh.json        |   19 +
 .../query-tests/queries/function_acosh.proto.bin   |    4 +
 .../queries/function_approx_count_distinct.json    |   19 +
 .../function_approx_count_distinct.proto.bin       |    4 +
 .../function_approx_count_distinct_rsd.json        |   23 +
 .../function_approx_count_distinct_rsd.proto.bin   |    5 +
 .../query-tests/queries/function_array.json        |   23 +
 .../query-tests/queries/function_array.proto.bin   |    5 +
 .../query-tests/queries/function_asc.json          |   20 +
 .../query-tests/queries/function_asc.proto.bin     |    4 +
 .../queries/function_asc_nulls_first.json          |   20 +
 .../queries/function_asc_nulls_first.proto.bin     |    4 +
 .../queries/function_asc_nulls_last.json           |   20 +
 .../queries/function_asc_nulls_last.proto.bin      |    4 +
 .../query-tests/queries/function_asin.json         |   19 +
 .../query-tests/queries/function_asin.proto.bin    |    4 +
 .../query-tests/queries/function_asinh.json        |   19 +
 .../query-tests/queries/function_asinh.proto.bin   |    4 +
 .../query-tests/queries/function_atan.json         |   19 +
 .../query-tests/queries/function_atan.proto.bin    |    4 +
 .../query-tests/queries/function_atan2.json        |   31 +
 .../query-tests/queries/function_atan2.proto.bin   |  Bin 0 -> 181 bytes
 .../query-tests/queries/function_atanh.json        |   19 +
 .../query-tests/queries/function_atanh.proto.bin   |    4 +
 .../query-tests/queries/function_avg.json          |   19 +
 .../query-tests/queries/function_avg.proto.bin     |    4 +
 .../query-tests/queries/function_bin.json          |   19 +
 .../query-tests/queries/function_bin.proto.bin     |    4 +
 .../query-tests/queries/function_bitwise_not.json  |   19 +
 .../queries/function_bitwise_not.proto.bin         |    5 +
 .../query-tests/queries/function_bround.json       |   23 +
 .../query-tests/queries/function_bround.proto.bin  |    5 +
 .../query-tests/queries/function_ceil.json         |   19 +
 .../query-tests/queries/function_ceil.proto.bin    |    4 +
 .../query-tests/queries/function_ceil_scale.json   |   23 +
 .../queries/function_ceil_scale.proto.bin          |    5 +
 .../query-tests/queries/function_coalesce.json     |   23 +
 .../queries/function_coalesce.proto.bin            |    5 +
 .../query-tests/queries/function_col.json          |    2 +-
 .../query-tests/queries/function_col.proto.bin     |    4 +-
 .../query-tests/queries/function_collect_list.json |   19 +
 .../queries/function_collect_list.proto.bin        |    4 +
 .../query-tests/queries/function_collect_set.json  |   19 +
 .../queries/function_collect_set.proto.bin         |    4 +
 .../query-tests/queries/function_conv.json         |   27 +
 .../query-tests/queries/function_conv.proto.bin    |    7 +
 .../query-tests/queries/function_corr.json         |   23 +
 .../query-tests/queries/function_corr.proto.bin    |    5 +
 .../query-tests/queries/function_cos.json          |   19 +
 .../query-tests/queries/function_cos.proto.bin     |    4 +
 .../query-tests/queries/function_cosh.json         |   19 +
 .../query-tests/queries/function_cosh.proto.bin    |    4 +
 .../query-tests/queries/function_cot.json          |   19 +
 .../query-tests/queries/function_cot.proto.bin     |    4 +
 .../query-tests/queries/function_count.json        |   19 +
 .../query-tests/queries/function_count.proto.bin   |    4 +
 .../queries/function_countDistinct.json            |   24 +
 .../queries/function_countDistinct.proto.bin       |    5 +
 .../query-tests/queries/function_covar_pop.json    |   23 +
 .../queries/function_covar_pop.proto.bin           |    5 +
 .../query-tests/queries/function_covar_samp.json   |   23 +
 .../queries/function_covar_samp.proto.bin          |    6 +
 .../query-tests/queries/function_csc.json          |   19 +
 .../query-tests/queries/function_csc.proto.bin     |    4 +
 .../query-tests/queries/function_degrees.json      |   19 +
 .../query-tests/queries/function_degrees.proto.bin |    4 +
 .../query-tests/queries/function_desc.json         |   20 +
 .../query-tests/queries/function_desc.proto.bin    |    4 +
 .../queries/function_desc_nulls_first.json         |   20 +
 .../queries/function_desc_nulls_first.proto.bin    |    4 +
 .../queries/function_desc_nulls_last.json          |   20 +
 .../queries/function_desc_nulls_last.proto.bin     |    4 +
 .../query-tests/queries/function_exp.json          |   19 +
 .../query-tests/queries/function_exp.proto.bin     |    4 +
 .../query-tests/queries/function_expm1.json        |   19 +
 .../query-tests/queries/function_expm1.proto.bin   |    4 +
 .../query-tests/queries/function_expr.json         |   14 +
 .../query-tests/queries/function_expr.proto.bin    |    3 +
 .../query-tests/queries/function_factorial.json    |   28 +
 .../queries/function_factorial.proto.bin           |    6 +
 .../query-tests/queries/function_first.json        |   23 +
 .../query-tests/queries/function_first.proto.bin   |    5 +
 .../query-tests/queries/function_floor.json        |   19 +
 .../query-tests/queries/function_floor.proto.bin   |    4 +
 .../query-tests/queries/function_floor_scale.json  |   23 +
 .../queries/function_floor_scale.proto.bin         |    5 +
 .../query-tests/queries/function_greatest.json     |   32 +
 .../queries/function_greatest.proto.bin            |    7 +
 .../query-tests/queries/function_hex.json          |   19 +
 .../query-tests/queries/function_hex.proto.bin     |    4 +
 .../query-tests/queries/function_hypot.json        |   23 +
 .../query-tests/queries/function_hypot.proto.bin   |    5 +
 .../queries/function_input_file_name.json          |   14 +
 .../queries/function_input_file_name.proto.bin     |    3 +
 .../query-tests/queries/function_isnan.json        |   19 +
 .../query-tests/queries/function_isnan.proto.bin   |    4 +
 .../query-tests/queries/function_isnull.json       |   19 +
 .../query-tests/queries/function_isnull.proto.bin  |    4 +
 .../query-tests/queries/function_kurtosis.json     |   19 +
 .../queries/function_kurtosis.proto.bin            |    4 +
 .../query-tests/queries/function_last.json         |   23 +
 .../query-tests/queries/function_last.proto.bin    |  Bin 0 -> 171 bytes
 .../query-tests/queries/function_least.json        |   32 +
 .../query-tests/queries/function_least.proto.bin   |    7 +
 .../query-tests/queries/function_log.json          |   19 +
 .../query-tests/queries/function_log.proto.bin     |    4 +
 .../query-tests/queries/function_log10.json        |   19 +
 .../query-tests/queries/function_log10.proto.bin   |    4 +
 .../query-tests/queries/function_log1p.json        |   19 +
 .../query-tests/queries/function_log1p.proto.bin   |    4 +
 .../query-tests/queries/function_log2.json         |   19 +
 .../query-tests/queries/function_log2.proto.bin    |    4 +
 .../queries/function_log_with_base.json            |   23 +
 .../queries/function_log_with_base.proto.bin       |  Bin 0 -> 177 bytes
 .../query-tests/queries/function_map.json          |   31 +
 .../query-tests/queries/function_map.proto.bin     |    7 +
 .../queries/function_map_from_arrays.json          |   41 +
 .../queries/function_map_from_arrays.proto.bin     |    9 +
 .../query-tests/queries/function_max_by.json       |   23 +
 .../query-tests/queries/function_max_by.proto.bin  |    5 +
 .../query-tests/queries/function_median.json       |   19 +
 .../query-tests/queries/function_median.proto.bin  |    4 +
 .../query-tests/queries/function_min.json          |   19 +
 .../query-tests/queries/function_min.proto.bin     |    4 +
 .../query-tests/queries/function_min_by.json       |   23 +
 .../query-tests/queries/function_min_by.proto.bin  |    5 +
 .../query-tests/queries/function_mode.json         |   19 +
 .../query-tests/queries/function_mode.proto.bin    |    4 +
 .../function_monotonically_increasing_id.json      |   14 +
 .../function_monotonically_increasing_id.proto.bin |    3 +
 .../query-tests/queries/function_nanvl.json        |   23 +
 .../query-tests/queries/function_nanvl.proto.bin   |  Bin 0 -> 179 bytes
 .../query-tests/queries/function_negate.json       |   19 +
 .../query-tests/queries/function_negate.proto.bin  |    4 +
 .../queries/function_percentile_approx.json        |   27 +
 .../queries/function_percentile_approx.proto.bin   |    6 +
 .../query-tests/queries/function_pmod.json         |   23 +
 .../query-tests/queries/function_pmod.proto.bin    |    5 +
 .../query-tests/queries/function_pow.json          |   23 +
 .../query-tests/queries/function_pow.proto.bin     |    5 +
 .../query-tests/queries/function_product.json      |   19 +
 .../query-tests/queries/function_product.proto.bin |    4 +
 .../query-tests/queries/function_radians.json      |   19 +
 .../query-tests/queries/function_radians.proto.bin |    4 +
 .../queries/function_rand_with_seed.json           |   19 +
 .../queries/function_rand_with_seed.proto.bin      |    4 +
 .../queries/function_randn_with_seed.json          |   19 +
 .../queries/function_randn_with_seed.proto.bin     |    4 +
 .../query-tests/queries/function_rint.json         |   19 +
 .../query-tests/queries/function_rint.proto.bin    |    4 +
 .../query-tests/queries/function_round.json        |   23 +
 .../query-tests/queries/function_round.proto.bin   |    5 +
 .../query-tests/queries/function_sec.json          |   19 +
 .../query-tests/queries/function_sec.proto.bin     |    4 +
 .../query-tests/queries/function_shiftleft.json    |   23 +
 .../queries/function_shiftleft.proto.bin           |    5 +
 .../query-tests/queries/function_shiftright.json   |   23 +
 .../queries/function_shiftright.proto.bin          |    6 +
 .../queries/function_shiftrightunsigned.json       |   23 +
 .../queries/function_shiftrightunsigned.proto.bin  |    5 +
 .../query-tests/queries/function_signum.json       |   19 +
 .../query-tests/queries/function_signum.proto.bin  |    4 +
 .../query-tests/queries/function_sin.json          |   19 +
 .../query-tests/queries/function_sin.proto.bin     |    4 +
 .../query-tests/queries/function_sinh.json         |   19 +
 .../query-tests/queries/function_sinh.proto.bin    |    4 +
 .../query-tests/queries/function_skewness.json     |   19 +
 .../queries/function_skewness.proto.bin            |    4 +
 .../queries/function_spark_partition_id.json       |   14 +
 .../queries/function_spark_partition_id.proto.bin  |    3 +
 .../query-tests/queries/function_sqrt.json         |   19 +
 .../query-tests/queries/function_sqrt.proto.bin    |    4 +
 .../query-tests/queries/function_stddev.json       |   19 +
 .../query-tests/queries/function_stddev.proto.bin  |    4 +
 .../query-tests/queries/function_stddev_pop.json   |   19 +
 .../queries/function_stddev_pop.proto.bin          |    5 +
 .../query-tests/queries/function_stddev_samp.json  |   19 +
 .../queries/function_stddev_samp.proto.bin         |    4 +
 .../query-tests/queries/function_struct.json       |   23 +
 .../query-tests/queries/function_struct.proto.bin  |    5 +
 .../query-tests/queries/function_sum.json          |   19 +
 .../query-tests/queries/function_sum.proto.bin     |    4 +
 .../query-tests/queries/function_sum_distinct.json |   20 +
 .../queries/function_sum_distinct.proto.bin        |    4 +
 .../query-tests/queries/function_tan.json          |   19 +
 .../query-tests/queries/function_tan.proto.bin     |    4 +
 .../query-tests/queries/function_tanh.json         |   19 +
 .../query-tests/queries/function_tanh.proto.bin    |    4 +
 .../query-tests/queries/function_unhex.json        |   19 +
 .../query-tests/queries/function_unhex.proto.bin   |    4 +
 .../query-tests/queries/function_var_pop.json      |   19 +
 .../query-tests/queries/function_var_pop.proto.bin |    4 +
 .../query-tests/queries/function_var_samp.json     |   19 +
 .../queries/function_var_samp.proto.bin            |    4 +
 .../query-tests/queries/function_variance.json     |   19 +
 .../queries/function_variance.proto.bin            |    4 +
 304 files changed, 5399 insertions(+), 40 deletions(-)

diff --git a/connector/connect/client/jvm/src/main/scala/org/apache/spark/sql/Column.scala b/connector/connect/client/jvm/src/main/scala/org/apache/spark/sql/Column.scala
index 638029308d2..c3e1113aa45 100644
--- a/connector/connect/client/jvm/src/main/scala/org/apache/spark/sql/Column.scala
+++ b/connector/connect/client/jvm/src/main/scala/org/apache/spark/sql/Column.scala
@@ -1254,9 +1254,15 @@ private[sql] object Column {
     new Column(builder.build())
   }
 
-  private[sql] def fn(name: String, inputs: Column*): Column = Column { builder =>
-    builder.getUnresolvedFunctionBuilder
-      .setFunctionName(name)
-      .addAllArguments(inputs.map(_.expr).asJava)
+  private[sql] def fn(name: String, inputs: Column*): Column = {
+    fn(name, isDistinct = false, inputs: _*)
+  }
+
+  private[sql] def fn(name: String, isDistinct: Boolean, inputs: Column*): Column = Column {
+    builder =>
+      builder.getUnresolvedFunctionBuilder
+        .setFunctionName(name)
+        .setIsDistinct(isDistinct)
+        .addAllArguments(inputs.map(_.expr).asJava)
   }
 }
diff --git a/connector/connect/client/jvm/src/main/scala/org/apache/spark/sql/functions.scala b/connector/connect/client/jvm/src/main/scala/org/apache/spark/sql/functions.scala
index 6f433245cf3..c137ad9bdc9 100644
--- a/connector/connect/client/jvm/src/main/scala/org/apache/spark/sql/functions.scala
+++ b/connector/connect/client/jvm/src/main/scala/org/apache/spark/sql/functions.scala
@@ -28,7 +28,40 @@ import org.apache.spark.sql.connect.client.unsupported
 import org.apache.spark.sql.expressions.{ScalarUserDefinedFunction, UserDefinedFunction}
 
 /**
- * Commonly used functions available for DataFrame operations.
+ * Commonly used functions available for DataFrame operations. Using functions defined here
+ * provides a little bit more compile-time safety to make sure the function exists.
+ *
+ * Spark also includes more built-in functions that are less common and are not defined here. You
+ * can still access them (and all the functions defined here) using the `functions.expr()` API and
+ * calling them through a SQL expression string. You can find the entire list of functions at SQL
+ * API documentation of your Spark version, see also <a
+ * href="https://spark.apache.org/docs/latest/api/sql/index.html">the latest list</a>
+ *
+ * As an example, `isnan` is a function that is defined here. You can use `isnan(col("myCol"))` to
+ * invoke the `isnan` function. This way the programming language's compiler ensures `isnan`
+ * exists and is of the proper form. You can also use `expr("isnan(myCol)")` function to invoke
+ * the same function. In this case, Spark itself will ensure `isnan` exists when it analyzes the
+ * query.
+ *
+ * `regr_count` is an example of a function that is built-in but not defined here, because it is
+ * less commonly used. To invoke it, use `expr("regr_count(yCol, xCol)")`.
+ *
+ * This function APIs usually have methods with `Column` signature only because it can support not
+ * only `Column` but also other types such as a native string. The other variants currently exist
+ * for historical reasons.
+ *
+ * @groupname udf_funcs UDF functions
+ * @groupname agg_funcs Aggregate functions
+ * @groupname datetime_funcs Date time functions
+ * @groupname sort_funcs Sorting functions
+ * @groupname normal_funcs Non-aggregate functions
+ * @groupname math_funcs Math functions
+ * @groupname misc_funcs Misc functions
+ * @groupname window_funcs Window functions
+ * @groupname string_funcs String functions
+ * @groupname collection_funcs Collection functions
+ * @groupname partition_transforms Partition transform functions
+ * @groupname Ungrouped Support functions for DataFrames
  *
  * @since 3.4.0
  */
@@ -45,12 +78,12 @@ object functions {
   def col(colName: String): Column = Column(colName)
 
   /**
-   * Aggregate function: returns the maximum value of the expression in a group.
+   * Returns a [[Column]] based on the given column name. Alias of [[col]].
    *
-   * @group agg_funcs
+   * @group normal_funcs
    * @since 3.4.0
    */
-  def max(e: Column): Column = Column.fn("max", e)
+  def column(colName: String): Column = col(colName)
 
   private def createLiteral(f: proto.Expression.Literal.Builder => Unit): Column = Column {
     builder =>
@@ -76,6 +109,7 @@ object functions {
    *
    * @since 3.4.0
    */
+  @scala.annotation.tailrec
   def lit(literal: Any): Column = {
     literal match {
       case c: Column => c
@@ -99,49 +133,2115 @@ object functions {
       case _ => unsupported(s"literal $literal not supported (yet).")
     }
   }
+  //////////////////////////////////////////////////////////////////////////////////////////////
+  // Sort functions
+  //////////////////////////////////////////////////////////////////////////////////////////////
 
   /**
-   * Evaluates a list of conditions and returns one of multiple possible result expressions. If
-   * otherwise is not defined at the end, null is returned for unmatched conditions.
+   * Returns a sort expression based on ascending order of the column.
+   * {{{
+   *   df.sort(asc("dept"), desc("age"))
+   * }}}
    *
+   * @group sort_funcs
+   * @since 3.4.0
+   */
+  def asc(columnName: String): Column = Column(columnName).asc
+
+  /**
+   * Returns a sort expression based on ascending order of the column, and null values return
+   * before non-null values.
    * {{{
-   *   // Example: encoding gender string column into integer.
+   *   df.sort(asc_nulls_first("dept"), desc("age"))
+   * }}}
    *
-   *   // Scala:
-   *   people.select(when(people("gender") === "male", 0)
-   *     .when(people("gender") === "female", 1)
-   *     .otherwise(2))
+   * @group sort_funcs
+   * @since 3.4.0
+   */
+  def asc_nulls_first(columnName: String): Column = Column(columnName).asc_nulls_first
+
+  /**
+   * Returns a sort expression based on ascending order of the column, and null values appear
+   * after non-null values.
+   * {{{
+   *   df.sort(asc_nulls_last("dept"), desc("age"))
+   * }}}
    *
-   *   // Java:
-   *   people.select(when(col("gender").equalTo("male"), 0)
-   *     .when(col("gender").equalTo("female"), 1)
-   *     .otherwise(2))
+   * @group sort_funcs
+   * @since 3.4.0
+   */
+  def asc_nulls_last(columnName: String): Column = Column(columnName).asc_nulls_last
+
+  /**
+   * Returns a sort expression based on the descending order of the column.
+   * {{{
+   *   df.sort(asc("dept"), desc("age"))
    * }}}
    *
-   * @group normal_funcs
+   * @group sort_funcs
    * @since 3.4.0
    */
-  def when(condition: Column, value: Any): Column = Column { builder =>
-    builder.getUnresolvedFunctionBuilder
-      .setFunctionName("when")
-      .addArguments(condition.expr)
-      .addArguments(lit(value).expr)
-  }
+  def desc(columnName: String): Column = Column(columnName).desc
 
   /**
-   * Parses the expression string into the column that it represents, similar to
-   * [[Dataset#selectExpr]].
+   * Returns a sort expression based on the descending order of the column, and null values appear
+   * before non-null values.
    * {{{
-   *   // get the number of words of each length
-   *   df.groupBy(expr("length(word)")).count()
+   *   df.sort(asc("dept"), desc_nulls_first("age"))
    * }}}
    *
-   * @group normal_funcs
+   * @group sort_funcs
+   * @since 3.4.0
    */
-  def expr(expr: String): Column = Column { builder =>
-    builder.getExpressionStringBuilder.setExpression(expr)
+  def desc_nulls_first(columnName: String): Column = Column(columnName).desc_nulls_first
+
+  /**
+   * Returns a sort expression based on the descending order of the column, and null values appear
+   * after non-null values.
+   * {{{
+   *   df.sort(asc("dept"), desc_nulls_last("age"))
+   * }}}
+   *
+   * @group sort_funcs
+   * @since 3.4.0
+   */
+  def desc_nulls_last(columnName: String): Column = Column(columnName).desc_nulls_last
+
+  //////////////////////////////////////////////////////////////////////////////////////////////
+  // Aggregate functions
+  //////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use approx_count_distinct", "2.1.0")
+  def approxCountDistinct(e: Column): Column = approx_count_distinct(e)
+
+  /**
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use approx_count_distinct", "2.1.0")
+  def approxCountDistinct(columnName: String): Column = approx_count_distinct(columnName)
+
+  /**
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use approx_count_distinct", "2.1.0")
+  def approxCountDistinct(e: Column, rsd: Double): Column = approx_count_distinct(e, rsd)
+
+  /**
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use approx_count_distinct", "2.1.0")
+  def approxCountDistinct(columnName: String, rsd: Double): Column = {
+    approx_count_distinct(Column(columnName), rsd)
+  }
+
+  /**
+   * Aggregate function: returns the approximate number of distinct items in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def approx_count_distinct(e: Column): Column = Column.fn("approx_count_distinct", e)
+
+  /**
+   * Aggregate function: returns the approximate number of distinct items in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def approx_count_distinct(columnName: String): Column = approx_count_distinct(
+    column(columnName))
+
+  /**
+   * Aggregate function: returns the approximate number of distinct items in a group.
+   *
+   * @param rsd
+   *   maximum relative standard deviation allowed (default = 0.05)
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def approx_count_distinct(e: Column, rsd: Double): Column = {
+    Column.fn("approx_count_distinct", e, lit(rsd))
+  }
+
+  /**
+   * Aggregate function: returns the approximate number of distinct items in a group.
+   *
+   * @param rsd
+   *   maximum relative standard deviation allowed (default = 0.05)
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def approx_count_distinct(columnName: String, rsd: Double): Column = {
+    approx_count_distinct(Column(columnName), rsd)
+  }
+
+  /**
+   * Aggregate function: returns the average of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def avg(e: Column): Column = Column.fn("avg", e)
+
+  /**
+   * Aggregate function: returns the average of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def avg(columnName: String): Column = avg(Column(columnName))
+
+  /**
+   * Aggregate function: returns a list of objects with duplicates.
+   *
+   * @note
+   *   The function is non-deterministic because the order of collected results depends on the
+   *   order of the rows which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def collect_list(e: Column): Column = Column.fn("collect_list", e)
+
+  /**
+   * Aggregate function: returns a list of objects with duplicates.
+   *
+   * @note
+   *   The function is non-deterministic because the order of collected results depends on the
+   *   order of the rows which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def collect_list(columnName: String): Column = collect_list(Column(columnName))
+
+  /**
+   * Aggregate function: returns a set of objects with duplicate elements eliminated.
+   *
+   * @note
+   *   The function is non-deterministic because the order of collected results depends on the
+   *   order of the rows which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def collect_set(e: Column): Column = Column.fn("collect_set", e)
+
+  /**
+   * Aggregate function: returns a set of objects with duplicate elements eliminated.
+   *
+   * @note
+   *   The function is non-deterministic because the order of collected results depends on the
+   *   order of the rows which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def collect_set(columnName: String): Column = collect_set(Column(columnName))
+
+  /**
+   * Aggregate function: returns the Pearson Correlation Coefficient for two columns.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def corr(column1: Column, column2: Column): Column = Column.fn("corr", column1, column2)
+
+  /**
+   * Aggregate function: returns the Pearson Correlation Coefficient for two columns.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def corr(columnName1: String, columnName2: String): Column = {
+    corr(Column(columnName1), Column(columnName2))
+  }
+
+  /**
+   * Aggregate function: returns the number of items in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def count(e: Column): Column = Column.fn("count", e)
+
+  /**
+   * Aggregate function: returns the number of distinct items in a group.
+   *
+   * An alias of `count_distinct`, and it is encouraged to use `count_distinct` directly.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def countDistinct(expr: Column, exprs: Column*): Column = count_distinct(expr, exprs: _*)
+
+  /**
+   * Aggregate function: returns the number of distinct items in a group.
+   *
+   * An alias of `count_distinct`, and it is encouraged to use `count_distinct` directly.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def countDistinct(columnName: String, columnNames: String*): Column =
+    count_distinct(Column(columnName), columnNames.map(Column.apply): _*)
+
+  /**
+   * Aggregate function: returns the number of distinct items in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def count_distinct(expr: Column, exprs: Column*): Column =
+    Column.fn("count", isDistinct = true, expr +: exprs: _*)
+
+  /**
+   * Aggregate function: returns the population covariance for two columns.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def covar_pop(column1: Column, column2: Column): Column =
+    Column.fn("covar_pop", column1, column2)
+
+  /**
+   * Aggregate function: returns the population covariance for two columns.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def covar_pop(columnName1: String, columnName2: String): Column = {
+    covar_pop(Column(columnName1), Column(columnName2))
+  }
+
+  /**
+   * Aggregate function: returns the sample covariance for two columns.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def covar_samp(column1: Column, column2: Column): Column =
+    Column.fn("covar_samp", column1, column2)
+
+  /**
+   * Aggregate function: returns the sample covariance for two columns.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def covar_samp(columnName1: String, columnName2: String): Column =
+    covar_samp(Column(columnName1), Column(columnName2))
+
+  /**
+   * Aggregate function: returns the first value in a group.
+   *
+   * The function by default returns the first values it sees. It will return the first non-null
+   * value it sees when ignoreNulls is set to true. If all values are null, then null is returned.
+   *
+   * @note
+   *   The function is non-deterministic because its results depends on the order of the rows
+   *   which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def first(e: Column, ignoreNulls: Boolean): Column =
+    Column.fn("first", e, lit(ignoreNulls))
+
+  /**
+   * Aggregate function: returns the first value of a column in a group.
+   *
+   * The function by default returns the first values it sees. It will return the first non-null
+   * value it sees when ignoreNulls is set to true. If all values are null, then null is returned.
+   *
+   * @note
+   *   The function is non-deterministic because its results depends on the order of the rows
+   *   which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def first(columnName: String, ignoreNulls: Boolean): Column = {
+    first(Column(columnName), ignoreNulls)
   }
 
+  /**
+   * Aggregate function: returns the first value in a group.
+   *
+   * The function by default returns the first values it sees. It will return the first non-null
+   * value it sees when ignoreNulls is set to true. If all values are null, then null is returned.
+   *
+   * @note
+   *   The function is non-deterministic because its results depends on the order of the rows
+   *   which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def first(e: Column): Column = first(e, ignoreNulls = false)
+
+  /**
+   * Aggregate function: returns the first value of a column in a group.
+   *
+   * The function by default returns the first values it sees. It will return the first non-null
+   * value it sees when ignoreNulls is set to true. If all values are null, then null is returned.
+   *
+   * @note
+   *   The function is non-deterministic because its results depends on the order of the rows
+   *   which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def first(columnName: String): Column = first(Column(columnName))
+
+  /**
+   * Aggregate function: indicates whether a specified column in a GROUP BY list is aggregated or
+   * not, returns 1 for aggregated or 0 for not aggregated in the result set.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def grouping(e: Column): Column = Column.fn("grouping", e)
+
+  /**
+   * Aggregate function: indicates whether a specified column in a GROUP BY list is aggregated or
+   * not, returns 1 for aggregated or 0 for not aggregated in the result set.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def grouping(columnName: String): Column = grouping(Column(columnName))
+
+  /**
+   * Aggregate function: returns the level of grouping, equals to
+   *
+   * {{{
+   *   (grouping(c1) <<; (n-1)) + (grouping(c2) <<; (n-2)) + ... + grouping(cn)
+   * }}}
+   *
+   * @note
+   *   The list of columns should match with grouping columns exactly, or empty (means all the
+   *   grouping columns).
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def grouping_id(cols: Column*): Column = Column.fn("grouping_id", cols: _*)
+
+  /**
+   * Aggregate function: returns the level of grouping, equals to
+   *
+   * {{{
+   *   (grouping(c1) <<; (n-1)) + (grouping(c2) <<; (n-2)) + ... + grouping(cn)
+   * }}}
+   *
+   * @note
+   *   The list of columns should match with grouping columns exactly.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def grouping_id(colName: String, colNames: String*): Column =
+    grouping_id((Seq(colName) ++ colNames).map(n => Column(n)): _*)
+
+  /**
+   * Aggregate function: returns the kurtosis of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def kurtosis(e: Column): Column = Column.fn("kurtosis", e)
+
+  /**
+   * Aggregate function: returns the kurtosis of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def kurtosis(columnName: String): Column = kurtosis(Column(columnName))
+
+  /**
+   * Aggregate function: returns the last value in a group.
+   *
+   * The function by default returns the last values it sees. It will return the last non-null
+   * value it sees when ignoreNulls is set to true. If all values are null, then null is returned.
+   *
+   * @note
+   *   The function is non-deterministic because its results depends on the order of the rows
+   *   which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def last(e: Column, ignoreNulls: Boolean): Column =
+    Column.fn("last", e, lit(ignoreNulls))
+
+  /**
+   * Aggregate function: returns the last value of the column in a group.
+   *
+   * The function by default returns the last values it sees. It will return the last non-null
+   * value it sees when ignoreNulls is set to true. If all values are null, then null is returned.
+   *
+   * @note
+   *   The function is non-deterministic because its results depends on the order of the rows
+   *   which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def last(columnName: String, ignoreNulls: Boolean): Column =
+    last(Column(columnName), ignoreNulls)
+
+  /**
+   * Aggregate function: returns the last value in a group.
+   *
+   * The function by default returns the last values it sees. It will return the last non-null
+   * value it sees when ignoreNulls is set to true. If all values are null, then null is returned.
+   *
+   * @note
+   *   The function is non-deterministic because its results depends on the order of the rows
+   *   which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def last(e: Column): Column = last(e, ignoreNulls = false)
+
+  /**
+   * Aggregate function: returns the last value of the column in a group.
+   *
+   * The function by default returns the last values it sees. It will return the last non-null
+   * value it sees when ignoreNulls is set to true. If all values are null, then null is returned.
+   *
+   * @note
+   *   The function is non-deterministic because its results depends on the order of the rows
+   *   which may be non-deterministic after a shuffle.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def last(columnName: String): Column = last(Column(columnName), ignoreNulls = false)
+
+  /**
+   * Aggregate function: returns the most frequent value in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def mode(e: Column): Column = Column.fn("mode", e)
+
+  /**
+   * Aggregate function: returns the maximum value of the expression in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def max(e: Column): Column = Column.fn("max", e)
+
+  /**
+   * Aggregate function: returns the maximum value of the column in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def max(columnName: String): Column = max(Column(columnName))
+
+  /**
+   * Aggregate function: returns the value associated with the maximum value of ord.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def max_by(e: Column, ord: Column): Column = Column.fn("max_by", e, ord)
+
+  /**
+   * Aggregate function: returns the average of the values in a group. Alias for avg.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def mean(e: Column): Column = avg(e)
+
+  /**
+   * Aggregate function: returns the average of the values in a group. Alias for avg.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def mean(columnName: String): Column = avg(columnName)
+
+  /**
+   * Aggregate function: returns the median of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def median(e: Column): Column = Column.fn("median", e)
+
+  /**
+   * Aggregate function: returns the minimum value of the expression in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def min(e: Column): Column = Column.fn("min", e)
+
+  /**
+   * Aggregate function: returns the minimum value of the column in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def min(columnName: String): Column = min(Column(columnName))
+
+  /**
+   * Aggregate function: returns the value associated with the minimum value of ord.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def min_by(e: Column, ord: Column): Column = Column.fn("min_by", e, ord)
+
+  /**
+   * Aggregate function: returns the approximate `percentile` of the numeric column `col` which is
+   * the smallest value in the ordered `col` values (sorted from least to greatest) such that no
+   * more than `percentage` of `col` values is less than the value or equal to that value.
+   *
+   * If percentage is an array, each value must be between 0.0 and 1.0. If it is a single floating
+   * point value, it must be between 0.0 and 1.0.
+   *
+   * The accuracy parameter is a positive numeric literal which controls approximation accuracy at
+   * the cost of memory. Higher value of accuracy yields better accuracy, 1.0/accuracy is the
+   * relative error of the approximation.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def percentile_approx(e: Column, percentage: Column, accuracy: Column): Column =
+    Column.fn("percentile_approx", e, percentage, accuracy)
+
+  /**
+   * Aggregate function: returns the product of all numerical elements in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def product(e: Column): Column = Column.fn("product", e)
+
+  /**
+   * Aggregate function: returns the skewness of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def skewness(e: Column): Column = Column.fn("skewness", e)
+
+  /**
+   * Aggregate function: returns the skewness of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def skewness(columnName: String): Column = skewness(Column(columnName))
+
+  /**
+   * Aggregate function: alias for `stddev_samp`.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def stddev(e: Column): Column = Column.fn("stddev", e)
+
+  /**
+   * Aggregate function: alias for `stddev_samp`.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def stddev(columnName: String): Column = stddev(Column(columnName))
+
+  /**
+   * Aggregate function: returns the sample standard deviation of the expression in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def stddev_samp(e: Column): Column = Column.fn("stddev_samp", e)
+
+  /**
+   * Aggregate function: returns the sample standard deviation of the expression in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def stddev_samp(columnName: String): Column = stddev_samp(Column(columnName))
+
+  /**
+   * Aggregate function: returns the population standard deviation of the expression in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def stddev_pop(e: Column): Column = Column.fn("stddev_pop", e)
+
+  /**
+   * Aggregate function: returns the population standard deviation of the expression in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def stddev_pop(columnName: String): Column = stddev_pop(Column(columnName))
+
+  /**
+   * Aggregate function: returns the sum of all values in the expression.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def sum(e: Column): Column = Column.fn("sum", e)
+
+  /**
+   * Aggregate function: returns the sum of all values in the given column.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def sum(columnName: String): Column = sum(Column(columnName))
+
+  /**
+   * Aggregate function: returns the sum of distinct values in the expression.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use sum_distinct", "3.2.0")
+  def sumDistinct(e: Column): Column = sum_distinct(e)
+
+  /**
+   * Aggregate function: returns the sum of distinct values in the expression.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use sum_distinct", "3.2.0")
+  def sumDistinct(columnName: String): Column = sum_distinct(Column(columnName))
+
+  /**
+   * Aggregate function: returns the sum of distinct values in the expression.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def sum_distinct(e: Column): Column = Column.fn("sum", isDistinct = true, e)
+
+  /**
+   * Aggregate function: alias for `var_samp`.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def variance(e: Column): Column = Column.fn("variance", e)
+
+  /**
+   * Aggregate function: alias for `var_samp`.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def variance(columnName: String): Column = variance(Column(columnName))
+
+  /**
+   * Aggregate function: returns the unbiased variance of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def var_samp(e: Column): Column = Column.fn("var_samp", e)
+
+  /**
+   * Aggregate function: returns the unbiased variance of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def var_samp(columnName: String): Column = var_samp(Column(columnName))
+
+  /**
+   * Aggregate function: returns the population variance of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def var_pop(e: Column): Column = Column.fn("var_pop", e)
+
+  /**
+   * Aggregate function: returns the population variance of the values in a group.
+   *
+   * @group agg_funcs
+   * @since 3.4.0
+   */
+  def var_pop(columnName: String): Column = var_pop(Column(columnName))
+
+  //////////////////////////////////////////////////////////////////////////////////////////////
+  // Non-aggregate functions
+  //////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Creates a new array column. The input columns must all have the same data type.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def array(cols: Column*): Column = Column.fn("array", cols: _*)
+
+  /**
+   * Creates a new array column. The input columns must all have the same data type.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def array(colName: String, colNames: String*): Column = {
+    array((colName +: colNames).map(col): _*)
+  }
+
+  /**
+   * Creates a new map column. The input columns must be grouped as key-value pairs, e.g. (key1,
+   * value1, key2, value2, ...). The key columns must all have the same data type, and can't be
+   * null. The value columns must all have the same data type.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def map(cols: Column*): Column = Column.fn("map", cols: _*)
+
+  /**
+   * Creates a new map column. The array in the first column is used for keys. The array in the
+   * second column is used for values. All elements in the array for key should not be null.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def map_from_arrays(keys: Column, values: Column): Column =
+    Column.fn("map_from_arrays", keys, values)
+
+  /**
+   * Returns the first column that is not null, or null if all inputs are null.
+   *
+   * For example, `coalesce(a, b, c)` will return a if a is not null, or b if a is null and b is
+   * not null, or c if both a and b are null but c is not null.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def coalesce(e: Column*): Column = Column.fn("coalesce", e: _*)
+
+  /**
+   * Creates a string column for the file name of the current Spark task.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def input_file_name(): Column = Column.fn("input_file_name")
+
+  /**
+   * Return true iff the column is NaN.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def isnan(e: Column): Column = e.isNaN
+
+  /**
+   * Return true iff the column is null.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def isnull(e: Column): Column = e.isNull
+
+  /**
+   * A column expression that generates monotonically increasing 64-bit integers.
+   *
+   * The generated ID is guaranteed to be monotonically increasing and unique, but not
+   * consecutive. The current implementation puts the partition ID in the upper 31 bits, and the
+   * record number within each partition in the lower 33 bits. The assumption is that the data
+   * frame has less than 1 billion partitions, and each partition has less than 8 billion records.
+   *
+   * As an example, consider a `DataFrame` with two partitions, each with 3 records. This
+   * expression would return the following IDs:
+   *
+   * {{{
+   * 0, 1, 2, 8589934592 (1L << 33), 8589934593, 8589934594.
+   * }}}
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use monotonically_increasing_id()", "2.0.0")
+  def monotonicallyIncreasingId(): Column = monotonically_increasing_id()
+
+  /**
+   * A column expression that generates monotonically increasing 64-bit integers.
+   *
+   * The generated ID is guaranteed to be monotonically increasing and unique, but not
+   * consecutive. The current implementation puts the partition ID in the upper 31 bits, and the
+   * record number within each partition in the lower 33 bits. The assumption is that the data
+   * frame has less than 1 billion partitions, and each partition has less than 8 billion records.
+   *
+   * As an example, consider a `DataFrame` with two partitions, each with 3 records. This
+   * expression would return the following IDs:
+   *
+   * {{{
+   * 0, 1, 2, 8589934592 (1L << 33), 8589934593, 8589934594.
+   * }}}
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def monotonically_increasing_id(): Column = Column.fn("monotonically_increasing_id")
+
+  /**
+   * Returns col1 if it is not NaN, or col2 if col1 is NaN.
+   *
+   * Both inputs should be floating point columns (DoubleType or FloatType).
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def nanvl(col1: Column, col2: Column): Column = Column.fn("nanvl", col1, col2)
+
+  /**
+   * Unary minus, i.e. negate the expression.
+   * {{{
+   *   // Select the amount column and negates all values.
+   *   // Scala:
+   *   df.select( -df("amount") )
+   *
+   *   // Java:
+   *   df.select( negate(df.col("amount")) );
+   * }}}
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def negate(e: Column): Column = -e
+
+  /**
+   * Inversion of boolean expression, i.e. NOT.
+   * {{{
+   *   // Scala: select rows that are not active (isActive === false)
+   *   df.filter( !df("isActive") )
+   *
+   *   // Java:
+   *   df.filter( not(df.col("isActive")) );
+   * }}}
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def not(e: Column): Column = !e
+
+  /**
+   * Generate a random column with independent and identically distributed (i.i.d.) samples
+   * uniformly distributed in [0.0, 1.0).
+   *
+   * @note
+   *   The function is non-deterministic in general case.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def rand(seed: Long): Column = Column.fn("rand", lit(seed))
+
+  /**
+   * Generate a random column with independent and identically distributed (i.i.d.) samples
+   * uniformly distributed in [0.0, 1.0).
+   *
+   * @note
+   *   The function is non-deterministic in general case.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def rand(): Column = Column.fn("rand")
+
+  /**
+   * Generate a column with independent and identically distributed (i.i.d.) samples from the
+   * standard normal distribution.
+   *
+   * @note
+   *   The function is non-deterministic in general case.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def randn(seed: Long): Column = Column.fn("randn", lit(seed))
+
+  /**
+   * Generate a column with independent and identically distributed (i.i.d.) samples from the
+   * standard normal distribution.
+   *
+   * @note
+   *   The function is non-deterministic in general case.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def randn(): Column = Column.fn("randn")
+
+  /**
+   * Partition ID.
+   *
+   * @note
+   *   This is non-deterministic because it depends on data partitioning and task scheduling.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def spark_partition_id(): Column = Column.fn("spark_partition_id")
+
+  /**
+   * Computes the square root of the specified float value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def sqrt(e: Column): Column = Column.fn("sqrt", e)
+
+  /**
+   * Computes the square root of the specified float value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def sqrt(colName: String): Column = sqrt(Column(colName))
+
+  /**
+   * Creates a new struct column. If the input column is a column in a `DataFrame`, or a derived
+   * column expression that is named (i.e. aliased), its name would be retained as the
+   * StructField's name, otherwise, the newly generated StructField's name would be auto generated
+   * as `col` with a suffix `index + 1`, i.e. col1, col2, col3, ...
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def struct(cols: Column*): Column = Column.fn("struct", cols: _*)
+
+  /**
+   * Creates a new struct column that composes multiple input columns.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def struct(colName: String, colNames: String*): Column = {
+    struct((colName +: colNames).map(col): _*)
+  }
+
+  /**
+   * Evaluates a list of conditions and returns one of multiple possible result expressions. If
+   * otherwise is not defined at the end, null is returned for unmatched conditions.
+   *
+   * {{{
+   *   // Example: encoding gender string column into integer.
+   *
+   *   // Scala:
+   *   people.select(when(people("gender") === "male", 0)
+   *     .when(people("gender") === "female", 1)
+   *     .otherwise(2))
+   *
+   *   // Java:
+   *   people.select(when(col("gender").equalTo("male"), 0)
+   *     .when(col("gender").equalTo("female"), 1)
+   *     .otherwise(2))
+   * }}}
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def when(condition: Column, value: Any): Column = Column { builder =>
+    builder.getUnresolvedFunctionBuilder
+      .setFunctionName("when")
+      .addArguments(condition.expr)
+      .addArguments(lit(value).expr)
+  }
+
+  /**
+   * Computes bitwise NOT (~) of a number.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use bitwise_not", "3.2.0")
+  def bitwiseNOT(e: Column): Column = bitwise_not(e)
+
+  /**
+   * Computes bitwise NOT (~) of a number.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  def bitwise_not(e: Column): Column = Column.fn("~", e)
+
+  /**
+   * Parses the expression string into the column that it represents, similar to
+   * [[Dataset#selectExpr]].
+   * {{{
+   *   // get the number of words of each length
+   *   df.groupBy(expr("length(word)")).count()
+   * }}}
+   *
+   * @group normal_funcs
+   */
+  def expr(expr: String): Column = Column { builder =>
+    builder.getExpressionStringBuilder.setExpression(expr)
+  }
+
+  //////////////////////////////////////////////////////////////////////////////////////////////
+  // Math Functions
+  //////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Computes the absolute value of a numeric value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def abs(e: Column): Column = Column.fn("abs", e)
+
+  /**
+   * @return
+   *   inverse cosine of `e` in radians, as if computed by `java.lang.Math.acos`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def acos(e: Column): Column = Column.fn("acos", e)
+
+  /**
+   * @return
+   *   inverse cosine of `columnName`, as if computed by `java.lang.Math.acos`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def acos(columnName: String): Column = acos(Column(columnName))
+
+  /**
+   * @return
+   *   inverse hyperbolic cosine of `e`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def acosh(e: Column): Column = Column.fn("acosh", e)
+
+  /**
+   * @return
+   *   inverse hyperbolic cosine of `columnName`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def acosh(columnName: String): Column = acosh(Column(columnName))
+
+  /**
+   * @return
+   *   inverse sine of `e` in radians, as if computed by `java.lang.Math.asin`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def asin(e: Column): Column = Column.fn("asin", e)
+
+  /**
+   * @return
+   *   inverse sine of `columnName`, as if computed by `java.lang.Math.asin`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def asin(columnName: String): Column = asin(Column(columnName))
+
+  /**
+   * @return
+   *   inverse hyperbolic sine of `e`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def asinh(e: Column): Column = Column.fn("asinh", e)
+
+  /**
+   * @return
+   *   inverse hyperbolic sine of `columnName`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def asinh(columnName: String): Column = asinh(Column(columnName))
+
+  /**
+   * @return
+   *   inverse tangent of `e` as if computed by `java.lang.Math.atan`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan(e: Column): Column = Column.fn("atan", e)
+
+  /**
+   * @return
+   *   inverse tangent of `columnName`, as if computed by `java.lang.Math.atan`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan(columnName: String): Column = atan(Column(columnName))
+
+  /**
+   * @param y
+   *   coordinate on y-axis
+   * @param x
+   *   coordinate on x-axis
+   * @return
+   *   the <i>theta</i> component of the point (<i>r</i>, <i>theta</i>) in polar coordinates that
+   *   corresponds to the point (<i>x</i>, <i>y</i>) in Cartesian coordinates, as if computed by
+   *   `java.lang.Math.atan2`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan2(y: Column, x: Column): Column = Column.fn("atan2", y, x)
+
+  /**
+   * @param y
+   *   coordinate on y-axis
+   * @param xName
+   *   coordinate on x-axis
+   * @return
+   *   the <i>theta</i> component of the point (<i>r</i>, <i>theta</i>) in polar coordinates that
+   *   corresponds to the point (<i>x</i>, <i>y</i>) in Cartesian coordinates, as if computed by
+   *   `java.lang.Math.atan2`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan2(y: Column, xName: String): Column = atan2(y, Column(xName))
+
+  /**
+   * @param yName
+   *   coordinate on y-axis
+   * @param x
+   *   coordinate on x-axis
+   * @return
+   *   the <i>theta</i> component of the point (<i>r</i>, <i>theta</i>) in polar coordinates that
+   *   corresponds to the point (<i>x</i>, <i>y</i>) in Cartesian coordinates, as if computed by
+   *   `java.lang.Math.atan2`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan2(yName: String, x: Column): Column = atan2(Column(yName), x)
+
+  /**
+   * @param yName
+   *   coordinate on y-axis
+   * @param xName
+   *   coordinate on x-axis
+   * @return
+   *   the <i>theta</i> component of the point (<i>r</i>, <i>theta</i>) in polar coordinates that
+   *   corresponds to the point (<i>x</i>, <i>y</i>) in Cartesian coordinates, as if computed by
+   *   `java.lang.Math.atan2`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan2(yName: String, xName: String): Column =
+    atan2(Column(yName), Column(xName))
+
+  /**
+   * @param y
+   *   coordinate on y-axis
+   * @param xValue
+   *   coordinate on x-axis
+   * @return
+   *   the <i>theta</i> component of the point (<i>r</i>, <i>theta</i>) in polar coordinates that
+   *   corresponds to the point (<i>x</i>, <i>y</i>) in Cartesian coordinates, as if computed by
+   *   `java.lang.Math.atan2`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan2(y: Column, xValue: Double): Column = atan2(y, lit(xValue))
+
+  /**
+   * @param yName
+   *   coordinate on y-axis
+   * @param xValue
+   *   coordinate on x-axis
+   * @return
+   *   the <i>theta</i> component of the point (<i>r</i>, <i>theta</i>) in polar coordinates that
+   *   corresponds to the point (<i>x</i>, <i>y</i>) in Cartesian coordinates, as if computed by
+   *   `java.lang.Math.atan2`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan2(yName: String, xValue: Double): Column = atan2(Column(yName), xValue)
+
+  /**
+   * @param yValue
+   *   coordinate on y-axis
+   * @param x
+   *   coordinate on x-axis
+   * @return
+   *   the <i>theta</i> component of the point (<i>r</i>, <i>theta</i>) in polar coordinates that
+   *   corresponds to the point (<i>x</i>, <i>y</i>) in Cartesian coordinates, as if computed by
+   *   `java.lang.Math.atan2`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan2(yValue: Double, x: Column): Column = atan2(lit(yValue), x)
+
+  /**
+   * @param yValue
+   *   coordinate on y-axis
+   * @param xName
+   *   coordinate on x-axis
+   * @return
+   *   the <i>theta</i> component of the point (<i>r</i>, <i>theta</i>) in polar coordinates that
+   *   corresponds to the point (<i>x</i>, <i>y</i>) in Cartesian coordinates, as if computed by
+   *   `java.lang.Math.atan2`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atan2(yValue: Double, xName: String): Column = atan2(yValue, Column(xName))
+
+  /**
+   * @return
+   *   inverse hyperbolic tangent of `e`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atanh(e: Column): Column = Column.fn("atanh", e)
+
+  /**
+   * @return
+   *   inverse hyperbolic tangent of `columnName`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def atanh(columnName: String): Column = atanh(Column(columnName))
+
+  /**
+   * An expression that returns the string representation of the binary value of the given long
+   * column. For example, bin("12") returns "1100".
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def bin(e: Column): Column = Column.fn("bin", e)
+
+  /**
+   * An expression that returns the string representation of the binary value of the given long
+   * column. For example, bin("12") returns "1100".
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def bin(columnName: String): Column = bin(Column(columnName))
+
+  /**
+   * Computes the cube-root of the given value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def cbrt(e: Column): Column = Column.fn("cbrt", e)
+
+  /**
+   * Computes the cube-root of the given column.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def cbrt(columnName: String): Column = cbrt(Column(columnName))
+
+  /**
+   * Computes the ceiling of the given value of `e` to `scale` decimal places.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def ceil(e: Column, scale: Column): Column = Column.fn("ceil", e, scale)
+
+  /**
+   * Computes the ceiling of the given value of `e` to 0 decimal places.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def ceil(e: Column): Column = Column.fn("ceil", e)
+
+  /**
+   * Computes the ceiling of the given value of `e` to 0 decimal places.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def ceil(columnName: String): Column = ceil(Column(columnName))
+
+  /**
+   * Convert a number in a string column from one base to another.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def conv(num: Column, fromBase: Int, toBase: Int): Column =
+    Column.fn("conv", num, lit(fromBase), lit(toBase))
+
+  /**
+   * @param e
+   *   angle in radians
+   * @return
+   *   cosine of the angle, as if computed by `java.lang.Math.cos`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def cos(e: Column): Column = Column.fn("cos", e)
+
+  /**
+   * @param columnName
+   *   angle in radians
+   * @return
+   *   cosine of the angle, as if computed by `java.lang.Math.cos`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def cos(columnName: String): Column = cos(Column(columnName))
+
+  /**
+   * @param e
+   *   hyperbolic angle
+   * @return
+   *   hyperbolic cosine of the angle, as if computed by `java.lang.Math.cosh`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def cosh(e: Column): Column = Column.fn("cosh", e)
+
+  /**
+   * @param columnName
+   *   hyperbolic angle
+   * @return
+   *   hyperbolic cosine of the angle, as if computed by `java.lang.Math.cosh`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def cosh(columnName: String): Column = cosh(Column(columnName))
+
+  /**
+   * @param e
+   *   angle in radians
+   * @return
+   *   cotangent of the angle
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def cot(e: Column): Column = Column.fn("cot", e)
+
+  /**
+   * @param e
+   *   angle in radians
+   * @return
+   *   cosecant of the angle
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def csc(e: Column): Column = Column.fn("csc", e)
+
+  /**
+   * Computes the exponential of the given value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def exp(e: Column): Column = Column.fn("exp", e)
+
+  /**
+   * Computes the exponential of the given column.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def exp(columnName: String): Column = exp(Column(columnName))
+
+  /**
+   * Computes the exponential of the given value minus one.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def expm1(e: Column): Column = Column.fn("expm1", e)
+
+  /**
+   * Computes the exponential of the given column minus one.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def expm1(columnName: String): Column = expm1(Column(columnName))
+
+  /**
+   * Computes the factorial of the given value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def factorial(e: Column): Column = Column.fn("factorial", e)
+
+  /**
+   * Computes the floor of the given value of `e` to `scale` decimal places.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def floor(e: Column, scale: Column): Column = Column.fn("floor", e, scale)
+
+  /**
+   * Computes the floor of the given value of `e` to 0 decimal places.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def floor(e: Column): Column = Column.fn("floor", e)
+
+  /**
+   * Computes the floor of the given column value to 0 decimal places.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def floor(columnName: String): Column = floor(Column(columnName))
+
+  /**
+   * Returns the greatest value of the list of values, skipping null values. This function takes
+   * at least 2 parameters. It will return null iff all parameters are null.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def greatest(exprs: Column*): Column = Column.fn("greatest", exprs: _*)
+
+  /**
+   * Returns the greatest value of the list of column names, skipping null values. This function
+   * takes at least 2 parameters. It will return null iff all parameters are null.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def greatest(columnName: String, columnNames: String*): Column =
+    greatest((columnName +: columnNames).map(Column.apply): _*)
+
+  /**
+   * Computes hex value of the given column.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def hex(column: Column): Column = Column.fn("hex", column)
+
+  /**
+   * Inverse of hex. Interprets each pair of characters as a hexadecimal number and converts to
+   * the byte representation of number.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def unhex(column: Column): Column = Column.fn("unhex", column)
+
+  /**
+   * Computes `sqrt(a^2^ + b^2^)` without intermediate overflow or underflow.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def hypot(l: Column, r: Column): Column = Column.fn("hypot", l, r)
+
+  /**
+   * Computes `sqrt(a^2^ + b^2^)` without intermediate overflow or underflow.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def hypot(l: Column, rightName: String): Column = hypot(l, Column(rightName))
+
+  /**
+   * Computes `sqrt(a^2^ + b^2^)` without intermediate overflow or underflow.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def hypot(leftName: String, r: Column): Column = hypot(Column(leftName), r)
+
+  /**
+   * Computes `sqrt(a^2^ + b^2^)` without intermediate overflow or underflow.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def hypot(leftName: String, rightName: String): Column =
+    hypot(Column(leftName), Column(rightName))
+
+  /**
+   * Computes `sqrt(a^2^ + b^2^)` without intermediate overflow or underflow.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def hypot(l: Column, r: Double): Column = hypot(l, lit(r))
+
+  /**
+   * Computes `sqrt(a^2^ + b^2^)` without intermediate overflow or underflow.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def hypot(leftName: String, r: Double): Column = hypot(Column(leftName), r)
+
+  /**
+   * Computes `sqrt(a^2^ + b^2^)` without intermediate overflow or underflow.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def hypot(l: Double, r: Column): Column = hypot(lit(l), r)
+
+  /**
+   * Computes `sqrt(a^2^ + b^2^)` without intermediate overflow or underflow.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def hypot(l: Double, rightName: String): Column = hypot(l, Column(rightName))
+
+  /**
+   * Returns the least value of the list of values, skipping null values. This function takes at
+   * least 2 parameters. It will return null iff all parameters are null.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def least(exprs: Column*): Column = Column.fn("least", exprs: _*)
+
+  /**
+   * Returns the least value of the list of column names, skipping null values. This function
+   * takes at least 2 parameters. It will return null iff all parameters are null.
+   *
+   * @group normal_funcs
+   * @since 3.4.0
+   */
+  @scala.annotation.varargs
+  def least(columnName: String, columnNames: String*): Column =
+    least((columnName +: columnNames).map(Column.apply): _*)
+
+  /**
+   * Computes the natural logarithm of the given value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log(e: Column): Column = Column.fn("log", e)
+
+  /**
+   * Computes the natural logarithm of the given column.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log(columnName: String): Column = log(Column(columnName))
+
+  /**
+   * Returns the first argument-base logarithm of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log(base: Double, a: Column): Column = Column.fn("log", lit(base), a)
+
+  /**
+   * Returns the first argument-base logarithm of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log(base: Double, columnName: String): Column = log(base, Column(columnName))
+
+  /**
+   * Computes the logarithm of the given value in base 10.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log10(e: Column): Column = Column.fn("log10", e)
+
+  /**
+   * Computes the logarithm of the given value in base 10.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log10(columnName: String): Column = log10(Column(columnName))
+
+  /**
+   * Computes the natural logarithm of the given value plus one.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log1p(e: Column): Column = Column.fn("log1p", e)
+
+  /**
+   * Computes the natural logarithm of the given column plus one.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log1p(columnName: String): Column = log1p(Column(columnName))
+
+  /**
+   * Computes the logarithm of the given column in base 2.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log2(expr: Column): Column = Column.fn("log2", expr)
+
+  /**
+   * Computes the logarithm of the given value in base 2.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def log2(columnName: String): Column = log2(Column(columnName))
+
+  /**
+   * Returns the value of the first argument raised to the power of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def pow(l: Column, r: Column): Column = Column.fn("power", l, r)
+
+  /**
+   * Returns the value of the first argument raised to the power of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def pow(l: Column, rightName: String): Column = pow(l, Column(rightName))
+
+  /**
+   * Returns the value of the first argument raised to the power of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def pow(leftName: String, r: Column): Column = pow(Column(leftName), r)
+
+  /**
+   * Returns the value of the first argument raised to the power of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def pow(leftName: String, rightName: String): Column = pow(Column(leftName), Column(rightName))
+
+  /**
+   * Returns the value of the first argument raised to the power of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def pow(l: Column, r: Double): Column = pow(l, lit(r))
+
+  /**
+   * Returns the value of the first argument raised to the power of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def pow(leftName: String, r: Double): Column = pow(Column(leftName), r)
+
+  /**
+   * Returns the value of the first argument raised to the power of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def pow(l: Double, r: Column): Column = pow(lit(l), r)
+
+  /**
+   * Returns the value of the first argument raised to the power of the second argument.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def pow(l: Double, rightName: String): Column = pow(l, Column(rightName))
+
+  /**
+   * Returns the positive value of dividend mod divisor.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def pmod(dividend: Column, divisor: Column): Column = Column.fn("pmod", dividend, divisor)
+
+  /**
+   * Returns the double value that is closest in value to the argument and is equal to a
+   * mathematical integer.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def rint(e: Column): Column = Column.fn("rint", e)
+
+  /**
+   * Returns the double value that is closest in value to the argument and is equal to a
+   * mathematical integer.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def rint(columnName: String): Column = rint(Column(columnName))
+
+  /**
+   * Returns the value of the column `e` rounded to 0 decimal places with HALF_UP round mode.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def round(e: Column): Column = round(e, 0)
+
+  /**
+   * Round the value of `e` to `scale` decimal places with HALF_UP round mode if `scale` is
+   * greater than or equal to 0 or at integral part when `scale` is less than 0.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def round(e: Column, scale: Int): Column = Column.fn("round", e, lit(scale))
+
+  /**
+   * Returns the value of the column `e` rounded to 0 decimal places with HALF_EVEN round mode.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def bround(e: Column): Column = bround(e, 0)
+
+  /**
+   * Round the value of `e` to `scale` decimal places with HALF_EVEN round mode if `scale` is
+   * greater than or equal to 0 or at integral part when `scale` is less than 0.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def bround(e: Column, scale: Int): Column = Column.fn("bround", e, lit(scale))
+
+  /**
+   * @param e
+   *   angle in radians
+   * @return
+   *   secant of the angle
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def sec(e: Column): Column = Column.fn("sec", e)
+
+  /**
+   * Shift the given value numBits left. If the given value is a long value, this function will
+   * return a long value else it will return an integer value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use shiftleft", "3.2.0")
+  def shiftLeft(e: Column, numBits: Int): Column = shiftleft(e, numBits)
+
+  /**
+   * Shift the given value numBits left. If the given value is a long value, this function will
+   * return a long value else it will return an integer value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def shiftleft(e: Column, numBits: Int): Column = Column.fn("shiftleft", e, lit(numBits))
+
+  /**
+   * (Signed) shift the given value numBits right. If the given value is a long value, it will
+   * return a long value else it will return an integer value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use shiftright", "3.2.0")
+  def shiftRight(e: Column, numBits: Int): Column = shiftright(e, numBits)
+
+  /**
+   * (Signed) shift the given value numBits right. If the given value is a long value, it will
+   * return a long value else it will return an integer value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def shiftright(e: Column, numBits: Int): Column = Column.fn("shiftright", e, lit(numBits))
+
+  /**
+   * Unsigned shift the given value numBits right. If the given value is a long value, it will
+   * return a long value else it will return an integer value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use shiftrightunsigned", "3.2.0")
+  def shiftRightUnsigned(e: Column, numBits: Int): Column = shiftrightunsigned(e, numBits)
+
+  /**
+   * Unsigned shift the given value numBits right. If the given value is a long value, it will
+   * return a long value else it will return an integer value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def shiftrightunsigned(e: Column, numBits: Int): Column =
+    Column.fn("shiftrightunsigned", e, lit(numBits))
+
+  /**
+   * Computes the signum of the given value.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def signum(e: Column): Column = Column.fn("signum", e)
+
+  /**
+   * Computes the signum of the given column.
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def signum(columnName: String): Column = signum(Column(columnName))
+
+  /**
+   * @param e
+   *   angle in radians
+   * @return
+   *   sine of the angle, as if computed by `java.lang.Math.sin`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def sin(e: Column): Column = Column.fn("sin", e)
+
+  /**
+   * @param columnName
+   *   angle in radians
+   * @return
+   *   sine of the angle, as if computed by `java.lang.Math.sin`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def sin(columnName: String): Column = sin(Column(columnName))
+
+  /**
+   * @param e
+   *   hyperbolic angle
+   * @return
+   *   hyperbolic sine of the given value, as if computed by `java.lang.Math.sinh`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def sinh(e: Column): Column = Column.fn("sinh", e)
+
+  /**
+   * @param columnName
+   *   hyperbolic angle
+   * @return
+   *   hyperbolic sine of the given value, as if computed by `java.lang.Math.sinh`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def sinh(columnName: String): Column = sinh(Column(columnName))
+
+  /**
+   * @param e
+   *   angle in radians
+   * @return
+   *   tangent of the given value, as if computed by `java.lang.Math.tan`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def tan(e: Column): Column = Column.fn("tan", e)
+
+  /**
+   * @param columnName
+   *   angle in radians
+   * @return
+   *   tangent of the given value, as if computed by `java.lang.Math.tan`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def tan(columnName: String): Column = tan(Column(columnName))
+
+  /**
+   * @param e
+   *   hyperbolic angle
+   * @return
+   *   hyperbolic tangent of the given value, as if computed by `java.lang.Math.tanh`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def tanh(e: Column): Column = Column.fn("tanh", e)
+
+  /**
+   * @param columnName
+   *   hyperbolic angle
+   * @return
+   *   hyperbolic tangent of the given value, as if computed by `java.lang.Math.tanh`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def tanh(columnName: String): Column = tanh(Column(columnName))
+
+  /**
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use degrees", "2.1.0")
+  def toDegrees(e: Column): Column = degrees(e)
+
+  /**
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use degrees", "2.1.0")
+  def toDegrees(columnName: String): Column = degrees(Column(columnName))
+
+  /**
+   * Converts an angle measured in radians to an approximately equivalent angle measured in
+   * degrees.
+   *
+   * @param e
+   *   angle in radians
+   * @return
+   *   angle in degrees, as if computed by `java.lang.Math.toDegrees`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def degrees(e: Column): Column = Column.fn("degrees", e)
+
+  /**
+   * Converts an angle measured in radians to an approximately equivalent angle measured in
+   * degrees.
+   *
+   * @param columnName
+   *   angle in radians
+   * @return
+   *   angle in degrees, as if computed by `java.lang.Math.toDegrees`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def degrees(columnName: String): Column = degrees(Column(columnName))
+
+  /**
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use radians", "2.1.0")
+  def toRadians(e: Column): Column = radians(e)
+
+  /**
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  @deprecated("Use radians", "2.1.0")
+  def toRadians(columnName: String): Column = radians(Column(columnName))
+
+  /**
+   * Converts an angle measured in degrees to an approximately equivalent angle measured in
+   * radians.
+   *
+   * @param e
+   *   angle in degrees
+   * @return
+   *   angle in radians, as if computed by `java.lang.Math.toRadians`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def radians(e: Column): Column = Column.fn("radians", e)
+
+  /**
+   * Converts an angle measured in degrees to an approximately equivalent angle measured in
+   * radians.
+   *
+   * @param columnName
+   *   angle in degrees
+   * @return
+   *   angle in radians, as if computed by `java.lang.Math.toRadians`
+   *
+   * @group math_funcs
+   * @since 3.4.0
+   */
+  def radians(columnName: String): Column = radians(Column(columnName))
+
+  //////////////////////////////////////////////////////////////////////////////////////////////
+  // Scala UDF functions
+  //////////////////////////////////////////////////////////////////////////////////////////////
+
   // scalastyle:off line.size.limit
 
   /**
diff --git a/connector/connect/client/jvm/src/test/scala/org/apache/spark/sql/FunctionTestSuite.scala b/connector/connect/client/jvm/src/test/scala/org/apache/spark/sql/FunctionTestSuite.scala
new file mode 100644
index 00000000000..2da2b6ff391
--- /dev/null
+++ b/connector/connect/client/jvm/src/test/scala/org/apache/spark/sql/FunctionTestSuite.scala
@@ -0,0 +1,168 @@
+/*
+ * 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.spark.sql
+
+import org.scalatest.funsuite.{AnyFunSuite => ConnectFunSuite} // scalastyle:ignore funsuite
+
+import org.apache.spark.sql.functions._
+
+/**
+ * Tests for client local function behavior.
+ *
+ * This mostly tests is various function variants produce the same columns.
+ */
+class FunctionTestSuite extends ConnectFunSuite {
+  private def testEquals(name: String, columns: Column*): Unit = {
+    test(name) {
+      assert(columns.nonEmpty)
+      val unique = columns.distinct
+      assert(unique.size == 1)
+    }
+  }
+
+  private val a = col("a")
+  private val b = col("b")
+  private val c = col("c")
+
+  testEquals("col/column", a, column("a"))
+  testEquals("asc/asc_nulls_first", asc("a"), asc_nulls_first("a"))
+  testEquals("desc/desc_nulls_last", desc("a"), desc_nulls_last("a"))
+  testEquals(
+    "approx_count_distinct",
+    approxCountDistinct(a),
+    approxCountDistinct("a"),
+    approx_count_distinct("a"),
+    approx_count_distinct(a))
+  testEquals(
+    "approx_count_distinct rsd",
+    approxCountDistinct(a, 0.1),
+    approxCountDistinct("a", 0.1),
+    approx_count_distinct("a", 0.1),
+    approx_count_distinct(a, 0.1))
+  testEquals("avg/mean", avg("a"), avg(a), mean(a), mean("a"))
+  testEquals("collect_list", collect_list("a"), collect_list(a))
+  testEquals("collect_set", collect_set("a"), collect_set(a))
+  testEquals("corr", corr("a", "b"), corr(a, b))
+  testEquals(
+    "count_distinct",
+    countDistinct(a, b, c),
+    countDistinct("a", "b", "c"),
+    count_distinct(a, b, c))
+  testEquals("covar_pop", covar_pop(a, b), covar_pop("a", "b"))
+  testEquals("covar_samp", covar_samp(a, b), covar_samp("a", "b"))
+  testEquals(
+    "first",
+    first("a"),
+    first(a),
+    first("a", ignoreNulls = false),
+    first(a, ignoreNulls = false))
+  testEquals("grouping", grouping("a"), grouping(a))
+  testEquals("grouping_id", grouping_id("a", "b"), grouping_id(a, b))
+  testEquals("kurtosis", kurtosis("a"), kurtosis(a))
+  testEquals(
+    "last",
+    last("a"),
+    last(a),
+    last("a", ignoreNulls = false),
+    last(a, ignoreNulls = false))
+  testEquals("max", max("a"), max(a))
+  testEquals("min", min("a"), min(a))
+  testEquals("skewness", skewness("a"), skewness(a))
+  testEquals("stddev", stddev("a"), stddev(a))
+  testEquals("stddev_samp", stddev_samp("a"), stddev_samp(a))
+  testEquals("stddev_pop", stddev_pop("a"), stddev_pop(a))
+  testEquals("sum", sum("a"), sum(a))
+  testEquals("sum_distinct", sumDistinct("a"), sumDistinct(a), sum_distinct(a))
+  testEquals("variance", variance("a"), variance(a))
+  testEquals("var_samp", var_samp("a"), var_samp(a))
+  testEquals("var_pop", var_pop("a"), var_pop(a))
+  testEquals("array", array(a, b, c), array("a", "b", "c"))
+  testEquals(
+    "monotonicallyIncreasingId",
+    monotonicallyIncreasingId(),
+    monotonically_increasing_id())
+  testEquals("sqrt", sqrt("a"), sqrt(a))
+  testEquals("struct", struct(a, c, b), struct("a", "c", "b"))
+  testEquals("bitwise_not", bitwiseNOT(a), bitwise_not(a))
+  testEquals("acos", acos("a"), acos(a))
+  testEquals("acosh", acosh("a"), acosh(a))
+  testEquals("asin", asin("a"), asin(a))
+  testEquals("asinh", asinh("a"), asinh(a))
+  testEquals("atan", atan("a"), atan(a))
+  testEquals("atan2", atan2(a, b), atan2(a, "b"), atan2("a", b), atan2("a", "b"))
+  testEquals("atanh", atanh("a"), atanh(a))
+  testEquals("bin", bin("a"), bin(a))
+  testEquals("cbrt", cbrt("a"), cbrt(a))
+  testEquals("ceil", ceil(a), ceil("a"))
+  testEquals("cos", cos("a"), cos(a))
+  testEquals("cosh", cosh("a"), cosh(a))
+  testEquals("exp", exp("a"), exp(a))
+  testEquals("expm1", expm1("a"), expm1(a))
+  testEquals("floor", floor(a), floor("a"))
+  testEquals("greatest", greatest(a, b, c), greatest("a", "b", "c"))
+  testEquals("hypot", hypot(a, b), hypot("a", b), hypot(a, "b"), hypot("a", "b"))
+  testEquals(
+    "hypot right fixed",
+    hypot(lit(3d), a),
+    hypot(lit(3d), "a"),
+    hypot(3d, a),
+    hypot(3d, "a"))
+  testEquals(
+    "hypot left fixed",
+    hypot(a, lit(4d)),
+    hypot(a, 4d),
+    hypot("a", lit(4d)),
+    hypot("a", 4d))
+  testEquals("least", least(a, b, c), least("a", "b", "c"))
+  testEquals("log", log("a"), log(a))
+  testEquals("log base", log(2.0, "a"), log(2.0, a))
+  testEquals("log10", log10("a"), log10(a))
+  testEquals("log1p", log1p("a"), log1p(a))
+  testEquals("log2", log2("a"), log2(a))
+  testEquals("pow", pow(a, b), pow(a, "b"), pow("a", b), pow("a", "b"))
+  testEquals("pow left fixed", pow(lit(7d), b), pow(lit(7d), "b"), pow(7d, b), pow(7d, "b"))
+  testEquals("pow right fixed", pow(a, lit(9d)), pow(a, 9d), pow("a", lit(9d)), pow("a", 9d))
+  testEquals("rint", rint(a), rint("a"))
+  testEquals("round", round(a), round(a, 0))
+  testEquals("bround", bround(a), bround(a, 0))
+  testEquals("shiftleft", shiftLeft(a, 2), shiftleft(a, 2))
+  testEquals("shiftright", shiftRight(a, 3), shiftright(a, 3))
+  testEquals("shiftrightunsigned", shiftRightUnsigned(a, 3), shiftrightunsigned(a, 3))
+  testEquals("signum", signum("a"), signum(a))
+  testEquals("sin", sin("a"), sin(a))
+  testEquals("sinh", sinh("a"), sinh(a))
+  testEquals("tan", tan("a"), tan(a))
+  testEquals("tanh", tanh("a"), tanh(a))
+  testEquals("degrees", toDegrees(a), toDegrees("a"), degrees(a), degrees("a"))
+  testEquals("radians", toRadians(a), toRadians("a"), radians(a), radians("a"))
+
+  test("rand no seed") {
+    val e = rand().expr
+    assert(e.hasUnresolvedFunction)
+    val fn = e.getUnresolvedFunction
+    assert(fn.getFunctionName == "rand")
+    assert(fn.getArgumentsCount == 0)
+  }
+
+  test("randn no seed") {
+    val e = randn().expr
+    assert(e.hasUnresolvedFunction)
+    val fn = e.getUnresolvedFunction
+    assert(fn.getFunctionName == "randn")
+    assert(fn.getArgumentsCount == 0)
+  }
+}
diff --git a/connector/connect/client/jvm/src/test/scala/org/apache/spark/sql/PlanGenerationTestSuite.scala b/connector/connect/client/jvm/src/test/scala/org/apache/spark/sql/PlanGenerationTestSuite.scala
index 8d4550dfe4f..b591daef391 100644
--- a/connector/connect/client/jvm/src/test/scala/org/apache/spark/sql/PlanGenerationTestSuite.scala
+++ b/connector/connect/client/jvm/src/test/scala/org/apache/spark/sql/PlanGenerationTestSuite.scala
@@ -30,6 +30,7 @@ import org.apache.spark.connect.proto
 import org.apache.spark.internal.Logging
 import org.apache.spark.sql.{functions => fn}
 import org.apache.spark.sql.connect.client.SparkConnectClient
+import org.apache.spark.sql.functions.lit
 import org.apache.spark.sql.types._
 
 // scalastyle:off
@@ -776,12 +777,414 @@ class PlanGenerationTestSuite extends ConnectFunSuite with BeforeAndAfterAll wit
   }
 
   /* Function API */
-  test("function col") {
-    select(fn.col("id"))
+  private def functionTest(name: String)(f: => Column): Unit = {
+    test("function " + name) {
+      complex.select(f)
+    }
+  }
+
+  functionTest("col") {
+    fn.col("id")
+  }
+
+  functionTest("asc") {
+    fn.asc("a")
+  }
+
+  functionTest("asc_nulls_first") {
+    fn.asc_nulls_first("a")
+  }
+
+  functionTest("asc_nulls_last") {
+    fn.asc_nulls_last("a")
+  }
+
+  functionTest("desc") {
+    fn.desc("a")
+  }
+
+  functionTest("desc_nulls_first") {
+    fn.desc_nulls_first("a")
+  }
+
+  functionTest("desc_nulls_last") {
+    fn.desc_nulls_last("a")
+  }
+
+  functionTest("approx_count_distinct") {
+    fn.approx_count_distinct("a")
+  }
+
+  functionTest("approx_count_distinct rsd") {
+    fn.approx_count_distinct("a", 0.1)
+  }
+
+  functionTest("avg") {
+    fn.avg("a")
+  }
+
+  functionTest("collect_list") {
+    fn.collect_list("a")
+  }
+
+  functionTest("collect_set") {
+    fn.collect_set("a")
+  }
+
+  functionTest("corr") {
+    fn.corr("a", "b")
+  }
+
+  functionTest("count") {
+    fn.count(fn.col("a"))
+  }
+
+  functionTest("countDistinct") {
+    fn.countDistinct("a", "g")
+  }
+
+  functionTest("covar_pop") {
+    fn.covar_pop("a", "b")
+  }
+
+  functionTest("covar_samp") {
+    fn.covar_samp("a", "b")
+  }
+
+  functionTest("first") {
+    fn.first("a", ignoreNulls = true)
+  }
+
+  functionTest("kurtosis") {
+    fn.kurtosis("a")
+  }
+
+  functionTest("last") {
+    fn.last("a", ignoreNulls = false)
+  }
+
+  functionTest("mode") {
+    fn.mode(fn.col("a"))
   }
 
   test("function max") {
-    select(fn.max(Column("id")))
+    select(fn.max("id"))
+  }
+
+  functionTest("max_by") {
+    fn.max_by(fn.col("a"), fn.col("b"))
+  }
+
+  functionTest("median") {
+    fn.median(fn.col("a"))
+  }
+
+  functionTest("min") {
+    fn.min("a")
+  }
+
+  functionTest("min_by") {
+    fn.min_by(fn.col("a"), fn.col("b"))
+  }
+
+  functionTest("percentile_approx") {
+    fn.percentile_approx(fn.col("a"), fn.lit(0.3), fn.lit(20))
+  }
+
+  functionTest("product") {
+    fn.product(fn.col("a"))
+  }
+
+  functionTest("skewness") {
+    fn.skewness("a")
+  }
+
+  functionTest("stddev") {
+    fn.stddev("a")
+  }
+
+  functionTest("stddev_samp") {
+    fn.stddev_samp("a")
+  }
+
+  functionTest("stddev_pop") {
+    fn.stddev_pop("a")
+  }
+
+  functionTest("sum") {
+    fn.sum("a")
+  }
+
+  functionTest("sum_distinct") {
+    fn.sum_distinct(fn.col("a"))
+  }
+
+  functionTest("variance") {
+    fn.variance("a")
+  }
+
+  functionTest("var_samp") {
+    fn.var_samp("a")
+  }
+
+  functionTest("var_pop") {
+    fn.var_pop("a")
+  }
+
+  functionTest("array") {
+    fn.array("a", "a")
+  }
+
+  functionTest("map") {
+    fn.map(fn.col("a"), fn.col("g"), lit(22), lit("dummy"))
+  }
+
+  functionTest("map_from_arrays") {
+    fn.map_from_arrays(fn.array(lit(1), lit(2)), fn.array(lit("one"), lit("two")))
+  }
+
+  functionTest("coalesce") {
+    fn.coalesce(fn.col("a"), lit(3))
+  }
+
+  functionTest("input_file_name") {
+    fn.input_file_name()
+  }
+
+  functionTest("isnan") {
+    fn.isnan(fn.col("b"))
+  }
+
+  functionTest("isnull") {
+    fn.isnull(fn.col("a"))
+  }
+
+  functionTest("monotonically_increasing_id") {
+    fn.monotonically_increasing_id()
+  }
+
+  functionTest("nanvl") {
+    fn.nanvl(lit(Double.NaN), fn.col("a"))
+  }
+
+  functionTest("negate") {
+    fn.negate(fn.col("a"))
+  }
+
+  functionTest("rand with seed") {
+    fn.rand(133)
+  }
+
+  functionTest("randn with seed") {
+    fn.randn(133)
+  }
+
+  functionTest("spark_partition_id") {
+    fn.spark_partition_id()
+  }
+
+  functionTest("sqrt") {
+    fn.sqrt("b")
+  }
+
+  functionTest("struct") {
+    fn.struct("a", "d")
+  }
+
+  functionTest("bitwise_not") {
+    fn.bitwise_not(fn.col("a"))
+  }
+
+  functionTest("expr") {
+    fn.expr("a + 1")
+  }
+
+  functionTest("abs") {
+    fn.abs(fn.col("a"))
+  }
+
+  functionTest("acos") {
+    fn.acos("b")
+  }
+
+  functionTest("acosh") {
+    fn.acosh("b")
+  }
+
+  functionTest("asin") {
+    fn.asin("b")
+  }
+
+  functionTest("asinh") {
+    fn.asinh("b")
+  }
+
+  functionTest("atan") {
+    fn.atan("b")
+  }
+
+  functionTest("atan2") {
+    fn.atan2(fn.col("a").cast("double"), "b")
+  }
+
+  functionTest("atanh") {
+    fn.atanh("b")
+  }
+
+  functionTest("bin") {
+    fn.bin("b")
+  }
+
+  functionTest("ceil") {
+    fn.ceil("b")
+  }
+
+  functionTest("ceil scale") {
+    fn.ceil(fn.col("b"), lit(2))
+  }
+
+  functionTest("conv") {
+    fn.conv(fn.col("b"), 10, 16)
+  }
+
+  functionTest("cos") {
+    fn.cos("b")
+  }
+
+  functionTest("cosh") {
+    fn.cosh("b")
+  }
+
+  functionTest("cot") {
+    fn.cot(fn.col("b"))
+  }
+
+  functionTest("csc") {
+    fn.csc(fn.col("b"))
+  }
+
+  functionTest("exp") {
+    fn.exp("b")
+  }
+
+  functionTest("expm1") {
+    fn.expm1("b")
+  }
+
+  functionTest("factorial") {
+    fn.factorial(fn.col("a") % 10)
+  }
+
+  functionTest("floor") {
+    fn.floor("b")
+  }
+
+  functionTest("floor scale") {
+    fn.floor(fn.col("b"), lit(2))
+  }
+
+  functionTest("greatest") {
+    fn.greatest(fn.col("a"), fn.col("d").getItem("a"))
+  }
+
+  functionTest("hex") {
+    fn.hex(fn.col("a"))
+  }
+
+  functionTest("unhex") {
+    fn.unhex(fn.col("a"))
+  }
+
+  functionTest("hypot") {
+    fn.hypot(fn.col("a"), fn.col("b"))
+  }
+
+  functionTest("least") {
+    fn.least(fn.col("a"), fn.col("d").getItem("a"))
+  }
+
+  functionTest("log") {
+    fn.log("b")
+  }
+
+  functionTest("log with base") {
+    fn.log(2, "b")
+  }
+
+  functionTest("log10") {
+    fn.log10("b")
+  }
+
+  functionTest("log1p") {
+    fn.log1p("a")
+  }
+
+  functionTest("log2") {
+    fn.log2("a")
+  }
+
+  functionTest("pow") {
+    fn.pow("a", "b")
+  }
+
+  functionTest("pmod") {
+    fn.pmod(fn.col("a"), fn.lit(10))
+  }
+
+  functionTest("rint") {
+    fn.rint("b")
+  }
+
+  functionTest("round") {
+    fn.round(fn.col("b"), 2)
+  }
+
+  functionTest("bround") {
+    fn.round(fn.col("b"), 2)
+  }
+
+  functionTest("sec") {
+    fn.sec(fn.col("b"))
+  }
+
+  functionTest("shiftleft") {
+    fn.shiftleft(fn.col("b"), 2)
+  }
+
+  functionTest("shiftright") {
+    fn.shiftright(fn.col("b"), 2)
+  }
+
+  functionTest("shiftrightunsigned") {
+    fn.shiftrightunsigned(fn.col("b"), 2)
+  }
+
+  functionTest("signum") {
+    fn.signum("b")
+  }
+
+  functionTest("sin") {
+    fn.sin("b")
+  }
+
+  functionTest("sinh") {
+    fn.sinh("b")
+  }
+
+  functionTest("tan") {
+    fn.tan("b")
+  }
+
+  functionTest("tanh") {
+    fn.tanh("b")
+  }
+
+  functionTest("degrees") {
+    fn.degrees("b")
+  }
+
+  functionTest("radians") {
+    fn.radians("b")
   }
 
   test("groupby agg") {
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_abs.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_abs.explain
new file mode 100644
index 00000000000..78093ca5448
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_abs.explain
@@ -0,0 +1,2 @@
+Project [abs(a#0) AS abs(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_acos.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_acos.explain
new file mode 100644
index 00000000000..e14a10911a4
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_acos.explain
@@ -0,0 +1,2 @@
+Project [ACOS(b#0) AS ACOS(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_acosh.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_acosh.explain
new file mode 100644
index 00000000000..735c181fd10
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_acosh.explain
@@ -0,0 +1,2 @@
+Project [ACOSH(b#0) AS ACOSH(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_approx_count_distinct.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_approx_count_distinct.explain
new file mode 100644
index 00000000000..2b002841dfc
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_approx_count_distinct.explain
@@ -0,0 +1,2 @@
+Aggregate [approx_count_distinct(a#0, 0.05, 0, 0) AS approx_count_distinct(a)#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_approx_count_distinct_rsd.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_approx_count_distinct_rsd.explain
new file mode 100644
index 00000000000..454b8a0ecc2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_approx_count_distinct_rsd.explain
@@ -0,0 +1,2 @@
+Aggregate [approx_count_distinct(a#0, 0.1, 0, 0) AS approx_count_distinct(a)#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_array.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_array.explain
new file mode 100644
index 00000000000..63726ee039b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_array.explain
@@ -0,0 +1,2 @@
+Project [array(a#0, a#0) AS array(a, a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_asc.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asc.explain
new file mode 100644
index 00000000000..8052f75b665
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asc.explain
@@ -0,0 +1,2 @@
+Project [a#0 ASC NULLS FIRST AS a ASC NULLS FIRST#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_asc_nulls_first.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asc_nulls_first.explain
new file mode 100644
index 00000000000..8052f75b665
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asc_nulls_first.explain
@@ -0,0 +1,2 @@
+Project [a#0 ASC NULLS FIRST AS a ASC NULLS FIRST#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_asc_nulls_last.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asc_nulls_last.explain
new file mode 100644
index 00000000000..3dcafb3bc9a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asc_nulls_last.explain
@@ -0,0 +1,2 @@
+Project [a#0 ASC NULLS LAST AS a ASC NULLS LAST#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_asin.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asin.explain
new file mode 100644
index 00000000000..d71385d4912
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asin.explain
@@ -0,0 +1,2 @@
+Project [ASIN(b#0) AS ASIN(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_asinh.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asinh.explain
new file mode 100644
index 00000000000..c341d6c7f35
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_asinh.explain
@@ -0,0 +1,2 @@
+Project [ASINH(b#0) AS ASINH(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_atan.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_atan.explain
new file mode 100644
index 00000000000..4be28fb2236
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_atan.explain
@@ -0,0 +1,2 @@
+Project [ATAN(b#0) AS ATAN(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_atan2.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_atan2.explain
new file mode 100644
index 00000000000..ebc8f138e7b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_atan2.explain
@@ -0,0 +1,2 @@
+Project [ATAN2(cast(a#0 as double), b#0) AS ATAN2(a, b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_atanh.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_atanh.explain
new file mode 100644
index 00000000000..68082ca2ec6
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_atanh.explain
@@ -0,0 +1,2 @@
+Project [ATANH(b#0) AS ATANH(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_avg.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_avg.explain
new file mode 100644
index 00000000000..f2849464dff
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_avg.explain
@@ -0,0 +1,2 @@
+Aggregate [avg(a#0) AS avg(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_bin.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_bin.explain
new file mode 100644
index 00000000000..00fe43204c9
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_bin.explain
@@ -0,0 +1,2 @@
+Project [bin(cast(b#0 as bigint)) AS bin(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_bitwise_not.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_bitwise_not.explain
new file mode 100644
index 00000000000..022a2d5095c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_bitwise_not.explain
@@ -0,0 +1,2 @@
+Project [~a#0 AS ~a#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_bround.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_bround.explain
new file mode 100644
index 00000000000..8bc86462fa2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_bround.explain
@@ -0,0 +1,2 @@
+Project [round(b#0, 2) AS round(b, 2)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_ceil.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_ceil.explain
new file mode 100644
index 00000000000..9cf776a8dba
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_ceil.explain
@@ -0,0 +1,2 @@
+Project [CEIL(b#0) AS CEIL(b)#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_ceil_scale.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_ceil_scale.explain
new file mode 100644
index 00000000000..cdf8d356e47
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_ceil_scale.explain
@@ -0,0 +1,2 @@
+Project [ceil(cast(b#0 as decimal(30,15)), 2) AS ceil(b, 2)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_coalesce.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_coalesce.explain
new file mode 100644
index 00000000000..61f494f6955
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_coalesce.explain
@@ -0,0 +1,2 @@
+Project [coalesce(a#0, 3) AS coalesce(a, 3)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_col.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_col.explain
index aac54ef5662..4519922d4cb 100644
--- a/connector/connect/common/src/test/resources/query-tests/explain-results/function_col.explain
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_col.explain
@@ -1,2 +1,2 @@
 Project [id#0L]
-+- LocalRelation <empty>, [id#0L, a#0, b#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_collect_list.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_collect_list.explain
new file mode 100644
index 00000000000..102f736c62e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_collect_list.explain
@@ -0,0 +1,2 @@
+Aggregate [collect_list(a#0, 0, 0) AS collect_list(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_collect_set.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_collect_set.explain
new file mode 100644
index 00000000000..18246a74ccc
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_collect_set.explain
@@ -0,0 +1,2 @@
+Aggregate [collect_set(a#0, 0, 0) AS collect_set(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_conv.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_conv.explain
new file mode 100644
index 00000000000..5b01bea3bea
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_conv.explain
@@ -0,0 +1,2 @@
+Project [conv(cast(b#0 as string), 10, 16, false) AS conv(b, 10, 16)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_corr.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_corr.explain
new file mode 100644
index 00000000000..1f7f4507e5e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_corr.explain
@@ -0,0 +1,2 @@
+Aggregate [corr(cast(a#0 as double), b#0) AS corr(a, b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_cos.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_cos.explain
new file mode 100644
index 00000000000..7eaea873192
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_cos.explain
@@ -0,0 +1,2 @@
+Project [COS(b#0) AS COS(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_cosh.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_cosh.explain
new file mode 100644
index 00000000000..55c72d81fac
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_cosh.explain
@@ -0,0 +1,2 @@
+Project [COSH(b#0) AS COSH(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_cot.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_cot.explain
new file mode 100644
index 00000000000..c4c720620e5
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_cot.explain
@@ -0,0 +1,2 @@
+Project [COT(b#0) AS COT(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_count.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_count.explain
new file mode 100644
index 00000000000..af2e5c27d5d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_count.explain
@@ -0,0 +1,2 @@
+Aggregate [count(a#0) AS count(a)#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_countDistinct.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_countDistinct.explain
new file mode 100644
index 00000000000..f74490f7b1f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_countDistinct.explain
@@ -0,0 +1,2 @@
+Aggregate [count(distinct a#0, g#0) AS count(DISTINCT a, g)#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_covar_pop.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_covar_pop.explain
new file mode 100644
index 00000000000..eb090cbbb14
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_covar_pop.explain
@@ -0,0 +1,2 @@
+Aggregate [covar_pop(cast(a#0 as double), b#0) AS covar_pop(a, b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_covar_samp.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_covar_samp.explain
new file mode 100644
index 00000000000..24dc636cfaa
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_covar_samp.explain
@@ -0,0 +1,2 @@
+Aggregate [covar_samp(cast(a#0 as double), b#0) AS covar_samp(a, b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_csc.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_csc.explain
new file mode 100644
index 00000000000..db0380a8d7e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_csc.explain
@@ -0,0 +1,2 @@
+Project [CSC(b#0) AS CSC(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_degrees.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_degrees.explain
new file mode 100644
index 00000000000..47caf440868
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_degrees.explain
@@ -0,0 +1,2 @@
+Project [DEGREES(b#0) AS DEGREES(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_desc.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_desc.explain
new file mode 100644
index 00000000000..5985746892b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_desc.explain
@@ -0,0 +1,2 @@
+Project [a#0 DESC NULLS LAST AS a DESC NULLS LAST#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_desc_nulls_first.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_desc_nulls_first.explain
new file mode 100644
index 00000000000..5d170cb3628
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_desc_nulls_first.explain
@@ -0,0 +1,2 @@
+Project [a#0 DESC NULLS FIRST AS a DESC NULLS FIRST#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_desc_nulls_last.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_desc_nulls_last.explain
new file mode 100644
index 00000000000..5985746892b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_desc_nulls_last.explain
@@ -0,0 +1,2 @@
+Project [a#0 DESC NULLS LAST AS a DESC NULLS LAST#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_exp.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_exp.explain
new file mode 100644
index 00000000000..e7299c1f2c7
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_exp.explain
@@ -0,0 +1,2 @@
+Project [EXP(b#0) AS EXP(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_expm1.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_expm1.explain
new file mode 100644
index 00000000000..aa111ee5f4c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_expm1.explain
@@ -0,0 +1,2 @@
+Project [EXPM1(b#0) AS EXPM1(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_expr.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_expr.explain
new file mode 100644
index 00000000000..c317af232f6
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_expr.explain
@@ -0,0 +1,2 @@
+Project [(a#0 + 1) AS (a + 1)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_factorial.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_factorial.explain
new file mode 100644
index 00000000000..e6b5c7ee90d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_factorial.explain
@@ -0,0 +1,2 @@
+Project [factorial((a#0 % 10)) AS factorial((a % 10))#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_first.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_first.explain
new file mode 100644
index 00000000000..0675353b706
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_first.explain
@@ -0,0 +1,2 @@
+Aggregate [first(a#0, true) AS first(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_floor.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_floor.explain
new file mode 100644
index 00000000000..67caaf17452
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_floor.explain
@@ -0,0 +1,2 @@
+Project [FLOOR(b#0) AS FLOOR(b)#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_floor_scale.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_floor_scale.explain
new file mode 100644
index 00000000000..c788eae3ab7
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_floor_scale.explain
@@ -0,0 +1,2 @@
+Project [floor(cast(b#0 as decimal(30,15)), 2) AS floor(b, 2)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_greatest.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_greatest.explain
new file mode 100644
index 00000000000..6347277cc59
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_greatest.explain
@@ -0,0 +1,2 @@
+Project [greatest(a#0, d#0.a) AS greatest(a, d.a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_hex.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_hex.explain
new file mode 100644
index 00000000000..0c01682b26e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_hex.explain
@@ -0,0 +1,2 @@
+Project [hex(cast(a#0 as bigint)) AS hex(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_hypot.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_hypot.explain
new file mode 100644
index 00000000000..524aa4388cf
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_hypot.explain
@@ -0,0 +1,2 @@
+Project [HYPOT(cast(a#0 as double), b#0) AS HYPOT(a, b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_input_file_name.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_input_file_name.explain
new file mode 100644
index 00000000000..7f411a857af
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_input_file_name.explain
@@ -0,0 +1,2 @@
+Project [input_file_name() AS input_file_name()#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_isnan.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_isnan.explain
new file mode 100644
index 00000000000..a93e063e4e1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_isnan.explain
@@ -0,0 +1,2 @@
+Project [isnan(b#0) AS isnan(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_isnull.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_isnull.explain
new file mode 100644
index 00000000000..a69a7d02807
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_isnull.explain
@@ -0,0 +1,2 @@
+Project [isnull(a#0) AS (a IS NULL)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_kurtosis.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_kurtosis.explain
new file mode 100644
index 00000000000..9af9e55d58e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_kurtosis.explain
@@ -0,0 +1,2 @@
+Aggregate [kurtosis(cast(a#0 as double)) AS kurtosis(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_last.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_last.explain
new file mode 100644
index 00000000000..a7ae558d5c9
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_last.explain
@@ -0,0 +1,2 @@
+Aggregate [last(a#0, false) AS last(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_least.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_least.explain
new file mode 100644
index 00000000000..afc3f6ca52c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_least.explain
@@ -0,0 +1,2 @@
+Project [least(a#0, d#0.a) AS least(a, d.a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_log.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log.explain
new file mode 100644
index 00000000000..d3c3743b1ef
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log.explain
@@ -0,0 +1,2 @@
+Project [LOG(E(), b#0) AS LOG(E(), b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_log10.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log10.explain
new file mode 100644
index 00000000000..ed6ce6bf132
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log10.explain
@@ -0,0 +1,2 @@
+Project [LOG10(b#0) AS LOG10(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_log1p.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log1p.explain
new file mode 100644
index 00000000000..dc98083c1dc
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log1p.explain
@@ -0,0 +1,2 @@
+Project [LOG1P(cast(a#0 as double)) AS LOG1P(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_log2.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log2.explain
new file mode 100644
index 00000000000..dbf43897ba5
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log2.explain
@@ -0,0 +1,2 @@
+Project [LOG2(cast(a#0 as double)) AS LOG2(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_log_with_base.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log_with_base.explain
new file mode 100644
index 00000000000..662845c9159
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_log_with_base.explain
@@ -0,0 +1,2 @@
+Project [LOG(2.0, b#0) AS LOG(2.0, b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_map.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_map.explain
new file mode 100644
index 00000000000..67b9bdb45b5
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_map.explain
@@ -0,0 +1,2 @@
+Project [map(a#0, g#0, 22, dummy) AS map(a, g, 22, dummy)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_map_from_arrays.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_map_from_arrays.explain
new file mode 100644
index 00000000000..08be7f83ce3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_map_from_arrays.explain
@@ -0,0 +1,2 @@
+Project [map_from_arrays(array(1, 2), array(one, two)) AS map_from_arrays(array(1, 2), array(one, two))#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_max_by.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_max_by.explain
new file mode 100644
index 00000000000..3f5c38e707a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_max_by.explain
@@ -0,0 +1,2 @@
+Aggregate [max_by(a#0, b#0) AS max_by(a, b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_median.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_median.explain
new file mode 100644
index 00000000000..2fa602500c9
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_median.explain
@@ -0,0 +1,2 @@
+Aggregate [median(a#0) AS median(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_min.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_min.explain
new file mode 100644
index 00000000000..9008ca2719c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_min.explain
@@ -0,0 +1,2 @@
+Aggregate [min(a#0) AS min(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_min_by.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_min_by.explain
new file mode 100644
index 00000000000..f737fa2ac2a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_min_by.explain
@@ -0,0 +1,2 @@
+Aggregate [min_by(a#0, b#0) AS min_by(a, b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_mode.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_mode.explain
new file mode 100644
index 00000000000..dfa2113a2c3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_mode.explain
@@ -0,0 +1,2 @@
+Aggregate [mode(a#0, 0, 0) AS mode(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_monotonically_increasing_id.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_monotonically_increasing_id.explain
new file mode 100644
index 00000000000..22143169d05
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_monotonically_increasing_id.explain
@@ -0,0 +1,2 @@
+Project [monotonically_increasing_id() AS monotonically_increasing_id()#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_nanvl.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_nanvl.explain
new file mode 100644
index 00000000000..a84a06fbeaf
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_nanvl.explain
@@ -0,0 +1,2 @@
+Project [nanvl(NaN, cast(a#0 as double)) AS nanvl(NaN, a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_negate.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_negate.explain
new file mode 100644
index 00000000000..4f047e75f06
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_negate.explain
@@ -0,0 +1,2 @@
+Project [-a#0 AS negative(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_percentile_approx.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_percentile_approx.explain
new file mode 100644
index 00000000000..879accaa1b6
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_percentile_approx.explain
@@ -0,0 +1,2 @@
+Aggregate [percentile_approx(a#0, 0.3, 20, 0, 0) AS percentile_approx(a, 0.3, 20)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_pmod.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_pmod.explain
new file mode 100644
index 00000000000..3db50c9486f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_pmod.explain
@@ -0,0 +1,2 @@
+Project [pmod(a#0, 10) AS pmod(a, 10)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_pow.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_pow.explain
new file mode 100644
index 00000000000..c6c6c0603e3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_pow.explain
@@ -0,0 +1,2 @@
+Project [POWER(cast(a#0 as double), b#0) AS POWER(a, b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_product.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_product.explain
new file mode 100644
index 00000000000..e3ebed6a92b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_product.explain
@@ -0,0 +1,2 @@
+Aggregate [product(cast(a#0 as double)) AS product(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_radians.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_radians.explain
new file mode 100644
index 00000000000..012ffc6737d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_radians.explain
@@ -0,0 +1,2 @@
+Project [RADIANS(b#0) AS RADIANS(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_rand_with_seed.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_rand_with_seed.explain
new file mode 100644
index 00000000000..0d12a53fb99
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_rand_with_seed.explain
@@ -0,0 +1,2 @@
+Project [rand(133) AS rand(133)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_randn_with_seed.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_randn_with_seed.explain
new file mode 100644
index 00000000000..b976c0e3540
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_randn_with_seed.explain
@@ -0,0 +1,2 @@
+Project [randn(133) AS randn(133)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_rint.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_rint.explain
new file mode 100644
index 00000000000..2231e53941c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_rint.explain
@@ -0,0 +1,2 @@
+Project [rint(b#0) AS rint(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_round.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_round.explain
new file mode 100644
index 00000000000..8bc86462fa2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_round.explain
@@ -0,0 +1,2 @@
+Project [round(b#0, 2) AS round(b, 2)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_sec.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sec.explain
new file mode 100644
index 00000000000..f18fb62333b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sec.explain
@@ -0,0 +1,2 @@
+Project [SEC(b#0) AS SEC(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_shiftleft.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_shiftleft.explain
new file mode 100644
index 00000000000..f89a8be7cee
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_shiftleft.explain
@@ -0,0 +1,2 @@
+Project [shiftleft(cast(b#0 as int), 2) AS shiftleft(b, 2)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_shiftright.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_shiftright.explain
new file mode 100644
index 00000000000..b436f52e912
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_shiftright.explain
@@ -0,0 +1,2 @@
+Project [shiftright(cast(b#0 as int), 2) AS shiftright(b, 2)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_shiftrightunsigned.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_shiftrightunsigned.explain
new file mode 100644
index 00000000000..282ad156b38
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_shiftrightunsigned.explain
@@ -0,0 +1,2 @@
+Project [shiftrightunsigned(cast(b#0 as int), 2) AS shiftrightunsigned(b, 2)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_signum.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_signum.explain
new file mode 100644
index 00000000000..807fa330083
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_signum.explain
@@ -0,0 +1,2 @@
+Project [SIGNUM(b#0) AS SIGNUM(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_sin.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sin.explain
new file mode 100644
index 00000000000..7e4f0af50cd
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sin.explain
@@ -0,0 +1,2 @@
+Project [SIN(b#0) AS SIN(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_sinh.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sinh.explain
new file mode 100644
index 00000000000..7feea457330
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sinh.explain
@@ -0,0 +1,2 @@
+Project [SINH(b#0) AS SINH(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_skewness.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_skewness.explain
new file mode 100644
index 00000000000..bac5abec395
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_skewness.explain
@@ -0,0 +1,2 @@
+Aggregate [skewness(cast(a#0 as double)) AS skewness(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_spark_partition_id.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_spark_partition_id.explain
new file mode 100644
index 00000000000..3afea21244b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_spark_partition_id.explain
@@ -0,0 +1,2 @@
+Project [SPARK_PARTITION_ID() AS SPARK_PARTITION_ID()#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_sqrt.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sqrt.explain
new file mode 100644
index 00000000000..2eaea5dd3c8
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sqrt.explain
@@ -0,0 +1,2 @@
+Project [SQRT(b#0) AS SQRT(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_stddev.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_stddev.explain
new file mode 100644
index 00000000000..106191e5a32
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_stddev.explain
@@ -0,0 +1,2 @@
+Aggregate [stddev(cast(a#0 as double)) AS stddev(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_stddev_pop.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_stddev_pop.explain
new file mode 100644
index 00000000000..239e6e9b90f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_stddev_pop.explain
@@ -0,0 +1,2 @@
+Aggregate [stddev_pop(cast(a#0 as double)) AS stddev_pop(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_stddev_samp.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_stddev_samp.explain
new file mode 100644
index 00000000000..2eef377ff7f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_stddev_samp.explain
@@ -0,0 +1,2 @@
+Aggregate [stddev_samp(cast(a#0 as double)) AS stddev_samp(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_struct.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_struct.explain
new file mode 100644
index 00000000000..35720e40af2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_struct.explain
@@ -0,0 +1,2 @@
+Project [struct(a, a#0, d, d#0) AS struct(a, d)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_sum.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sum.explain
new file mode 100644
index 00000000000..cade1df0c0e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sum.explain
@@ -0,0 +1,2 @@
+Aggregate [sum(a#0) AS sum(a)#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_sum_distinct.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sum_distinct.explain
new file mode 100644
index 00000000000..fd97165c2b5
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_sum_distinct.explain
@@ -0,0 +1,2 @@
+Aggregate [sum(distinct a#0) AS sum(DISTINCT a)#0L]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_tan.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_tan.explain
new file mode 100644
index 00000000000..9dca6e6485f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_tan.explain
@@ -0,0 +1,2 @@
+Project [TAN(b#0) AS TAN(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_tanh.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_tanh.explain
new file mode 100644
index 00000000000..062b38fdc29
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_tanh.explain
@@ -0,0 +1,2 @@
+Project [TANH(b#0) AS TANH(b)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_unhex.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_unhex.explain
new file mode 100644
index 00000000000..776ba5a0c86
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_unhex.explain
@@ -0,0 +1,2 @@
+Project [unhex(cast(a#0 as string), false) AS unhex(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_var_pop.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_var_pop.explain
new file mode 100644
index 00000000000..d20b55fd4d0
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_var_pop.explain
@@ -0,0 +1,2 @@
+Aggregate [var_pop(cast(a#0 as double)) AS var_pop(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_var_samp.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_var_samp.explain
new file mode 100644
index 00000000000..a784b37bf2b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_var_samp.explain
@@ -0,0 +1,2 @@
+Aggregate [var_samp(cast(a#0 as double)) AS var_samp(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/explain-results/function_variance.explain b/connector/connect/common/src/test/resources/query-tests/explain-results/function_variance.explain
new file mode 100644
index 00000000000..3b8bcea178d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/explain-results/function_variance.explain
@@ -0,0 +1,2 @@
+Aggregate [variance(cast(a#0 as double)) AS variance(a)#0]
++- LocalRelation <empty>, [id#0L, a#0, b#0, d#0, e#0, f#0, g#0]
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_abs.json b/connector/connect/common/src/test/resources/query-tests/queries/function_abs.json
new file mode 100644
index 00000000000..16002c3f4d1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_abs.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "abs",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_abs.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_abs.proto.bin
new file mode 100644
index 00000000000..3f56daaa382
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_abs.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+abs
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_acos.json b/connector/connect/common/src/test/resources/query-tests/queries/function_acos.json
new file mode 100644
index 00000000000..01f3eb936eb
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_acos.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "acos",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_acos.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_acos.proto.bin
new file mode 100644
index 00000000000..e42dfe0c28d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_acos.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+acos
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_acosh.json b/connector/connect/common/src/test/resources/query-tests/queries/function_acosh.json
new file mode 100644
index 00000000000..d3af379493c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_acosh.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "acosh",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_acosh.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_acosh.proto.bin
new file mode 100644
index 00000000000..5d6e171aee5
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_acosh.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+acosh
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct.json b/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct.json
new file mode 100644
index 00000000000..069fe54c6dc
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "approx_count_distinct",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct.proto.bin
new file mode 100644
index 00000000000..1c06f900447
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string> 
+approx_count_distinct
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct_rsd.json b/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct_rsd.json
new file mode 100644
index 00000000000..fbdc69cd793
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct_rsd.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "approx_count_distinct",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "literal": {
+            "double": 0.1
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct_rsd.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct_rsd.proto.bin
new file mode 100644
index 00000000000..12f2ec5362d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_approx_count_distinct_rsd.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>-+
+approx_count_distinct
+a
+	Y�������?
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_array.json b/connector/connect/common/src/test/resources/query-tests/queries/function_array.json
new file mode 100644
index 00000000000..7c75a9def64
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_array.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "array",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_array.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_array.proto.bin
new file mode 100644
index 00000000000..0a5b09e8b99
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_array.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+array
+a
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asc.json b/connector/connect/common/src/test/resources/query-tests/queries/function_asc.json
new file mode 100644
index 00000000000..9d963d55ec1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asc.json
@@ -0,0 +1,20 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "sortOrder": {
+        "child": {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        },
+        "direction": "SORT_DIRECTION_ASCENDING",
+        "nullOrdering": "SORT_NULLS_FIRST"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asc.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_asc.proto.bin
new file mode 100644
index 00000000000..8236485b4f6
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asc.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
J
+
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_first.json b/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_first.json
new file mode 100644
index 00000000000..9d963d55ec1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_first.json
@@ -0,0 +1,20 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "sortOrder": {
+        "child": {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        },
+        "direction": "SORT_DIRECTION_ASCENDING",
+        "nullOrdering": "SORT_NULLS_FIRST"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_first.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_first.proto.bin
new file mode 100644
index 00000000000..8236485b4f6
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_first.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
J
+
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_last.json b/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_last.json
new file mode 100644
index 00000000000..cf6adf0cc36
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_last.json
@@ -0,0 +1,20 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "sortOrder": {
+        "child": {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        },
+        "direction": "SORT_DIRECTION_ASCENDING",
+        "nullOrdering": "SORT_NULLS_LAST"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_last.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_last.proto.bin
new file mode 100644
index 00000000000..8292c9d24d7
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asc_nulls_last.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
J
+
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asin.json b/connector/connect/common/src/test/resources/query-tests/queries/function_asin.json
new file mode 100644
index 00000000000..fd61c2ffbf1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asin.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "asin",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asin.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_asin.proto.bin
new file mode 100644
index 00000000000..3b4b86cc15b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asin.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+asin
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asinh.json b/connector/connect/common/src/test/resources/query-tests/queries/function_asinh.json
new file mode 100644
index 00000000000..6d41470ca61
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asinh.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "asinh",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_asinh.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_asinh.proto.bin
new file mode 100644
index 00000000000..c125ca3114a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_asinh.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+asinh
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_atan.json b/connector/connect/common/src/test/resources/query-tests/queries/function_atan.json
new file mode 100644
index 00000000000..bab8ef27ec3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_atan.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "atan",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_atan.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_atan.proto.bin
new file mode 100644
index 00000000000..e946720aad4
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_atan.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+atan
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_atan2.json b/connector/connect/common/src/test/resources/query-tests/queries/function_atan2.json
new file mode 100644
index 00000000000..04a3490df12
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_atan2.json
@@ -0,0 +1,31 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "atan2",
+        "arguments": [{
+          "cast": {
+            "expr": {
+              "unresolvedAttribute": {
+                "unparsedIdentifier": "a"
+              }
+            },
+            "type": {
+              "double": {
+              }
+            }
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_atan2.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_atan2.proto.bin
new file mode 100644
index 00000000000..3271fecbf81
Binary files /dev/null and b/connector/connect/common/src/test/resources/query-tests/queries/function_atan2.proto.bin differ
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_atanh.json b/connector/connect/common/src/test/resources/query-tests/queries/function_atanh.json
new file mode 100644
index 00000000000..2ae1d25ed06
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_atanh.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "atanh",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_atanh.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_atanh.proto.bin
new file mode 100644
index 00000000000..89c594f4baa
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_atanh.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+atanh
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_avg.json b/connector/connect/common/src/test/resources/query-tests/queries/function_avg.json
new file mode 100644
index 00000000000..f9e582b9219
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_avg.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "avg",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_avg.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_avg.proto.bin
new file mode 100644
index 00000000000..24bbef4be5e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_avg.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+avg
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_bin.json b/connector/connect/common/src/test/resources/query-tests/queries/function_bin.json
new file mode 100644
index 00000000000..658990a6f90
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_bin.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "bin",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_bin.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_bin.proto.bin
new file mode 100644
index 00000000000..d499f54e721
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_bin.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+bin
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_bitwise_not.json b/connector/connect/common/src/test/resources/query-tests/queries/function_bitwise_not.json
new file mode 100644
index 00000000000..c350c65312d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_bitwise_not.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "~",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_bitwise_not.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_bitwise_not.proto.bin
new file mode 100644
index 00000000000..9acca430f5f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_bitwise_not.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+
+~
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_bround.json b/connector/connect/common/src/test/resources/query-tests/queries/function_bround.json
new file mode 100644
index 00000000000..c9080049212
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_bround.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "round",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }, {
+          "literal": {
+            "integer": 2
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_bround.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_bround.proto.bin
new file mode 100644
index 00000000000..90b949a0a68
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_bround.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+round
+b
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_ceil.json b/connector/connect/common/src/test/resources/query-tests/queries/function_ceil.json
new file mode 100644
index 00000000000..5f3753452ea
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_ceil.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "ceil",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_ceil.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_ceil.proto.bin
new file mode 100644
index 00000000000..ce56aea7a56
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_ceil.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+ceil
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_ceil_scale.json b/connector/connect/common/src/test/resources/query-tests/queries/function_ceil_scale.json
new file mode 100644
index 00000000000..94a61a5fd05
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_ceil_scale.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "ceil",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }, {
+          "literal": {
+            "integer": 2
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_ceil_scale.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_ceil_scale.proto.bin
new file mode 100644
index 00000000000..4d3b25dada4
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_ceil_scale.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+ceil
+b
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_coalesce.json b/connector/connect/common/src/test/resources/query-tests/queries/function_coalesce.json
new file mode 100644
index 00000000000..aa36f12c054
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_coalesce.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "coalesce",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "literal": {
+            "integer": 3
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_coalesce.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_coalesce.proto.bin
new file mode 100644
index 00000000000..36b892c6476
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_coalesce.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+coalesce
+a
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_col.json b/connector/connect/common/src/test/resources/query-tests/queries/function_col.json
index 8d4b511b1f9..63988117f43 100644
--- a/connector/connect/common/src/test/resources/query-tests/queries/function_col.json
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_col.json
@@ -2,7 +2,7 @@
   "project": {
     "input": {
       "localRelation": {
-        "schema": "struct\u003cid:bigint,a:int,b:double\u003e"
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
       }
     },
     "expressions": [{
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_col.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_col.proto.bin
index e926353d836..4a4eb9b5986 100644
--- a/connector/connect/common/src/test/resources/query-tests/queries/function_col.proto.bin
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_col.proto.bin
@@ -1,3 +1,3 @@
-.
-$Z" struct<id:bigint,a:int,b:double>
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
 id
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_collect_list.json b/connector/connect/common/src/test/resources/query-tests/queries/function_collect_list.json
new file mode 100644
index 00000000000..109392a141e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_collect_list.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "collect_list",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_collect_list.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_collect_list.proto.bin
new file mode 100644
index 00000000000..b96919003c0
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_collect_list.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+collect_list
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_collect_set.json b/connector/connect/common/src/test/resources/query-tests/queries/function_collect_set.json
new file mode 100644
index 00000000000..fa06e613e75
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_collect_set.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "collect_set",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_collect_set.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_collect_set.proto.bin
new file mode 100644
index 00000000000..dda4b4f0ff2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_collect_set.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+collect_set
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_conv.json b/connector/connect/common/src/test/resources/query-tests/queries/function_conv.json
new file mode 100644
index 00000000000..6ea114c4511
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_conv.json
@@ -0,0 +1,27 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "conv",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }, {
+          "literal": {
+            "integer": 10
+          }
+        }, {
+          "literal": {
+            "integer": 16
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_conv.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_conv.proto.bin
new file mode 100644
index 00000000000..9dd42bd34c0
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_conv.proto.bin
@@ -0,0 +1,7 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+conv
+b
+0
+
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_corr.json b/connector/connect/common/src/test/resources/query-tests/queries/function_corr.json
new file mode 100644
index 00000000000..d1fc5417f8d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_corr.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "corr",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_corr.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_corr.proto.bin
new file mode 100644
index 00000000000..d8bb18b3c06
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_corr.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+corr
+a
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_cos.json b/connector/connect/common/src/test/resources/query-tests/queries/function_cos.json
new file mode 100644
index 00000000000..f53521db9c2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_cos.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "cos",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_cos.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_cos.proto.bin
new file mode 100644
index 00000000000..d21e15b0aa0
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_cos.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+cos
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_cosh.json b/connector/connect/common/src/test/resources/query-tests/queries/function_cosh.json
new file mode 100644
index 00000000000..151c7f835eb
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_cosh.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "cosh",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_cosh.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_cosh.proto.bin
new file mode 100644
index 00000000000..202a4ba8a8f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_cosh.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+cosh
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_cot.json b/connector/connect/common/src/test/resources/query-tests/queries/function_cot.json
new file mode 100644
index 00000000000..2100af7d09e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_cot.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "cot",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_cot.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_cot.proto.bin
new file mode 100644
index 00000000000..d26a2d30cca
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_cot.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+cot
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_count.json b/connector/connect/common/src/test/resources/query-tests/queries/function_count.json
new file mode 100644
index 00000000000..77eff56f6ef
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_count.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "count",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_count.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_count.proto.bin
new file mode 100644
index 00000000000..97667ca8360
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_count.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+count
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_countDistinct.json b/connector/connect/common/src/test/resources/query-tests/queries/function_countDistinct.json
new file mode 100644
index 00000000000..d33f9d958e1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_countDistinct.json
@@ -0,0 +1,24 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "count",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "g"
+          }
+        }],
+        "isDistinct": true
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_countDistinct.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_countDistinct.proto.bin
new file mode 100644
index 00000000000..a4582f98013
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_countDistinct.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+count
+a
+g
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_covar_pop.json b/connector/connect/common/src/test/resources/query-tests/queries/function_covar_pop.json
new file mode 100644
index 00000000000..a1227d5b54a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_covar_pop.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "covar_pop",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_covar_pop.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_covar_pop.proto.bin
new file mode 100644
index 00000000000..ffcfae52acb
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_covar_pop.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+	covar_pop
+a
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_covar_samp.json b/connector/connect/common/src/test/resources/query-tests/queries/function_covar_samp.json
new file mode 100644
index 00000000000..c7d6ddf1273
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_covar_samp.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "covar_samp",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_covar_samp.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_covar_samp.proto.bin
new file mode 100644
index 00000000000..c830d80acc3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_covar_samp.proto.bin
@@ -0,0 +1,6 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+
+covar_samp
+a
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_csc.json b/connector/connect/common/src/test/resources/query-tests/queries/function_csc.json
new file mode 100644
index 00000000000..ceb722b1b1f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_csc.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "csc",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_csc.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_csc.proto.bin
new file mode 100644
index 00000000000..147af78100d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_csc.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+csc
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_degrees.json b/connector/connect/common/src/test/resources/query-tests/queries/function_degrees.json
new file mode 100644
index 00000000000..152c92cbe6c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_degrees.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "degrees",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_degrees.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_degrees.proto.bin
new file mode 100644
index 00000000000..772d2ee9d3b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_degrees.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+degrees
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_desc.json b/connector/connect/common/src/test/resources/query-tests/queries/function_desc.json
new file mode 100644
index 00000000000..8f1d61d70ac
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_desc.json
@@ -0,0 +1,20 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "sortOrder": {
+        "child": {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        },
+        "direction": "SORT_DIRECTION_DESCENDING",
+        "nullOrdering": "SORT_NULLS_LAST"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_desc.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_desc.proto.bin
new file mode 100644
index 00000000000..a1237f80486
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_desc.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
J
+
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_first.json b/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_first.json
new file mode 100644
index 00000000000..fa0654bbda7
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_first.json
@@ -0,0 +1,20 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "sortOrder": {
+        "child": {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        },
+        "direction": "SORT_DIRECTION_DESCENDING",
+        "nullOrdering": "SORT_NULLS_FIRST"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_first.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_first.proto.bin
new file mode 100644
index 00000000000..22de37fb20f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_first.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
J
+
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_last.json b/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_last.json
new file mode 100644
index 00000000000..8f1d61d70ac
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_last.json
@@ -0,0 +1,20 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "sortOrder": {
+        "child": {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        },
+        "direction": "SORT_DIRECTION_DESCENDING",
+        "nullOrdering": "SORT_NULLS_LAST"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_last.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_last.proto.bin
new file mode 100644
index 00000000000..a1237f80486
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_desc_nulls_last.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
J
+
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_exp.json b/connector/connect/common/src/test/resources/query-tests/queries/function_exp.json
new file mode 100644
index 00000000000..a563d4dfbe5
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_exp.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "exp",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_exp.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_exp.proto.bin
new file mode 100644
index 00000000000..290c68a7f1f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_exp.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+exp
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_expm1.json b/connector/connect/common/src/test/resources/query-tests/queries/function_expm1.json
new file mode 100644
index 00000000000..7d18209a0f7
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_expm1.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "expm1",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_expm1.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_expm1.proto.bin
new file mode 100644
index 00000000000..09ddfe15343
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_expm1.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+expm1
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_expr.json b/connector/connect/common/src/test/resources/query-tests/queries/function_expr.json
new file mode 100644
index 00000000000..30c40ef354c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_expr.json
@@ -0,0 +1,14 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "expressionString": {
+        "expression": "a + 1"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_expr.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_expr.proto.bin
new file mode 100644
index 00000000000..d0ef70d31e7
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_expr.proto.bin
@@ -0,0 +1,3 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>	"
+a + 1
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_factorial.json b/connector/connect/common/src/test/resources/query-tests/queries/function_factorial.json
new file mode 100644
index 00000000000..a2f3f83141c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_factorial.json
@@ -0,0 +1,28 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "factorial",
+        "arguments": [{
+          "unresolvedFunction": {
+            "functionName": "%",
+            "arguments": [{
+              "unresolvedAttribute": {
+                "unparsedIdentifier": "a"
+              }
+            }, {
+              "literal": {
+                "integer": 10
+              }
+            }]
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_factorial.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_factorial.proto.bin
new file mode 100644
index 00000000000..15d31d60740
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_factorial.proto.bin
@@ -0,0 +1,6 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>!
+	factorial
+%
+a
+0
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_first.json b/connector/connect/common/src/test/resources/query-tests/queries/function_first.json
new file mode 100644
index 00000000000..e483363cec5
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_first.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "first",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "literal": {
+            "boolean": true
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_first.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_first.proto.bin
new file mode 100644
index 00000000000..a52b2870750
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_first.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+first
+a
+
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_floor.json b/connector/connect/common/src/test/resources/query-tests/queries/function_floor.json
new file mode 100644
index 00000000000..02607b93e47
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_floor.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "floor",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_floor.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_floor.proto.bin
new file mode 100644
index 00000000000..3e9ccb0b2a8
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_floor.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+floor
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_floor_scale.json b/connector/connect/common/src/test/resources/query-tests/queries/function_floor_scale.json
new file mode 100644
index 00000000000..fd092a4e07e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_floor_scale.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "floor",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }, {
+          "literal": {
+            "integer": 2
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_floor_scale.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_floor_scale.proto.bin
new file mode 100644
index 00000000000..c03a3ceb086
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_floor_scale.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+floor
+b
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_greatest.json b/connector/connect/common/src/test/resources/query-tests/queries/function_greatest.json
new file mode 100644
index 00000000000..80d411803e7
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_greatest.json
@@ -0,0 +1,32 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "greatest",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedExtractValue": {
+            "child": {
+              "unresolvedAttribute": {
+                "unparsedIdentifier": "d"
+              }
+            },
+            "extraction": {
+              "literal": {
+                "string": "a"
+              }
+            }
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_greatest.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_greatest.proto.bin
new file mode 100644
index 00000000000..3f8f3a5e37d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_greatest.proto.bin
@@ -0,0 +1,7 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>%#
+greatest
+ab
+
+d
+ja
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_hex.json b/connector/connect/common/src/test/resources/query-tests/queries/function_hex.json
new file mode 100644
index 00000000000..051304a992a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_hex.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "hex",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_hex.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_hex.proto.bin
new file mode 100644
index 00000000000..a5961db2133
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_hex.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+hex
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_hypot.json b/connector/connect/common/src/test/resources/query-tests/queries/function_hypot.json
new file mode 100644
index 00000000000..3e64ad01515
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_hypot.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "hypot",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_hypot.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_hypot.proto.bin
new file mode 100644
index 00000000000..4250484e005
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_hypot.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+hypot
+a
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_input_file_name.json b/connector/connect/common/src/test/resources/query-tests/queries/function_input_file_name.json
new file mode 100644
index 00000000000..9d3c651874a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_input_file_name.json
@@ -0,0 +1,14 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "input_file_name"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_input_file_name.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_input_file_name.proto.bin
new file mode 100644
index 00000000000..4d773db4952
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_input_file_name.proto.bin
@@ -0,0 +1,3 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+input_file_name
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_isnan.json b/connector/connect/common/src/test/resources/query-tests/queries/function_isnan.json
new file mode 100644
index 00000000000..0eb722a08ec
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_isnan.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "isNaN",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_isnan.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_isnan.proto.bin
new file mode 100644
index 00000000000..1f96b82d070
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_isnan.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+isNaN
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_isnull.json b/connector/connect/common/src/test/resources/query-tests/queries/function_isnull.json
new file mode 100644
index 00000000000..3d51a2f8748
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_isnull.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "isNull",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_isnull.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_isnull.proto.bin
new file mode 100644
index 00000000000..8abf3ceadc1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_isnull.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+isNull
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_kurtosis.json b/connector/connect/common/src/test/resources/query-tests/queries/function_kurtosis.json
new file mode 100644
index 00000000000..0d987d1252e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_kurtosis.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "kurtosis",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_kurtosis.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_kurtosis.proto.bin
new file mode 100644
index 00000000000..ea0ec7f993b
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_kurtosis.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+kurtosis
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_last.json b/connector/connect/common/src/test/resources/query-tests/queries/function_last.json
new file mode 100644
index 00000000000..428660970ab
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_last.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "last",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "literal": {
+            "boolean": false
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_last.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_last.proto.bin
new file mode 100644
index 00000000000..e14ee792a6c
Binary files /dev/null and b/connector/connect/common/src/test/resources/query-tests/queries/function_last.proto.bin differ
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_least.json b/connector/connect/common/src/test/resources/query-tests/queries/function_least.json
new file mode 100644
index 00000000000..1c83d818738
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_least.json
@@ -0,0 +1,32 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "least",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedExtractValue": {
+            "child": {
+              "unresolvedAttribute": {
+                "unparsedIdentifier": "d"
+              }
+            },
+            "extraction": {
+              "literal": {
+                "string": "a"
+              }
+            }
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_least.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_least.proto.bin
new file mode 100644
index 00000000000..9533cf00cf4
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_least.proto.bin
@@ -0,0 +1,7 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>" 
+least
+ab
+
+d
+ja
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log.json b/connector/connect/common/src/test/resources/query-tests/queries/function_log.json
new file mode 100644
index 00000000000..b9628776cbb
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_log.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "log",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_log.proto.bin
new file mode 100644
index 00000000000..537849aed11
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_log.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+log
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log10.json b/connector/connect/common/src/test/resources/query-tests/queries/function_log10.json
new file mode 100644
index 00000000000..6aa99f1521a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_log10.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "log10",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log10.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_log10.proto.bin
new file mode 100644
index 00000000000..f508b2aeebd
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_log10.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+log10
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log1p.json b/connector/connect/common/src/test/resources/query-tests/queries/function_log1p.json
new file mode 100644
index 00000000000..359ab79adf3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_log1p.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "log1p",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log1p.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_log1p.proto.bin
new file mode 100644
index 00000000000..f1b7134a1d9
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_log1p.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+log1p
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log2.json b/connector/connect/common/src/test/resources/query-tests/queries/function_log2.json
new file mode 100644
index 00000000000..ade59f2f866
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_log2.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "log2",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log2.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_log2.proto.bin
new file mode 100644
index 00000000000..a7fec7a802f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_log2.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+log2
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log_with_base.json b/connector/connect/common/src/test/resources/query-tests/queries/function_log_with_base.json
new file mode 100644
index 00000000000..185d36b202d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_log_with_base.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "log",
+        "arguments": [{
+          "literal": {
+            "double": 2.0
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_log_with_base.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_log_with_base.proto.bin
new file mode 100644
index 00000000000..172793b7d46
Binary files /dev/null and b/connector/connect/common/src/test/resources/query-tests/queries/function_log_with_base.proto.bin differ
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_map.json b/connector/connect/common/src/test/resources/query-tests/queries/function_map.json
new file mode 100644
index 00000000000..3f2bb1cf110
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_map.json
@@ -0,0 +1,31 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "map",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "g"
+          }
+        }, {
+          "literal": {
+            "integer": 22
+          }
+        }, {
+          "literal": {
+            "string": "dummy"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_map.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_map.proto.bin
new file mode 100644
index 00000000000..a774137b38c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_map.proto.bin
@@ -0,0 +1,7 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>&$
+map
+a
+g
+0	
+jdummy
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_map_from_arrays.json b/connector/connect/common/src/test/resources/query-tests/queries/function_map_from_arrays.json
new file mode 100644
index 00000000000..9a999a689ff
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_map_from_arrays.json
@@ -0,0 +1,41 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "map_from_arrays",
+        "arguments": [{
+          "unresolvedFunction": {
+            "functionName": "array",
+            "arguments": [{
+              "literal": {
+                "integer": 1
+              }
+            }, {
+              "literal": {
+                "integer": 2
+              }
+            }]
+          }
+        }, {
+          "unresolvedFunction": {
+            "functionName": "array",
+            "arguments": [{
+              "literal": {
+                "string": "one"
+              }
+            }, {
+              "literal": {
+                "string": "two"
+              }
+            }]
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_map_from_arrays.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_map_from_arrays.proto.bin
new file mode 100644
index 00000000000..1cc02430683
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_map_from_arrays.proto.bin
@@ -0,0 +1,9 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>GE
+map_from_arrays
+array
+0
+0
+array
+jone
+jtwo
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_max_by.json b/connector/connect/common/src/test/resources/query-tests/queries/function_max_by.json
new file mode 100644
index 00000000000..dff4f19d5b6
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_max_by.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "max_by",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_max_by.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_max_by.proto.bin
new file mode 100644
index 00000000000..ae2694bd057
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_max_by.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+max_by
+a
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_median.json b/connector/connect/common/src/test/resources/query-tests/queries/function_median.json
new file mode 100644
index 00000000000..f09852dc5e3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_median.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "median",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_median.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_median.proto.bin
new file mode 100644
index 00000000000..9e68ef19aae
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_median.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+median
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_min.json b/connector/connect/common/src/test/resources/query-tests/queries/function_min.json
new file mode 100644
index 00000000000..35ab6361cdf
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_min.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "min",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_min.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_min.proto.bin
new file mode 100644
index 00000000000..aa820535cfb
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_min.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+min
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_min_by.json b/connector/connect/common/src/test/resources/query-tests/queries/function_min_by.json
new file mode 100644
index 00000000000..84a56f69c25
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_min_by.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "min_by",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_min_by.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_min_by.proto.bin
new file mode 100644
index 00000000000..a746bab5389
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_min_by.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+min_by
+a
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_mode.json b/connector/connect/common/src/test/resources/query-tests/queries/function_mode.json
new file mode 100644
index 00000000000..257a1e6ba7d
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_mode.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "mode",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_mode.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_mode.proto.bin
new file mode 100644
index 00000000000..d7fb046953e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_mode.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+mode
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_monotonically_increasing_id.json b/connector/connect/common/src/test/resources/query-tests/queries/function_monotonically_increasing_id.json
new file mode 100644
index 00000000000..e4caa30e4ef
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_monotonically_increasing_id.json
@@ -0,0 +1,14 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "monotonically_increasing_id"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_monotonically_increasing_id.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_monotonically_increasing_id.proto.bin
new file mode 100644
index 00000000000..04cdd9f2590
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_monotonically_increasing_id.proto.bin
@@ -0,0 +1,3 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+monotonically_increasing_id
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_nanvl.json b/connector/connect/common/src/test/resources/query-tests/queries/function_nanvl.json
new file mode 100644
index 00000000000..0af98419ff1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_nanvl.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "nanvl",
+        "arguments": [{
+          "literal": {
+            "double": "NaN"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_nanvl.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_nanvl.proto.bin
new file mode 100644
index 00000000000..59f2d8a49f4
Binary files /dev/null and b/connector/connect/common/src/test/resources/query-tests/queries/function_nanvl.proto.bin differ
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_negate.json b/connector/connect/common/src/test/resources/query-tests/queries/function_negate.json
new file mode 100644
index 00000000000..7256a697270
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_negate.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "negative",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_negate.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_negate.proto.bin
new file mode 100644
index 00000000000..7f45c5e08ee
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_negate.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+negative
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_percentile_approx.json b/connector/connect/common/src/test/resources/query-tests/queries/function_percentile_approx.json
new file mode 100644
index 00000000000..15569edc49e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_percentile_approx.json
@@ -0,0 +1,27 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "percentile_approx",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "literal": {
+            "double": 0.3
+          }
+        }, {
+          "literal": {
+            "integer": 20
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_percentile_approx.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_percentile_approx.proto.bin
new file mode 100644
index 00000000000..246a2c6b899
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_percentile_approx.proto.bin
@@ -0,0 +1,6 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>/-
+percentile_approx
+a
+	Y333333�?
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_pmod.json b/connector/connect/common/src/test/resources/query-tests/queries/function_pmod.json
new file mode 100644
index 00000000000..e1741769851
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_pmod.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "pmod",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "literal": {
+            "integer": 10
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_pmod.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_pmod.proto.bin
new file mode 100644
index 00000000000..36967776636
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_pmod.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+pmod
+a
+0
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_pow.json b/connector/connect/common/src/test/resources/query-tests/queries/function_pow.json
new file mode 100644
index 00000000000..5816a7c8460
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_pow.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "power",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_pow.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_pow.proto.bin
new file mode 100644
index 00000000000..00e5d023e0f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_pow.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+power
+a
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_product.json b/connector/connect/common/src/test/resources/query-tests/queries/function_product.json
new file mode 100644
index 00000000000..7a3d4c43f9c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_product.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "product",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_product.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_product.proto.bin
new file mode 100644
index 00000000000..21a5feb50f4
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_product.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+product
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_radians.json b/connector/connect/common/src/test/resources/query-tests/queries/function_radians.json
new file mode 100644
index 00000000000..f585cf1089a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_radians.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "radians",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_radians.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_radians.proto.bin
new file mode 100644
index 00000000000..a4f6f9531f2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_radians.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+radians
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_rand_with_seed.json b/connector/connect/common/src/test/resources/query-tests/queries/function_rand_with_seed.json
new file mode 100644
index 00000000000..4532f9fa850
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_rand_with_seed.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "rand",
+        "arguments": [{
+          "literal": {
+            "long": "133"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_rand_with_seed.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_rand_with_seed.proto.bin
new file mode 100644
index 00000000000..7ce12ed0d1e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_rand_with_seed.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+rand
+8�
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_randn_with_seed.json b/connector/connect/common/src/test/resources/query-tests/queries/function_randn_with_seed.json
new file mode 100644
index 00000000000..88f12466cb7
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_randn_with_seed.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "randn",
+        "arguments": [{
+          "literal": {
+            "long": "133"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_randn_with_seed.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_randn_with_seed.proto.bin
new file mode 100644
index 00000000000..3ba184d4d0c
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_randn_with_seed.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+randn
+8�
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_rint.json b/connector/connect/common/src/test/resources/query-tests/queries/function_rint.json
new file mode 100644
index 00000000000..7e86e340854
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_rint.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "rint",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_rint.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_rint.proto.bin
new file mode 100644
index 00000000000..81377729ceb
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_rint.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+rint
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_round.json b/connector/connect/common/src/test/resources/query-tests/queries/function_round.json
new file mode 100644
index 00000000000..c9080049212
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_round.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "round",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }, {
+          "literal": {
+            "integer": 2
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_round.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_round.proto.bin
new file mode 100644
index 00000000000..90b949a0a68
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_round.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+round
+b
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sec.json b/connector/connect/common/src/test/resources/query-tests/queries/function_sec.json
new file mode 100644
index 00000000000..9c5b436dfa2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sec.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "sec",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sec.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_sec.proto.bin
new file mode 100644
index 00000000000..a3e2a41d7c3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sec.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+sec
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_shiftleft.json b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftleft.json
new file mode 100644
index 00000000000..5f2f9aaec54
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftleft.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "shiftleft",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }, {
+          "literal": {
+            "integer": 2
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_shiftleft.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftleft.proto.bin
new file mode 100644
index 00000000000..11f8f737d72
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftleft.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+	shiftleft
+b
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_shiftright.json b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftright.json
new file mode 100644
index 00000000000..9da302a0061
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftright.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "shiftright",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }, {
+          "literal": {
+            "integer": 2
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_shiftright.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftright.proto.bin
new file mode 100644
index 00000000000..6775161f619
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftright.proto.bin
@@ -0,0 +1,6 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+
+shiftright
+b
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_shiftrightunsigned.json b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftrightunsigned.json
new file mode 100644
index 00000000000..4565a88d45e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftrightunsigned.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "shiftrightunsigned",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }, {
+          "literal": {
+            "integer": 2
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_shiftrightunsigned.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftrightunsigned.proto.bin
new file mode 100644
index 00000000000..3c13eef3d45
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_shiftrightunsigned.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>#!
+shiftrightunsigned
+b
+0
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_signum.json b/connector/connect/common/src/test/resources/query-tests/queries/function_signum.json
new file mode 100644
index 00000000000..4b29b4ef04a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_signum.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "signum",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_signum.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_signum.proto.bin
new file mode 100644
index 00000000000..2fddfe1d63f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_signum.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+signum
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sin.json b/connector/connect/common/src/test/resources/query-tests/queries/function_sin.json
new file mode 100644
index 00000000000..238b7bfb7a3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sin.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "sin",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sin.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_sin.proto.bin
new file mode 100644
index 00000000000..2743ff0a1ec
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sin.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+sin
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sinh.json b/connector/connect/common/src/test/resources/query-tests/queries/function_sinh.json
new file mode 100644
index 00000000000..5d4f56b387f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sinh.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "sinh",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sinh.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_sinh.proto.bin
new file mode 100644
index 00000000000..13492acdba5
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sinh.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+sinh
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_skewness.json b/connector/connect/common/src/test/resources/query-tests/queries/function_skewness.json
new file mode 100644
index 00000000000..f328e02df8a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_skewness.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "skewness",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_skewness.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_skewness.proto.bin
new file mode 100644
index 00000000000..c4ecdc95ab3
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_skewness.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+skewness
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_spark_partition_id.json b/connector/connect/common/src/test/resources/query-tests/queries/function_spark_partition_id.json
new file mode 100644
index 00000000000..d07adf80e1a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_spark_partition_id.json
@@ -0,0 +1,14 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "spark_partition_id"
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_spark_partition_id.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_spark_partition_id.proto.bin
new file mode 100644
index 00000000000..16dfd3e4755
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_spark_partition_id.proto.bin
@@ -0,0 +1,3 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+spark_partition_id
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sqrt.json b/connector/connect/common/src/test/resources/query-tests/queries/function_sqrt.json
new file mode 100644
index 00000000000..fe4b6ac5e7f
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sqrt.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "sqrt",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sqrt.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_sqrt.proto.bin
new file mode 100644
index 00000000000..bd86cdf8ee9
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sqrt.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+sqrt
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_stddev.json b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev.json
new file mode 100644
index 00000000000..766918cadf1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "stddev",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_stddev.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev.proto.bin
new file mode 100644
index 00000000000..5558c9428ec
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+stddev
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_pop.json b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_pop.json
new file mode 100644
index 00000000000..4f3e80c8db1
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_pop.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "stddev_pop",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_pop.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_pop.proto.bin
new file mode 100644
index 00000000000..8ae3277a81e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_pop.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+
+stddev_pop
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_samp.json b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_samp.json
new file mode 100644
index 00000000000..dc8450d608e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_samp.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "stddev_samp",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_samp.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_samp.proto.bin
new file mode 100644
index 00000000000..cb5ec806228
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_stddev_samp.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+stddev_samp
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_struct.json b/connector/connect/common/src/test/resources/query-tests/queries/function_struct.json
new file mode 100644
index 00000000000..4efade2ea12
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_struct.json
@@ -0,0 +1,23 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "struct",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }, {
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "d"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_struct.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_struct.proto.bin
new file mode 100644
index 00000000000..62537a07c99
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_struct.proto.bin
@@ -0,0 +1,5 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+struct
+a
+d
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sum.json b/connector/connect/common/src/test/resources/query-tests/queries/function_sum.json
new file mode 100644
index 00000000000..6735b7a0e16
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sum.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "sum",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sum.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_sum.proto.bin
new file mode 100644
index 00000000000..47e99c8d52a
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sum.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+sum
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sum_distinct.json b/connector/connect/common/src/test/resources/query-tests/queries/function_sum_distinct.json
new file mode 100644
index 00000000000..d4335e2d1ef
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sum_distinct.json
@@ -0,0 +1,20 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "sum",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }],
+        "isDistinct": true
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_sum_distinct.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_sum_distinct.proto.bin
new file mode 100644
index 00000000000..1f1026cbd60
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_sum_distinct.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+sum
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_tan.json b/connector/connect/common/src/test/resources/query-tests/queries/function_tan.json
new file mode 100644
index 00000000000..73442dc5b69
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_tan.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "tan",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_tan.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_tan.proto.bin
new file mode 100644
index 00000000000..5849d81e189
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_tan.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+tan
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_tanh.json b/connector/connect/common/src/test/resources/query-tests/queries/function_tanh.json
new file mode 100644
index 00000000000..6e257193545
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_tanh.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "tanh",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "b"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_tanh.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_tanh.proto.bin
new file mode 100644
index 00000000000..f17641e49c2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_tanh.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+tanh
+b
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_unhex.json b/connector/connect/common/src/test/resources/query-tests/queries/function_unhex.json
new file mode 100644
index 00000000000..dff5f2c2edd
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_unhex.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "unhex",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_unhex.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_unhex.proto.bin
new file mode 100644
index 00000000000..493c70a49f7
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_unhex.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+unhex
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_var_pop.json b/connector/connect/common/src/test/resources/query-tests/queries/function_var_pop.json
new file mode 100644
index 00000000000..4cf7abc8b84
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_var_pop.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "var_pop",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_var_pop.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_var_pop.proto.bin
new file mode 100644
index 00000000000..2646cfadba0
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_var_pop.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+var_pop
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_var_samp.json b/connector/connect/common/src/test/resources/query-tests/queries/function_var_samp.json
new file mode 100644
index 00000000000..7077feb5c5e
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_var_samp.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "var_samp",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_var_samp.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_var_samp.proto.bin
new file mode 100644
index 00000000000..93ac12e8119
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_var_samp.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+var_samp
+a
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_variance.json b/connector/connect/common/src/test/resources/query-tests/queries/function_variance.json
new file mode 100644
index 00000000000..61310a665d6
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_variance.json
@@ -0,0 +1,19 @@
+{
+  "project": {
+    "input": {
+      "localRelation": {
+        "schema": "struct\u003cid:bigint,a:int,b:double,d:struct\u003cid:bigint,a:int,b:double\u003e,e:array\u003cint\u003e,f:map\u003cstring,struct\u003cid:bigint,a:int,b:double\u003e\u003e,g:string\u003e"
+      }
+    },
+    "expressions": [{
+      "unresolvedFunction": {
+        "functionName": "variance",
+        "arguments": [{
+          "unresolvedAttribute": {
+            "unparsedIdentifier": "a"
+          }
+        }]
+      }
+    }]
+  }
+}
\ No newline at end of file
diff --git a/connector/connect/common/src/test/resources/query-tests/queries/function_variance.proto.bin b/connector/connect/common/src/test/resources/query-tests/queries/function_variance.proto.bin
new file mode 100644
index 00000000000..fec1298adc2
--- /dev/null
+++ b/connector/connect/common/src/test/resources/query-tests/queries/function_variance.proto.bin
@@ -0,0 +1,4 @@
+�
+�Z��struct<id:bigint,a:int,b:double,d:struct<id:bigint,a:int,b:double>,e:array<int>,f:map<string,struct<id:bigint,a:int,b:double>>,g:string>
+variance
+a
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org