I have searched, but was not able to find how to get the parameters names and values of a stored procedure from the catch section of a try/catch in SQL server 2008.
I know how to get the parameters for example:
SELECT parm.name AS Parameter
,typ.name AS [Type]
FROM sys.procedures sp
JOIN sys.parameters parm ON sp.object_id = parm.object_id
JOIN sys.types typ ON parm.system_type_id = typ.system_type_id
WHERE sp.name = OBJECT_NAME(##procid)
Basically what I am looking for is the SP that executed with parameters and values so I can log and troubleshoot. Something like:
wsp_GetUser_s #UserID = 123, #UserName = 'juser'
There is no feature in Microsoft SQL Server's catch block to automatically log what parameters were passed in to the database object.
If you want to know what parameters are passed in, I recommend running a trace or using Extended Events.
If neither of those options are feasible I recommend creating a table to store this information. One column can have the Stored Procedure name and another column can have the parameters. The parameters column can contain a comma delimited list of whatever parameters were passed into the stored procedure.
Example:
create table dbo.Parameters (
RowID int identity(1,1),
StoredProcedure varchar(255),
Parameters varchar(max)
)
create proc dbo.wsp_GetUser_s (
#UserID int,
#UserName varchar(255)
)
as
begin try
select *
from dbo.Users
where UserID = #UserID
and UserName = #UserName
-- We'll only log to the Parameters table if we don't find a match
if ##rowcount < 1
begin
RAISERROR ('Did not find user. Logging passed parameters to dbo.Parameters table', -- Message text.
16, -- Severity.
1 -- State.
);
end
end try
begin catch
-- This could be moved into the catch block if you wanted to log this for all calls and not only when there is no match found for the passed in parameters.
insert into dbo.Parameters ( StoredProcedure, Parameters)
select 'wsp_GetUser_s', '#UserID=' + #UserID + ', #UserName=' + #UserName
end catch
Related
I'm checking the validity of existing stored procedures, by obtaining their definition and running the ALTER statement on them.
The problem I have is that any stored procedure which doesn't compile (because a dependency has gone) isn't being flagged as such.
If I try to run the same ALTER command in SSMS I do get the error message.
EDIT: No, I don't....
DECLARE #def nvarchar(MAX)
BEGIN TRY
-- refresh the stored procedure
SELECT #def = REPLACE(definition,'CREATE PROCEDURE ','ALTER PROCEDURE ')
FROM sys.sql_modules
WHERE ... -- selecting/limiting clause
EXEC (#def);
END TRY
BEGIN CATCH
PRINT 'Validation failed : ' + ERROR_MESSAGE()
END CATCH
What do I have to do to trap the non-compile error? Thanks
SQL Server stored procedures use deferred name resolution:
When a stored procedure is created, the statements in the procedure are parsed for syntactical accuracy. If a syntactical error is encountered in the procedure definition, an error is returned and the stored procedure is not created. If the statements are syntactically correct, the text of the stored procedure is stored in the sys.sql_modules catalog view.
When a stored procedure is executed for the first time, the query processor reads the text of the stored procedure from the sys.sql_modules catalog view and checks that the names of the objects used by the procedure are present. This process is called deferred name resolution because table objects referenced by the stored procedure need not exist when the stored procedure is created, but only when it is executed.
So the behavior you observe is intentional. What you need is to find out what procedures depend on your missing tables. For this, see View the Dependencies of a Stored Procedure and the proper answer depends on your SQL Server version. SQL Server 2016 is somehow better at tracking this information and offers better views. Before that the process was notoriously difficult unreliable, read Keeping sysdepends up to date in SQL Server 2008.
Forget this - barking up the wrong tree ;-((
The stored proc will compile OK even if its dependencies have gone.
The editor in SSMS highlights the missing items, but doesn't stop the ALTER statement from working.
This query will identify all stored procs with missing dependencies:
-- table variable to store procedure names
DECLARE #v TABLE (RecID INT IDENTITY(1,1), spname sysname)
-- retrieve the list of stored procedures
INSERT INTO #v(spname)
SELECT
'[' + s.[name] + '].[' + sp.name + ']'
FROM sys.procedures sp
INNER JOIN sys.schemas s ON s.schema_id = sp.schema_id
WHERE is_ms_shipped = 0
AND sp.name like 'Get%'
-- counter variables
DECLARE #cnt INT, #Tot INT
SELECT #cnt = 1
SELECT #Tot = COUNT(*) FROM #v
DECLARE #spname sysname
DECLARE #ref nvarchar(MAX)
-- start the loop
WHILE #Cnt <= #Tot BEGIN
SELECT #spname = spname
FROM #v
WHERE RecID = #Cnt
BEGIN
SELECT #ref = referenced_entity_name
FROM sys.dm_sql_referenced_entities (#spname, 'OBJECT')
WHERE referenced_id IS NULL;
END
SET #Cnt = #cnt + 1
END
I am writing scripts to generate stored procedures within a database whose current schema notation will be unknown (think shared hosting).
I have decided to use dynamic SQL within the stored procedures so that the web application can pass the database schema based on a user defined setting to the SQL Server in order for it to fire properly.
When I started writing the stored procedures, I noticed that dynamic SQL opens up a whole SQL injection problem I would not normally have so I re-wrote the procedure to combat this. However even though SQL allows me to run the script to generate the stored procedure, each time I try to run the test stored procedure, I get a syntax error
Incorrect syntax near the keyword 'WHERE'
I believe this is to do with the parameter for the schema but I am at a loss as to why this is not working? I am entering the value dbo for the schema.
/*
Name : usp_GetTestTicker
Description : returns test ticker
*/
if not exists (select * from dbo.sysobjects
where id = object_id(N'usp_GetTestTicker')
and OBJECTPROPERTY(id, N'IsProcedure') = 1)
BEGIN
DECLARE #sql as nvarchar(150)
SET #sql = 'CREATE procedure usp_GetTestTicker AS'
EXEC(#sql)
END
GO
ALTER PROCEDURE usp_GetTestTicker
#schema VARCHAR(25),
#TickerItemId INT
AS
SET NOCOUNT ON
BEGIN
DECLARE #sql_cmd NVARCHAR(MAX)
DECLARE #sql_params NVARCHAR(MAX)
SET #sql_cmd = N'SELECT * FROM #schema.TickerItem WHERE TickerItemId = #TickerItemId'
SET #sql_params = N'#schema VARCHAR(25), #TickerItemId INT'
EXEC sp_executesql #sql_cmd, #sql_params, #schema, #TickerItemId
END
GO
To prevent SQL injection, you will need to validate the schema against the sys.schemas table, e.g.
ALTER PROCEDURE usp_GetTestTicker
#schema NVARCHAR(25),
#TickerItemId INT
AS
BEGIN
SET NOCOUNT ON
IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = #schema)
BEGIN
-- throw an error here. Your web code will have to handle the error and report an invalid schema
END
ELSE
BEGIN
DECLARE #sql_cmd NVARCHAR(MAX), #sql_params NVARCHAR(MAX)
SET #sql_cmd = N'SELECT * FROM ' + #schema + '.TickerItem WHERE TickerItemId = #TickerItemId'
SET #sql_params = N'#TickerItemId INT'
EXEC sp_executesql #sql_cmd, #sql_params, #TickerItemId
END
END
I am trying to code a stored procedure in SQL that does the following
Takes 2 inputs (BatchType and "Column Name").
Searches database and gives the batchdate and the data in the column = "Column name"
Code is as give below
ALTER PROCEDURE [dbo].[chartmilldata]
-- Add the parameters for the stored procedure here
(#BatchType nvarchar (50),
#Data nvarchar(50))
AS
BEGIN
-- Insert statements for procedure here
SELECT BatchDate,#Data FROM --Database-- WHERE BatchType = #BatchType
END
I am trying to select column from the database based on operator input. But I am not getting the output. It would be great if someone can give me a direction.
You may want to build out your SELECT statement as a string then execute it using sp_executesql.
See this page for more info:
https://msdn.microsoft.com/en-us/library/ms188001.aspx
This will allow you to set your query to substitute in your column name via your variable and then execute the statement. Be sure to sanitize your inputs though!
You'd need to use dynamic SQL, HOWEVER I would not recommend this solution, I don't think there is anything I can add as to why I wouldn't recommend it that isn't explained better in Erland Sommarskog in The Curse and Blessings of Dynamic SQL.
Nonetheless, if you had to do it in a stored procedure you could use something like:
ALTER PROCEDURE [dbo].[chartmilldata]
-- Add the parameters for the stored procedure here
(#BatchType nvarchar (50),
#Data nvarchar(50))
AS
BEGIN
-- DECLARE AND SET SQL TO EXECUTE
DECLARE #SQL NVARCHAR(MAX) = N'SELECT BatchDate = NULL, ' +
QUOTENAME(#Data) + N' = NULL;';
-- CHECK COLUMN IS VALID IN THE TABLE
IF EXISTS
( SELECT 1
FROM sys.columns
WHERE name = #Data
AND object_id = OBJECT_ID('dbo.YourTable', 'U')
)
BEGIN
SET #SQL = 'SELECT BatchDate, ' + QUOTENAME(#Data) +
' FROM dbo.YourTable WHERE BatchType = #BatchType;';
END
EXECUTE sp_executesql #SQL, N'#BatchType NVARCHAR(50)', #BatchType;
END
It would probably be advisable to change your input parameter #Data to be NVARCHAR(128) (or the alias SYSNAME) though, since this is the maximum for column names.
I'm trying to make this code work, ...
SELECT *
FROM UserInGroup
DECLARE #SqlQuery nvarchar(500),
#userIds nvarchar(50),
#GroupId nvarchar(50);
SET #userIds = '1, 2';
SET #SqlQuery =
'INSERT INTO UserInGroup
(GroupId, UserId)
SELECT ' + #GroupId + ', UserId
FROM [User]
WHERE UserId IN ('+ #userIds +')';
EXECUTE #SqlQuery
GO
SELECT *
FROM UserInGroup
but I'm getting the following error:
Msg 2812, Level 16, State 62, Line 16
Could not find stored procedure ''.
I've tried to put this in a stored procedure, but I'm getting nothing.
You need to change the way you execute
EXECUTE #SqlQuery to ->> Exec (#SqlQuery)
You might find it in detail here about EXECUTE (Transact-SQL)
Your method is subject to SQL Injection. You need to use parametrised sp_executesql or use user defined table-valued function and join with it to get the data
If you're using SQL Server 2008 or newer I would encourage you to use a table valued parameter that you could join on the user table. Then you would not need any dynamic SQL. More on that here.
Then your procedure might look something like this:
Create procedure myBrandNewProcedureUsingTableValuedParameters
#userIds myCustomTableType readonly,
#GroupId nvarchar(50)
AS
BEGIN
INSERT INTO UserInGroup
(GroupId, UserId)
SELECT #GroupId, [User].UserId
FROM [User]
INNER JOIN
#userIds as u
on [User].UserID = u.UserID
END
I have a stored procedure which returns user Token if authentication passes like this
BEGIN
SET FMTONLY OFF --Tricky Part
DECLARE #token uniqueidentifier
DECLARE #user_id as int
SET #user_id = (SELECT UserID FROM Users
WHERE #email = Email AND #password = PasswordKey)
IF #user_id IS NOT NULL
BEGIN
SET #token = NEWID()
UPDATE Users SET Token = #token
WHERE UserID = #user_id
SELECT * FROM Users WHERE UserID = #user_id
END
END
Without SET FMTONLY OFF it returns Token BUT only if user entered correct cardinalities else error
A member of the type, 'Token', does not have a corresponding column in the data reader with the same name.
occurs.
Now I have another stored procedure (almost same as this one) which returns single Product determined by ID which I pass to the stored procedure and it works fine even when I send non-existing ones. In function import, one stored procedure shows me columns which returns and another one doesn't. For clarity here are two images which shows stored procedures and function import Images
Instead of using:
SELECT * FROM Users WHERE UserID = #user_id
List out the names of the columns that you wish to return from the Users table instead of just using SELECT *.
SELECT ColumnName,
AnotherColumn,
YouGetThePoint
FROM ...
It sounds like the DataReader is being populated with column names that are different than the expected column names. Have you stepped through with a debugger and/or listed out the actual column names that are being returned from the procedures to is if they are just being given arbitrary names (e.g. T1, T2).