morrySnow commented on code in PR #65100:
URL: https://github.com/apache/doris/pull/65100#discussion_r3510505065


##########
fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java:
##########
@@ -769,16 +769,45 @@ public void setName(String name) {
     }
 
     public synchronized void addFunction(Function function, boolean 
ifNotExists) throws UserException {
-        function.checkWritable();
-        if (FunctionUtil.addFunctionImpl(function, ifNotExists, false, 
name2Function)) {
-            Env.getCurrentEnv().getEditLog().logAddFunction(function);
-            try {
+        addFunctions(ImmutableList.of(function), ifNotExists);
+    }
+
+    public synchronized void addTableFunction(Function function, boolean 
ifNotExists) throws UserException {
+        // Doris table functions are registered as two functions: the normal 
function and its outer variant.
+        Function outerFunction = function.clone();
+        FunctionName name = outerFunction.getFunctionName();
+        name.setFn(name.getFunction() + "_outer");
+        addFunctions(ImmutableList.of(function, outerFunction), ifNotExists);
+    }
+
+    private void addFunctions(List<Function> functions, boolean ifNotExists) 
throws UserException {
+        List<Function> addedFunctions = Lists.newArrayList();
+        try {
+            for (Function function : functions) {
+                function.checkWritable();
+                if (FunctionUtil.addFunctionImpl(function, ifNotExists, false, 
name2Function)) {

Review Comment:
   Fixed in commit 2624ebd108a. Database.addTableFunction() now treats the base 
UDTF and generated _outer function as one pair for IF NOT EXISTS: it skips only 
when both exact signatures already exist and both are UDTFs; any 
partial/base/companion collision throws before either half is registered. The 
actual add then runs with ifNotExists=false for both functions in the existing 
rollback batch, so a companion-name collision cannot leave the base function 
visible or logged. Added CreateFunctionTest coverage for the unrelated _outer 
collision and the existing-pair IF NOT EXISTS skip path.



##########
fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java:
##########
@@ -769,16 +769,45 @@ public void setName(String name) {
     }
 
     public synchronized void addFunction(Function function, boolean 
ifNotExists) throws UserException {
-        function.checkWritable();
-        if (FunctionUtil.addFunctionImpl(function, ifNotExists, false, 
name2Function)) {
-            Env.getCurrentEnv().getEditLog().logAddFunction(function);
-            try {
+        addFunctions(ImmutableList.of(function), ifNotExists);
+    }
+
+    public synchronized void addTableFunction(Function function, boolean 
ifNotExists) throws UserException {
+        // Doris table functions are registered as two functions: the normal 
function and its outer variant.
+        Function outerFunction = function.clone();
+        FunctionName name = outerFunction.getFunctionName();
+        name.setFn(name.getFunction() + "_outer");
+        addFunctions(ImmutableList.of(function, outerFunction), ifNotExists);
+    }
+
+    private void addFunctions(List<Function> functions, boolean ifNotExists) 
throws UserException {
+        List<Function> addedFunctions = Lists.newArrayList();
+        try {
+            for (Function function : functions) {
+                function.checkWritable();
+                if (FunctionUtil.addFunctionImpl(function, ifNotExists, false, 
name2Function)) {
+                    addedFunctions.add(function);
+                }
+            }
+            for (Function function : addedFunctions) {
                 FunctionUtil.translateToNereidsThrows(this.getFullName(), 
function);
-            } catch (Exception e) {
-                name2Function.remove(function.getFunctionName().getFunction());
-                throw e;
             }
+        } catch (Exception e) {
+            for (Function function : addedFunctions) {
+                FunctionUtil.dropFromNereids(this.getFullName(), 
getFunctionSearchDesc(function));
+            }
+            for (int i = addedFunctions.size() - 1; i >= 0; i--) {
+                FunctionUtil.removeFunctionImpl(addedFunctions.get(i), 
name2Function);
+            }
+            throw e;
         }
+        for (Function function : addedFunctions) {
+            Env.getCurrentEnv().getEditLog().logAddFunction(function);

Review Comment:
   Fixed in commit 2624ebd108a. The successful local table-function path no 
longer writes two independent OP_ADD_FUNCTION records. I added 
CreateFunctionInfo plus OP_ADD_FUNCTIONS, JournalEntity read support, 
EditLog.logAddFunctions(), and replay through Env.replayCreateFunctions(). 
Database.addTableFunction() now logs the base and _outer functions with one 
OP_ADD_FUNCTIONS payload after both catalog registration and Nereids 
translation succeed, so replay cannot observe a durable base-only table 
function from this success path. Added CreateFunctionTest coverage verifying 
the table-function success path calls logAddFunctions once and never 
logAddFunction.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to