{"id":72,"date":"2014-06-18T00:00:00","date_gmt":"2013-01-01T00:00:00","guid":{"rendered":"https:\/\/www.sqlhammer.com\/blog\/broken-ownership-chain-dynamic-sql"},"modified":"2026-03-18T21:51:04","modified_gmt":"2026-03-18T21:51:04","slug":"broken-ownership-chain-dynamic-sql","status":"publish","type":"post","link":"https:\/\/sqlhammer.com\/index.php\/2014\/06\/18\/broken-ownership-chain-dynamic-sql\/","title":{"rendered":"Broken ownership chain &#8211; Dynamic SQL"},"content":{"rendered":"<p>Today I had a co-worker come to my desk wondering why his service was getting a permissions error when selecting from a table. His confusion was rooted in the fact that his service has been using this stored procedure for over a year. He is granting access to the underlying tables by granting execute rights to the stored procedure only.<\/p>\n<p>This method works most of the time but ownership chaining is not fool proof. The reason that he was getting select permissions errors was because he had changed his stored procedure to include some dynamic SQL. He was using <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms175170.aspx\">sp_executesql<\/a>\u00a0but even if he was using <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms188332.aspx\">EXECUTE <\/a>instead he would have ran into the same problem. The sp_executesql article on MSDN states:<\/p>\n<p>> When either\u00a0sp_executesql\u00a0or the EXECUTE statement executes a string, the string is executed as its own self-contained batch. SQL Server compiles the Transact-SQL statement or statements in the string into an execution plan that is separate from the execution plan of the batch that contained the\u00a0sp_executesql\u00a0or the EXECUTE statement.<\/p>\n<p>This is where ownership chaining breaks down. An <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/ms188676(v=SQL.105\">ownership chain<\/a>.aspx)\u00a0is completely within the context of a batch. Since we now know that sp_executesql and EXECUTE create new batches when they compile, we end up stepping out of the security context that we want to be in. If you want to grant execute rights only, you are going to have to avoid dynamic SQL, unfortunately.<\/p>\n<hr \/>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/dh.jpg\" alt=\"\" \/><strong>Written by Derik Hammer of <a href=\"http:\/\/www.sqlhammer.com\/\">SQL Hammer<\/a><\/strong><\/p>\n<p>Derik is a data professional focusing on Microsoft SQL Server. His passion focuses around <a href=\"http:\/\/www.sqlhammer.com\/blog\/category\/high-availability\/\">high-availability<\/a>, <a href=\"http:\/\/www.sqlhammer.com\/blog\/category\/general\/disaster-recovery\/\">disaster recovery<\/a>, continuous integration, and automated maintenance. his experience has spanned long-term database administration, consulting, and\u00a0entrepreneurial ventures.<\/p>\n<p>Derik gives the SQL community credit for plugging the gaps in his knowledge when he was a junior DBA and, now that his skills have matured, started <a href=\"http:\/\/www.sqlhammer.com\/\">SQLHammer.com<\/a> as one small way to give back and continue the cycle of shared learning.<\/p>\n<p>Derik is the owner and lead author of SQL Hammer, a <a href=\"http:\/\/www.sqlhammer.com\/\">Microsoft SQL Server resource<\/a>.<\/p>\n<p>For more information, visit <a href=\"http:\/\/www.sqlhammer.com\/\">http:\/\/www.sqlhammer.com<\/a>. Follow Derik on <a href=\"http:\/\/twitter.com\/SQLHammer\">Twitter<\/a> for <strong>SQL tips and chat<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today I had a co-worker come to my desk wondering why his service was getting a permissions error when selecting from a table. His confusion was rooted in the fact that his service has been using this stored procedure for over a year. He is granting access to the underlying tables by granting execute rights [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":523,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-72","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/posts\/72","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/comments?post=72"}],"version-history":[{"count":1,"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/posts\/72\/revisions"}],"predecessor-version":[{"id":335,"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/posts\/72\/revisions\/335"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/media\/523"}],"wp:attachment":[{"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/media?parent=72"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/categories?post=72"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sqlhammer.com\/index.php\/wp-json\/wp\/v2\/tags?post=72"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}