Skip to content

Commit acf1ca7

Browse files
committed
fix
1 parent 2987c8e commit acf1ca7

7 files changed

Lines changed: 120 additions & 29 deletions

File tree

fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionToSqlConverter.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ public static String toSql(ScalarFunction fn, boolean ifNotExists) {
5656
if (fn.isGlobal()) {
5757
sb.append("GLOBAL ");
5858
}
59-
sb.append("FUNCTION ");
59+
sb.append(fn.isUDTFunction() ? "TABLES FUNCTION " : "FUNCTION ");
6060

6161
if (ifNotExists) {
6262
sb.append("IF NOT EXISTS ");
6363
}
6464
sb.append(fn.signatureString())
65-
.append(" RETURNS " + fn.getReturnType())
65+
.append(" RETURNS " + getScalarFunctionReturnTypeSql(fn))
6666
.append(" PROPERTIES (");
6767
sb.append("\n \"SYMBOL\"=").append("\"" + fn.getSymbolName() + "\"");
6868
if (fn.getPrepareFnSymbol() != null) {
@@ -77,14 +77,18 @@ public static String toSql(ScalarFunction fn, boolean ifNotExists) {
7777
.append("\"" + (fn.getLocation() == null ? "" : fn.getLocation().toString()) + "\"");
7878
boolean isReturnNull = fn.getNullableMode() == NullableMode.ALWAYS_NULLABLE;
7979
sb.append(",\n \"ALWAYS_NULLABLE\"=").append("\"" + isReturnNull + "\"");
80-
sb.append(",\n \"VOLATILITY\"=").append("\"" + fn.getVolatility().toSql() + "\"");
80+
if (!fn.isUDTFunction()) {
81+
sb.append(",\n \"VOLATILITY\"=").append("\"" + fn.getVolatility().toSql() + "\"");
82+
}
8183
} else if (fn.getBinaryType() == Function.BinaryType.PYTHON_UDF) {
8284
sb.append(",\n \"FILE\"=")
8385
.append("\"" + (fn.getLocation() == null ? "" : fn.getLocation().toString()) + "\"");
8486
boolean isReturnNull = fn.getNullableMode() == NullableMode.ALWAYS_NULLABLE;
8587
sb.append(",\n \"ALWAYS_NULLABLE\"=").append("\"" + isReturnNull + "\"");
8688
sb.append(",\n \"RUNTIME_VERSION\"=").append("\"" + Strings.nullToEmpty(fn.getRuntimeVersion()) + "\"");
87-
sb.append(",\n \"VOLATILITY\"=").append("\"" + fn.getVolatility().toSql() + "\"");
89+
if (!fn.isUDTFunction()) {
90+
sb.append(",\n \"VOLATILITY\"=").append("\"" + fn.getVolatility().toSql() + "\"");
91+
}
8892
} else {
8993
sb.append(",\n \"OBJECT_FILE\"=")
9094
.append("\"" + (fn.getLocation() == null ? "" : fn.getLocation().toString()) + "\"");
@@ -99,6 +103,13 @@ public static String toSql(ScalarFunction fn, boolean ifNotExists) {
99103
return sb.toString();
100104
}
101105

106+
private static String getScalarFunctionReturnTypeSql(ScalarFunction fn) {
107+
if (fn.isUDTFunction()) {
108+
return new ArrayType(fn.getReturnType()).toSql();
109+
}
110+
return fn.getReturnType().toSql();
111+
}
112+
102113
/**
103114
* Converts an {@link AggregateFunction} to its SQL representation.
104115
*/

fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/AddProjectForUniqueFunction.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
import org.apache.doris.nereids.trees.expressions.NamedExpression;
2727
import org.apache.doris.nereids.trees.expressions.Slot;
2828
import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator;
29-
import org.apache.doris.nereids.trees.expressions.VolatileExpression;
3029
import org.apache.doris.nereids.trees.expressions.functions.Function;
30+
import org.apache.doris.nereids.trees.expressions.functions.scalar.UniqueFunction;
3131
import org.apache.doris.nereids.trees.plans.JoinType;
3232
import org.apache.doris.nereids.trees.plans.Plan;
3333
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
@@ -278,8 +278,8 @@ public List<NamedExpression> tryGenUniqueFunctionAlias(Collection<? extends Expr
278278
for (Expression target : targets) {
279279
target.foreach(e -> {
280280
Expression expr = (Expression) e;
281-
if (expr instanceof VolatileExpression && ((VolatileExpression) expr).isVolatile()) {
282-
unqiueFunctionCounter.merge(expr, 1, Integer::sum);
281+
if (expr instanceof UniqueFunction) {
282+
unqiueFunctionCounter.merge((UniqueFunction) expr, 1, Integer::sum);
283283
}
284284
});
285285
}

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/VolatileIdentity.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,14 @@ public VolatileIdentity withIgnoreUniqueId(boolean ignoreUniqueId) {
7070

7171
/** Compare volatile expressions by identity unless either side temporarily ignores it. */
7272
public boolean equalsByIdentity(VolatileIdentity other, boolean fallbackEquals) {
73-
if (!isVolatile() && !other.isVolatile()) {
73+
if ((!isVolatile() && !other.isVolatile())
74+
|| (ignoreUniqueId && other.ignoreUniqueId())) {
7475
return fallbackEquals;
7576
}
76-
if (!isVolatile() || !other.isVolatile()) {
77+
if ((!isVolatile() || !other.isVolatile())
78+
|| (ignoreUniqueId || other.ignoreUniqueId())) {
7779
return false;
7880
}
79-
if (ignoreUniqueId || other.ignoreUniqueId()) {
80-
return fallbackEquals;
81-
}
8281
return uniqueId.equals(other.getUniqueIdOptional());
8382
}
8483

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowFunctionsCommand.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,9 @@ private String buildProperties(Function function) {
295295
}
296296
if (function instanceof ScalarFunction) {
297297
ScalarFunction scalarFunction = (ScalarFunction) function;
298-
if (function.getBinaryType() == Function.BinaryType.JAVA_UDF
299-
|| function.getBinaryType() == Function.BinaryType.PYTHON_UDF) {
298+
if (!scalarFunction.isUDTFunction()
299+
&& (function.getBinaryType() == Function.BinaryType.JAVA_UDF
300+
|| function.getBinaryType() == Function.BinaryType.PYTHON_UDF)) {
300301
properties.put("VOLATILITY", function.getVolatility().toSql());
301302
}
302303
properties.put("SYMBOL", Strings.nullToEmpty(scalarFunction.getSymbolName()));
@@ -351,4 +352,9 @@ private String buildProperties(Function function) {
351352
.collect(Collectors.joining(", "));
352353
}
353354

355+
@VisibleForTesting
356+
String buildPropertiesForTest(Function function) {
357+
return buildProperties(function);
358+
}
359+
354360
}

fe/fe-core/src/test/java/org/apache/doris/catalog/FunctionToSqlConverterTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,46 @@ void testScalarFunction_pythonUdf_moduleReplaySql() throws AnalysisException {
143143
Assertions.assertFalse(sql.contains("AS $$"));
144144
}
145145

146+
@Test
147+
void testScalarFunction_javaUdtfReplaySql() {
148+
FunctionName name = new FunctionName("testDb", "java_table_fn");
149+
Type[] argTypes = {Type.INT};
150+
ScalarFunction fn = ScalarFunction.createUdf(BinaryType.JAVA_UDF, name, argTypes,
151+
Type.INT, false, null, "com.example.TableFn", null, null);
152+
fn.setUDTFunction(true);
153+
fn.setVolatility(FunctionVolatility.IMMUTABLE);
154+
155+
String sql = FunctionToSqlConverter.toSql(fn, true);
156+
157+
Assertions.assertTrue(sql.startsWith("CREATE TABLES FUNCTION IF NOT EXISTS "));
158+
Assertions.assertTrue(sql.contains("java_table_fn(int)"));
159+
Assertions.assertTrue(sql.contains("RETURNS array<int>"));
160+
Assertions.assertTrue(sql.contains("\"TYPE\"=\"JAVA_UDF\""));
161+
Assertions.assertFalse(sql.contains("VOLATILITY"));
162+
}
163+
164+
@Test
165+
void testScalarFunction_pythonUdtfReplaySql() {
166+
FunctionName name = new FunctionName("testDb", "py_table_fn");
167+
Type[] argTypes = {Type.INT};
168+
ScalarFunction fn = ScalarFunction.createUdf(BinaryType.PYTHON_UDF, name, argTypes,
169+
Type.INT, false, null, "evaluate", null, null);
170+
fn.setUDTFunction(true);
171+
fn.setRuntimeVersion("3.10.2");
172+
fn.setFunctionCode("def evaluate(x):\n yield x");
173+
fn.setVolatility(FunctionVolatility.IMMUTABLE);
174+
175+
String sql = FunctionToSqlConverter.toSql(fn, false);
176+
177+
Assertions.assertTrue(sql.startsWith("CREATE TABLES FUNCTION "));
178+
Assertions.assertTrue(sql.contains("py_table_fn(int)"));
179+
Assertions.assertTrue(sql.contains("RETURNS array<int>"));
180+
Assertions.assertTrue(sql.contains("\"RUNTIME_VERSION\"=\"3.10.2\""));
181+
Assertions.assertTrue(sql.contains("\"TYPE\"=\"PYTHON_UDF\""));
182+
Assertions.assertTrue(sql.contains("AS $$\ndef evaluate(x):\n yield x\n$$;"));
183+
Assertions.assertFalse(sql.contains("VOLATILITY"));
184+
}
185+
146186
// ======================== ScalarFunction — IF NOT EXISTS ========================
147187

148188
@Test

fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/udf/UdfVolatilityTest.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,15 @@
2121
import org.apache.doris.catalog.Function.NullableMode;
2222
import org.apache.doris.catalog.FunctionSignature;
2323
import org.apache.doris.catalog.FunctionVolatility;
24-
import org.apache.doris.nereids.rules.rewrite.AddProjectForUniqueFunction;
2524
import org.apache.doris.nereids.trees.expressions.Expression;
26-
import org.apache.doris.nereids.trees.expressions.NamedExpression;
2725
import org.apache.doris.nereids.trees.expressions.VolatileIdentity;
2826
import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
2927
import org.apache.doris.nereids.types.IntegerType;
3028
import org.apache.doris.nereids.util.ExpressionUtils;
3129

32-
import com.google.common.collect.ImmutableList;
3330
import org.junit.jupiter.api.Assertions;
3431
import org.junit.jupiter.api.Test;
3532

36-
import java.util.List;
37-
3833
class UdfVolatilityTest {
3934

4035
@Test
@@ -69,16 +64,6 @@ void testVolatileAndImmutableUdfAreNotEqual() {
6964
Assertions.assertNotEquals(volatileUdf, immutable);
7065
}
7166

72-
@Test
73-
void testAddProjectForRepeatedVolatileUdf() {
74-
PythonUdf udf = pythonUdf(FunctionVolatility.VOLATILE, VolatileIdentity.newVolatileIdentity());
75-
List<NamedExpression> aliases = new AddProjectForUniqueFunction()
76-
.tryGenUniqueFunctionAlias(ImmutableList.of(udf, udf));
77-
78-
Assertions.assertEquals(1, aliases.size());
79-
Assertions.assertEquals(udf, aliases.get(0).child(0));
80-
}
81-
8267
@Test
8368
void testJavaUdfVolatility() {
8469
JavaUdf udf = javaUdf(FunctionVolatility.STABLE, VolatileIdentity.NON_VOLATILE);

fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFunctionsCommandTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
import org.apache.doris.catalog.AccessPrivilegeWithCols;
2525
import org.apache.doris.catalog.Env;
2626
import org.apache.doris.catalog.Function;
27+
import org.apache.doris.catalog.FunctionName;
28+
import org.apache.doris.catalog.FunctionVolatility;
29+
import org.apache.doris.catalog.ScalarFunction;
30+
import org.apache.doris.catalog.Type;
2731
import org.apache.doris.common.AnalysisException;
2832
import org.apache.doris.common.UserException;
2933
import org.apache.doris.mysql.privilege.Auth;
@@ -111,6 +115,52 @@ void testLike() {
111115
Assertions.assertTrue(sf.like("test_for_create_function", "test_for_create_function%"));
112116
}
113117

118+
@Test
119+
void testBuildProperties_scalarUdfEmitsVolatility() {
120+
ShowFunctionsCommand sf = new ShowFunctionsCommand("test", true, null);
121+
ScalarFunction fn = ScalarFunction.createUdf(Function.BinaryType.JAVA_UDF,
122+
new FunctionName("test", "java_scalar_fn"), new Type[] {Type.INT},
123+
Type.INT, false, null, "com.example.ScalarFn", null, null);
124+
fn.setVolatility(FunctionVolatility.IMMUTABLE);
125+
126+
String properties = sf.buildPropertiesForTest(fn);
127+
128+
Assertions.assertTrue(properties.contains("SYMBOL=com.example.ScalarFn"));
129+
Assertions.assertTrue(properties.contains("VOLATILITY=immutable"));
130+
}
131+
132+
@Test
133+
void testBuildProperties_javaUdtfDoesNotEmitVolatility() {
134+
ShowFunctionsCommand sf = new ShowFunctionsCommand("test", true, null);
135+
ScalarFunction fn = ScalarFunction.createUdf(Function.BinaryType.JAVA_UDF,
136+
new FunctionName("test", "java_table_fn"), new Type[] {Type.INT},
137+
Type.INT, false, null, "com.example.TableFn", null, null);
138+
fn.setUDTFunction(true);
139+
fn.setVolatility(FunctionVolatility.IMMUTABLE);
140+
141+
String properties = sf.buildPropertiesForTest(fn);
142+
143+
Assertions.assertTrue(properties.contains("SYMBOL=com.example.TableFn"));
144+
Assertions.assertFalse(properties.contains("VOLATILITY"));
145+
}
146+
147+
@Test
148+
void testBuildProperties_pythonUdtfDoesNotEmitVolatility() {
149+
ShowFunctionsCommand sf = new ShowFunctionsCommand("test", true, null);
150+
ScalarFunction fn = ScalarFunction.createUdf(Function.BinaryType.PYTHON_UDF,
151+
new FunctionName("test", "py_table_fn"), new Type[] {Type.INT},
152+
Type.INT, false, null, "evaluate", null, null);
153+
fn.setUDTFunction(true);
154+
fn.setRuntimeVersion("3.10.2");
155+
fn.setVolatility(FunctionVolatility.IMMUTABLE);
156+
157+
String properties = sf.buildPropertiesForTest(fn);
158+
159+
Assertions.assertTrue(properties.contains("RUNTIME_VERSION=3.10.2"));
160+
Assertions.assertTrue(properties.contains("SYMBOL=evaluate"));
161+
Assertions.assertFalse(properties.contains("VOLATILITY"));
162+
}
163+
114164
@Test
115165
void testAuth() throws Exception {
116166
auth = Env.getCurrentEnv().getAuth();

0 commit comments

Comments
 (0)