This is an automated email from the ASF dual-hosted git repository.
ruifengz 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 24207e2e9cd1 [SPARK-54834][SQL] Add new interfaces SimpleProcedure and
SimpleFunction
24207e2e9cd1 is described below
commit 24207e2e9cd1bfa198775253511eac03039ca6c1
Author: Wenchen Fan <[email protected]>
AuthorDate: Fri Dec 26 16:41:13 2025 +0800
[SPARK-54834][SQL] Add new interfaces SimpleProcedure and SimpleFunction
### What changes were proposed in this pull request?
It's common that a procedure does not have any overload and the `bind`
method always return the same `BoundProcedure`. This PR adds a new interface
`SimpleProcedure ` for this use case, which allows people to implement a
`BoundProcedure` directly without thinking about how to bind. The same applies
to v2 functions.
### Why are the changes needed?
Simplify a common use case when people implement procedures and functions.
### Does this PR introduce _any_ user-facing change?
No, it's developer facing
### How was this patch tested?
new tests
### Was this patch authored or co-authored using generative AI tooling?
cursor 2.2.43
Closes #53595 from cloud-fan/procedure.
Authored-by: Wenchen Fan <[email protected]>
Signed-off-by: Ruifeng Zheng <[email protected]>
---
.../catalog/functions/SimpleFunction.java | 42 ++++++++++++++++++++++
.../catalog/procedures/SimpleProcedure.java | 42 ++++++++++++++++++++++
.../sql/connector/DataSourceV2FunctionSuite.scala | 19 ++++++++++
.../spark/sql/connector/ProcedureSuite.scala | 20 ++++++++---
4 files changed, 119 insertions(+), 4 deletions(-)
diff --git
a/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/functions/SimpleFunction.java
b/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/functions/SimpleFunction.java
new file mode 100644
index 000000000000..39c2622385b7
--- /dev/null
+++
b/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/functions/SimpleFunction.java
@@ -0,0 +1,42 @@
+/*
+ * 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.connector.catalog.functions;
+
+import org.apache.spark.annotation.Evolving;
+import org.apache.spark.sql.types.StructType;
+
+/**
+ * A function that does not require binding to input types.
+ * <p>
+ * This interface is designed for functions that have no overloads and do not
need custom binding
+ * logic. Implementations can directly provide function parameters and
execution logic without
+ * implementing the {@link UnboundFunction#bind(StructType) bind} method.
+ * <p>
+ * The default {@link #bind(StructType) bind} method simply returns {@code
this}, as the function
+ * is already considered bound.
+ *
+ * @since 4.2.0
+ */
+@Evolving
+public interface SimpleFunction extends UnboundFunction, BoundFunction {
+ @Override
+ default BoundFunction bind(StructType inputType) {
+ return this;
+ }
+}
+
diff --git
a/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/procedures/SimpleProcedure.java
b/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/procedures/SimpleProcedure.java
new file mode 100644
index 000000000000..e464a3703e09
--- /dev/null
+++
b/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/procedures/SimpleProcedure.java
@@ -0,0 +1,42 @@
+/*
+ * 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.connector.catalog.procedures;
+
+import org.apache.spark.annotation.Evolving;
+import org.apache.spark.sql.types.StructType;
+
+/**
+ * A procedure that does not require binding to input types.
+ * <p>
+ * This interface is designed for procedures that have no overloads and do not
need custom binding
+ * logic. Implementations can directly provide procedure parameters and
execution logic without
+ * implementing the {@link UnboundProcedure#bind(StructType) bind} method.
+ * <p>
+ * The default {@link #bind(StructType) bind} method simply returns {@code
this}, as the procedure
+ * is already considered bound.
+ *
+ * @since 4.2.0
+ */
+@Evolving
+public interface SimpleProcedure extends UnboundProcedure, BoundProcedure {
+ @Override
+ default BoundProcedure bind(StructType inputType) {
+ return this;
+ }
+}
+
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/connector/DataSourceV2FunctionSuite.scala
b/sql/core/src/test/scala/org/apache/spark/sql/connector/DataSourceV2FunctionSuite.scala
index 366528e46ff2..23e221d6ecaf 100644
---
a/sql/core/src/test/scala/org/apache/spark/sql/connector/DataSourceV2FunctionSuite.scala
+++
b/sql/core/src/test/scala/org/apache/spark/sql/connector/DataSourceV2FunctionSuite.scala
@@ -702,6 +702,25 @@ class DataSourceV2FunctionSuite extends
DatasourceV2SQLBase {
comparePlans(df1.queryExecution.optimizedPlan,
df2.queryExecution.optimizedPlan)
checkAnswer(df1, Row(3) :: Nil)
}
+
+ test("simple function") {
+
catalog("testcat").asInstanceOf[SupportsNamespaces].createNamespace(Array("ns"),
emptyProps)
+ addFunction(Identifier.of(Array("ns"), "simple_strlen"), SimpleStrLen)
+ checkAnswer(sql("SELECT testcat.ns.simple_strlen('abc')"), Row(3) :: Nil)
+ checkAnswer(sql("SELECT testcat.ns.simple_strlen('hello world')"), Row(11)
:: Nil)
+ }
+}
+
+case object SimpleStrLen extends SimpleFunction with ScalarFunction[Int] {
+ override def inputTypes(): Array[DataType] = Array(StringType)
+ override def resultType(): DataType = IntegerType
+ override def name(): String = "simple_strlen"
+ override def description(): String = "simple string length function"
+
+ override def produceResult(input: InternalRow): Int = {
+ val s = input.getString(0)
+ s.length
+ }
}
case object StrLenDefault extends ScalarFunction[Int] {
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/connector/ProcedureSuite.scala
b/sql/core/src/test/scala/org/apache/spark/sql/connector/ProcedureSuite.scala
index a88e6dbbe6de..bcf288056471 100644
---
a/sql/core/src/test/scala/org/apache/spark/sql/connector/ProcedureSuite.scala
+++
b/sql/core/src/test/scala/org/apache/spark/sql/connector/ProcedureSuite.scala
@@ -26,7 +26,7 @@ import org.apache.spark.sql.{AnalysisException, QueryTest,
Row}
import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.util.TypeUtils.toSQLId
import org.apache.spark.sql.connector.catalog.{BasicInMemoryTableCatalog,
DefaultValue, Identifier, InMemoryCatalog}
-import org.apache.spark.sql.connector.catalog.procedures.{BoundProcedure,
ProcedureParameter, UnboundProcedure}
+import org.apache.spark.sql.connector.catalog.procedures.{BoundProcedure,
ProcedureParameter, SimpleProcedure, UnboundProcedure}
import
org.apache.spark.sql.connector.catalog.procedures.ProcedureParameter.Mode
import
org.apache.spark.sql.connector.catalog.procedures.ProcedureParameter.Mode.{IN,
INOUT, OUT}
import org.apache.spark.sql.connector.expressions.{Expression,
GeneralScalarExpression, LiteralValue}
@@ -486,6 +486,12 @@ class ProcedureSuite extends QueryTest with
SharedSparkSession with BeforeAndAft
checkAnswer(sql("CALL cat.ns.sum(5)"), Row(9) :: Nil)
}
+ test("simple procedure") {
+ catalog.createProcedure(Identifier.of(Array("ns"), "simple_sum"),
SimpleSum)
+ checkAnswer(sql("CALL cat.ns.simple_sum(3, 7)"), Row(10) :: Nil)
+ checkAnswer(sql("CALL cat.ns.simple_sum(in2 => 4, in1 => 6)"), Row(10) ::
Nil)
+ }
+
test("SPARK-51780: Implement DESC PROCEDURE") {
catalog.createProcedure(Identifier.of(Array("ns"), "foo"), UnboundSum)
catalog.createProcedure(Identifier.of(Array("ns", "db"), "abc"),
UnboundLongSum)
@@ -610,7 +616,7 @@ class ProcedureSuite extends QueryTest with
SharedSparkSession with BeforeAndAft
object UnboundNonExecutableSum extends UnboundProcedure {
override def name: String = "sum"
override def description: String = "sum integers"
- override def bind(inputType: StructType): BoundProcedure = Sum
+ override def bind(inputType: StructType): BoundProcedure = NonExecutableSum
}
object NonExecutableSum extends BoundProcedure {
@@ -633,10 +639,10 @@ class ProcedureSuite extends QueryTest with
SharedSparkSession with BeforeAndAft
object UnboundSum extends UnboundProcedure {
override def name: String = "sum"
override def description: String = "sum integers"
- override def bind(inputType: StructType): BoundProcedure = Sum
+ override def bind(inputType: StructType): BoundProcedure = new Sum
}
- object Sum extends BoundProcedure {
+ class Sum extends BoundProcedure {
override def name: String = "sum"
override def description: String = "sum integers"
@@ -897,4 +903,10 @@ class ProcedureSuite extends QueryTest with
SharedSparkSession with BeforeAndAft
override def defaultValue: DefaultValue = null
override def comment: String = null
}
+
+ object SimpleSum extends Sum with SimpleProcedure {
+ override def name: String = "simple_sum"
+
+ override def description: String = "simple sum integers"
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]