@@ -1786,49 +1786,60 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17861786 column_name = c.name,
17871787 definition = cc.definition,
17881788 /*
1789- UDF detection: Looks for schema-qualified object references like [schema].[function]
1790- Note: This is a heuristic check and may have rare false positives if ].[ appears
1791- in string literals or comments within the computed column definition
1789+ UDF detection: Uses sys.sql_expression_dependencies, filtered to user-defined
1790+ function object types (FN, IF, TF, FS, FT). This avoids the false positives
1791+ the previous string-heuristic produced for schema-qualified type names,
1792+ system functions called as [sys].[fn_xxx](), and ].[ embedded in string
1793+ literals or comments.
17921794 */
17931795 contains_udf =
17941796 CASE
1795- WHEN cc.definition LIKE '' %|].|[%'' ESCAPE '' |''
1796- AND cc.definition LIKE '' %|].|[%(%'' ESCAPE '' |''
1797+ WHEN refs.udf_names IS NOT NULL
17971798 THEN 1
17981799 ELSE 0
17991800 END,
1800- udf_names =
1801- CASE
1802- WHEN cc.definition LIKE '' %|].|[%'' ESCAPE '' |''
1803- AND cc.definition LIKE '' %|].|[%(%'' ESCAPE '' |''
1804- AND CHARINDEX(N'' ['' , cc.definition) > 0
1805- AND CHARINDEX(N'' ].['' , cc.definition) > 0
1806- AND CHARINDEX(N'' ]'' , cc.definition, CHARINDEX(N'' ].['' , cc.definition) + 3) > 0
1807- THEN
1808- SUBSTRING
1809- (
1810- cc.definition,
1811- CHARINDEX(N'' ['' , cc.definition),
1812- CHARINDEX
1813- (
1814- N'' ]'' ,
1815- cc.definition,
1816- CHARINDEX
1817- (
1818- N'' ].['' ,
1819- cc.definition
1820- ) + 3
1821- ) -
1822- CHARINDEX(N'' ['' , cc.definition) + 1
1823- )
1824- ELSE NULL
1825- END
1801+ udf_names = refs.udf_names
18261802 FROM #filtered_objects AS fo
18271803 JOIN ' + QUOTENAME (@current_database_name) + N' .sys.columns AS c
18281804 ON fo.object_id = c.object_id
18291805 JOIN ' + QUOTENAME (@current_database_name) + N' .sys.computed_columns AS cc
18301806 ON c.object_id = cc.object_id
18311807 AND c.column_id = cc.column_id
1808+ OUTER APPLY
1809+ (
1810+ SELECT
1811+ udf_names =
1812+ STUFF
1813+ (
1814+ (
1815+ SELECT
1816+ N'' , '' +
1817+ QUOTENAME(s.name) +
1818+ N'' .'' +
1819+ QUOTENAME(o.name)
1820+ FROM ' + QUOTENAME (@current_database_name) + N' .sys.sql_expression_dependencies AS sed
1821+ JOIN ' + QUOTENAME (@current_database_name) + N' .sys.objects AS o
1822+ ON o.object_id = sed.referenced_id
1823+ JOIN ' + QUOTENAME (@current_database_name) + N' .sys.schemas AS s
1824+ ON s.schema_id = o.schema_id
1825+ WHERE sed.referencing_id = cc.object_id
1826+ AND sed.referencing_minor_id = cc.column_id
1827+ AND sed.referencing_class = 1
1828+ AND sed.referenced_class = 1
1829+ AND o.type IN (N'' FN'' , N'' IF'' , N'' TF'' , N'' FS'' , N'' FT'' )
1830+ ORDER BY
1831+ s.name,
1832+ o.name
1833+ FOR
1834+ XML
1835+ PATH(N'' '' ),
1836+ TYPE
1837+ ).value('' .'' , '' nvarchar(max)'' ),
1838+ 1,
1839+ 2,
1840+ N'' ''
1841+ )
1842+ ) AS refs
18321843 OPTION(RECOMPILE);' ;
18331844
18341845 IF @debug = 1
@@ -1883,46 +1894,56 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18831894 constraint_name = cc.name,
18841895 definition = cc.definition,
18851896 /*
1886- UDF detection: Looks for schema-qualified object references like [schema].[function]
1887- Note: This is a heuristic check and may have rare false positives if ].[ appears
1888- in string literals or comments within the computed column definition
1897+ UDF detection: Uses sys.sql_expression_dependencies, filtered to user-defined
1898+ function object types (FN, IF, TF, FS, FT). This avoids the false positives
1899+ the previous string-heuristic produced for schema-qualified type names,
1900+ system functions called as [sys].[fn_xxx](), and ].[ embedded in string
1901+ literals or comments.
18891902 */
18901903 contains_udf =
18911904 CASE
1892- WHEN cc.definition LIKE '' %|].|[%'' ESCAPE '' |''
1893- AND cc.definition LIKE '' %|].|[%(%'' ESCAPE '' |''
1905+ WHEN refs.udf_names IS NOT NULL
18941906 THEN 1
18951907 ELSE 0
18961908 END,
1897- udf_names =
1898- CASE
1899- WHEN cc.definition LIKE '' %|].|[%'' ESCAPE '' |''
1900- AND cc.definition LIKE '' %|].|[%(%'' ESCAPE '' |''
1901- AND CHARINDEX(N'' ['' , cc.definition) > 0
1902- AND CHARINDEX(N'' ].['' , cc.definition) > 0
1903- AND CHARINDEX(N'' ]'' , cc.definition, CHARINDEX(N'' ].['' , cc.definition) + 3) > 0
1904- THEN
1905- SUBSTRING
1906- (
1907- cc.definition,
1908- CHARINDEX(N'' ['' , cc.definition),
1909- CHARINDEX
1910- (
1911- N'' ]'' ,
1912- cc.definition,
1913- CHARINDEX
1914- (
1915- N'' ].['' ,
1916- cc.definition
1917- ) + 3
1918- ) -
1919- CHARINDEX(N'' ['' , cc.definition) + 1
1920- )
1921- ELSE NULL
1922- END
1909+ udf_names = refs.udf_names
19231910 FROM #filtered_objects AS fo
19241911 JOIN ' + QUOTENAME (@current_database_name) + N' .sys.check_constraints AS cc
19251912 ON fo.object_id = cc.parent_object_id
1913+ OUTER APPLY
1914+ (
1915+ SELECT
1916+ udf_names =
1917+ STUFF
1918+ (
1919+ (
1920+ SELECT
1921+ N'' , '' +
1922+ QUOTENAME(s.name) +
1923+ N'' .'' +
1924+ QUOTENAME(o.name)
1925+ FROM ' + QUOTENAME (@current_database_name) + N' .sys.sql_expression_dependencies AS sed
1926+ JOIN ' + QUOTENAME (@current_database_name) + N' .sys.objects AS o
1927+ ON o.object_id = sed.referenced_id
1928+ JOIN ' + QUOTENAME (@current_database_name) + N' .sys.schemas AS s
1929+ ON s.schema_id = o.schema_id
1930+ WHERE sed.referencing_id = cc.object_id
1931+ AND sed.referencing_class = 1
1932+ AND sed.referenced_class = 1
1933+ AND o.type IN (N'' FN'' , N'' IF'' , N'' TF'' , N'' FS'' , N'' FT'' )
1934+ ORDER BY
1935+ s.name,
1936+ o.name
1937+ FOR
1938+ XML
1939+ PATH(N'' '' ),
1940+ TYPE
1941+ ).value('' .'' , '' nvarchar(max)'' ),
1942+ 1,
1943+ 2,
1944+ N'' ''
1945+ )
1946+ ) AS refs
19261947 OPTION(RECOMPILE);' ;
19271948
19281949 IF @debug = 1
@@ -4127,7 +4148,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41274148 ),
41284149 table_name = N ' brought to you by erikdarling.com' ,
41294150 index_name = N ' for support: https://code.erikdarling.com/' ,
4130- consolidation_rule = N ' run date: ' + CONVERT (nvarchar (30 ), SYSDATETIME (), 120 ),
4151+ consolidation_rule =
4152+ N ' run date: ' +
4153+ CONVERT (nvarchar (30 ), SYSDATETIME (), 120 ) +
4154+ N ' | ' +
4155+ CASE
4156+ WHEN @uptime_warning = 1
4157+ THEN N ' WARNING: Server uptime only ' +
4158+ @uptime_days +
4159+ N ' days - usage data may be incomplete!'
4160+ ELSE N ' Server uptime: ' +
4161+ @uptime_days +
4162+ N ' days'
4163+ END ,
41314164 script_type = N ' Index Cleanup Scripts' ,
41324165 additional_info = N ' A detailed index analysis report appears after these scripts' ,
41334166 target_index_name = N ' ALWAYS TEST THESE RECOMMENDATIONS' ,
0 commit comments