-1

I have a pretty extensive SQL Server query setup that performs the following functions. For each RDL report in our system (RDL is stored in a table as binary), I extract the CommandText from each dataset and store it in a table as VARCHAR(MAX). I have a separate table that holds client-created custom database objects (i.e. views, tables, stored procedures, and functions). The goal is for us to scan each report's CommandText for any references to the custom objects we've previously identified. I created a custom function that does the actual CONTAINS scan, and the CommandText is setup for FullText searching.

To be frank, everything works as I want. The issue is that the first time I run the script as a whole (Which includes building the report table to hold the report details, populating said table, creating the fulltext catalog and index, then updating the report table by querying it against the custom search function), the function does not return any results on objects that it should. If I then manually re-run the UPDATE statement that calls the function, it then returns the results as expected.

I do have all the major parts of this split up into batches (i.e. using GO) but it doesn't seem to make a difference. We really want this to be a single script if possible, so I appreciate any pointers or ideas to make sense of this. Scripts below for reference...

This is the part of my query that builds the full-text search index after my custom table that has all the report RDL details in it is populated:

    CREATE UNIQUE CLUSTERED INDEX idx_ID ON dbo.tmpPremRptCmdTxt (ID)

    CREATE FULLTEXT CATALOG Prem_tmpPremRptCmdTxt_FTCat 
    CREATE FULLTEXT INDEX ON tmpPremRptCmdTxt
    (  
        DataSet_CommandText            
        Language 1033                 
    )  
        KEY INDEX idx_ID  
        ON Prem_tmpPremRptCmdTxt_FTCat  
        WITH CHANGE_TRACKING OFF

This is the part of the query that calls the function to do the scans and updates the report table if it finds any custom object references:

UPDATE tmpPremRptCmdTxt SET [CustomObjectsUsedInCommandText] = ISNULL(CustRptObjs.[CustomObjectsLocated], '')
FROM tmpPremRptCmdTxt 
LEFT JOIN (
    SELECT 
        ResultSet.ReportID, ResultSet.DatasetID
        , STRING_AGG('[' + CONVERT(VARCHAR(MAX), ResultSet.CustomObjects) + '] (' + ResultSet.ObjectType + ')', '; ') as [CustomObjectsLocated]
    FROM (
        SELECT 
            Rpt.ReportID, Rpt.DatasetID, Cob.ObjectType
            , dbo.[fnPremFTSearch_v2](MAX(Rpt.ID), Rpt.ReportID, Rpt.DatasetID, Cob.ObjectName) as CustomObjects
        FROM tmpPremRptCmdTxt Rpt
        OUTER APPLY         
        (
            SELECT DISTINCT ObjectName, ObjectType 
            FROM tmpPremCustomObjects       
        ) Cob
        WHERE ISNULL(Rpt.DataSet_CommandText, '') <> ''     
        GROUP BY Rpt.ReportName, Rpt.ReportID, Rpt.DatasetID, Cob.ObjectName,ObjectType
        HAVING dbo.[fnPremFTSearch_v2](MAX(Rpt.ID), Rpt.ReportID, Rpt.DatasetID, Cob.ObjectName) IS NOT NULL
    ) ResultSet
    GROUP BY ResultSet.ReportID, ResultSet.DatasetID
) CustRptObjs ON CustRptObjs.ReportID = tmpPremRptCmdTxt.ReportID
    AND CustRptObjs.DatasetID = tmpPremRptCmdTxt.DatasetID

This is the code of the function that I call to do the scan:


CREATE FUNCTION [dbo].[fnPremFTSearch_v2](@ID INT, @ReportID INT, @DatasetID INT, @ObjectName AS VARCHAR(256))
    RETURNS VARCHAR(256)
AS
BEGIN
    DECLARE @ReturnText VARCHAR(256) = ''
    , @SearchText VARCHAR(256) = CONCAT('"', @ObjectName, '"')

    SELECT @ReturnText = @ObjectName 
    FROM tmpPremRptCmdTxt
    WHERE ReportID = @ReportID 
    AND DatasetID = @DatasetID
    AND ID = @ID
    AND CONTAINS(DataSet_CommandText, @SearchText)
    AND DataSet_CommandText LIKE CONCAT('%',@ObjectName, '%') --Weeds out any near matches...i.e. "EmployeeDetail$" would return if CommandText contained "EmployeeDetail" but not "EmployeeDetail$"

    IF (@ReturnText = '')
        SET @ReturnText = NULL

    RETURN @ReturnText
END
GO

svenGUTT
  • 399
  • 4
  • 11
  • 3
    Do you realize that Full-Text indexes aren't updated synchronously as regular indexes are? Ref: [Get Started with Full-Text Search](https://learn.microsoft.com/en-us/sql/relational-databases/search/get-started-with-full-text-search) _Populating a full-text index can be time-consuming and resource-intensive. Therefore, index updating is usually performed as an asynchronous process that runs in the background and keeps the full-text index up to date after modifications in the base table._ – AlwaysLearning Jul 25 '23 at 23:18
  • 2
    It really makes me laugh when people say something like "To be frank, everything works as I want." And then go on to explain that it isn't working as they want. – Dale K Jul 25 '23 at 23:32
  • Why does this have to be a function? If you have multiple steps to execute something, Id recommend moving this to a stored procedure call. – QuestionGuyBob Jul 26 '23 at 14:23
  • AlwaysLearning - This is my first time utilizing full-text indexes, so I don't have a comprehensive background on their functionality, so thank you for the detail on that. I kind of figured it might just be a timing issue. Dale K - Today's my birthday, but glad I was able to bestow you with the gift of laughter. QuestionGuyBob - it's inline so I can pass in column values from another table and form a dynamic search from it. STP or not that function would still be needed, unless I am missing something. – svenGUTT Jul 26 '23 at 14:58

1 Answers1

0

Might be a bit on the hacky side, but inspired by the comment from @AlwaysLearning about the asynchronous nature of populating the index, I was able to "fix" this by simply adding a wait command after creating the FTI. I just added the below code and now my end-result is returning the expected results.

WAITFOR DELAY '00:00:02';

svenGUTT
  • 399
  • 4
  • 11