I assume this is not deterministic simply because DB_NAME()
is not deterministic? If DB_NAME()
is not deterministic, why is it not deterministic?
ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
WITH SCHEMABINDING
AS
BEGIN
RETURN CASE WHEN DB_NAME() = 'PRODUCTION' THEN CONVERT(bit, 1) ELSE CONVERT(bit, 0) END
END
Update: This version works, is deterministic, allows the same code to be used in any database and removes the hardcoding of the database name (which also allows me to remove another automatic system health exception about database name coding)
ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
WITH SCHEMABINDING
AS
BEGIN
RETURN (SELECT IS_PRODUCTION FROM TheSchema.IS_PRODUCTION)
END
FYI This is the code snippet in my system health self-reporting system which I use to monitor potential problems.
SELECT 'Non-deterministic Scalar UDF' AS Problem
,QUOTENAME(ROUTINE_SCHEMA) + '.' + QUOTENAME(ROUTINE_NAME) AS ROUTINE_NAME
FROM INFORMATION_SCHEMA.ROUTINES WITH (NOLOCK)
WHERE IS_DETERMINISTIC = 'NO'
AND ROUTINE_TYPE = 'FUNCTION'
AND DATA_TYPE <> 'TABLE'
ORDER BY ROUTINE_SCHEMA
,ROUTINE_NAME
Sure, I can think of one way to make it deterministic. Deploy this function on your production database:
ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
WITH SCHEMABINDING
AS
BEGIN
RETURN CONVERT(bit, 1)
END
And deploy this one to your test database:
ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] ()
RETURNS bit
WITH SCHEMABINDING
AS
BEGIN
RETURN CONVERT(bit, 0)
END
This may seem silly but IMO the database name should not be "hard coded" any more so than the return value of some UDF.
Better yet, just put this information in a configuration table somewhere.
Couldn't you maybe rewrite your function not to determine the DB_NAME() internally, but get it send in as a parameter??
ALTER FUNCTION [TheSchema].[udf_IS_PRODUCTION] (DatabaseName VARCHAR(255))
RETURNS bit
WITH SCHEMABINDING
AS
BEGIN
RETURN CASE WHEN DatabaseName = 'PRODUCTION'
THEN CONVERT(bit, 1)
ELSE CONVERT(bit, 0)
END
END
Not it should be deterministic, right?
When you call it, you can use DB_NAME()
as a function to determine the database name
A deterministic function, by definition, is a function whose return value is uniquely identified by the values of its agruments.
Now, given the arguments to DB_NAME()
(which are none), can you tell what will it return?
In strictess sense of determinism, the result is not based on the input parameters, but on the state of an external object that is not within your control.
The name could be altered etc,
Alter Database Modify Name = new_name
On 2005, SQL doesn't prevent the function being created though when I tried it against the default schema.
If you get into a situation where it refuses to accept a function based on non-determinism and you have to work around it (with the risks etc), the route around it is to create a view that uses the function, and then select from the view within the function.