I have the following problem: there's a user, A, who has to execute a stored procedure (spTest). In spTest's body, sp_trace_generateevent is called.
The problem is that sp_trace_generateevent requires alter trace permissions, and I don't want user A to have those permissions. I would still like user A to be able to execute spTest. How can I do that?
Try this:
EXECUTE AS user = 'special_user'
EXECUTE YourProcerdure
REVERT
See these links for more information:
Understanding Context Switching <- has examples of things like you are trying to do
Understanding Execution Context
EXECUTE AS Clause (Transact-SQL)
EXECUTE AS (Transact-SQL)
As others have suggested you can achieve what you wish using the Execute As clause. For examples of implementation choices take a look at the Books Online documentation for the Execute As clause.
For further reading and to develop more understanding of this topic, what you are looking to achieve comes under the security concept of Context Switching.
This is what I did (and succeeded):
let Source = Sql.Database("server", "database",
[Query= "EXECUTE AS USER='user' EXECUTE [schema].[spname] 'parm1', 'parm2'"])
in
Source
When you go to execute that specific stored procedure you will need to create a different connection using the needed user credentials.
Related
I've checked familiar posts and I hope that this hasn't been covered before.
I'm looking into ways to abstract the name of the DB and the schema in calling a stored procedure in a different database than the current location. Something in the following way:
execute [DatabaseName].[schema].[storedProcedureName]
The idea would be to allow the DB and the schema to be provided depending on a run time requirement. The obvious way to do this is to use dynamic sql but for the system I'm using thats a big no-no. Does anyone know of anyway to abstract the DB name and schema in this case? The only options I can think of are storing the name etc in variables and some how incorporating that into the execute call or being able to store an instance of the DB, but i don't know if thats even possible.
Any feedback will be useful, Thanks.
I'm not sure about abstracting it as you describe (like a parameter or something?), but one idea might be to do something like this:
IF #db = 'dababase1'
BEGIN
IF #schema = 'schema1'
BEGIN
EXECUTE database1.schema1.procedure
END
IF #schema = 'schema2'
BEGIN
EXECUTE database1.schema2.procedure
END
...
END
IF #db = 'database2'
BEGIN
...
You'd have to know at design time what all of the possible databases and schemas were though...
It's a bit hard to understand the why behind this approach. What is calling your stored procedures? That might be the better place to change database by using a different connection string?
If you want to switch DB inside a TSQL statement then look at the USE command and to run as a different user with access to another schema look at EXECUTE AS
I think you're maybe looking for a construct like SYNONYM? This should allow that level of abstraction I believe
CREATE SYNONYM MySP FOR MyDatabase1.dbo.MySP
http://blog.sqlauthority.com/2008/01/07/sql-server-2005-introduction-and-explanation-to-synonym-helpful-t-sql-feature-for-developer/
I am testing the permissions in mssql and run into a problem. I've made a 'Countries' table and a 'spCountries' Stored procedure. Now I've made a user 'silverlight' and gave it no rights to the Countries table. The user can execute the stored procedure.
Now when I do a Select it fails like it should, but in a exec spCountries, al the data is visible. How can I check for the permissions in the stored procedure?
Is this also possible if the stored procedure does EXEC "SELECT * FROM Countries" instead of just SELECT FROM ...?
Maybe it's also better just to return an empty recordset instead of an error...
Does somebody have an idea?
SELECT has_perms_by_name('dbo.Countries', 'OBJECT', 'SELECT')
That's due to ownership chaining. Basically, if the same principal (e.g. dbo) owns an SP and a table used int it, permissions for the table are not checked.
Actually, this makes sense. For instance, it allows you to give a user acces to some data, but only in specifiс ways coded in the SPs.
If you use dynamic SQL, the permissions are calculated every time. Since SQL2005 you can use EXECUTE AS clause to specify execution context. For example, EXECUTE AS OWNER makes dynamic SQL in the SP execute in SP owner's context, giving similar effect to ownership chaining with static SQL.
That is how permissions work in SQL Server.
So you can give permissions on stored procedures without having to give permissions to the underlying objects. This allows you to exercise control over exactly what updates etc. people can make.
Don't give the user silverlight permissions to execute the stored procedure if you don't want them to execute it!
Edit: Although having read the question again it sounds like maybe this is the kind of thing you need?
I have an existing SQL 2005 stored procedure that for some reason, outputs its results in the Messages pane in SSMS instead of the Results pane. (Its actually a CLR procedure already compiled and deployed to all our servers, and used for another daily process. So I can't change it, I just want to use its output.)
For the sake of discussion, here's a stored proc that behaves the same way:
CREATE PROCEDURE [dbo].[OutputTest]
#Param1 int, #Param2 varchar(100)
AS
BEGIN
SET NOCOUNT ON;
PRINT 'C,10000,15000';
PRINT 'D,30000,90000';
PRINT 'E,500,50000';
END
So no actual SELECT statement in there, and if you run this, you'll see these results only on the Messages pane.
Is there any way for me to use these results as part of a larger query? Put them in a temp table or something, so I can parse them out?
None of the "normal stuff" works, because there is no true "output" here:
INSERT INTO #output
EXEC OutputTest 100, 'bob'
just shows
C,10000,15000
D,30000,90000
E,500,50000
(0 row(s) affected)
on the messages pane, and the temp table doesn't actually get anything put into it.
Can you execute the stored proc from C# code? If so, you might be able to hook into the SqlCommand event called SqlInfoMessage:
SqlConnection _con = new SqlConnection("server=.;
database=Northwind;integrated Security=SSPI;");
_con.InfoMessage += new SqlInfoMessageEventHandler(_con_InfoMessage);
The event handler will look like this:
static void _con_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
string myMsg = e.Message;
}
The "e.Message" is the message printed out to the message window in SQL Server Mgmt Studio.
While it won't be pretty and might require some ugly parsing code, at least you could get a hold of those messages that way, I hope!
Marc
You cannot trap, catch or use these messages from within SQL Server. You can, however, receive them from within a client application.
I don't think there is a way but even if there is I think you should seriously consider whether it is a good idea. This sounds like a fudge which can only cause you pain in the long term. Creating an alternative proc that does exactly what you want sounds to me like a better plan.
there is no way to get messages from the message pane in your result.
if you think about it the SSMS is just a client that parses those messages the way you see it.
if you wan to use them in your app take a look at Connection Events in ADO.NET
The only way I could think that this might be possible is if the output is printed via the RAISERROR command. In that case, you might be able to capture it elsewhere using TRY/CATCH.
But that's just an idea: I've never done it. In fact, the only thing we do that's remotely close is that we have a command line tool to run stored procedures in batch jobs rather than using sql server agent to schedule them. This way all of our nightly jobs are scheduled in one place (the windows task scheduler) rather than two, and the command line tool captures the anything printed to the message window into a common logging system that we monitor. So some of procedures will output quite a lot of detail to that window.
If Proc A executes Proc B, is there a way for Proc B to look-up that it was called by A instead of having a parameter where A passes B its ID?
Per request: The reason I'm interested in this is multi-fold
1) General knowledge, I'm sure if it can be done it would involve clever use of some system tables/variables that may help me do other things down the road.
2) As others have mentioned, logging/auditing. I'd like to make a procedure that logs a begin, end and message entry that requires no parameters, and accepts one optional parameter of a user specified message. This would allow one to simply drop an exec in the top and bottom of a proc to make it work and the audit procedure would figure out the rest on its own.
I know this info is available in the log files, but parsing those and giving them to users is not all that straight forward, whereas, this would give easy access to that basic info.
3) Used in conjunction with a semaphore such a generalized procedure could ensure that related processes are not executed simultaneously regardless of sessions/transactions etc.
use a prarameter like this:
CREATE PROCEDURE ParentProcedure
AS
DECLARE #ProcID int
SET #ProcID=##PROCID
EXEC ChildProcedure #ProcID
RETURN 0
go
and this...
CREATE PROCEDURE ChildProcedure
(
#ProcID int=null --optional
)
AS
if #ProcID IS NOT NULL
BEGIN
PRINT 'called by '+OBJECT_NAME(#ProcID)
END
RETURN 0
go
no, it cant tell what sproc called it. You'd need to add an extra parameter in to tell it who the caller is
In MSSQL Server 2008 you can use sys.dm_exec_procedures_stats, this dynamic management view can show you when stored procedure (see also sys.procedures to obtain name of the procedure) was executed and so on.
SELECT s.*, d.*
FROM sys.procedures s
INNER JOIN sys.dm_exec_procedure_stats d
ON s.object_id = d.object_id
ORDER BY [d.last_execution_time] DESC;
Parent-procedure will be shown in this result set very close, because this procedure will be executed earlier.
Of course, this is not complete solution of your problem, but you may obtain some info.
and yes, if there is concurrency, this solution doesn't works. It can help in development or debug only.
If a stored procedure needs to behave differently based on who calls it, then it needs to add a parameter. That way, if you add stored procedure "Z", the code will still work - "Z" can pass the parameter the way that "C" passed it, or the way "D" passed it. If that's not good enough, then new logic needs to be added in "B".
Why would you want to do that?
AFAIK, there is no way for proc B to know who called it.
EDIT: As KM shows that it is possible (as per the code), I am interested in understanding the reason behind doing this. Can you post that as well, by adding it to your question?
I know some ways that we can use in order to determine that whether our own Stored procedure has been executed successfully or not. (using output parameter, putting a select such as select 1 at the end of the stored procedure if it has been executed without any error, ...)
so which one is better and why?
Using RAISERROR in case of error in the procedure integrates better with most clients than using fake out parameters. They simply call the procedure and the RAISERROR translates into an exception in the client application, and exceptions are hard to avoid by the application code, they have to be caught and dealt with.
Having a print statement that clearly states whether the SP has been created or not would be more readable.
e.g.
CREATE PROCEDURE CustOrdersDetail #OrderID int
AS
...
...
...
GO
IF OBJECT_ID('dbo.CustOrdersDetail') IS NOT NULL
PRINT '<<< CREATED PROCEDURE dbo.CustOrdersDetail >>>'
ELSE
PRINT '<<< FAILED CREATING PROCEDURE dbo.CustOrdersDetail >>>'
GO
SP is very much like a method/subroutine/procedure & they all have a task to complete. The task could be as simple as computing & returning a result or could be just a simple manipulation to a record in a table. Depending on the task, you could either return a out value indicating the result of the task whether it was a success, failure or the actual results.
If you need common T-SQL solution for your entire project/database, you can use the output parameter for all procedures. But RAISEERROR is the way to handle errors in your client code, not T-SQL.
Why don't use different return values which then can be handled in code?
Introducing an extra output paramter or an extra select is unnecessary.
If the only thing you need to know is whether there is a problem, a successful execution is good enough choice. Have a look at the discussions of XACT_ABORT and TRY...CATCH here and here.
If you want to know specific error, return code is the right way to pass this information to the caller.
In the majority of production scenarios I tend to deploy a custom error reporting component within the database tier, as part of the solution. Nothing fancy, just a handful of log tables and a few of stored procedures that manage the error logging process.
All stored procedure code that is executed on a production server is then encapsulated using the TRY-CATCH-BLOCK feature available within SQL Server 2005 and above.
This means that in the unlikely event that a given stored procedures were to fail, the details of the error that occurred and the stored procedure that generated it are recorded to a log table. A simple stored procedure call is made from within the CATCH BLOCK in order to record the relevant details.
The foundations for this implementation are actually explained in books online here
Should you wish, you can easily extend this implementation further, for example by incorporating email notification to a DBA or even an SMS alert could be sent dependent on the severity of the error.
An implementation of this sort ensures that if your stored procedure did not report failure then it was of course successful.
Once you have a simple and robust framework in place, it is then straightforward to duplicate and rollout your base implementation to other production servers/application platforms.
Nothing special here, just simple error logging and reporting that works.
If on the other hand you also need to record the successful execution of stored procedures then again, a similar solution can be devised that incorporates log table/s.
I think this question is screaming out for a blog post……..