-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDeleteTopic.sql
157 lines (137 loc) · 7.52 KB
/
DeleteTopic.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
--------------------------------------------------------------------------------------------------------------------------------
-- DELETE TOPIC
--------------------------------------------------------------------------------------------------------------------------------
-- Deletes a topic in the tree, including all child topics.
--------------------------------------------------------------------------------------------------------------------------------
CREATE PROCEDURE [dbo].[DeleteTopic]
@TopicID INT
AS
--------------------------------------------------------------------------------------------------------------------------------
-- DISABLE NOCOUNT
--------------------------------------------------------------------------------------------------------------------------------
-- Prevent extra result sets from interfering with SELECT statements
SET NOCOUNT ON;
--------------------------------------------------------------------------------------------------------------------------------
-- DECLARE AND SET VARIABLES
--------------------------------------------------------------------------------------------------------------------------------
DECLARE @RangeLeft INT
DECLARE @RangeRight INT
DECLARE @RangeWidth INT
DECLARE @Topics TABLE (TopicId INT)
DECLARE @IsNestedTransaction BIT;
BEGIN TRY
--------------------------------------------------------------------------------------------------------------------------------
-- BEGIN TRANSACTION
--------------------------------------------------------------------------------------------------------------------------------
-- ### NOTE JJC20191208: This application includes a number of read operations that join the Topics table with other
-- tables modified as part of this procedure. Many of those read operations will fail while this operation is happening. For
-- example, common joins between Topics and Attributes may fail since critical AttributeKeys such as Key,
-- ParentId, and ContentType may be missing during this operation. For this reason, we are opting to use an aggressive isolation
-- level—SERIALIZABLE—to ensure that all callers outside of this transcation receive a stable (pre-transaction) state of the
-- data until this transaction is committed.
--------------------------------------------------------------------------------------------------------------------------------
-- ### NOTE JJC20191208: The SERIALIZABLE isolation level also has the benefit (for our needs) of maintaining any holds for the
-- duration of the transaction. This includes any rows within the scope of where clauses within this procedure. Critically, it
-- also includes a TABLOCK established early on, which prevents the nested set hierarchy from being modified until completion.
-- See additional notes below for further explanation of the decision to use a TABLOCK.
--------------------------------------------------------------------------------------------------------------------------------
IF (@@TRANCOUNT = 0)
BEGIN
SET @IsNestedTransaction = 0;
BEGIN TRANSACTION;
END
ELSE
BEGIN
SET @IsNestedTransaction = 1;
END
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
--------------------------------------------------------------------------------------------------------------------------------
-- DEFINE RANGE TO DELETE
--------------------------------------------------------------------------------------------------------------------------------
-- ### NOTE JJC20191208: We usually avoid broad hints like TABLOCK. That said, the delete operation requires multiple
-- operations against the topics table which will fail if the topic range shifts. Locking the table helps ensure that data
-- integrity issues aren't introduced by concurrent modification of the nested set.
--------------------------------------------------------------------------------------------------------------------------------
-- ### NOTE JJC20191208: Note that locks are NOT required on the child tables, such as Attributes, AttributeXml, and
-- Relationships. This is because those queries are much narrower in scope, and the standard out-of-the-box row locks
-- that come with the SERIALIZABLE isolation level when those calls are executed will be more than sufficient.
--------------------------------------------------------------------------------------------------------------------------------
SELECT @RangeLeft = RangeLeft,
@RangeRight = RangeRight,
@RangeWidth = RangeRight - RangeLeft + 1
FROM Topics
WITH ( TABLOCK)
WHERE TopicID = @TopicID
;
--------------------------------------------------------------------------------------------------------------------------------
-- STORE RANGE IN TABLE VARIABLE
--------------------------------------------------------------------------------------------------------------------------------
INSERT
INTO @Topics(TopicId)
SELECT TopicId
FROM Topics
WHERE RangeLeft
BETWEEN @RangeLeft
AND @RangeRight
--------------------------------------------------------------------------------------------------------------------------------
-- DELETE RELATED ATTRIBUTES
--------------------------------------------------------------------------------------------------------------------------------
DELETE Attributes
FROM Attributes Attributes
INNER JOIN @Topics Topics
ON Topics.TopicId = Attributes.TopicID
DELETE ExtendedAttributes
FROM ExtendedAttributes ExtendedAttributes
INNER JOIN @Topics Topics
ON Topics.TopicId = ExtendedAttributes.TopicID
DELETE TopicReferences
FROM TopicReferences TopicReferences
INNER JOIN @Topics Topics
ON Topics.TopicId = TopicReferences.Source_TopicID
DELETE TopicReferences
FROM TopicReferences TopicReferences
INNER JOIN @Topics Topics
ON Topics.TopicId = TopicReferences.Target_TopicID
DELETE Relationships
FROM Relationships Relationships
INNER JOIN @Topics Topics
ON Topics.TopicId = Relationships.Source_TopicID
DELETE Relationships
FROM Relationships Relationships
INNER JOIN @Topics Topics
ON Topics.TopicId = Relationships.Target_TopicID
--------------------------------------------------------------------------------------------------------------------------------
-- DELETE RANGE
--------------------------------------------------------------------------------------------------------------------------------
DELETE TopicsActual
FROM Topics TopicsActual
INNER JOIN @Topics Topics
ON Topics.TopicId = TopicsActual.TopicID
--------------------------------------------------------------------------------------------------------------------------------
-- CLOSE LEFT GAP
--------------------------------------------------------------------------------------------------------------------------------
UPDATE Topics
SET RangeRight = RangeRight - @RangeWidth
WHERE RangeRight > @RangeRight
UPDATE Topics
SET RangeLeft = RangeLeft - @RangeWidth
WHERE RangeLeft > @RangeRight
--------------------------------------------------------------------------------------------------------------------------------
-- COMMIT TRANSACTION
--------------------------------------------------------------------------------------------------------------------------------
IF (@@TRANCOUNT > 0 AND @IsNestedTransaction = 0)
BEGIN
COMMIT
END
END TRY
--------------------------------------------------------------------------------------------------------------------------------
-- HANDLE ERRORS
--------------------------------------------------------------------------------------------------------------------------------
BEGIN CATCH
IF (@@TRANCOUNT > 0 AND @IsNestedTransaction = 0)
BEGIN
ROLLBACK;
END;
THROW
RETURN;
END CATCH