2017-12-18 11 views
0

MS SQL Server 2014 DBに共有APIを実装しようとしています。そのアーキテクチャーでは、スキーマは同様の構造を持ち、dboが所有する共有APIを使用し、同時に独自のAPIを公開する必要があります。オブジェクト名を修飾せずに互いに呼び出すには、EXECUTE AS USERステートメントが、現在のユーザーの特定のデフォルトスキーマへのコンテキスト切り替えに使用されます。ストアドプロシージャのユーザーのデフォルトスキーマにアクセスすると、SQL Serverのユーザーを切り替えることができません

問題はここにある:ユーザコンテキストの切り替えに即時アクセスが正常に動作している間(例えばEXECUTE AS USERSELECT * from test_tbl;が続く)、ストアドプロシージャのデフォルトのスキーマを介してアクセスがエラーMsg 208, Level 16, State 1で失敗します。

私の質問を投稿する前に、何度か実験やテストを行い、数日間MSDN、Web、SQLフォーラムを検索しました。

-- DB creation 
CREATE DATABASE [test_sql] 
CONTAINMENT = NONE 
ON PRIMARY 
(NAME = N'test_sql', FILENAME = N'<MDF>' , SIZE = 5120KB , FILEGROWTH = 1024KB) 
LOG ON 
(NAME = N'test_sql_log', FILENAME = N'<LDF>' , SIZE = 2048KB , FILEGROWTH = 10%) 
COLLATE Cyrillic_General_CI_AS 
GO 
ALTER DATABASE [test_sql] SET COMPATIBILITY_LEVEL = 120 
GO 
ALTER DATABASE [test_sql] SET ANSI_NULL_DEFAULT OFF 
GO 
ALTER DATABASE [test_sql] SET ANSI_NULLS OFF 
GO 
ALTER DATABASE [test_sql] SET ANSI_PADDING OFF 
GO 
ALTER DATABASE [test_sql] SET ANSI_WARNINGS OFF 
GO 
ALTER DATABASE [test_sql] SET ARITHABORT OFF 
GO 
ALTER DATABASE [test_sql] SET AUTO_CLOSE OFF 
GO 
ALTER DATABASE [test_sql] SET AUTO_SHRINK OFF 
GO 
ALTER DATABASE [test_sql] SET AUTO_CREATE_STATISTICS ON 
GO 
ALTER DATABASE [test_sql] SET AUTO_UPDATE_STATISTICS ON 
GO 
ALTER DATABASE [test_sql] SET CURSOR_CLOSE_ON_COMMIT OFF 
GO 
ALTER DATABASE [test_sql] SET CURSOR_DEFAULT GLOBAL 
GO 
ALTER DATABASE [test_sql] SET CONCAT_NULL_YIELDS_NULL OFF 
GO 
ALTER DATABASE [test_sql] SET NUMERIC_ROUNDABORT OFF 
GO 
ALTER DATABASE [test_sql] SET QUOTED_IDENTIFIER OFF 
GO 
ALTER DATABASE [test_sql] SET RECURSIVE_TRIGGERS OFF 
GO 
ALTER DATABASE [test_sql] SET DISABLE_BROKER 
GO 
ALTER DATABASE [test_sql] SET AUTO_UPDATE_STATISTICS_ASYNC OFF 
GO 
ALTER DATABASE [test_sql] SET DATE_CORRELATION_OPTIMIZATION OFF 
GO 
ALTER DATABASE [test_sql] SET PARAMETERIZATION SIMPLE 
GO 
ALTER DATABASE [test_sql] SET READ_COMMITTED_SNAPSHOT OFF 
GO 
ALTER DATABASE [test_sql] SET READ_WRITE 
GO 
ALTER DATABASE [test_sql] SET RECOVERY FULL 
GO 
ALTER DATABASE [test_sql] SET MULTI_USER 
GO 
ALTER DATABASE [test_sql] SET PAGE_VERIFY CHECKSUM 
GO 
ALTER DATABASE [test_sql] SET TARGET_RECOVERY_TIME = 0 SECONDS 
GO 
ALTER DATABASE [test_sql] SET DELAYED_DURABILITY = DISABLED 
GO 
USE [test_sql] 
GO 
IF NOT EXISTS (SELECT name FROM sys.filegroups WHERE is_default=1 AND name = N'PRIMARY') ALTER DATABASE [test_sql] MODIFY FILEGROUP [PRIMARY] DEFAULT 
GO 

-- Srv login, DB user and schema creation 
CREATE LOGIN [test_usr_login] WITH PASSWORD=N'test_usr_login', DEFAULT_DATABASE=[test_sql], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF 
GO 
CREATE USER [test_usr] FOR LOGIN [test_usr_login] WITH DEFAULT_SCHEMA=[test_schema] 
GO 
CREATE SCHEMA [test_schema] AUTHORIZATION [test_usr] 
GO 

-- Table and stored proc creation 
IF OBJECT_id("[test_schema].[test_tbl]", "U") IS NOT NULL 
DROP TABLE [test_schema].[test_tbl]; 
GO 
CREATE TABLE [test_schema].[test_tbl](
    [tc] [nchar](10) NULL 
) ON [PRIMARY] 
GO 

IF OBJECT_id("[dbo].[TA]", "P") IS NOT NULL 
DROP PROCEDURE [dbo].[TA]; 
GO 
CREATE PROCEDURE [dbo].[TA] AS BEGIN 
    SET NOCOUNT ON; 
    SELECT * FROM 
    (VALUES 
    ('CURRENT_USER', CURRENT_USER), 
    ('SCHEMA_NAME', SCHEMA_NAME()), 
    ('have_UNqualified_select', cast(HAS_PERMS_BY_NAME("[test_tbl]", "OBJECT", "SELECT") as nchar(10))), 
    ('have_qualified_select', cast(HAS_PERMS_BY_NAME("[test_schema].[test_tbl]", "OBJECT", "SELECT") as nchar(10))) 
) AS tmptbl([key], val); -- select permissions fro [test_tbl] of the current user 
    SELECT tc as qualified_tc FROM [test_schema].[test_tbl]; -- qualified select 
    SELECT tc as UNqualified_tc from [test_tbl]; -- unqualified select fails with Msg 208 
END 
GO 

GRANT EXECUTE ON [dbo].[TA] TO [test_usr] 
GO 

テストスクリプト:再生する

スクリプト(<MDF><LDF>はappropritateファイルパスとの置換を必要とする)

USE [test_sql] 
GO 
DECLARE @return_value int 
execute as login = N'test_usr_login'; -- even when logged in with test_usr_logn, Msg 208 occurs 
EXEC @return_value = [dbo].[TA] 
revert 
SELECT 'Return Value' = @return_value 
GO 

出力メッセージ:

メッセージ208、レベル16 、状態1、プロシージャTA、行14無効なオブジェクト名 'test_tbl'。

(1行(複数可)の影響を受ける)

出力結果:

key val 
CURRENT_USER test_usr 
SCHEMA_NAME test_schema 
have_UNqualified_select 1   
have_qualified_select 1   

私が説明した問題の解決に光をもたらす可能性が誰をいただければ幸いです。

+0

スキーマ "test_schema"に "test_tbl"テーブルを作成しましたが、プロシージャでスキーマを指定しませんでした。とにかく、スキーマを指定する必要がある場合は、デフォルトのスキーマとして実行することがわかります。 –

+0

@SeanLange共有APIのコンセプトは、修飾されていない「test_tbl」によって実装されています。このテーブルには、デフォルトのスキーマ([MSDN](https://msdn.microsoft.com/en-us/library/ms190387.aspx) )。それ以外の場合は、スキーマ名の依存関係のため、APIを共有として提供できません。私は私の質問に光をもたらします[SOF](/質問/ 27357352/SQL-デフォルト・スキーマ解像度・イン・ストアド・プロシージャ)で、別の同様の質問を見つけました。 –

答えて

1

問題はここにある:ユーザーコンテキストでの即時アクセス 切り替えが正常に動作している間(例えば test_tblからSELECT *続いUSER AS EXECUTE;)エラーメッセージで失敗し 、ストアドプロシージャのデフォルトのスキーマを介したアクセス208、レベル16、状態1

ここでの問題は、SQL Serverが非修飾オブジェクト名を解決する方法を知らないことです。

スキーマを指定せずにplain sqlを実行してオブジェクトを使用すると、最初のユーザーdefault schemaがチェックされ、オブジェクトが見つからない場合はdboスキーマがチェックされます。 dboでもオブジェクトが見つからない場合は、エラーが発生します。

ストアドプロシージャとは異なります。 schemaが指定されていない場合、spのスキーマが最初にチェックされ、オブジェクトが見つからない場合はdboスキーマがチェックされ、再度見つからなければエラーが発生します。 User default schemaはストアドプロシージャの場合は決してチェックされません

+0

したがって、いくつかのスキーマ間でSPを共有する方法はありますか?あなたは別のアプローチを使用することができ、あなたのテーブルを変更することができた場合は、すべてのスキーマ –

+0

。非修飾test_tblテーブルの代わりに、分割ビューを作成することができます。これを行うには、check_name制約付きのすべての表にschema_name列を追加します。あなたのすべての "類似"テーブルのすべてのユニオンとしてビューを作成します。次に、ビューを使用する前に計算できる適切なスキーマによるtest_tableフィルタリングの代わりに、このビューを使用します。クエリでオプション(再コンパイル)を使用すると、スキーマ名を含む変数がスニッフィングされ、正しいもの以外のすべてのテーブルが実行計画から除外されます – sepupic

+0

で、このSPのコピーを作成する場合のみ – sepupic

関連する問題