SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- [PRDEX_TEST_DYNAMIC_SQL] -- ================================================================= -- Central guard for dynamic SQL safety checks -- -- Returns: INTEGER; 0 = ok; 0 <> nicht ok -- ================================================================= -- Copyright (c) 2025 by Digital Data GmbH -- -- Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim -- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works -- ================================================================= -- Creation Date / Author: 24.02.2026 / MK -- Version Date / Editor: 24.02.2026 / MK -- Version Number: 1.0.0.0 -- ================================================================= -- History: -- 24.02.2026 / MK - First Version CREATE OR ALTER PROCEDURE [dbo].[PRDEX_TEST_DYNAMIC_SQL]( @pQUERY NVARCHAR(MAX), @pRETURN_STATUS INT, @pQUERY_NAME NVARCHAR(100) = N'@QUERY' ) AS BEGIN TRY --================================================-- Set session options --===============================================-- SET NOCOUNT ON; ---------------------------------------------------------------------------------------------------------------------------- --=========================================-- declare new vars because of parameter sniffing --===========================-- DECLARE @QUERY NVARCHAR(MAX) = ISNULL(@pQUERY,N''), @RETURN_STATUS INT = ISNULL(@pRETURN_STATUS,50000), @QUERY_NAME NVARCHAR(100) = ISNULL(@pQUERY_NAME,N'@QUERY'), @QUERY_SCAN NVARCHAR(MAX) = N'', @QUERY_SCAN_NORM NVARCHAR(MAX) = N'', @COMMENT_START INT = 0, @COMMENT_END INT = 0, @SCAN_POS INT = 1, @TOKEN_START INT = 0, @TOKEN_END INT = 0, @QUOTE_START INT = 0, @QUOTE_END INT = 0, @TOKEN NVARCHAR(200) = N'', @HAS_UNRESOLVED_PLACEHOLDER BIT = 0, @HAS_RESTRICTED_SQL BIT = 0, @RETURN_ERROR_TEXT NVARCHAR(MAX) = N''; ---------------------------------------------------------------------------------------------------------------------------- --=========================================-- validate query content --====================================================-- SET @QUERY_SCAN = UPPER(@QUERY); SET @COMMENT_START = CHARINDEX('/*',@QUERY_SCAN); WHILE (@COMMENT_START > 0) BEGIN SET @COMMENT_END = CHARINDEX('*/',@QUERY_SCAN,@COMMENT_START + 2); IF (@COMMENT_END = 0) BREAK; SET @QUERY_SCAN = STUFF(@QUERY_SCAN,@COMMENT_START,(@COMMENT_END - @COMMENT_START + 2),REPLICATE(' ',(@COMMENT_END - @COMMENT_START + 2))); SET @COMMENT_START = CHARINDEX('/*',@QUERY_SCAN,@COMMENT_START + 1); END; SET @COMMENT_START = CHARINDEX('--',@QUERY_SCAN); WHILE (@COMMENT_START > 0) BEGIN SET @COMMENT_END = CHARINDEX(CHAR(10),@QUERY_SCAN,@COMMENT_START + 2); IF (@COMMENT_END = 0) SET @COMMENT_END = LEN(@QUERY_SCAN) + 1; SET @QUERY_SCAN = STUFF(@QUERY_SCAN,@COMMENT_START,(@COMMENT_END - @COMMENT_START),REPLICATE(' ',(@COMMENT_END - @COMMENT_START))); SET @COMMENT_START = CHARINDEX('--',@QUERY_SCAN,@COMMENT_START + 1); END; SET @QUERY_SCAN_NORM = REPLACE(REPLACE(REPLACE(@QUERY_SCAN,CHAR(9),' '),CHAR(10),' '),CHAR(13),' '); WHILE (CHARINDEX(' ',@QUERY_SCAN_NORM) > 0) BEGIN SET @QUERY_SCAN_NORM = REPLACE(@QUERY_SCAN_NORM,' ',' '); END; SET @QUOTE_START = CHARINDEX('''',@QUERY_SCAN); WHILE (@QUOTE_START > 0) BEGIN SET @QUOTE_END = CHARINDEX('''',@QUERY_SCAN,@QUOTE_START + 1); IF (@QUOTE_END = 0) BREAK; SET @QUERY_SCAN = STUFF(@QUERY_SCAN,@QUOTE_START,(@QUOTE_END - @QUOTE_START + 1),REPLICATE(' ',(@QUOTE_END - @QUOTE_START + 1))); SET @QUOTE_START = CHARINDEX('''',@QUERY_SCAN,@QUOTE_START + 1); END; WHILE (1 = 1) BEGIN SET @TOKEN_START = CHARINDEX('%',@QUERY_SCAN,@SCAN_POS); IF (@TOKEN_START = 0) BREAK; SET @TOKEN_END = CHARINDEX('%',@QUERY_SCAN,@TOKEN_START + 1); IF (@TOKEN_END = 0) BREAK; SET @TOKEN = SUBSTRING(@QUERY_SCAN,@TOKEN_START + 1,@TOKEN_END - @TOKEN_START - 1); IF (LEN(@TOKEN) > 0) AND (LEFT(@TOKEN,1) LIKE '[A-Z_]') AND (@TOKEN NOT LIKE '%[^A-Z0-9_]%') BEGIN SET @HAS_UNRESOLVED_PLACEHOLDER = 1; BREAK; END; SET @SCAN_POS = @TOKEN_END + 1; END; SET @HAS_RESTRICTED_SQL = CASE WHEN (CHARINDEX(';--',@QUERY_SCAN_NORM) > 0) OR (CHARINDEX('; --',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%XP_CMDSHELL%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%SP_OA%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%OPENROWSET%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%OPENDATASOURCE%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%BULK INSERT%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%SP_CONFIGURE%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%RECONFIGURE%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%ALTER SERVER%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%ALTER LOGIN%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%CREATE LOGIN%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%DROP LOGIN%',@QUERY_SCAN_NORM) > 0) OR (PATINDEX('%DROP DATABASE%',@QUERY_SCAN_NORM) > 0) THEN 1 ELSE 0 END; ---------------------------------------------------------------------------------------------------------------------------- IF (@HAS_UNRESOLVED_PLACEHOLDER = 1) OR (@HAS_RESTRICTED_SQL = 1) BEGIN SET @RETURN_ERROR_TEXT = CONCAT('Blocked unsafe query content in ',@QUERY_NAME,'. Detected unresolved placeholder tokens (%TOKEN%) or restricted statements.'); THROW @RETURN_STATUS,@RETURN_ERROR_TEXT,1; END; RETURN 0; END TRY BEGIN CATCH THROW; END CATCH; GO