This is an automated email from the ASF dual-hosted git repository. wenchen 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 a32bfd7be493 [SPARK-53008][SQL] Infer SQL Data Access from SQL UDF body a32bfd7be493 is described below commit a32bfd7be493d869036df90a5a65b13a563eea55 Author: Allison Wang <allison.w...@databricks.com> AuthorDate: Mon Aug 4 10:09:45 2025 +0800 [SPARK-53008][SQL] Infer SQL Data Access from SQL UDF body ### What changes were proposed in this pull request? This PR derives the SQL data access routine of the function and check if the SQL function matches its data access routine. If the data access is CONTAINS SQL, the expression should not access operators and expressions that read SQL data. ### Why are the changes needed? To support SQL UDF data access routine. ### Does this PR introduce _any_ user-facing change? Yes. It will block the SQL UDF creation if the body does not match the SQL data access pattern. ### How was this patch tested? New sql query tests. ### Was this patch authored or co-authored using generative AI tooling? No Closes #51714 from allisonwang-db/spark-53008-derive-sql-data-access. Authored-by: Allison Wang <allison.w...@databricks.com> Signed-off-by: Wenchen Fan <wenc...@databricks.com> --- .../src/main/resources/error/error-conditions.json | 6 + .../command/CreateSQLFunctionCommand.scala | 45 +++- .../sql-tests/analyzer-results/sql-udf.sql.out | 234 +++++++++++++++++ .../test/resources/sql-tests/inputs/sql-udf.sql | 41 +++ .../resources/sql-tests/results/sql-udf.sql.out | 292 +++++++++++++++++++++ 5 files changed, 616 insertions(+), 2 deletions(-) diff --git a/common/utils/src/main/resources/error/error-conditions.json b/common/utils/src/main/resources/error/error-conditions.json index e4482342d483..60b2df793230 100644 --- a/common/utils/src/main/resources/error/error-conditions.json +++ b/common/utils/src/main/resources/error/error-conditions.json @@ -3638,6 +3638,12 @@ ], "sqlState" : "42K08" }, + "INVALID_SQL_FUNCTION_DATA_ACCESS" : { + "message" : [ + "Cannot create a SQL function with CONTAINS SQL that accesses a table/view or a SQL function that reads SQL data. Please use READS SQL DATA instead." + ], + "sqlState" : "42K0E" + }, "INVALID_SQL_FUNCTION_PLAN_STRUCTURE" : { "message" : [ "Invalid SQL function plan structure", diff --git a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/CreateSQLFunctionCommand.scala b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/CreateSQLFunctionCommand.scala index d7773c717269..6f98675c2c99 100644 --- a/sql/core/src/main/scala/org/apache/spark/sql/execution/command/CreateSQLFunctionCommand.scala +++ b/sql/core/src/main/scala/org/apache/spark/sql/execution/command/CreateSQLFunctionCommand.scala @@ -20,12 +20,12 @@ package org.apache.spark.sql.execution.command import org.apache.spark.SparkException import org.apache.spark.sql.{AnalysisException, Row, SparkSession} import org.apache.spark.sql.catalyst.FunctionIdentifier -import org.apache.spark.sql.catalyst.analysis.{withPosition, Analyzer, SQLFunctionExpression, SQLFunctionNode, SQLTableFunction, UnresolvedAlias, UnresolvedAttribute, UnresolvedFunction, UnresolvedRelation, UnresolvedTableValuedFunction} +import org.apache.spark.sql.catalyst.analysis.{withPosition, Analyzer, SQLFunctionExpression, SQLFunctionNode, SQLScalarFunction, SQLTableFunction, UnresolvedAlias, UnresolvedAttribute, UnresolvedFunction, UnresolvedRelation, UnresolvedTableValuedFunction} import org.apache.spark.sql.catalyst.catalog.{SessionCatalog, SQLFunction, UserDefinedFunction, UserDefinedFunctionErrors} import org.apache.spark.sql.catalyst.expressions.{Alias, Cast, Expression, Generator, LateralSubquery, Literal, ScalarSubquery, SubqueryExpression, WindowExpression} import org.apache.spark.sql.catalyst.expressions.aggregate.AggregateExpression import org.apache.spark.sql.catalyst.plans.Inner -import org.apache.spark.sql.catalyst.plans.logical.{LateralJoin, LogicalPlan, OneRowRelation, Project, UnresolvedWith} +import org.apache.spark.sql.catalyst.plans.logical.{LateralJoin, LocalRelation, LogicalPlan, OneRowRelation, Project, Range, UnresolvedWith, View} import org.apache.spark.sql.catalyst.trees.TreePattern.UNRESOLVED_ATTRIBUTE import org.apache.spark.sql.connector.catalog.CatalogV2Implicits.MultipartIdentifierHelper import org.apache.spark.sql.errors.QueryCompilationErrors @@ -247,10 +247,14 @@ case class CreateSQLFunctionCommand( // Derive determinism of the SQL function. val deterministic = analyzedPlan.deterministic + // Derive and check a SQL function with CONTAINS SQL data access should not reads SQL data. + val readsSQLData = deriveSQLDataAccess(analyzedPlan) + function.copy( // Assign the return type, inferring from the function body if needed. returnType = inferredReturnType, deterministic = Some(function.deterministic.getOrElse(deterministic)), + containsSQL = Some(function.containsSQL.getOrElse(!readsSQLData)), properties = properties ) } @@ -445,6 +449,43 @@ case class CreateSQLFunctionCommand( } } + /** + * Derive the SQL data access routine of the function and check if the SQL function matches + * its data access routine. If the data access is CONTAINS SQL, the expression should not + * access operators and expressions that read SQL data. + * + * Returns true is SQL data access routine is READS SQL DATA, otherwise returns false. + */ + private def deriveSQLDataAccess(plan: LogicalPlan): Boolean = { + // Find logical plan nodes that read SQL data. + val readsSQLData = plan.find { + case _: View => true + case p if p.children.isEmpty => p match { + case _: OneRowRelation | _: LocalRelation | _: Range => false + case _ => true + } + case f: SQLFunctionNode => f.function.containsSQL.contains(false) + case p: LogicalPlan => + lazy val sub = p.subqueries.exists(deriveSQLDataAccess) + // If the SQL function contains another SQL function that has SQL data access routine + // to be READS SQL DATA, then this SQL function will also be READS SQL DATA. + p.expressions.exists(expr => expr.find { + case f: SQLScalarFunction => f.function.containsSQL.contains(false) + case sub: SubqueryExpression => deriveSQLDataAccess(sub.plan) + case _ => false + }.isDefined) + }.isDefined + + if (containsSQL.contains(true) && readsSQLData) { + throw new AnalysisException( + errorClass = "INVALID_SQL_FUNCTION_DATA_ACCESS", + messageParameters = Map.empty + ) + } + + readsSQLData + } + /** * Generate the function properties, including: * 1. the SQL configs when creating the function. diff --git a/sql/core/src/test/resources/sql-tests/analyzer-results/sql-udf.sql.out b/sql/core/src/test/resources/sql-tests/analyzer-results/sql-udf.sql.out index 24b6da66c47e..2b8a47c9ca63 100644 --- a/sql/core/src/test/resources/sql-tests/analyzer-results/sql-udf.sql.out +++ b/sql/core/src/test/resources/sql-tests/analyzer-results/sql-udf.sql.out @@ -3989,6 +3989,174 @@ org.apache.spark.sql.AnalysisException } +-- !query +CREATE FUNCTION foo3_12a(x INT) RETURNS INT CONTAINS SQL RETURN x +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12a, x INT, INT, x, true, false, false, false, false + + +-- !query +CREATE FUNCTION foo3_12b(x INT) RETURNS INT READS SQL DATA RETURN x +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12b, x INT, INT, x, false, false, false, false, false + + +-- !query +CREATE FUNCTION foo3_12c(x INT) RETURNS INT CONTAINS SQL RETURN (SELECT x) +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12c, x INT, INT, (SELECT x), true, false, false, false, false + + +-- !query +CREATE FUNCTION foo3_12d(x INT) RETURNS INT CONTAINS SQL RETURN (SELECT COUNT(*) FROM range(0, 3)) +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12d, x INT, INT, (SELECT COUNT(*) FROM range(0, 3)), true, false, false, false, false + + +-- !query +CREATE FUNCTION foo3_12e(x INT) RETURNS INT CONTAINS SQL RETURN (SELECT COUNT(*) FROM VALUES (0, 1)) +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12e, x INT, INT, (SELECT COUNT(*) FROM VALUES (0, 1)), true, false, false, false, false + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN SELECT SUM(c2) FROM t1 +-- !query analysis +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN foo3_12b(x) + 1 +-- !query analysis +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN 1 + (SELECT SUM(c2) FROM t1) +-- !query analysis +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12g(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT x, x + 1 +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12g, x INT, a INT, b INT, SELECT x, x + 1, true, true, false, false, false + + +-- !query +CREATE FUNCTION foo3_12h(x INT) RETURNS TABLE (a INT, b INT) READS SQL DATA RETURN SELECT x, x + 1 +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12h, x INT, a INT, b INT, SELECT x, x + 1, false, true, false, false, false + + +-- !query +CREATE FUNCTION foo3_12i(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT * FROM VALUES (0, 1) +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12i, x INT, a INT, b INT, SELECT * FROM VALUES (0, 1), true, true, false, false, false + + +-- !query +CREATE FUNCTION foo3_12j(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT id, id + 1 FROM RANGE(3) +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12j, x INT, a INT, b INT, SELECT id, id + 1 FROM RANGE(3), true, true, false, false, false + + +-- !query +CREATE FUNCTION foo3_12k(x INT) RETURNS TABLE (a INT, b INT) RETURN SELECT c1, c2 FROM t1 +-- !query analysis +CreateSQLFunctionCommand spark_catalog.default.foo3_12k, x INT, a INT, b INT, SELECT c1, c2 FROM t1, true, false, false, false + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT c1, c2 FROM t1 +-- !query analysis +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT foo3_12b(x), x +-- !query analysis +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT * FROM foo3_12h(x) +-- !query analysis +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT * FROM foo3_12k(x) +-- !query analysis +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE TABLE tbl USING PARQUET AS SELECT c1 FROM t2 +-- !query analysis +CreateDataSourceTableAsSelectCommand `spark_catalog`.`default`.`tbl`, ErrorIfExists, [c1] + +- Project [c1#x] + +- SubqueryAlias spark_catalog.default.t2 + +- View (`spark_catalog`.`default`.`t2`, [c1#x, c2#x]) + +- Project [cast(col1#x as int) AS c1#x, cast(col2#x as int) AS c2#x] + +- LocalRelation [col1#x, col2#x] + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN SELECT SUM(c1) FROM tbl +-- !query analysis +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT) CONTAINS SQL RETURN SELECT * FROM tbl +-- !query analysis +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +DROP TABLE tbl +-- !query analysis +DropTable false, false ++- ResolvedIdentifier V2SessionCatalog(spark_catalog), default.tbl + + -- !query CREATE FUNCTION foo3_14a() RETURNS INT RETURN 1 -- !query analysis @@ -5084,6 +5252,72 @@ DROP FUNCTION IF EXISTS foo3_4f DropFunctionCommand spark_catalog.default.foo3_4f, true, false +-- !query +DROP FUNCTION IF EXISTS foo3_12a +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12a, true, false + + +-- !query +DROP FUNCTION IF EXISTS foo3_12b +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12b, true, false + + +-- !query +DROP FUNCTION IF EXISTS foo3_12c +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12c, true, false + + +-- !query +DROP FUNCTION IF EXISTS foo3_12d +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12d, true, false + + +-- !query +DROP FUNCTION IF EXISTS foo3_12e +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12e, true, false + + +-- !query +DROP FUNCTION IF EXISTS foo3_12f +-- !query analysis +NoopCommand DROP FUNCTION, [foo3_12f] + + +-- !query +DROP FUNCTION IF EXISTS foo3_12g +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12g, true, false + + +-- !query +DROP FUNCTION IF EXISTS foo3_12h +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12h, true, false + + +-- !query +DROP FUNCTION IF EXISTS foo3_12i +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12i, true, false + + +-- !query +DROP FUNCTION IF EXISTS foo3_12j +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12j, true, false + + +-- !query +DROP FUNCTION IF EXISTS foo3_12k +-- !query analysis +DropFunctionCommand spark_catalog.default.foo3_12k, true, false + + -- !query DROP FUNCTION IF EXISTS foo4_0 -- !query analysis diff --git a/sql/core/src/test/resources/sql-tests/inputs/sql-udf.sql b/sql/core/src/test/resources/sql-tests/inputs/sql-udf.sql index 6a43bb5ac051..e796b7b192b3 100644 --- a/sql/core/src/test/resources/sql-tests/inputs/sql-udf.sql +++ b/sql/core/src/test/resources/sql-tests/inputs/sql-udf.sql @@ -818,6 +818,36 @@ CREATE FUNCTION foo3_5d(x INT) RETURNS TABLE (a INT) RETURN SELECT foo3_5a(x); CREATE FUNCTION foo3_5d(x INT) RETURNS INT RETURN (SELECT SUM(a) FROM t); CREATE FUNCTION foo3_5d(x INT) RETURNS TABLE (a INT) RETURN SELECT a FROM t; +-- 3.12 SQL data access routine +-- Scalar functions +CREATE FUNCTION foo3_12a(x INT) RETURNS INT CONTAINS SQL RETURN x; +CREATE FUNCTION foo3_12b(x INT) RETURNS INT READS SQL DATA RETURN x; +CREATE FUNCTION foo3_12c(x INT) RETURNS INT CONTAINS SQL RETURN (SELECT x); +CREATE FUNCTION foo3_12d(x INT) RETURNS INT CONTAINS SQL RETURN (SELECT COUNT(*) FROM range(0, 3)); +CREATE FUNCTION foo3_12e(x INT) RETURNS INT CONTAINS SQL RETURN (SELECT COUNT(*) FROM VALUES (0, 1)); +-- Expect error: cannot create a SQL function with CONTAINS SQL that accesses SQL data +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN SELECT SUM(c2) FROM t1; +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN foo3_12b(x) + 1; +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN 1 + (SELECT SUM(c2) FROM t1); + +-- Table functions +CREATE FUNCTION foo3_12g(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT x, x + 1; +CREATE FUNCTION foo3_12h(x INT) RETURNS TABLE (a INT, b INT) READS SQL DATA RETURN SELECT x, x + 1; +CREATE FUNCTION foo3_12i(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT * FROM VALUES (0, 1); +CREATE FUNCTION foo3_12j(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT id, id + 1 FROM RANGE(3); +-- Derived SQL data access: READS SQL DATA. +CREATE FUNCTION foo3_12k(x INT) RETURNS TABLE (a INT, b INT) RETURN SELECT c1, c2 FROM t1; +-- Expect error: cannot create a SQL function with CONTAINS SQL that accesses SQL data +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT c1, c2 FROM t1; +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT foo3_12b(x), x; +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT * FROM foo3_12h(x); +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT * FROM foo3_12k(x); + +CREATE TABLE tbl USING PARQUET AS SELECT c1 FROM t2; +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN SELECT SUM(c1) FROM tbl; +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT) CONTAINS SQL RETURN SELECT * FROM tbl; +DROP TABLE tbl; + -- 3.14 Invalid usage of SQL scalar/table functions in query clauses. CREATE FUNCTION foo3_14a() RETURNS INT RETURN 1; CREATE FUNCTION foo3_14b() RETURNS TABLE (a INT) RETURN SELECT 1; @@ -981,6 +1011,17 @@ DROP FUNCTION IF EXISTS foo3_4c; DROP FUNCTION IF EXISTS foo3_4d; DROP FUNCTION IF EXISTS foo3_4e; DROP FUNCTION IF EXISTS foo3_4f; +DROP FUNCTION IF EXISTS foo3_12a; +DROP FUNCTION IF EXISTS foo3_12b; +DROP FUNCTION IF EXISTS foo3_12c; +DROP FUNCTION IF EXISTS foo3_12d; +DROP FUNCTION IF EXISTS foo3_12e; +DROP FUNCTION IF EXISTS foo3_12f; +DROP FUNCTION IF EXISTS foo3_12g; +DROP FUNCTION IF EXISTS foo3_12h; +DROP FUNCTION IF EXISTS foo3_12i; +DROP FUNCTION IF EXISTS foo3_12j; +DROP FUNCTION IF EXISTS foo3_12k; DROP FUNCTION IF EXISTS foo4_0; DROP FUNCTION IF EXISTS foo4_1; DROP FUNCTION IF EXISTS foo4_2; diff --git a/sql/core/src/test/resources/sql-tests/results/sql-udf.sql.out b/sql/core/src/test/resources/sql-tests/results/sql-udf.sql.out index a2993b4a855a..de65b20b1408 100644 --- a/sql/core/src/test/resources/sql-tests/results/sql-udf.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/sql-udf.sql.out @@ -4175,6 +4175,210 @@ org.apache.spark.sql.AnalysisException } +-- !query +CREATE FUNCTION foo3_12a(x INT) RETURNS INT CONTAINS SQL RETURN x +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12b(x INT) RETURNS INT READS SQL DATA RETURN x +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12c(x INT) RETURNS INT CONTAINS SQL RETURN (SELECT x) +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12d(x INT) RETURNS INT CONTAINS SQL RETURN (SELECT COUNT(*) FROM range(0, 3)) +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12e(x INT) RETURNS INT CONTAINS SQL RETURN (SELECT COUNT(*) FROM VALUES (0, 1)) +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN SELECT SUM(c2) FROM t1 +-- !query schema +struct<> +-- !query output +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN foo3_12b(x) + 1 +-- !query schema +struct<> +-- !query output +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN 1 + (SELECT SUM(c2) FROM t1) +-- !query schema +struct<> +-- !query output +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12g(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT x, x + 1 +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12h(x INT) RETURNS TABLE (a INT, b INT) READS SQL DATA RETURN SELECT x, x + 1 +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12i(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT * FROM VALUES (0, 1) +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12j(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT id, id + 1 FROM RANGE(3) +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12k(x INT) RETURNS TABLE (a INT, b INT) RETURN SELECT c1, c2 FROM t1 +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT c1, c2 FROM t1 +-- !query schema +struct<> +-- !query output +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT foo3_12b(x), x +-- !query schema +struct<> +-- !query output +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT * FROM foo3_12h(x) +-- !query schema +struct<> +-- !query output +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT, b INT) CONTAINS SQL RETURN SELECT * FROM foo3_12k(x) +-- !query schema +struct<> +-- !query output +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE TABLE tbl USING PARQUET AS SELECT c1 FROM t2 +-- !query schema +struct<> +-- !query output + + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS INT CONTAINS SQL RETURN SELECT SUM(c1) FROM tbl +-- !query schema +struct<> +-- !query output +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +CREATE FUNCTION foo3_12f(x INT) RETURNS TABLE (a INT) CONTAINS SQL RETURN SELECT * FROM tbl +-- !query schema +struct<> +-- !query output +org.apache.spark.sql.AnalysisException +{ + "errorClass" : "INVALID_SQL_FUNCTION_DATA_ACCESS", + "sqlState" : "42K0E" +} + + +-- !query +DROP TABLE tbl +-- !query schema +struct<> +-- !query output + + + -- !query CREATE FUNCTION foo3_14a() RETURNS INT RETURN 1 -- !query schema @@ -5401,6 +5605,94 @@ struct<> +-- !query +DROP FUNCTION IF EXISTS foo3_12a +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12b +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12c +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12d +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12e +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12f +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12g +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12h +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12i +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12j +-- !query schema +struct<> +-- !query output + + + +-- !query +DROP FUNCTION IF EXISTS foo3_12k +-- !query schema +struct<> +-- !query output + + + -- !query DROP FUNCTION IF EXISTS foo4_0 -- !query schema --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@spark.apache.org For additional commands, e-mail: commits-h...@spark.apache.org