sql-servert-sqlssms-17

Cannot see expected PRINT or RAISERROR output when a later error is raised


I'm getting an error message in a stored procedure, saying that I can't insert a NULL value into a table, when I should be getting errors earlier in the code if the value is null.

Here's the relevant part of the stored procedure:

CREATE PROCEDURE [dbo].[udp_AddUpdateStaffVariable] 
    -- Add the parameters for the stored procedure here
    @StaffID int=null,
    @VariableTypeID int,
    @VariableIntValue int=null,
    @VariableVarcharValue varchar(max)=null,
    @VariableDatetimeValue datetime=null,
    @VariableDecimalValue decimal=null
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
BEGIN TRY  
    DECLARE @PrintOutput varchar(150)
    SET @PrintOutput = '@StaffID = ' + CASE WHEN @StaffID = NULL THEN 'Null' ELSE CONVERT(varchar(20), @StaffID) END
    RAISERROR (@PrintOutput, 10, 1) WITH NOWAIT

    IF (@StaffID = NULL)    -- If the staffid of the current user was not supplied, find it in the Staff table
    BEGIN
        DECLARE @CurrentUser nvarchar(255) = SUSER_SNAME();
        SELECT @StaffID = [StaffID] FROM [dbo].[Staff] WHERE [UserName] = @CurrentUser;
        SET @PrintOutput = '@StaffID = ' + CASE WHEN @StaffID = NULL THEN 'Null' ELSE CONVERT(varchar(20), @StaffID) END
        RAISERROR (@PrintOutput, 10, 1) WITH NOWAIT
        IF @StaffID = NULL -- raise error if staffid wasn't found
        BEGIN
            RAISERROR (50001 --error number
                , 16 -- severity
                , 1 --state
                , @CurrentUser -- parameter
                )
        END
    END

    -- Get the variable data type (used to determine where the variable is stored)
    DECLARE @VarDataTypeDesc varchar(20)
    DECLARE @StaffVarID int

    SELECT @VarDataTypeDesc = dt.[StaffVariableDataType] 
    FROM [list].[DataTypes] dt INNER JOIN [list].[StaffVariableTypes] svt ON dt.DataTypeID = svt.DataTypeID 
    WHERE svt.VariableTypeID = @VariableTypeID

    -- update or add the staff variable
    IF EXISTS (SELECT 1 FROM [dbo].[StaffVariables] WHERE StaffID = @StaffID AND [VariableTypeID] = @VariableTypeID) -- update
    BEGIN
        IF @VarDataTypeDesc = 'int'
        BEGIN -- only update here - other data types are updated further down
            UPDATE [dbo].[StaffVariables] SET VariableIntValue = @VariableIntValue WHERE StaffID = @StaffID AND VariableTypeID = @VariableTypeID
        END
        ELSE -- StaffVariableID is only needed if the variable type is not int
        BEGIN
            SELECT @StaffVarID = StaffVariableID FROM [dbo].[StaffVariables] WHERE StaffID = @StaffID AND [VariableTypeID] = @VariableTypeID
        END
    END
    ELSE -- insert
    BEGIN
        IF @VarDataTypeDesc = 'int'
        BEGIN
            INSERT INTO [dbo].[StaffVariables] (StaffID, VariableTypeID, VariableIntValue) 
            VALUES (@StaffID, @VariableTypeID, @VariableIntValue)
        END
        ELSE -- StaffVariableID is only needed if the variable type is not int
        BEGIN
            DECLARE @StaffVarIDTbl table(ID int)
            INSERT INTO [dbo].[StaffVariables] (StaffID, VariableTypeID, VariableIntValue) 
            OUTPUT INSERTED.[StaffVariableID] INTO @StaffVarIDTbl 
            VALUES (@StaffID, @VariableTypeID, @VariableIntValue)

            SELECT @StaffVarID = ID FROM @StaffVarIDTbl
        END
    END

-- Cutting out the section where I deal with other variable types besides int here - not relevant to this problem

END TRY  
BEGIN CATCH  
    DECLARE @ErrorMessage NVARCHAR(4000);  
    DECLARE @ErrorSeverity INT;  
    DECLARE @ErrorState INT;  

    SELECT   
        @ErrorMessage = ERROR_MESSAGE(),  
        @ErrorSeverity = ERROR_SEVERITY(),  
        @ErrorState = ERROR_STATE();  

    -- Use RAISERROR inside the CATCH block to return error  
    -- information about the original error that caused  
    -- execution to jump to the CATCH block.  
    RAISERROR (@ErrorMessage, -- Message text.  
               @ErrorSeverity, -- Severity.  
               @ErrorState -- State.  
               );  
END CATCH;  
END

Here's the test procedure run code:

DECLARE @return_value int

EXEC    @return_value = [dbo].[udp_AddUpdateStaffVariable]
        @VariableTypeID = 1,
        @VariableIntValue = 10

SELECT  'Return Value' = @return_value

GO

...and here's the response:

Msg 50000, Level 16, State 2, Procedure dbo.udp_AddUpdateStaffVariable, Line 130 [Batch Start Line 2]
Cannot insert the value NULL into column 'StaffID', table 'SnippingDbName.dbo.StaffVariables'; column does not allow nulls. INSERT fails.

(1 row affected)

Completion time: 2020-06-01T21:17:08.2049072-05:00

So... here's the question. The error seems to indicate that it either never ran the whole, if @StaffID = NULL portion of the code, or it did, and didn't find the StaffID and set the @StaffID variable. But if that were the case, why can't I see the results of my earlier RAISERROR statements?

I initially tried PRINT and switched to RAISERROR when PRINT wasn't working.

SQL Server 2017 Developer Edition, SSMS 15.0.18183.0


Solution

  • It was a syntax error, that people commenting on the question figured out. IF (@StaffID = NULL) should have been, IF (@StaffID IS NULL) Fixing that in all places in the procedure fixed the problem, and altering my test Staff record so UserName doesn't match SUSER_SNAME() resulted in the expected error.