2012-01-26 13 views
0

私はmssql2008 R2のSQL ServerのUPDATE文

問題を抱えている: ユーザーは、テーブルの上にいくつかの列の権限を持っています。彼はテーブルの列の一部を更新することができます(すべてではありません)。権限に違反しないようにUPDATE文を作成する必要があります。 好ましくは動的クエリなし。

この機能はMSSQLサーバーにはありますか?

答えて

2

動的SQL(またはアプリケーション層またはAPI層の動的クエリ構築なし)を使用しないでください。私はそれがとてもかわいいとは思わない。 UPDATEコマンドには、ユーザーが影響を受ける列にどのような権限があるかについての固有の知識はありません。クエリをエンジンに提出し、最高のものを願っています。ユーザーがすべての列に対して権限を持っていない場合は、エラーを戻し、目的のステートメントを変更して回避することはできません。私は、実際には、すべての意図した列が更新されていなくても、更新を続行することは非常に悪いことだと思います。すべては言っ

は、私はあなたがこのような何かを行うことができたとし、それはかなりすべてであることを行っていません - あなたは、データベースプリンシパルに頼っていない場合は実際には非常に簡単になります。

DECLARE 
    @dpid INT = DATABASE_PRINCIPAL_ID(), 
    @obj INT = OBJECT_ID('dbo.foo'), 
    @col SYSNAME = N'bar'; 

UPDATE dbo.foo SET bar = CASE 
    WHEN EXISTS -- check they've been granted UPDATE at column or table level: 
    (
    SELECT 1 
     FROM sys.database_permissions AS dp 
     INNER JOIN sys.objects AS o 
     ON dp.major_id = o.[object_id] 
     LEFT OUTER JOIN sys.columns AS c 
     ON dp.minor_id = COALESCE(c.column_id, 0) 
     WHERE dp.grantee_principal_id = @dpid 
     AND o.[object_id] = @obj 
     AND (c.name = @col OR c.column_id IS NULL) 
     AND dp.[permission_name] = 'UPDATE' 
     AND dp.[state] = 'G' -- GRANT 
) 
    AND NOT EXISTS -- since DENY trumps GRANT, make sure that doesn't also exist: 
    (
    SELECT 1 
     FROM sys.database_permissions AS dp 
     INNER JOIN sys.objects AS o 
     ON dp.major_id = o.[object_id] 
     LEFT OUTER JOIN sys.columns AS c 
     ON dp.minor_id = COALESCE(c.column_id, 0) 
     WHERE dp.grantee_principal_id = @dpid 
     AND o.[object_id] = @obj 
     AND (c.name = @col OR c.column_id IS NULL) 
     AND dp.[permission_name] = 'UPDATE' 
     AND dp.[state] = 'D' -- DENY 
) 
THEN @bar ELSE bar END 
-- WHERE... 
; 

これはあなたが求めているものではありません。技術的には列を更新しますが、それ自体に設定します(たとえば、引き続きトリガーで更新された列として表示されます)が、入力が表に適用されないようにします。明示的なGRANT UPDATEまたはDENY UPDATE以外の指定されたユーザーまたはロール以外の方法で付与された権限についてもチェックしませんでした。たとえば、GRANT ALLまたはADグループメンバーシップによって継承された権限は、これを複雑にする可能性があります。もちろん、チェックする列が複数ある場合は、これを管理することはあまり面白くないでしょう。

WHEN句に他の条件を追加することができます。特定の

CASE 
    WHEN DATABASE_PRINCIPAL_ID() = 1 THEN @bar 
    WHEN SUSER_SNAME = 'some_user' THEN @bar 
    WHEN (...stuff from above...) 
    ELSE bar 
END 
-- WHERE... 
; 
+0

は、はい、確か、UPDATEは知りませんが、私は(タッチ)を変更しないUPDATEを伝えることができます:あなたが明示的にチェックを回避したい()、またはユーザーDBOのチェックを回避するために、あなたが持っている可能性があり明示的な列? –

+0

はい、それを節に含めないでください。あなたは 'UPDATE foo SET bar = bar + 1 WITH BUT_DO_NOT_TOUCH_THIS'と言うことはできません... –

+0

私を笑わないでください:-)わかりました、あなたの答えとコメントを理解しています。たぶんあなたは自分の状況(あなたの視点に基づいて)で何をすべきかアドバイスできますか? –