According to books online (https://technet.microsoft.com/en-us/library/ms189915(v=sql.105).aspx) we have:
In SQL Server, if the current schema contains a procedure with the specified name, that procedure is returned. If a nonqualified stored procedure is specified, the Database Engine searches for the procedure in the following order:
• The sys schema of the current database.
• The caller's default schema if executed in a batch or in dynamic SQL; or, if the non-qualified procedure name appears inside the body of another procedure definition, the schema containing this other procedure is searched next.
• The dbo schema in the current database.
I tried testing the case with a stored procedure Proc1 which calls proc2. I define them in the same schema, but call proc2 without the schema name. It doesn't work, so what does the second part of item two on the list above mean?
Use AdventureWorks
GO
CREATE SCHEMA MySchema
GO
CREATE PROCEDURE MySchema.PROC2
AS
BEGIN
SELECT 1
END
GO
CREATE PROCEDURE MySchema.PROC1
AS
BEGIN
SELECT 2
-- calling proc2 without schema name
-- expecting it will work, since proc1 and proc2 are in same schema
EXEC PROC2
END
GO
--calling proc1 (my default schema is dbo)
--Could not find stored procedure 'PROC2'.
EXEC MySchema.PROC1
I know best practice is to always use the schema name - I'm just curious what they mean by the second item. I've tested this on version 2016.
The page you have linked to is the documentation for a specific system stored procedure. Its meaning is limited to what this stored procedure does.
CREATE PROCEDURE MySchema.PROC1
AS
BEGIN
SELECT 2
-- calling proc2 without schema name
-- expecting it will work, since proc1 and proc2 are in same schema
EXEC sp_stored_procedures 'PROC2'
END
Produces 2 result sets - the first contains 2, the second contains information about the MySchema.PROC2 stored procedure.
Related
I have got a script of stored procedure from my senior, like :
BEGIN
EXEC dbo.sp_executesql #statement = N'create procedure [dbo].[up_transfer_data_from_isfoc_to_unicode_sp]
as
begin
declare #errx as int
begin try
truncate table u_lrc..dir
truncate table u_lrc..k_2
truncate table u_lrc..k_name
truncate table u_lrc..k_gata
truncate table u_lrc..order1
truncate table u_lrc..remark
insert into u_lrc..dir
select code,[lrc].name
from lrc..dir
Where dir, K_2, k_name and others are Table names whereas lrc and u_lrc are databases. u_lrc is a copy of lrc database.
What is (..) is doing here and examples of its usage ?
SQL Server uses three (really four) part naming for objects stored in the database -- tables, functions, stored procedures, and so on. This is explained in the documentation.
The three part names are ...
Typing the schema name gets cumbersome and many people just use the default schema of dbo.
So, the .. is a reference to the table in the u_lrc database using the default schema.
I should point out that the fourth part is optional (as are the second and third parts). It is for the server name.
If you run the following in sql server...
CREATE SCHEMA [cp]
GO
CREATE TABLE [cp].[TestIt](
[ID] [int] NULL
) ON [PRIMARY]
GO
CREATE PROCEDURE cp.ProcSub
AS
BEGIN
Print 'Proc Sub'
END
GO
CREATE PROCEDURE cp.ProcMain
AS
BEGIN
Print 'Proc Main'
EXEC ProcSub
END
GO
CREATE PROCEDURE cp.ProcMain2
AS
BEGIN
Print 'Proc Main2'
SELECT * FROM TestIt
END
GO
exec cp.ProcMain2
GO
exec cp.ProcMain
GO
You get the error
Could not find stored procedure 'ProcSub'
Which makes it impossible to compartmentalize procedures into a schema without hard coding the schema into the execution call. Is this by design or a bug as doing a select on tables looks in the procedures schema first.
If anyone has a work around I'd be interested to hear it, although the idea is that I can give a developer two stored procedures which call each other and can put into whatever schema they like in 'their' database that they can run for the purpose of being a utility that looks at the objects of another given schema in the same database.
I have looked to see if I might be able to get round it with Synonyms but they seem to have the same problem associated with them.
This is by design, because the default schema is not set for the user calling the procedure.
When schema is not specified in the query, sql server will try the default schema first and then the dbo (if different) schema. So you need to set the default schema or make your procedure creation using fully qualified names.
Check out:
Beginning with SQL Server 2005, each user has a default schema. The
default schema can be set and changed by using the DEFAULT_SCHEMA
option of CREATE USER or ALTER USER. If DEFAULT_SCHEMA is left
undefined, the database user will have dbo as its default schema.
https://technet.microsoft.com/en-us/library/ms190387%28v=sql.105%29.aspx
Let's say that in a multi-schema db we have these 2 procs:
Create proc S1004.proc1
As
Exec proc2
GO
Create proc S1004.proc2
As
Select 1
Then, when I try to run proc1 from sa login, sql issues an error : Could not find stored procedure 'proc2'.
I know that if we add schema to proc2 in the body of proc1, then it can resolve the schema.
Is there any other solution for this problem.
If you can use your schema in the 'scope' of user (be aware that users and schemas are separated in SQL Server), you could get away with this:
CREATE USER S1004 FOR LOGIN S1004 WITH DEFAULT_SCHEMA = S1004;
GO
CREATE PROCEDURE S1004.proc1
WITH EXECUTE AS 'S1004'
AS
EXECUTE proc2
GO
CREATE PROCEDURE S1004.proc2
AS
SELECT 1
EXEC S1004.proc1
What happens here is that you create user S1004 with a default schema with the same name. That schema will be searched for object when object is not found immediately in the scope of current schema.
When you need to resolve your schema in a procedure, you run the procedure in the context of that user (see WITH EXECUTE AS 'S1004') and schema resolution will succeed.
However, pay attention that this changes execution scope to the another user. It's a workaround, but under the circumstances it's the best you can get.
I have a stored procedure in SQL Server 2008 such as:
CREATE PROCEDURE [dbo].[test]
AS
BEGIN
SET NOCOUNT ON;
SELECT user_name();
SELECT SCHEMA_NAME()
SELECT * FROM MyView
END
I have a view named testuser.MyView. I then call the SP using:
exec as user = 'testuser' exec test
This shows the user_name and SCHEMA_NAME are both set to testuser
However I also get a Invalid object name 'MyView'. message, as the SP is still looking up the view name in the dbo schema.
Is there anyway to change how the SP is executed so the MyView object references testuser.MyView without having to use a fully qualified name?
I am trying to use a single set of many stored procedures, on identical table structures in different schemas. I really want to avoid rewriting all the SPs using dynamic SQL, or to create copies of all the SPs each using qualified names.
Unqualified object names are resolved using the module owner's default schema. This behavior can't be changed so you'll need to resort to the other methods you mentioned.
Since you already create separate tables and views for each user with the same structure, why not create stored procedures in the user's schema at the same time?
I want to know what are the default permissions for sql server stored procedures.
For example, I created a user in database but no role or no permissions granted except execute permission like:
GRANT EXECUTE ON SCHEMA :: [dbo] TO [newUser]
later on me (as a sa login) created a stored procedure that makes just a select from a table like:
CREATE PROCEDURE dbo.selectX AS
BEGIN
SELECT ID, NAME FROM MyTable
END
and my user [newUser] can execute and see the result of select statement like:
EXEC dbo.selectX
up until now, I can assume that stored procedures have default permissions that my user don't have.
I tried other dmls like UPDATE, INSERT, DELETE and user managed to execute procedures successfully.
But! when I created a proceure with ddl as create table .. such as:
CREATE PROCEDURE dbo.crtNT AS
BEGIN
CREATE TABLE del(id int) --for test
END
and when the newUser executes this procedure error occurs like:
CREATE TABLE permission denied in database 'MyDb'
And here is my question: By default, do stored procedures have permission with DML(select, insert, update vs.) but not with DDL(create, drop table vs.)? Because I didn't see any explanation about this situation in Books Online or anywhere else.
Any comments will be welcomed.
You are correct in your assumption that DDL statements are treated differently.
The procedures with DML statements work through the mechanism of Ownership Chaining however as this quote from the EXECUTE AS documentation states
Remember that ownership chaining applies only to DML statements.