Không cho phép UDF mới chứa con trỏ


7

Có cách nào để ngăn các nhà phát triển tạo các hàm do người dùng xác định mới sử dụng con trỏ không? Một trình kích hoạt cơ sở dữ liệu có thể đọc mã của UDF sẽ làm gì?


2
Cách mới để làm điều này là với Chính sách .
Nick Chammas

4
Và cách cũ để làm điều này là với mã xem lại!
HLGEM

Câu trả lời:


11
CREATE TRIGGER PreventCursorUDFs
    ON DATABASE 
    FOR CREATE_FUNCTION
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @EventData XML = EVENTDATA();

    IF LOWER(@EventData.value('(/EVENT_INSTANCE/TSQLCommand)[1]','NVARCHAR(MAX)'))
      LIKE N'%declare%cursor%fetch%'
    BEGIN
        RAISERROR('Yo, no cursors in functions!', 11, 1);
        ROLLBACK;
    END
END
GO

Với một cảnh báo, điều này cũng sẽ không cho phép kích hoạt có chứa một nhận xét, như:

/* we used to do this a dumb way, using DECLARE CURSOR and FETCH */
/* now we're a little smarter and use this table-valued function */

... hoặc nếu bạn có các truy vấn thực sự bất tiện, chẳng hạn như:

SELECT [declare] = [cursor] * 10 FROM dbo.[fetch];

... hoặc thậm chí nếu bạn gọi chức năng của mình:

CREATE FUNCTION dbo.ModeClarevoyantForCursoryFetching()
RETURNS TABLE
AS ...

BIÊN TẬP

Giải quyết câu hỏi của Nick ở đây thay vì như một bình luận, bởi vì nó sẽ trở nên hơi dài dòng.

PBM là tuyệt vời cho một số thứ, nhưng không tuyệt vời ở những thứ khác. Yêu cầu này thuộc danh mục "những thứ khác". Vấn đề chính là định nghĩa (ví dụ OBJECT_DEFINITION()) không được hiển thị dưới dạng một thuộc tính cho các khía cạnh như các hàm do người dùng xác định. Điều này có nghĩa là tình trạng của bạn không thể đơn giản diễn tả một cái gì đó như:

@ObjectDefinition NOT LIKE '%DECLARE%CURSOR%FETCH%'

Nếu đây là trường hợp, bạn có thể tạo điều kiện này, bọc chính sách xung quanh nó, đặt nó thành "Ngăn chặn: thay đổi" và đi ăn trưa. Để thực hiện điều này như là một chính sách đòi hỏi một chút công việc.

Vì @ObjectDefDef không phải là Trường hợp lệ cho khía cạnh này, chúng tôi cần lấy nó bằng cách sử dụng ExecuteSql(). Vì vậy, điều kiện của bạn sẽ phải là một cái gì đó như:

ExecuteSql('Numeric', 'SELECT x = PATINDEX(''%declare%cursor%fetch'',
  LOWER(OBJECT_DEFINITION(OBJECT_ID(@@SchemaName + ''.'' + @@ObjectName))))')

Xấu xí phải không? Khi điều này đánh giá về 0, chính sách sẽ thành công; khi nó <> 0, chính sách sẽ thất bại. (Hãy nhớ rằng một chính sách được cho là được thể hiện theo trạng thái mà bạn muốn hệ thống ở trong đó, chứ không phải là trạng thái mà bạn không có.)

Vì vậy, để bắt đầu, bạn sẽ tạo một điều kiện bằng cách mở Object Explorer, mở rộng Quản lý> Quản lý chính sách, nhấp chuột phải vào Điều kiện và chọn Điều kiện mới ... Đặt tên, chọn khía cạnh Chức năng do người dùng xác định và nhấp vào nút Chỉnh sửa nâng cao . Ở đó bạn có thể nhập ExecuteSql()chuỗi ở trên và nhấp vào OK.

nhập mô tả hình ảnh ở đây

Thay đổi Toán tử thành =, nhập 0 làm Giá trị và bấm OK. Bây giờ tạo một Chính sách. Nhấp chuột phải vào Chính sách, Chính sách mới ... Đặt tên cho nó, chọn điều kiện bạn vừa tạo và sau đó chọn Chế độ đánh giá:

nhập mô tả hình ảnh ở đây

À ồ. Tại sao không có hành động "Ngăn chặn"? Về ngăn chặn: thay đổi tất nhiên sẽ cho phép bạn ngăn chặn chức năng được tạo. Vì các thuộc tính như ID và định nghĩa không có sẵn thông qua khía cạnh, đòi hỏi chúng tôi phải trải qua ExecuteSql(), chúng tôi phải chịu một hạn chế ngăn các chính sách với các điều kiện sử dụng ExecuteSql()được tự động hóa. Mặc dù bài đăng trên blog PBM từ năm 2008 này cho thấy rằng hạn chế này đã được gỡ bỏ, tôi vẫn thấy nó được thi hành trong SQL Server 2012 với Bản cập nhật tích lũy số 1 được áp dụng (11.0.2316).

Vì vậy, hiện tại, bạn có thể thực hiện việc này bằng chính sách, nhưng bạn sẽ không thể ngăn chức năng đó được tạo ra - bạn sẽ chỉ có thể điều tra các vi phạm sau khi thực tế (bằng cách chọn Theo yêu cầu hoặc Theo lịch). Hãy nhớ rằng ngay cả khi bạn chạy chính sách này theo yêu cầu, nó vẫn sử dụng logic chính xác như trình kích hoạt DDL, do đó phải chịu cùng một cảnh báo: nó có thể đưa ra các thông báo sai nếu bạn có nhận xét hoặc truy vấn không phải con trỏ hợp lệ bao gồm cùng một chuỗi các từ.

Nếu bạn muốn các thuộc tính có sẵn cho các khía cạnh linh hoạt hơn và hoàn thiện hơn, điều này sẽ cho phép kiểm soát nhiều hơn trong việc sử dụng các chính sách có lợi cho trình kích hoạt DDL, vui lòng bỏ phiếu và nhận xét về hai mục Kết nối này:

http://connect.microsoft.com/QueryServer/feedback/details/552345/pbm-add-objectid-as-a-parameter-for-executesql

http://connect.microsoft.com/QueryServer/feedback/details/649944/pbm-enable-the-ability-to-pass-more-parameter-to-executesql

Tôi không biết về một mặt hàng giải quyết các hạn chế ExecuteSql()nói chung. Tôi sẽ xem sau và nộp một cái nếu tôi không thể tìm thấy. Tôi nghĩ rằng bài đăng trên blog phản ánh thực tế là bây giờ bạn có thể chạy chúng theo lịch trình, nhưng nếu bạn có thể chạy nó theo lịch trình, tại sao nó không thể hoạt động ở chế độ "ngăn chặn"?

Đóng vòng lặp: đây là mục Connect mới. Vui lòng bỏ phiếu và / hoặc thêm nhận xét mô tả trường hợp sử dụng / nhu cầu kinh doanh của bạn (điều này thường có giá trị hơn nhiều so với chỉ phiếu thô):

http://connect.microsoft.com/QueryServer/feedback/details/749317/allow-on-change-prevent-for-polaho-with-executesql-conditions


2
+1 Câu trả lời tuyệt vời và cách tiếp cận thông minh. Chưa kể thông báo lỗi tuyệt vời :)
Thomas Stringer

Bạn rõ ràng quen thuộc với Quản lý dựa trên chính sách. Loại hạn chế này có thể được thi hành tốt hơn bằng PBM không?
Nick Chammas

1
Tôi cũng thích tin nhắn trả lại. Tôi thậm chí có thể mã hóa tên của người duy nhất ở đây sử dụng con trỏ. Hấp dẫn. Không
William Meitzen

Đáng buồn thay, mục Kết nối mà tôi nêu ra đã bị đóng vì "sẽ không sửa."
Aaron Bertrand
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.