2009-04-02 36 views
15

Làm thế nào để ngăn chặn việc thực hiện đệ quy kích hoạt? Giả sử tôi muốn xây dựng mô tả "có thể có cây" trên biểu đồ tài khoản. Vì vậy, những gì tôi làm là khi một bản ghi mới được chèn/cập nhật, tôi cập nhật bản ghi của phụ huynh là down_qty, vì vậy điều này sẽ kích hoạt trình kích hoạt cập nhật đệ quy.Ngăn chặn kích hoạt đệ quy trong PostgreSQL

Ngay bây giờ, mã của tôi là ok - Tôi đặt này trên dòng đầu tiên UPDATE kích hoạt của:

-- prevents recursive trigger 
if new.track_recursive_trigger <> old.track_recursive_trigger then 
    return new; 
end if; 

Và đây là đoạn code mẫu từ cò của tôi khi tôi cần phải cập nhật qty kỷ lục của cha mẹ:

update account_category set 
    track_recursive_trigger = track_recursive_trigger + 1, -- i put this line to prevent recursive trigger 
    down_qty = down_qty - (old.down_qty + 1) 
where account_category_id = m_parent_account; 

Tôi đang suy nghĩ xem có cách nào trong PostgreSQL phát hiện trình kích hoạt đệ quy mà không đưa vào trường mới hay không, tương tự như số trigger_nestlevel của MSSQL.

[EDIT]

Tôi lặp bên trong cây, tôi cần phải bong bóng lên down_qty của mỗi account_category trở lại gốc rễ của nó. Ví dụ: tôi chèn danh mục tài khoản mới, cần tăng số down_qty của số phụ huynh account_category, tương tự như vậy khi tôi thay đổi phụ huynh của danh mục tài khoản account_category, tôi cần phải giảm số down_qty của số account_category trước đó của cha mẹ account_category. Mặc dù tôi nghĩ rằng nó có thể, tôi không cho phép PostgreSQL kích hoạt đệ quy. Tôi đã sử dụng MSSQL trước khi kích hoạt mức độ đệ quy sâu chỉ giới hạn ở mức 16.

+1

Tôi nghĩ bạn nên giải thích chi tiết hơn một chút, vì tôi có thể thấy không có nguy cơ gọi đệ quy ở đây trừ khi bạn có : bản ghi đó là cha mẹ của chính nó, hoặc vòng trong cây của bạn (mà không phải là cây sau đó). –

Trả lời

6

Trong pg, tùy thuộc vào bạn theo dõi đệ quy kích hoạt.

Nếu chức năng kích hoạt thực thi lệnh SQL thì các lệnh này có thể kích hoạt lại. Điều này được gọi là kích hoạt tầng. Không có giới hạn trực tiếp về số lượng tầng thác . Có thể cho các thác đến gây ra một lời gọi đệ quy của kích hoạt tương tự ; ví dụ, kích hoạt INSERT có thể thực thi lệnh chèn thêm một hàng vào cùng một bảng, gây kích hoạt INSERT để được kích hoạt lại. Đó là trách nhiệm của lập trình viên để tránh đệ quy vô hạn trong các trường hợp như vậy.

http://www.postgresql.org/docs/8.3/static/trigger-definition.html

3

Tại beggining của định nghĩa của cò bạn có thể vô hiệu hóa trigger trên đó bảng cụ thể, và kích hoạt lại chúng vào cuối (và chắc chắn rằng một ngoại lệ không chấm dứt việc thực hiện trước khi mong đợi!). Điều này có nhiều lỗ sâu, nhưng có thể làm việc cho một số triển khai ánh sáng. Lưu ý rằng để thực hiện điều này, bạn cũng sẽ cần các đặc quyền để vô hiệu hóa các trình kích hoạt.

+0

điều này không hoạt động, bởi vì: không thể ALTER TABLE "trigger_table" vì nó đang được sử dụng bởi các truy vấn hoạt động trong phiên này –

54

Đây là những gì tôi làm trong PostgreSQL 9.2, mặc dù tôi phải thừa nhận rằng tôi không tìm thấy cách tiếp cận này được ghi lại. Có một hàm pg_trigger_depth()documented here, mà tôi sử dụng để phân biệt giữa các cuộc gọi gốc và lồng nhau trong trình kích hoạt.

CREATE TRIGGER trg_taxonomic_positions 
AFTER INSERT OR UPDATE OF taxonomic_position 
ON taxon_concepts 
FOR EACH ROW 
WHEN (pg_trigger_depth() = 0) 
EXECUTE PROCEDURE trg_taxonomic_positions() 
+0

tìm kiếm tốt đẹp! điều này giúp giải quyết một loạt các vấn đề khác. –

+0

Điểm! Giải pháp hoàn hảo, cảm ơn! – theory

+4

Brilliant! Thật không may, chức năng này không có trong 9.1 :(Tôi tự hỏi nếu có một sự thay thế cho nó ... – mvp

2

Để tránh đệ quy không bị chặn, hãy xem my answer here.Như những người khác đã nhận xét, nếu cấu trúc dữ liệu của bạn là một cây đúng (gốc) sẽ không có (các) gốc) và đệ quy sẽ luôn dừng ở gốc. Đối với các nút chỉ với một phụ huynh con trỏ, cách duy nhất để đệ quy không bị chặn sẽ là nếu có các vòng lặp hiện tại. (phương pháp trong liên kết của tôi sẽ truy cập bất kỳ nút nào tối đa một lần)

Các vấn đề liên quan