Hi @Viorel
Note: What I write here based on my personal experience and test and it is not documented well. I hope that I get it and explain it accurately.
As I started to say, this is a bit more complex than table valued function.
By default (without disabling the inline), when we execute a scalar UDF in SQL Server 2019, then SQL Server automatically "choose" if to execute it as a scalar expressions or as scalar subqueries that are executed inline (this part is documented). This is different from table valued function which are executed according to the structure of the function.
This means that the same function can be executed as inline once and as scalar expression in a different execution, and this is what you have here.
Check the execution plan when you execute the original sub function and the execution plan when you add your change. The Execution Plans are exactly the same, since the Server ignore the part you added when executing it directly (It "understand" that this part is not in-used").
This is why when you execute this directly you get inline UDF function.
CREATE OR ALTER FUNCTION [dbo].[GetSub2_testA] ()
RETURNS NVARCHAR(4000)
with inline = on
AS
BEGIN
--declare @r nvarchar(4000)
--select top(1) @r = name from sys.columns
---- or: select top(1) @r = type_desc from sys.events
RETURN (
SELECT TOP 1 name
FROM [sys].[columns]
)
END
GO
CREATE OR ALTER FUNCTION [dbo].[GetSub2_testB] ()
RETURNS NVARCHAR(4000)
with inline = on
AS
BEGIN
declare @r nvarchar(4000)
select top(1) @r = name from sys.columns
-- or: select top(1) @r = type_desc from sys.events
RETURN (
SELECT TOP 1 name
FROM [sys].[columns]
)
END
GO
-- we get the same Execution Plans
SELECT [dbo].[GetSub2_testA]()
SELECT [dbo].[GetSub2_testB]()
GO
Now, execute the nested functions using your updated function
Check the execution plan and see that there is no inline execution when you execute the nested functions using your change.
When you are using your update then the server "notice" the extra part in the function and execute it as scalar expression. You can see that the EP is simple and does not include the content of the function and if you will check the SELECT action in the EP then you will not see any inline execution.
There are many cases that SQL Server parse query differently when it come as part of complex query. Seems like in nested functions it simply use the "function as it is" with the extra code which make it a multi statement function, while when you execute it directly then the server ignore the first statement and parse it as inline function.
I hope I succeed to explain the behavior well :-)