Merge lp:~wgrant/launchpad/db-baseline-2210 into lp:launchpad
- db-baseline-2210
- Merge into devel
Proposed by
William Grant
Status: | Merged |
---|---|
Merged at revision: | 18888 |
Proposed branch: | lp:~wgrant/launchpad/db-baseline-2210 |
Merge into: | lp:launchpad |
Diff against target: |
38895 lines (+17239/-16332) 3 files modified
database/schema/Makefile (+2/-2) database/schema/launchpad-2210-00-0.sql (+17234/-16330) database/schema/patch-2210-00-0.sql (+3/-0) |
To merge this branch: | bzr merge lp:~wgrant/launchpad/db-baseline-2210 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stuart Bishop (community) | Approve | ||
Review via email: mp+363648@code.launchpad.net |
Commit message
Rebaseline schema, version 2210.
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'database/schema/Makefile' | |||
2 | --- database/schema/Makefile 2018-05-14 13:11:14 +0000 | |||
3 | +++ database/schema/Makefile 2019-02-26 07:46:16 +0000 | |||
4 | @@ -61,9 +61,9 @@ | |||
5 | 61 | # on production. It is generated using newbaseline.py in | 61 | # on production. It is generated using newbaseline.py in |
6 | 62 | # bzr+ssh://devpad.canonical.com/code/stub/dbascripts | 62 | # bzr+ssh://devpad.canonical.com/code/stub/dbascripts |
7 | 63 | # | 63 | # |
9 | 64 | REV=2209 | 64 | REV=2210 |
10 | 65 | BASELINE=launchpad-${REV}-00-0.sql | 65 | BASELINE=launchpad-${REV}-00-0.sql |
12 | 66 | MD5SUM=cc7a493c924196409a22392a16443d52 launchpad-2209-00-0.sql | 66 | MD5SUM=36ae7078cd41916bbbd9c116b2e6aea7 launchpad-2210-00-0.sql |
13 | 67 | 67 | ||
14 | 68 | default: all | 68 | default: all |
15 | 69 | 69 | ||
16 | 70 | 70 | ||
17 | === renamed file 'database/schema/patch-2209-00-0.sql' => 'database/schema/archive/patch-2209-00-0.sql' | |||
18 | === renamed file 'database/schema/patch-2209-00-1.sql' => 'database/schema/archive/patch-2209-00-1.sql' | |||
19 | === renamed file 'database/schema/patch-2209-00-2.sql' => 'database/schema/archive/patch-2209-00-2.sql' | |||
20 | === renamed file 'database/schema/patch-2209-00-3.sql' => 'database/schema/archive/patch-2209-00-3.sql' | |||
21 | === renamed file 'database/schema/patch-2209-00-5.sql' => 'database/schema/archive/patch-2209-00-5.sql' | |||
22 | === renamed file 'database/schema/patch-2209-00-6.sql' => 'database/schema/archive/patch-2209-00-6.sql' | |||
23 | === renamed file 'database/schema/patch-2209-00-7.sql' => 'database/schema/archive/patch-2209-00-7.sql' | |||
24 | === renamed file 'database/schema/patch-2209-00-8.sql' => 'database/schema/archive/patch-2209-00-8.sql' | |||
25 | === renamed file 'database/schema/patch-2209-00-9.sql' => 'database/schema/archive/patch-2209-00-9.sql' | |||
26 | === renamed file 'database/schema/patch-2209-01-0.sql' => 'database/schema/archive/patch-2209-01-0.sql' | |||
27 | === renamed file 'database/schema/patch-2209-01-1.sql' => 'database/schema/archive/patch-2209-01-1.sql' | |||
28 | === renamed file 'database/schema/patch-2209-02-0.sql' => 'database/schema/archive/patch-2209-02-0.sql' | |||
29 | === renamed file 'database/schema/patch-2209-04-0.sql' => 'database/schema/archive/patch-2209-04-0.sql' | |||
30 | === renamed file 'database/schema/patch-2209-05-1.sql' => 'database/schema/archive/patch-2209-05-1.sql' | |||
31 | === renamed file 'database/schema/patch-2209-06-1.sql' => 'database/schema/archive/patch-2209-06-1.sql' | |||
32 | === renamed file 'database/schema/patch-2209-07-0.sql' => 'database/schema/archive/patch-2209-07-0.sql' | |||
33 | === renamed file 'database/schema/patch-2209-07-1.sql' => 'database/schema/archive/patch-2209-07-1.sql' | |||
34 | === renamed file 'database/schema/patch-2209-08-1.sql' => 'database/schema/archive/patch-2209-08-1.sql' | |||
35 | === renamed file 'database/schema/patch-2209-09-0.sql' => 'database/schema/archive/patch-2209-09-0.sql' | |||
36 | === renamed file 'database/schema/patch-2209-10-0.sql' => 'database/schema/archive/patch-2209-10-0.sql' | |||
37 | === renamed file 'database/schema/patch-2209-11-0.sql' => 'database/schema/archive/patch-2209-11-0.sql' | |||
38 | === renamed file 'database/schema/patch-2209-11-1.sql' => 'database/schema/archive/patch-2209-11-1.sql' | |||
39 | === renamed file 'database/schema/patch-2209-11-2.sql' => 'database/schema/archive/patch-2209-11-2.sql' | |||
40 | === renamed file 'database/schema/patch-2209-11-3.sql' => 'database/schema/archive/patch-2209-11-3.sql' | |||
41 | === renamed file 'database/schema/patch-2209-11-4.sql' => 'database/schema/archive/patch-2209-11-4.sql' | |||
42 | === renamed file 'database/schema/patch-2209-11-5.sql' => 'database/schema/archive/patch-2209-11-5.sql' | |||
43 | === renamed file 'database/schema/patch-2209-12-0.sql' => 'database/schema/archive/patch-2209-12-0.sql' | |||
44 | === renamed file 'database/schema/patch-2209-12-1.sql' => 'database/schema/archive/patch-2209-12-1.sql' | |||
45 | === renamed file 'database/schema/patch-2209-12-2.sql' => 'database/schema/archive/patch-2209-12-2.sql' | |||
46 | === renamed file 'database/schema/patch-2209-12-3.sql' => 'database/schema/archive/patch-2209-12-3.sql' | |||
47 | === renamed file 'database/schema/patch-2209-12-4.sql' => 'database/schema/archive/patch-2209-12-4.sql' | |||
48 | === renamed file 'database/schema/patch-2209-12-5.sql' => 'database/schema/archive/patch-2209-12-5.sql' | |||
49 | === renamed file 'database/schema/patch-2209-14-0.sql' => 'database/schema/archive/patch-2209-14-0.sql' | |||
50 | === renamed file 'database/schema/patch-2209-15-0.sql' => 'database/schema/archive/patch-2209-15-0.sql' | |||
51 | === renamed file 'database/schema/patch-2209-15-1.sql' => 'database/schema/archive/patch-2209-15-1.sql' | |||
52 | === renamed file 'database/schema/patch-2209-15-2.sql' => 'database/schema/archive/patch-2209-15-2.sql' | |||
53 | === renamed file 'database/schema/patch-2209-15-3.sql' => 'database/schema/archive/patch-2209-15-3.sql' | |||
54 | === renamed file 'database/schema/patch-2209-16-0.sql' => 'database/schema/archive/patch-2209-16-0.sql' | |||
55 | === renamed file 'database/schema/patch-2209-16-1.sql' => 'database/schema/archive/patch-2209-16-1.sql' | |||
56 | === renamed file 'database/schema/patch-2209-16-2.sql' => 'database/schema/archive/patch-2209-16-2.sql' | |||
57 | === renamed file 'database/schema/patch-2209-16-3.sql' => 'database/schema/archive/patch-2209-16-3.sql' | |||
58 | === renamed file 'database/schema/patch-2209-16-4.sql' => 'database/schema/archive/patch-2209-16-4.sql' | |||
59 | === renamed file 'database/schema/patch-2209-16-5.sql' => 'database/schema/archive/patch-2209-16-5.sql' | |||
60 | === renamed file 'database/schema/patch-2209-16-6.sql' => 'database/schema/archive/patch-2209-16-6.sql' | |||
61 | === renamed file 'database/schema/patch-2209-16-7.sql' => 'database/schema/archive/patch-2209-16-7.sql' | |||
62 | === renamed file 'database/schema/patch-2209-16-8.sql' => 'database/schema/archive/patch-2209-16-8.sql' | |||
63 | === renamed file 'database/schema/patch-2209-17-0.sql' => 'database/schema/archive/patch-2209-17-0.sql' | |||
64 | === renamed file 'database/schema/patch-2209-17-1.sql' => 'database/schema/archive/patch-2209-17-1.sql' | |||
65 | === renamed file 'database/schema/patch-2209-18-0.sql' => 'database/schema/archive/patch-2209-18-0.sql' | |||
66 | === renamed file 'database/schema/patch-2209-18-1.sql' => 'database/schema/archive/patch-2209-18-1.sql' | |||
67 | === renamed file 'database/schema/patch-2209-18-2.sql' => 'database/schema/archive/patch-2209-18-2.sql' | |||
68 | === renamed file 'database/schema/patch-2209-18-3.sql' => 'database/schema/archive/patch-2209-18-3.sql' | |||
69 | === renamed file 'database/schema/patch-2209-18-4.sql' => 'database/schema/archive/patch-2209-18-4.sql' | |||
70 | === renamed file 'database/schema/patch-2209-19-0.sql' => 'database/schema/archive/patch-2209-19-0.sql' | |||
71 | === renamed file 'database/schema/patch-2209-19-1.sql' => 'database/schema/archive/patch-2209-19-1.sql' | |||
72 | === renamed file 'database/schema/patch-2209-19-2.sql' => 'database/schema/archive/patch-2209-19-2.sql' | |||
73 | === renamed file 'database/schema/patch-2209-19-3.sql' => 'database/schema/archive/patch-2209-19-3.sql' | |||
74 | === renamed file 'database/schema/patch-2209-20-0.sql' => 'database/schema/archive/patch-2209-20-0.sql' | |||
75 | === renamed file 'database/schema/patch-2209-20-1.sql' => 'database/schema/archive/patch-2209-20-1.sql' | |||
76 | === renamed file 'database/schema/patch-2209-21-0.sql' => 'database/schema/archive/patch-2209-21-0.sql' | |||
77 | === renamed file 'database/schema/patch-2209-21-1.sql' => 'database/schema/archive/patch-2209-21-1.sql' | |||
78 | === renamed file 'database/schema/patch-2209-21-2.sql' => 'database/schema/archive/patch-2209-21-2.sql' | |||
79 | === renamed file 'database/schema/patch-2209-21-3.sql' => 'database/schema/archive/patch-2209-21-3.sql' | |||
80 | === renamed file 'database/schema/patch-2209-21-4.sql' => 'database/schema/archive/patch-2209-21-4.sql' | |||
81 | === renamed file 'database/schema/patch-2209-22-0.sql' => 'database/schema/archive/patch-2209-22-0.sql' | |||
82 | === renamed file 'database/schema/patch-2209-23-0.sql' => 'database/schema/archive/patch-2209-23-0.sql' | |||
83 | === renamed file 'database/schema/patch-2209-23-1.sql' => 'database/schema/archive/patch-2209-23-1.sql' | |||
84 | === renamed file 'database/schema/patch-2209-23-2.sql' => 'database/schema/archive/patch-2209-23-2.sql' | |||
85 | === renamed file 'database/schema/patch-2209-23-3.sql' => 'database/schema/archive/patch-2209-23-3.sql' | |||
86 | === renamed file 'database/schema/patch-2209-23-4.sql' => 'database/schema/archive/patch-2209-23-4.sql' | |||
87 | === renamed file 'database/schema/patch-2209-23-5.sql' => 'database/schema/archive/patch-2209-23-5.sql' | |||
88 | === renamed file 'database/schema/patch-2209-24-1.sql' => 'database/schema/archive/patch-2209-24-1.sql' | |||
89 | === renamed file 'database/schema/patch-2209-24-2.sql' => 'database/schema/archive/patch-2209-24-2.sql' | |||
90 | === renamed file 'database/schema/patch-2209-24-3.sql' => 'database/schema/archive/patch-2209-24-3.sql' | |||
91 | === renamed file 'database/schema/patch-2209-25-1.sql' => 'database/schema/archive/patch-2209-25-1.sql' | |||
92 | === renamed file 'database/schema/patch-2209-26-0.sql' => 'database/schema/archive/patch-2209-26-0.sql' | |||
93 | === renamed file 'database/schema/patch-2209-26-1.sql' => 'database/schema/archive/patch-2209-26-1.sql' | |||
94 | === renamed file 'database/schema/patch-2209-26-2.sql' => 'database/schema/archive/patch-2209-26-2.sql' | |||
95 | === renamed file 'database/schema/patch-2209-26-3.sql' => 'database/schema/archive/patch-2209-26-3.sql' | |||
96 | === renamed file 'database/schema/patch-2209-26-4.sql' => 'database/schema/archive/patch-2209-26-4.sql' | |||
97 | === renamed file 'database/schema/patch-2209-26-5.sql' => 'database/schema/archive/patch-2209-26-5.sql' | |||
98 | === renamed file 'database/schema/patch-2209-27-1.sql' => 'database/schema/archive/patch-2209-27-1.sql' | |||
99 | === renamed file 'database/schema/patch-2209-27-2.sql' => 'database/schema/archive/patch-2209-27-2.sql' | |||
100 | === renamed file 'database/schema/patch-2209-27-3.sql' => 'database/schema/archive/patch-2209-27-3.sql' | |||
101 | === renamed file 'database/schema/patch-2209-27-4.sql' => 'database/schema/archive/patch-2209-27-4.sql' | |||
102 | === renamed file 'database/schema/patch-2209-28-1.sql' => 'database/schema/archive/patch-2209-28-1.sql' | |||
103 | === renamed file 'database/schema/patch-2209-28-2.sql' => 'database/schema/archive/patch-2209-28-2.sql' | |||
104 | === renamed file 'database/schema/patch-2209-28-4.sql' => 'database/schema/archive/patch-2209-28-4.sql' | |||
105 | === renamed file 'database/schema/patch-2209-28-5.sql' => 'database/schema/archive/patch-2209-28-5.sql' | |||
106 | === renamed file 'database/schema/patch-2209-28-6.sql' => 'database/schema/archive/patch-2209-28-6.sql' | |||
107 | === renamed file 'database/schema/patch-2209-29-0.sql' => 'database/schema/archive/patch-2209-29-0.sql' | |||
108 | === renamed file 'database/schema/patch-2209-30-1.sql' => 'database/schema/archive/patch-2209-30-1.sql' | |||
109 | === renamed file 'database/schema/patch-2209-30-2.sql' => 'database/schema/archive/patch-2209-30-2.sql' | |||
110 | === renamed file 'database/schema/patch-2209-31-1.sql' => 'database/schema/archive/patch-2209-31-1.sql' | |||
111 | === renamed file 'database/schema/patch-2209-31-2.sql' => 'database/schema/archive/patch-2209-31-2.sql' | |||
112 | === renamed file 'database/schema/patch-2209-31-3.sql' => 'database/schema/archive/patch-2209-31-3.sql' | |||
113 | === renamed file 'database/schema/patch-2209-32-0.sql' => 'database/schema/archive/patch-2209-32-0.sql' | |||
114 | === renamed file 'database/schema/patch-2209-34-1.sql' => 'database/schema/archive/patch-2209-34-1.sql' | |||
115 | === renamed file 'database/schema/patch-2209-35-1.sql' => 'database/schema/archive/patch-2209-35-1.sql' | |||
116 | === renamed file 'database/schema/patch-2209-35-2.sql' => 'database/schema/archive/patch-2209-35-2.sql' | |||
117 | === renamed file 'database/schema/patch-2209-35-3.sql' => 'database/schema/archive/patch-2209-35-3.sql' | |||
118 | === renamed file 'database/schema/patch-2209-35-4.sql' => 'database/schema/archive/patch-2209-35-4.sql' | |||
119 | === renamed file 'database/schema/patch-2209-36-0.sql' => 'database/schema/archive/patch-2209-36-0.sql' | |||
120 | === renamed file 'database/schema/patch-2209-36-1.sql' => 'database/schema/archive/patch-2209-36-1.sql' | |||
121 | === renamed file 'database/schema/patch-2209-37-0.sql' => 'database/schema/archive/patch-2209-37-0.sql' | |||
122 | === renamed file 'database/schema/patch-2209-38-0.sql' => 'database/schema/archive/patch-2209-38-0.sql' | |||
123 | === renamed file 'database/schema/patch-2209-38-1.sql' => 'database/schema/archive/patch-2209-38-1.sql' | |||
124 | === renamed file 'database/schema/patch-2209-38-2.sql' => 'database/schema/archive/patch-2209-38-2.sql' | |||
125 | === renamed file 'database/schema/patch-2209-38-3.sql' => 'database/schema/archive/patch-2209-38-3.sql' | |||
126 | === renamed file 'database/schema/patch-2209-39-0.sql' => 'database/schema/archive/patch-2209-39-0.sql' | |||
127 | === renamed file 'database/schema/patch-2209-39-1.sql' => 'database/schema/archive/patch-2209-39-1.sql' | |||
128 | === renamed file 'database/schema/patch-2209-40-0.sql' => 'database/schema/archive/patch-2209-40-0.sql' | |||
129 | === renamed file 'database/schema/patch-2209-40-1.sql' => 'database/schema/archive/patch-2209-40-1.sql' | |||
130 | === renamed file 'database/schema/patch-2209-40-2.sql' => 'database/schema/archive/patch-2209-40-2.sql' | |||
131 | === renamed file 'database/schema/patch-2209-40-3.sql' => 'database/schema/archive/patch-2209-40-3.sql' | |||
132 | === renamed file 'database/schema/patch-2209-41-0.sql' => 'database/schema/archive/patch-2209-41-0.sql' | |||
133 | === renamed file 'database/schema/patch-2209-41-1.sql' => 'database/schema/archive/patch-2209-41-1.sql' | |||
134 | === renamed file 'database/schema/patch-2209-41-2.sql' => 'database/schema/archive/patch-2209-41-2.sql' | |||
135 | === renamed file 'database/schema/patch-2209-41-3.sql' => 'database/schema/archive/patch-2209-41-3.sql' | |||
136 | === renamed file 'database/schema/patch-2209-41-4.sql' => 'database/schema/archive/patch-2209-41-4.sql' | |||
137 | === renamed file 'database/schema/patch-2209-41-5.sql' => 'database/schema/archive/patch-2209-41-5.sql' | |||
138 | === renamed file 'database/schema/patch-2209-42-0.sql' => 'database/schema/archive/patch-2209-42-0.sql' | |||
139 | === renamed file 'database/schema/patch-2209-43-0.sql' => 'database/schema/archive/patch-2209-43-0.sql' | |||
140 | === renamed file 'database/schema/patch-2209-44-0.sql' => 'database/schema/archive/patch-2209-44-0.sql' | |||
141 | === renamed file 'database/schema/patch-2209-44-1.sql' => 'database/schema/archive/patch-2209-44-1.sql' | |||
142 | === renamed file 'database/schema/patch-2209-44-2.sql' => 'database/schema/archive/patch-2209-44-2.sql' | |||
143 | === renamed file 'database/schema/patch-2209-44-3.sql' => 'database/schema/archive/patch-2209-44-3.sql' | |||
144 | === renamed file 'database/schema/patch-2209-44-4.sql' => 'database/schema/archive/patch-2209-44-4.sql' | |||
145 | === renamed file 'database/schema/patch-2209-45-0.sql' => 'database/schema/archive/patch-2209-45-0.sql' | |||
146 | === renamed file 'database/schema/patch-2209-46-0.sql' => 'database/schema/archive/patch-2209-46-0.sql' | |||
147 | === renamed file 'database/schema/patch-2209-47-0.sql' => 'database/schema/archive/patch-2209-47-0.sql' | |||
148 | === renamed file 'database/schema/patch-2209-47-1.sql' => 'database/schema/archive/patch-2209-47-1.sql' | |||
149 | === renamed file 'database/schema/patch-2209-48-0.sql' => 'database/schema/archive/patch-2209-48-0.sql' | |||
150 | === renamed file 'database/schema/patch-2209-49-0.sql' => 'database/schema/archive/patch-2209-49-0.sql' | |||
151 | === renamed file 'database/schema/patch-2209-49-1.sql' => 'database/schema/archive/patch-2209-49-1.sql' | |||
152 | === renamed file 'database/schema/patch-2209-49-2.sql' => 'database/schema/archive/patch-2209-49-2.sql' | |||
153 | === renamed file 'database/schema/patch-2209-50-0.sql' => 'database/schema/archive/patch-2209-50-0.sql' | |||
154 | === renamed file 'database/schema/patch-2209-51-0.sql' => 'database/schema/archive/patch-2209-51-0.sql' | |||
155 | === renamed file 'database/schema/patch-2209-51-1.sql' => 'database/schema/archive/patch-2209-51-1.sql' | |||
156 | === renamed file 'database/schema/patch-2209-51-2.sql' => 'database/schema/archive/patch-2209-51-2.sql' | |||
157 | === renamed file 'database/schema/patch-2209-52-0.sql' => 'database/schema/archive/patch-2209-52-0.sql' | |||
158 | === renamed file 'database/schema/patch-2209-53-0.sql' => 'database/schema/archive/patch-2209-53-0.sql' | |||
159 | === renamed file 'database/schema/patch-2209-53-1.sql' => 'database/schema/archive/patch-2209-53-1.sql' | |||
160 | === renamed file 'database/schema/patch-2209-53-3.sql' => 'database/schema/archive/patch-2209-53-3.sql' | |||
161 | === renamed file 'database/schema/patch-2209-53-4.sql' => 'database/schema/archive/patch-2209-53-4.sql' | |||
162 | === renamed file 'database/schema/patch-2209-53-5.sql' => 'database/schema/archive/patch-2209-53-5.sql' | |||
163 | === renamed file 'database/schema/patch-2209-53-6.sql' => 'database/schema/archive/patch-2209-53-6.sql' | |||
164 | === renamed file 'database/schema/patch-2209-53-7.sql' => 'database/schema/archive/patch-2209-53-7.sql' | |||
165 | === renamed file 'database/schema/patch-2209-53-8.sql' => 'database/schema/archive/patch-2209-53-8.sql' | |||
166 | === renamed file 'database/schema/patch-2209-53-9.sql' => 'database/schema/archive/patch-2209-53-9.sql' | |||
167 | === renamed file 'database/schema/patch-2209-54-0.sql' => 'database/schema/archive/patch-2209-54-0.sql' | |||
168 | === renamed file 'database/schema/patch-2209-55-0.sql' => 'database/schema/archive/patch-2209-55-0.sql' | |||
169 | === renamed file 'database/schema/patch-2209-56-0.sql' => 'database/schema/archive/patch-2209-56-0.sql' | |||
170 | === renamed file 'database/schema/patch-2209-56-1.sql' => 'database/schema/archive/patch-2209-56-1.sql' | |||
171 | === renamed file 'database/schema/patch-2209-56-2.sql' => 'database/schema/archive/patch-2209-56-2.sql' | |||
172 | === renamed file 'database/schema/patch-2209-56-3.sql' => 'database/schema/archive/patch-2209-56-3.sql' | |||
173 | === renamed file 'database/schema/patch-2209-56-4.sql' => 'database/schema/archive/patch-2209-56-4.sql' | |||
174 | === renamed file 'database/schema/patch-2209-57-0.sql' => 'database/schema/archive/patch-2209-57-0.sql' | |||
175 | === renamed file 'database/schema/patch-2209-58-0.sql' => 'database/schema/archive/patch-2209-58-0.sql' | |||
176 | === renamed file 'database/schema/patch-2209-58-1.sql' => 'database/schema/archive/patch-2209-58-1.sql' | |||
177 | === renamed file 'database/schema/patch-2209-58-2.sql' => 'database/schema/archive/patch-2209-58-2.sql' | |||
178 | === renamed file 'database/schema/patch-2209-58-3.sql' => 'database/schema/archive/patch-2209-58-3.sql' | |||
179 | === renamed file 'database/schema/patch-2209-58-4.sql' => 'database/schema/archive/patch-2209-58-4.sql' | |||
180 | === renamed file 'database/schema/patch-2209-59-0.sql' => 'database/schema/archive/patch-2209-59-0.sql' | |||
181 | === renamed file 'database/schema/patch-2209-59-1.sql' => 'database/schema/archive/patch-2209-59-1.sql' | |||
182 | === renamed file 'database/schema/patch-2209-59-2.sql' => 'database/schema/archive/patch-2209-59-2.sql' | |||
183 | === renamed file 'database/schema/patch-2209-60-0.sql' => 'database/schema/archive/patch-2209-60-0.sql' | |||
184 | === renamed file 'database/schema/patch-2209-61-0.sql' => 'database/schema/archive/patch-2209-61-0.sql' | |||
185 | === renamed file 'database/schema/patch-2209-61-1.sql' => 'database/schema/archive/patch-2209-61-1.sql' | |||
186 | === renamed file 'database/schema/patch-2209-61-2.sql' => 'database/schema/archive/patch-2209-61-2.sql' | |||
187 | === renamed file 'database/schema/patch-2209-61-3.sql' => 'database/schema/archive/patch-2209-61-3.sql' | |||
188 | === renamed file 'database/schema/patch-2209-61-4.sql' => 'database/schema/archive/patch-2209-61-4.sql' | |||
189 | === renamed file 'database/schema/patch-2209-61-5.sql' => 'database/schema/archive/patch-2209-61-5.sql' | |||
190 | === renamed file 'database/schema/patch-2209-61-6.sql' => 'database/schema/archive/patch-2209-61-6.sql' | |||
191 | === renamed file 'database/schema/patch-2209-61-7.sql' => 'database/schema/archive/patch-2209-61-7.sql' | |||
192 | === renamed file 'database/schema/patch-2209-61-8.sql' => 'database/schema/archive/patch-2209-61-8.sql' | |||
193 | === renamed file 'database/schema/patch-2209-61-9.sql' => 'database/schema/archive/patch-2209-61-9.sql' | |||
194 | === renamed file 'database/schema/patch-2209-62-0.sql' => 'database/schema/archive/patch-2209-62-0.sql' | |||
195 | === renamed file 'database/schema/patch-2209-62-1.sql' => 'database/schema/archive/patch-2209-62-1.sql' | |||
196 | === renamed file 'database/schema/patch-2209-64-0.sql' => 'database/schema/archive/patch-2209-64-0.sql' | |||
197 | === renamed file 'database/schema/patch-2209-64-1.sql' => 'database/schema/archive/patch-2209-64-1.sql' | |||
198 | === renamed file 'database/schema/patch-2209-65-0.sql' => 'database/schema/archive/patch-2209-65-0.sql' | |||
199 | === renamed file 'database/schema/patch-2209-66-0.sql' => 'database/schema/archive/patch-2209-66-0.sql' | |||
200 | === renamed file 'database/schema/patch-2209-66-1.sql' => 'database/schema/archive/patch-2209-66-1.sql' | |||
201 | === renamed file 'database/schema/patch-2209-67-0.sql' => 'database/schema/archive/patch-2209-67-0.sql' | |||
202 | === renamed file 'database/schema/patch-2209-67-1.sql' => 'database/schema/archive/patch-2209-67-1.sql' | |||
203 | === renamed file 'database/schema/patch-2209-67-2.sql' => 'database/schema/archive/patch-2209-67-2.sql' | |||
204 | === renamed file 'database/schema/patch-2209-67-3.sql' => 'database/schema/archive/patch-2209-67-3.sql' | |||
205 | === renamed file 'database/schema/patch-2209-68-0.sql' => 'database/schema/archive/patch-2209-68-0.sql' | |||
206 | === renamed file 'database/schema/patch-2209-68-1.sql' => 'database/schema/archive/patch-2209-68-1.sql' | |||
207 | === renamed file 'database/schema/patch-2209-68-2.sql' => 'database/schema/archive/patch-2209-68-2.sql' | |||
208 | === renamed file 'database/schema/patch-2209-69-0.sql' => 'database/schema/archive/patch-2209-69-0.sql' | |||
209 | === renamed file 'database/schema/patch-2209-69-1.sql' => 'database/schema/archive/patch-2209-69-1.sql' | |||
210 | === renamed file 'database/schema/patch-2209-69-2.sql' => 'database/schema/archive/patch-2209-69-2.sql' | |||
211 | === renamed file 'database/schema/patch-2209-69-3.sql' => 'database/schema/archive/patch-2209-69-3.sql' | |||
212 | === renamed file 'database/schema/patch-2209-69-4.sql' => 'database/schema/archive/patch-2209-69-4.sql' | |||
213 | === renamed file 'database/schema/patch-2209-69-5.sql' => 'database/schema/archive/patch-2209-69-5.sql' | |||
214 | === renamed file 'database/schema/patch-2209-69-6.sql' => 'database/schema/archive/patch-2209-69-6.sql' | |||
215 | === renamed file 'database/schema/patch-2209-69-7.sql' => 'database/schema/archive/patch-2209-69-7.sql' | |||
216 | === renamed file 'database/schema/patch-2209-69-8.sql' => 'database/schema/archive/patch-2209-69-8.sql' | |||
217 | === renamed file 'database/schema/patch-2209-69-9.sql' => 'database/schema/archive/patch-2209-69-9.sql' | |||
218 | === renamed file 'database/schema/patch-2209-70-0.sql' => 'database/schema/archive/patch-2209-70-0.sql' | |||
219 | === renamed file 'database/schema/patch-2209-71-0.sql' => 'database/schema/archive/patch-2209-71-0.sql' | |||
220 | === renamed file 'database/schema/patch-2209-71-1.sql' => 'database/schema/archive/patch-2209-71-1.sql' | |||
221 | === renamed file 'database/schema/patch-2209-72-0.sql' => 'database/schema/archive/patch-2209-72-0.sql' | |||
222 | === renamed file 'database/schema/patch-2209-73-0.sql' => 'database/schema/archive/patch-2209-73-0.sql' | |||
223 | === renamed file 'database/schema/patch-2209-73-1.sql' => 'database/schema/archive/patch-2209-73-1.sql' | |||
224 | === renamed file 'database/schema/patch-2209-74-0.sql' => 'database/schema/archive/patch-2209-74-0.sql' | |||
225 | === renamed file 'database/schema/patch-2209-75-0.sql' => 'database/schema/archive/patch-2209-75-0.sql' | |||
226 | === renamed file 'database/schema/patch-2209-75-1.sql' => 'database/schema/archive/patch-2209-75-1.sql' | |||
227 | === renamed file 'database/schema/patch-2209-77-0.sql' => 'database/schema/archive/patch-2209-77-0.sql' | |||
228 | === renamed file 'database/schema/patch-2209-77-1.sql' => 'database/schema/archive/patch-2209-77-1.sql' | |||
229 | === renamed file 'database/schema/patch-2209-77-2.sql' => 'database/schema/archive/patch-2209-77-2.sql' | |||
230 | === renamed file 'database/schema/patch-2209-77-3.sql' => 'database/schema/archive/patch-2209-77-3.sql' | |||
231 | === renamed file 'database/schema/patch-2209-78-0.sql' => 'database/schema/archive/patch-2209-78-0.sql' | |||
232 | === renamed file 'database/schema/patch-2209-78-1.sql' => 'database/schema/archive/patch-2209-78-1.sql' | |||
233 | === renamed file 'database/schema/patch-2209-78-2.sql' => 'database/schema/archive/patch-2209-78-2.sql' | |||
234 | === renamed file 'database/schema/patch-2209-79-0.sql' => 'database/schema/archive/patch-2209-79-0.sql' | |||
235 | === renamed file 'database/schema/patch-2209-80-0.sql' => 'database/schema/archive/patch-2209-80-0.sql' | |||
236 | === renamed file 'database/schema/patch-2209-80-1.sql' => 'database/schema/archive/patch-2209-80-1.sql' | |||
237 | === renamed file 'database/schema/patch-2209-80-2.sql' => 'database/schema/archive/patch-2209-80-2.sql' | |||
238 | === renamed file 'database/schema/patch-2209-81-0.sql' => 'database/schema/archive/patch-2209-81-0.sql' | |||
239 | === renamed file 'database/schema/patch-2209-82-0.sql' => 'database/schema/archive/patch-2209-82-0.sql' | |||
240 | === renamed file 'database/schema/patch-2209-82-1.sql' => 'database/schema/archive/patch-2209-82-1.sql' | |||
241 | === renamed file 'database/schema/patch-2209-83-0.sql' => 'database/schema/archive/patch-2209-83-0.sql' | |||
242 | === renamed file 'database/schema/patch-2209-83-1.sql' => 'database/schema/archive/patch-2209-83-1.sql' | |||
243 | === renamed file 'database/schema/patch-2209-83-2.sql' => 'database/schema/archive/patch-2209-83-2.sql' | |||
244 | === renamed file 'database/schema/patch-2209-83-3.sql' => 'database/schema/archive/patch-2209-83-3.sql' | |||
245 | === renamed file 'database/schema/patch-2209-83-4.sql' => 'database/schema/archive/patch-2209-83-4.sql' | |||
246 | === renamed file 'database/schema/patch-2209-83-5.sql' => 'database/schema/archive/patch-2209-83-5.sql' | |||
247 | === renamed file 'database/schema/patch-2209-83-6.sql' => 'database/schema/archive/patch-2209-83-6.sql' | |||
248 | === renamed file 'database/schema/patch-2209-84-0.sql' => 'database/schema/archive/patch-2209-84-0.sql' | |||
249 | === renamed file 'database/schema/patch-2209-84-1.sql' => 'database/schema/archive/patch-2209-84-1.sql' | |||
250 | === renamed file 'database/schema/patch-2209-85-0.sql' => 'database/schema/archive/patch-2209-85-0.sql' | |||
251 | === renamed file 'database/schema/patch-2209-85-1.sql' => 'database/schema/archive/patch-2209-85-1.sql' | |||
252 | === renamed file 'database/schema/patch-2209-86-0.sql' => 'database/schema/archive/patch-2209-86-0.sql' | |||
253 | === renamed file 'database/schema/launchpad-2209-00-0.sql' => 'database/schema/launchpad-2210-00-0.sql' | |||
254 | --- database/schema/launchpad-2209-00-0.sql 2015-07-21 09:04:01 +0000 | |||
255 | +++ database/schema/launchpad-2210-00-0.sql 2019-02-26 07:46:16 +0000 | |||
256 | @@ -1,9 +1,11 @@ | |||
258 | 1 | -- Generated Tue Dec 6 20:57:32 2011 UTC | 1 | -- Generated Mon Feb 25 21:35:23 2019 UTC |
259 | 2 | 2 | ||
260 | 3 | SET client_min_messages TO ERROR; | 3 | SET client_min_messages TO ERROR; |
261 | 4 | SET statement_timeout = 0; | 4 | SET statement_timeout = 0; |
262 | 5 | SET lock_timeout = 0; | ||
263 | 5 | SET client_encoding = 'UTF8'; | 6 | SET client_encoding = 'UTF8'; |
264 | 6 | SET standard_conforming_strings = off; | 7 | SET standard_conforming_strings = off; |
265 | 8 | SELECT pg_catalog.set_config('search_path', '', false); | ||
266 | 7 | SET check_function_bodies = false; | 9 | SET check_function_bodies = false; |
267 | 8 | SET client_min_messages = warning; | 10 | SET client_min_messages = warning; |
268 | 9 | SET escape_string_warning = off; | 11 | SET escape_string_warning = off; |
269 | @@ -11,56 +13,72 @@ | |||
270 | 11 | CREATE SCHEMA todrop; | 13 | CREATE SCHEMA todrop; |
271 | 12 | 14 | ||
272 | 13 | 15 | ||
288 | 14 | CREATE SCHEMA ts2; | 16 | CREATE SCHEMA trgm; |
289 | 15 | 17 | ||
290 | 16 | 18 | ||
291 | 17 | CREATE PROCEDURAL LANGUAGE plpgsql; | 19 | CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; |
292 | 18 | 20 | ||
293 | 19 | 21 | ||
294 | 20 | CREATE PROCEDURAL LANGUAGE plpythonu; | 22 | COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; |
295 | 21 | 23 | ||
296 | 22 | 24 | ||
297 | 23 | SET search_path = public, pg_catalog; | 25 | CREATE EXTENSION IF NOT EXISTS plpythonu WITH SCHEMA pg_catalog; |
298 | 24 | 26 | ||
299 | 25 | CREATE TYPE debversion; | 27 | |
300 | 26 | 28 | COMMENT ON EXTENSION plpythonu IS 'PL/PythonU untrusted procedural language'; | |
301 | 27 | 29 | ||
302 | 28 | CREATE FUNCTION debversionin(cstring) RETURNS debversion | 30 | |
303 | 31 | CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA trgm; | ||
304 | 32 | |||
305 | 33 | |||
306 | 34 | COMMENT ON EXTENSION pg_trgm IS 'text similarity measurement and index searching based on trigrams'; | ||
307 | 35 | |||
308 | 36 | |||
309 | 37 | CREATE EXTENSION IF NOT EXISTS pgstattuple WITH SCHEMA public; | ||
310 | 38 | |||
311 | 39 | |||
312 | 40 | COMMENT ON EXTENSION pgstattuple IS 'show tuple-level statistics'; | ||
313 | 41 | |||
314 | 42 | |||
315 | 43 | CREATE TYPE public.debversion; | ||
316 | 44 | |||
317 | 45 | |||
318 | 46 | CREATE FUNCTION public.debversionin(cstring) RETURNS public.debversion | ||
319 | 29 | LANGUAGE internal IMMUTABLE STRICT | 47 | LANGUAGE internal IMMUTABLE STRICT |
320 | 30 | AS $$textin$$; | 48 | AS $$textin$$; |
321 | 31 | 49 | ||
322 | 32 | 50 | ||
324 | 33 | CREATE FUNCTION debversionout(debversion) RETURNS cstring | 51 | CREATE FUNCTION public.debversionout(public.debversion) RETURNS cstring |
325 | 34 | LANGUAGE internal IMMUTABLE STRICT | 52 | LANGUAGE internal IMMUTABLE STRICT |
326 | 35 | AS $$textout$$; | 53 | AS $$textout$$; |
327 | 36 | 54 | ||
328 | 37 | 55 | ||
330 | 38 | CREATE FUNCTION debversionrecv(internal) RETURNS debversion | 56 | CREATE FUNCTION public.debversionrecv(internal) RETURNS public.debversion |
331 | 39 | LANGUAGE internal STABLE STRICT | 57 | LANGUAGE internal STABLE STRICT |
332 | 40 | AS $$textrecv$$; | 58 | AS $$textrecv$$; |
333 | 41 | 59 | ||
334 | 42 | 60 | ||
336 | 43 | CREATE FUNCTION debversionsend(debversion) RETURNS bytea | 61 | CREATE FUNCTION public.debversionsend(public.debversion) RETURNS bytea |
337 | 44 | LANGUAGE internal STABLE STRICT | 62 | LANGUAGE internal STABLE STRICT |
338 | 45 | AS $$textsend$$; | 63 | AS $$textsend$$; |
339 | 46 | 64 | ||
340 | 47 | 65 | ||
342 | 48 | CREATE TYPE debversion ( | 66 | CREATE TYPE public.debversion ( |
343 | 49 | INTERNALLENGTH = variable, | 67 | INTERNALLENGTH = variable, |
348 | 50 | INPUT = debversionin, | 68 | INPUT = public.debversionin, |
349 | 51 | OUTPUT = debversionout, | 69 | OUTPUT = public.debversionout, |
350 | 52 | RECEIVE = debversionrecv, | 70 | RECEIVE = public.debversionrecv, |
351 | 53 | SEND = debversionsend, | 71 | SEND = public.debversionsend, |
352 | 54 | CATEGORY = 'S', | 72 | CATEGORY = 'S', |
353 | 55 | ALIGNMENT = int4, | 73 | ALIGNMENT = int4, |
354 | 56 | STORAGE = extended | 74 | STORAGE = extended |
355 | 57 | ); | 75 | ); |
356 | 58 | 76 | ||
357 | 59 | 77 | ||
362 | 60 | COMMENT ON TYPE debversion IS 'Debian package version number'; | 78 | COMMENT ON TYPE public.debversion IS 'Debian package version number'; |
363 | 61 | 79 | ||
364 | 62 | 80 | ||
365 | 63 | CREATE TYPE pgstattuple_type AS ( | 81 | CREATE TYPE public.pgstattuple_type AS ( |
366 | 64 | table_len bigint, | 82 | table_len bigint, |
367 | 65 | tuple_count bigint, | 83 | tuple_count bigint, |
368 | 66 | tuple_len bigint, | 84 | tuple_len bigint, |
369 | @@ -73,77 +91,337 @@ | |||
370 | 73 | ); | 91 | ); |
371 | 74 | 92 | ||
372 | 75 | 93 | ||
444 | 76 | SET search_path = ts2, pg_catalog; | 94 | CREATE DOMAIN public.ts2_tsvector AS tsvector; |
445 | 77 | 95 | ||
446 | 78 | CREATE DOMAIN gtsq AS text; | 96 | |
447 | 79 | 97 | CREATE FUNCTION public._ftq(text) RETURNS text | |
448 | 80 | 98 | LANGUAGE plpythonu IMMUTABLE STRICT | |
449 | 81 | CREATE DOMAIN gtsvector AS pg_catalog.gtsvector; | 99 | AS $_$ |
450 | 82 | 100 | import re | |
451 | 83 | 101 | ||
452 | 84 | CREATE TYPE statinfo AS ( | 102 | # I think this method would be more robust if we used a real |
453 | 85 | word text, | 103 | # tokenizer and parser to generate the query string, but we need |
454 | 86 | ndoc integer, | 104 | # something suitable for use as a stored procedure which currently |
455 | 87 | nentry integer | 105 | # means no external dependancies. |
456 | 88 | ); | 106 | |
457 | 89 | 107 | # Convert to Unicode | |
458 | 90 | 108 | query = args[0].decode('utf8') | |
459 | 91 | CREATE TYPE tokenout AS ( | 109 | ## plpy.debug('1 query is %s' % repr(query)) |
460 | 92 | tokid integer, | 110 | |
461 | 93 | token text | 111 | # Replace tsquery operators with ' '. '<' begins all the phrase |
462 | 94 | ); | 112 | # search operators, and a standalone '>' is fine. |
463 | 95 | 113 | query = re.sub('[|&!<]', ' ', query) | |
464 | 96 | 114 | ||
465 | 97 | CREATE TYPE tokentype AS ( | 115 | # Normalize whitespace |
466 | 98 | tokid integer, | 116 | query = re.sub("(?u)\s+"," ", query) |
467 | 99 | alias text, | 117 | |
468 | 100 | descr text | 118 | # Convert AND, OR, NOT to tsearch2 punctuation |
469 | 101 | ); | 119 | query = re.sub(r"(?u)\bAND\b", "&", query) |
470 | 102 | 120 | query = re.sub(r"(?u)\bOR\b", "|", query) | |
471 | 103 | 121 | query = re.sub(r"(?u)\bNOT\b", " !", query) | |
472 | 104 | CREATE TYPE tsdebug AS ( | 122 | ## plpy.debug('2 query is %s' % repr(query)) |
473 | 105 | ts_name text, | 123 | |
474 | 106 | tok_type text, | 124 | # Deal with unwanted punctuation. |
475 | 107 | description text, | 125 | # ':' is used in queries to specify a weight of a word. |
476 | 108 | token text, | 126 | # '\' is treated differently in to_tsvector() and to_tsquery(). |
477 | 109 | dict_name text[], | 127 | punctuation = r'[:\\]' |
478 | 110 | tsvector pg_catalog.tsvector | 128 | query = re.sub(r"(?u)%s+" % (punctuation,), " ", query) |
479 | 111 | ); | 129 | ## plpy.debug('3 query is %s' % repr(query)) |
480 | 112 | 130 | ||
481 | 113 | 131 | # Now that we have handle case sensitive booleans, convert to lowercase | |
482 | 114 | CREATE DOMAIN tsquery AS pg_catalog.tsquery; | 132 | query = query.lower() |
483 | 115 | 133 | ||
484 | 116 | 134 | # Remove unpartnered bracket on the left and right | |
485 | 117 | CREATE DOMAIN tsvector AS pg_catalog.tsvector; | 135 | query = re.sub(r"(?ux) ^ ( [^(]* ) \)", r"(\1)", query) |
486 | 118 | 136 | query = re.sub(r"(?ux) \( ( [^)]* ) $", r"(\1)", query) | |
487 | 119 | 137 | ||
488 | 120 | SET search_path = public, pg_catalog; | 138 | # Remove spurious brackets |
489 | 121 | 139 | query = re.sub(r"(?u)\(([^\&\|]*?)\)", r" \1 ", query) | |
490 | 122 | CREATE FUNCTION activity() RETURNS SETOF pg_stat_activity | 140 | ## plpy.debug('5 query is %s' % repr(query)) |
491 | 123 | LANGUAGE sql SECURITY DEFINER | 141 | |
492 | 124 | SET search_path TO public | 142 | # Insert & between tokens without an existing boolean operator |
493 | 125 | AS $$ | 143 | # ( not proceeded by (|&! |
494 | 126 | SELECT | 144 | query = re.sub(r"(?u)(?<![\(\|\&\!])\s*\(", "&(", query) |
495 | 127 | datid, datname, procpid, usesysid, usename, | 145 | ## plpy.debug('6 query is %s' % repr(query)) |
496 | 128 | CASE | 146 | # ) not followed by )|& |
497 | 129 | WHEN current_query LIKE '<IDLE>%' | 147 | query = re.sub(r"(?u)\)(?!\s*(\)|\||\&|\s*$))", ")&", query) |
498 | 130 | OR current_query LIKE 'autovacuum:%' | 148 | ## plpy.debug('6.1 query is %s' % repr(query)) |
499 | 131 | THEN current_query | 149 | # Whitespace not proceded by (|&! not followed by &| |
500 | 132 | ELSE | 150 | query = re.sub(r"(?u)(?<![\(\|\&\!\s])\s+(?![\&\|\s])", "&", query) |
501 | 133 | '<HIDDEN>' | 151 | ## plpy.debug('7 query is %s' % repr(query)) |
502 | 134 | END AS current_query, | 152 | |
503 | 135 | waiting, xact_start, query_start, | 153 | # Detect and repair syntax errors - we are lenient because |
504 | 136 | backend_start, client_addr, client_port | 154 | # this input is generally from users. |
505 | 137 | FROM pg_catalog.pg_stat_activity; | 155 | |
506 | 138 | $$; | 156 | # Fix unbalanced brackets |
507 | 139 | 157 | openings = query.count("(") | |
508 | 140 | 158 | closings = query.count(")") | |
509 | 141 | COMMENT ON FUNCTION activity() IS 'SECURITY DEFINER wrapper around pg_stat_activity allowing unprivileged users to access most of its information.'; | 159 | if openings > closings: |
510 | 142 | 160 | query = query + " ) "*(openings-closings) | |
511 | 143 | 161 | elif closings > openings: | |
512 | 144 | CREATE FUNCTION add_test_openid_identifier(account_ integer) RETURNS boolean | 162 | query = " ( "*(closings-openings) + query |
513 | 145 | LANGUAGE plpgsql SECURITY DEFINER | 163 | ## plpy.debug('8 query is %s' % repr(query)) |
514 | 146 | SET search_path TO public | 164 | |
515 | 165 | # Strip ' character that do not have letters on both sides | ||
516 | 166 | query = re.sub(r"(?u)((?<!\w)'|'(?!\w))", "", query) | ||
517 | 167 | |||
518 | 168 | # Brackets containing nothing but whitespace and booleans, recursive | ||
519 | 169 | last = "" | ||
520 | 170 | while last != query: | ||
521 | 171 | last = query | ||
522 | 172 | query = re.sub(r"(?u)\([\s\&\|\!]*\)", "", query) | ||
523 | 173 | ## plpy.debug('9 query is %s' % repr(query)) | ||
524 | 174 | |||
525 | 175 | # An & or | following a ( | ||
526 | 176 | query = re.sub(r"(?u)(?<=\()[\&\|\s]+", "", query) | ||
527 | 177 | ## plpy.debug('10 query is %s' % repr(query)) | ||
528 | 178 | |||
529 | 179 | # An &, | or ! immediatly before a ) | ||
530 | 180 | query = re.sub(r"(?u)[\&\|\!\s]*[\&\|\!]+\s*(?=\))", "", query) | ||
531 | 181 | ## plpy.debug('11 query is %s' % repr(query)) | ||
532 | 182 | |||
533 | 183 | # An &,| or ! followed by another boolean. | ||
534 | 184 | query = re.sub(r"(?ux) \s* ( [\&\|\!] ) [\s\&\|]+", r"\1", query) | ||
535 | 185 | ## plpy.debug('12 query is %s' % repr(query)) | ||
536 | 186 | |||
537 | 187 | # Leading & or | | ||
538 | 188 | query = re.sub(r"(?u)^[\s\&\|]+", "", query) | ||
539 | 189 | ## plpy.debug('13 query is %s' % repr(query)) | ||
540 | 190 | |||
541 | 191 | # Trailing &, | or ! | ||
542 | 192 | query = re.sub(r"(?u)[\&\|\!\s]+$", "", query) | ||
543 | 193 | ## plpy.debug('14 query is %s' % repr(query)) | ||
544 | 194 | |||
545 | 195 | # If we have nothing but whitespace and tsearch2 operators, | ||
546 | 196 | # return NULL. | ||
547 | 197 | if re.search(r"(?u)^[\&\|\!\s\(\)]*$", query) is not None: | ||
548 | 198 | return None | ||
549 | 199 | |||
550 | 200 | # Convert back to UTF-8 | ||
551 | 201 | query = query.encode('utf8') | ||
552 | 202 | ## plpy.debug('15 query is %s' % repr(query)) | ||
553 | 203 | |||
554 | 204 | return query or None | ||
555 | 205 | $_$; | ||
556 | 206 | |||
557 | 207 | |||
558 | 208 | CREATE FUNCTION public.accessartifact_denorm_to_artifacts(artifact_id integer) RETURNS void | ||
559 | 209 | LANGUAGE plpgsql | ||
560 | 210 | AS $$ | ||
561 | 211 | DECLARE | ||
562 | 212 | artifact_row accessartifact%ROWTYPE; | ||
563 | 213 | BEGIN | ||
564 | 214 | SELECT * INTO artifact_row FROM accessartifact WHERE id = artifact_id; | ||
565 | 215 | IF artifact_row.bug IS NOT NULL THEN | ||
566 | 216 | PERFORM bug_flatten_access(artifact_row.bug); | ||
567 | 217 | END IF; | ||
568 | 218 | IF artifact_row.branch IS NOT NULL THEN | ||
569 | 219 | PERFORM branch_denorm_access(artifact_row.branch); | ||
570 | 220 | END IF; | ||
571 | 221 | IF artifact_row.gitrepository IS NOT NULL THEN | ||
572 | 222 | PERFORM gitrepository_denorm_access(artifact_row.gitrepository); | ||
573 | 223 | END IF; | ||
574 | 224 | IF artifact_row.specification IS NOT NULL THEN | ||
575 | 225 | PERFORM specification_denorm_access(artifact_row.specification); | ||
576 | 226 | END IF; | ||
577 | 227 | RETURN; | ||
578 | 228 | END; | ||
579 | 229 | $$; | ||
580 | 230 | |||
581 | 231 | |||
582 | 232 | COMMENT ON FUNCTION public.accessartifact_denorm_to_artifacts(artifact_id integer) IS 'Denormalize the policy access and artifact grants to bugs, branches, Git repositories, and specifications.'; | ||
583 | 233 | |||
584 | 234 | |||
585 | 235 | CREATE FUNCTION public.accessartifact_maintain_denorm_to_artifacts_trig() RETURNS trigger | ||
586 | 236 | LANGUAGE plpgsql | ||
587 | 237 | AS $$ | ||
588 | 238 | BEGIN | ||
589 | 239 | IF TG_OP = 'INSERT' THEN | ||
590 | 240 | PERFORM accessartifact_denorm_to_artifacts(NEW.artifact); | ||
591 | 241 | ELSIF TG_OP = 'UPDATE' THEN | ||
592 | 242 | PERFORM accessartifact_denorm_to_artifacts(NEW.artifact); | ||
593 | 243 | IF OLD.artifact != NEW.artifact THEN | ||
594 | 244 | PERFORM accessartifact_denorm_to_artifacts(OLD.artifact); | ||
595 | 245 | END IF; | ||
596 | 246 | ELSIF TG_OP = 'DELETE' THEN | ||
597 | 247 | PERFORM accessartifact_denorm_to_artifacts(OLD.artifact); | ||
598 | 248 | END IF; | ||
599 | 249 | RETURN NULL; | ||
600 | 250 | END; | ||
601 | 251 | $$; | ||
602 | 252 | |||
603 | 253 | |||
604 | 254 | CREATE FUNCTION public.accessartifactgrant_maintain_accesspolicygrantflat_trig() RETURNS trigger | ||
605 | 255 | LANGUAGE plpgsql SECURITY DEFINER | ||
606 | 256 | SET search_path TO 'public' | ||
607 | 257 | AS $$ | ||
608 | 258 | BEGIN | ||
609 | 259 | IF TG_OP = 'INSERT' THEN | ||
610 | 260 | INSERT INTO AccessPolicyGrantFlat | ||
611 | 261 | (policy, artifact, grantee) | ||
612 | 262 | SELECT policy, NEW.artifact, NEW.grantee | ||
613 | 263 | FROM AccessPolicyArtifact WHERE artifact = NEW.artifact; | ||
614 | 264 | ELSIF TG_OP = 'UPDATE' THEN | ||
615 | 265 | IF NEW.artifact != OLD.artifact OR NEW.grantee != OLD.grantee THEN | ||
616 | 266 | UPDATE AccessPolicyGrantFlat | ||
617 | 267 | SET artifact=NEW.artifact, grantee=NEW.grantee | ||
618 | 268 | WHERE artifact = OLD.artifact AND grantee = OLD.grantee; | ||
619 | 269 | END IF; | ||
620 | 270 | ELSIF TG_OP = 'DELETE' THEN | ||
621 | 271 | DELETE FROM AccessPolicyGrantFlat | ||
622 | 272 | WHERE artifact = OLD.artifact AND grantee = OLD.grantee; | ||
623 | 273 | END IF; | ||
624 | 274 | RETURN NULL; | ||
625 | 275 | END; | ||
626 | 276 | $$; | ||
627 | 277 | |||
628 | 278 | |||
629 | 279 | CREATE FUNCTION public.accesspolicyartifact_maintain_accesspolicyartifactflat_trig() RETURNS trigger | ||
630 | 280 | LANGUAGE plpgsql SECURITY DEFINER | ||
631 | 281 | SET search_path TO 'public' | ||
632 | 282 | AS $$ | ||
633 | 283 | BEGIN | ||
634 | 284 | IF TG_OP = 'INSERT' THEN | ||
635 | 285 | INSERT INTO AccessPolicyGrantFlat | ||
636 | 286 | (policy, artifact, grantee) | ||
637 | 287 | SELECT NEW.policy, NEW.artifact, grantee | ||
638 | 288 | FROM AccessArtifactGrant WHERE artifact = NEW.artifact; | ||
639 | 289 | ELSIF TG_OP = 'UPDATE' THEN | ||
640 | 290 | IF NEW.policy != OLD.policy OR NEW.artifact != OLD.artifact THEN | ||
641 | 291 | UPDATE AccessPolicyGrantFlat | ||
642 | 292 | SET policy=NEW.policy, artifact=NEW.artifact | ||
643 | 293 | WHERE policy = OLD.policy AND artifact = OLD.artifact; | ||
644 | 294 | END IF; | ||
645 | 295 | ELSIF TG_OP = 'DELETE' THEN | ||
646 | 296 | DELETE FROM AccessPolicyGrantFlat | ||
647 | 297 | WHERE policy = OLD.policy AND artifact = OLD.artifact; | ||
648 | 298 | END IF; | ||
649 | 299 | RETURN NULL; | ||
650 | 300 | END; | ||
651 | 301 | $$; | ||
652 | 302 | |||
653 | 303 | |||
654 | 304 | CREATE FUNCTION public.accesspolicygrant_maintain_accesspolicygrantflat_trig() RETURNS trigger | ||
655 | 305 | LANGUAGE plpgsql SECURITY DEFINER | ||
656 | 306 | SET search_path TO 'public' | ||
657 | 307 | AS $$ | ||
658 | 308 | BEGIN | ||
659 | 309 | IF TG_OP = 'INSERT' THEN | ||
660 | 310 | INSERT INTO AccessPolicyGrantFlat | ||
661 | 311 | (policy, grantee) VALUES (NEW.policy, NEW.grantee); | ||
662 | 312 | ELSIF TG_OP = 'UPDATE' THEN | ||
663 | 313 | IF NEW.policy != OLD.policy OR NEW.grantee != OLD.grantee THEN | ||
664 | 314 | UPDATE AccessPolicyGrantFlat | ||
665 | 315 | SET policy=NEW.policy, grantee=NEW.grantee | ||
666 | 316 | WHERE | ||
667 | 317 | policy = OLD.policy | ||
668 | 318 | AND grantee = OLD.grantee | ||
669 | 319 | AND artifact IS NULL; | ||
670 | 320 | END IF; | ||
671 | 321 | ELSIF TG_OP = 'DELETE' THEN | ||
672 | 322 | DELETE FROM AccessPolicyGrantFlat | ||
673 | 323 | WHERE | ||
674 | 324 | policy = OLD.policy | ||
675 | 325 | AND grantee = OLD.grantee | ||
676 | 326 | AND artifact IS NULL; | ||
677 | 327 | END IF; | ||
678 | 328 | RETURN NULL; | ||
679 | 329 | END; | ||
680 | 330 | $$; | ||
681 | 331 | |||
682 | 332 | |||
683 | 333 | CREATE FUNCTION public.activity() RETURNS SETOF pg_stat_activity | ||
684 | 334 | LANGUAGE plpgsql SECURITY DEFINER | ||
685 | 335 | SET search_path TO 'public' | ||
686 | 336 | AS $$ | ||
687 | 337 | DECLARE | ||
688 | 338 | a pg_stat_activity%ROWTYPE; | ||
689 | 339 | BEGIN | ||
690 | 340 | IF EXISTS ( | ||
691 | 341 | SELECT 1 FROM pg_attribute WHERE | ||
692 | 342 | attrelid = | ||
693 | 343 | (SELECT oid FROM pg_class | ||
694 | 344 | WHERE relname = 'pg_stat_activity') | ||
695 | 345 | AND attname = 'backend_type') THEN | ||
696 | 346 | -- >= 10 | ||
697 | 347 | RETURN QUERY SELECT | ||
698 | 348 | datid, datname, pid, usesysid, usename, application_name, | ||
699 | 349 | client_addr, client_hostname, client_port, backend_start, | ||
700 | 350 | xact_start, query_start, state_change, wait_event_type, | ||
701 | 351 | wait_event, state, backend_xid, backend_xmin, backend_type, | ||
702 | 352 | CASE | ||
703 | 353 | WHEN query LIKE '<IDLE>%' | ||
704 | 354 | OR query LIKE 'autovacuum:%' | ||
705 | 355 | THEN query | ||
706 | 356 | ELSE | ||
707 | 357 | '<HIDDEN>' | ||
708 | 358 | END AS query | ||
709 | 359 | FROM pg_catalog.pg_stat_activity; | ||
710 | 360 | ELSIF EXISTS ( | ||
711 | 361 | SELECT 1 FROM pg_attribute WHERE | ||
712 | 362 | attrelid = | ||
713 | 363 | (SELECT oid FROM pg_class | ||
714 | 364 | WHERE relname = 'pg_stat_activity') | ||
715 | 365 | AND attname = 'wait_event_type') THEN | ||
716 | 366 | -- >= 9.6 | ||
717 | 367 | RETURN QUERY SELECT | ||
718 | 368 | datid, datname, pid, usesysid, usename, application_name, | ||
719 | 369 | client_addr, client_hostname, client_port, backend_start, | ||
720 | 370 | xact_start, query_start, state_change, wait_event_type, | ||
721 | 371 | wait_event, state, backend_xid, backend_xmin, | ||
722 | 372 | CASE | ||
723 | 373 | WHEN query LIKE '<IDLE>%' | ||
724 | 374 | OR query LIKE 'autovacuum:%' | ||
725 | 375 | THEN query | ||
726 | 376 | ELSE | ||
727 | 377 | '<HIDDEN>' | ||
728 | 378 | END AS query | ||
729 | 379 | FROM pg_catalog.pg_stat_activity; | ||
730 | 380 | ELSIF EXISTS ( | ||
731 | 381 | SELECT 1 FROM pg_attribute WHERE | ||
732 | 382 | attrelid = | ||
733 | 383 | (SELECT oid FROM pg_class | ||
734 | 384 | WHERE relname = 'pg_stat_activity') | ||
735 | 385 | AND attname = 'backend_xid') THEN | ||
736 | 386 | -- >= 9.4 | ||
737 | 387 | RETURN QUERY SELECT | ||
738 | 388 | datid, datname, pid, usesysid, usename, application_name, | ||
739 | 389 | client_addr, client_hostname, client_port, backend_start, | ||
740 | 390 | xact_start, query_start, state_change, waiting, state, | ||
741 | 391 | backend_xid, backend_xmin, | ||
742 | 392 | CASE | ||
743 | 393 | WHEN query LIKE '<IDLE>%' | ||
744 | 394 | OR query LIKE 'autovacuum:%' | ||
745 | 395 | THEN query | ||
746 | 396 | ELSE | ||
747 | 397 | '<HIDDEN>' | ||
748 | 398 | END AS query | ||
749 | 399 | FROM pg_catalog.pg_stat_activity; | ||
750 | 400 | ELSE | ||
751 | 401 | -- >= 9.2; anything older is unsupported | ||
752 | 402 | RETURN QUERY SELECT | ||
753 | 403 | datid, datname, pid, usesysid, usename, application_name, | ||
754 | 404 | client_addr, client_hostname, client_port, backend_start, | ||
755 | 405 | xact_start, query_start, state_change, waiting, state, | ||
756 | 406 | CASE | ||
757 | 407 | WHEN query LIKE '<IDLE>%' | ||
758 | 408 | OR query LIKE 'autovacuum:%' | ||
759 | 409 | THEN query | ||
760 | 410 | ELSE | ||
761 | 411 | '<HIDDEN>' | ||
762 | 412 | END AS query | ||
763 | 413 | FROM pg_catalog.pg_stat_activity; | ||
764 | 414 | END IF; | ||
765 | 415 | END; | ||
766 | 416 | $$; | ||
767 | 417 | |||
768 | 418 | |||
769 | 419 | COMMENT ON FUNCTION public.activity() IS 'SECURITY DEFINER wrapper around pg_stat_activity allowing unprivileged users to access most of its information.'; | ||
770 | 420 | |||
771 | 421 | |||
772 | 422 | CREATE FUNCTION public.add_test_openid_identifier(account_ integer) RETURNS boolean | ||
773 | 423 | LANGUAGE plpgsql SECURITY DEFINER | ||
774 | 424 | SET search_path TO 'public' | ||
775 | 147 | AS $$ | 425 | AS $$ |
776 | 148 | BEGIN | 426 | BEGIN |
777 | 149 | -- The generated OpenIdIdentifier is not a valid OpenId Identity URL | 427 | -- The generated OpenIdIdentifier is not a valid OpenId Identity URL |
778 | @@ -161,10 +439,10 @@ | |||
779 | 161 | $$; | 439 | $$; |
780 | 162 | 440 | ||
781 | 163 | 441 | ||
786 | 164 | COMMENT ON FUNCTION add_test_openid_identifier(account_ integer) IS 'Add an OpenIdIdentifier to an account that can be used to login in the test environment. These identifiers are not usable on production or staging.'; | 442 | COMMENT ON FUNCTION public.add_test_openid_identifier(account_ integer) IS 'Add an OpenIdIdentifier to an account that can be used to login in the test environment. These identifiers are not usable on production or staging.'; |
787 | 165 | 443 | ||
788 | 166 | 444 | ||
789 | 167 | CREATE FUNCTION assert_patch_applied(major integer, minor integer, patch integer) RETURNS boolean | 445 | CREATE FUNCTION public.assert_patch_applied(major integer, minor integer, patch integer) RETURNS boolean |
790 | 168 | LANGUAGE plpythonu STABLE | 446 | LANGUAGE plpythonu STABLE |
791 | 169 | AS $$ | 447 | AS $$ |
792 | 170 | rv = plpy.execute(""" | 448 | rv = plpy.execute(""" |
793 | @@ -179,39 +457,98 @@ | |||
794 | 179 | $$; | 457 | $$; |
795 | 180 | 458 | ||
796 | 181 | 459 | ||
801 | 182 | COMMENT ON FUNCTION assert_patch_applied(major integer, minor integer, patch integer) IS 'Raise an exception if the given database patch has not been applied.'; | 460 | COMMENT ON FUNCTION public.assert_patch_applied(major integer, minor integer, patch integer) IS 'Raise an exception if the given database patch has not been applied.'; |
802 | 183 | 461 | ||
803 | 184 | 462 | ||
804 | 185 | CREATE FUNCTION bug_maintain_bug_summary() RETURNS trigger | 463 | CREATE FUNCTION public.branch_denorm_access(branch_id integer) RETURNS void |
805 | 464 | LANGUAGE sql SECURITY DEFINER | ||
806 | 465 | SET search_path TO 'public' | ||
807 | 466 | AS $_$ | ||
808 | 467 | UPDATE branch | ||
809 | 468 | SET access_policy = policies[1], access_grants = grants | ||
810 | 469 | FROM | ||
811 | 470 | build_access_cache( | ||
812 | 471 | (SELECT id FROM accessartifact WHERE branch = $1), | ||
813 | 472 | (SELECT information_type FROM branch WHERE id = $1)) | ||
814 | 473 | AS (policies integer[], grants integer[]) | ||
815 | 474 | WHERE id = $1; | ||
816 | 475 | $_$; | ||
817 | 476 | |||
818 | 477 | |||
819 | 478 | CREATE FUNCTION public.branch_maintain_access_cache_trig() RETURNS trigger | ||
820 | 479 | LANGUAGE plpgsql | ||
821 | 480 | AS $$ | ||
822 | 481 | BEGIN | ||
823 | 482 | PERFORM branch_denorm_access(NEW.id); | ||
824 | 483 | RETURN NULL; | ||
825 | 484 | END; | ||
826 | 485 | $$; | ||
827 | 486 | |||
828 | 487 | |||
829 | 488 | CREATE FUNCTION public.bug_build_access_cache(bug_id integer, information_type integer) RETURNS record | ||
830 | 489 | LANGUAGE sql | ||
831 | 490 | AS $_$ | ||
832 | 491 | SELECT build_access_cache( | ||
833 | 492 | (SELECT id FROM accessartifact WHERE bug = $1), $2); | ||
834 | 493 | $_$; | ||
835 | 494 | |||
836 | 495 | |||
837 | 496 | COMMENT ON FUNCTION public.bug_build_access_cache(bug_id integer, information_type integer) IS 'Build an access cache for the given bug. Returns ({AccessPolicyArtifact.policy}, {AccessArtifactGrant.grantee}) for private bugs, or (NULL, NULL) for public ones.'; | ||
838 | 497 | |||
839 | 498 | |||
840 | 499 | CREATE FUNCTION public.bug_flatten_access(bug_id integer) RETURNS void | ||
841 | 500 | LANGUAGE sql SECURITY DEFINER | ||
842 | 501 | SET search_path TO 'public' | ||
843 | 502 | AS $_$ | ||
844 | 503 | UPDATE bugtaskflat | ||
845 | 504 | SET access_policies = policies, access_grants = grants | ||
846 | 505 | FROM | ||
847 | 506 | build_access_cache( | ||
848 | 507 | (SELECT id FROM accessartifact WHERE bug = $1), | ||
849 | 508 | (SELECT information_type FROM bug WHERE id = $1)) | ||
850 | 509 | AS (policies integer[], grants integer[]) | ||
851 | 510 | WHERE bug = $1; | ||
852 | 511 | $_$; | ||
853 | 512 | |||
854 | 513 | |||
855 | 514 | COMMENT ON FUNCTION public.bug_flatten_access(bug_id integer) IS 'Recalculate the access cache on a bug''s flattened tasks.'; | ||
856 | 515 | |||
857 | 516 | |||
858 | 517 | CREATE FUNCTION public.bug_maintain_bugtaskflat_trig() RETURNS trigger | ||
859 | 186 | LANGUAGE plpgsql SECURITY DEFINER | 518 | LANGUAGE plpgsql SECURITY DEFINER |
861 | 187 | SET search_path TO public | 519 | SET search_path TO 'public' |
862 | 188 | AS $$ | 520 | AS $$ |
863 | 189 | BEGIN | 521 | BEGIN |
881 | 190 | -- There is no INSERT logic, as a bug will not have any summary | 522 | IF ( |
882 | 191 | -- information until BugTask rows have been attached. | 523 | NEW.duplicateof IS DISTINCT FROM OLD.duplicateof |
883 | 192 | IF TG_OP = 'UPDATE' THEN | 524 | OR NEW.owner IS DISTINCT FROM OLD.owner |
884 | 193 | IF OLD.duplicateof IS DISTINCT FROM NEW.duplicateof | 525 | OR NEW.fti IS DISTINCT FROM OLD.fti |
885 | 194 | OR OLD.private IS DISTINCT FROM NEW.private | 526 | OR NEW.information_type IS DISTINCT FROM OLD.information_type |
886 | 195 | OR (OLD.latest_patch_uploaded IS NULL) | 527 | OR NEW.date_last_updated IS DISTINCT FROM OLD.date_last_updated |
887 | 196 | <> (NEW.latest_patch_uploaded IS NULL) THEN | 528 | OR NEW.heat IS DISTINCT FROM OLD.heat |
888 | 197 | PERFORM unsummarise_bug(OLD); | 529 | OR NEW.latest_patch_uploaded IS DISTINCT FROM |
889 | 198 | PERFORM summarise_bug(NEW); | 530 | OLD.latest_patch_uploaded) THEN |
890 | 199 | END IF; | 531 | UPDATE bugtaskflat |
891 | 200 | 532 | SET | |
892 | 201 | ELSIF TG_OP = 'DELETE' THEN | 533 | duplicateof = NEW.duplicateof, |
893 | 202 | PERFORM unsummarise_bug(OLD); | 534 | bug_owner = NEW.owner, |
894 | 203 | END IF; | 535 | fti = NEW.fti, |
895 | 204 | 536 | information_type = NEW.information_type, | |
896 | 205 | PERFORM bug_summary_flush_temp_journal(); | 537 | date_last_updated = NEW.date_last_updated, |
897 | 206 | RETURN NULL; -- Ignored - this is an AFTER trigger | 538 | heat = NEW.heat, |
898 | 539 | latest_patch_uploaded = NEW.latest_patch_uploaded | ||
899 | 540 | WHERE bug = OLD.id; | ||
900 | 541 | END IF; | ||
901 | 542 | |||
902 | 543 | IF NEW.information_type IS DISTINCT FROM OLD.information_type THEN | ||
903 | 544 | PERFORM bug_flatten_access(OLD.id); | ||
904 | 545 | END IF; | ||
905 | 546 | RETURN NULL; | ||
906 | 207 | END; | 547 | END; |
907 | 208 | $$; | 548 | $$; |
908 | 209 | 549 | ||
909 | 210 | 550 | ||
914 | 211 | COMMENT ON FUNCTION bug_maintain_bug_summary() IS 'AFTER trigger on bug maintaining the bugs summaries in bugsummary.'; | 551 | CREATE FUNCTION public.valid_bug_name(text) RETURNS boolean |
911 | 212 | |||
912 | 213 | |||
913 | 214 | CREATE FUNCTION valid_bug_name(text) RETURNS boolean | ||
915 | 215 | LANGUAGE plpythonu IMMUTABLE STRICT | 552 | LANGUAGE plpythonu IMMUTABLE STRICT |
916 | 216 | AS $_$ | 553 | AS $_$ |
917 | 217 | import re | 554 | import re |
918 | @@ -223,7 +560,7 @@ | |||
919 | 223 | $_$; | 560 | $_$; |
920 | 224 | 561 | ||
921 | 225 | 562 | ||
923 | 226 | COMMENT ON FUNCTION valid_bug_name(text) IS 'validate a bug name | 563 | COMMENT ON FUNCTION public.valid_bug_name(text) IS 'validate a bug name |
924 | 227 | 564 | ||
925 | 228 | As per valid_name, except numeric-only names are not allowed (including | 565 | As per valid_name, except numeric-only names are not allowed (including |
926 | 229 | names that look like floats).'; | 566 | names that look like floats).'; |
927 | @@ -233,7 +570,7 @@ | |||
928 | 233 | 570 | ||
929 | 234 | SET default_with_oids = false; | 571 | SET default_with_oids = false; |
930 | 235 | 572 | ||
932 | 236 | CREATE TABLE bug ( | 573 | CREATE TABLE public.bug ( |
933 | 237 | id integer NOT NULL, | 574 | id integer NOT NULL, |
934 | 238 | datecreated timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL, | 575 | datecreated timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone) NOT NULL, |
935 | 239 | name text, | 576 | name text, |
936 | @@ -241,9 +578,7 @@ | |||
937 | 241 | description text NOT NULL, | 578 | description text NOT NULL, |
938 | 242 | owner integer NOT NULL, | 579 | owner integer NOT NULL, |
939 | 243 | duplicateof integer, | 580 | duplicateof integer, |
943 | 244 | fti ts2.tsvector, | 581 | fti public.ts2_tsvector, |
941 | 245 | private boolean DEFAULT false NOT NULL, | ||
942 | 246 | security_related boolean DEFAULT false NOT NULL, | ||
944 | 247 | date_last_updated timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL, | 582 | date_last_updated timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL, |
945 | 248 | date_made_private timestamp without time zone, | 583 | date_made_private timestamp without time zone, |
946 | 249 | who_made_private integer, | 584 | who_made_private integer, |
947 | @@ -255,60 +590,57 @@ | |||
948 | 255 | heat integer DEFAULT 0 NOT NULL, | 590 | heat integer DEFAULT 0 NOT NULL, |
949 | 256 | heat_last_updated timestamp without time zone, | 591 | heat_last_updated timestamp without time zone, |
950 | 257 | latest_patch_uploaded timestamp without time zone, | 592 | latest_patch_uploaded timestamp without time zone, |
952 | 258 | access_policy integer, | 593 | information_type integer NOT NULL, |
953 | 259 | CONSTRAINT notduplicateofself CHECK ((NOT (id = duplicateof))), | 594 | CONSTRAINT notduplicateofself CHECK ((NOT (id = duplicateof))), |
954 | 260 | CONSTRAINT sane_description CHECK (((ltrim(description) <> ''::text) AND (char_length(description) <= 50000))), | 595 | CONSTRAINT sane_description CHECK (((ltrim(description) <> ''::text) AND (char_length(description) <= 50000))), |
956 | 261 | CONSTRAINT valid_bug_name CHECK (valid_bug_name(name)) | 596 | CONSTRAINT valid_bug_name CHECK (public.valid_bug_name(name)) |
957 | 262 | ); | 597 | ); |
958 | 263 | 598 | ||
959 | 264 | 599 | ||
997 | 265 | COMMENT ON TABLE bug IS 'A software bug that requires fixing. This particular bug may be linked to one or more products or source packages to identify the location(s) that this bug is found.'; | 600 | COMMENT ON TABLE public.bug IS 'A software bug that requires fixing. This particular bug may be linked to one or more products or source packages to identify the location(s) that this bug is found.'; |
998 | 266 | 601 | ||
999 | 267 | 602 | ||
1000 | 268 | COMMENT ON COLUMN bug.name IS 'A lowercase name uniquely identifying the bug'; | 603 | COMMENT ON COLUMN public.bug.name IS 'A lowercase name uniquely identifying the bug'; |
1001 | 269 | 604 | ||
1002 | 270 | 605 | ||
1003 | 271 | COMMENT ON COLUMN bug.description IS 'A detailed description of the bug. Initially this will be set to the contents of the initial email or bug filing comment, but later it can be edited to give a more accurate description of the bug itself rather than the symptoms observed by the reporter.'; | 606 | COMMENT ON COLUMN public.bug.description IS 'A detailed description of the bug. Initially this will be set to the contents of the initial email or bug filing comment, but later it can be edited to give a more accurate description of the bug itself rather than the symptoms observed by the reporter.'; |
1004 | 272 | 607 | ||
1005 | 273 | 608 | ||
1006 | 274 | COMMENT ON COLUMN bug.private IS 'Is this bug private? If so, only explicit subscribers will be able to see it'; | 609 | COMMENT ON COLUMN public.bug.date_last_message IS 'When the last BugMessage was attached to this Bug. Maintained by a trigger on the BugMessage table.'; |
1007 | 275 | 610 | ||
1008 | 276 | 611 | ||
1009 | 277 | COMMENT ON COLUMN bug.security_related IS 'Is this bug a security issue?'; | 612 | COMMENT ON COLUMN public.bug.number_of_duplicates IS 'The number of bugs marked as duplicates of this bug, populated by a trigger after setting the duplicateof of bugs.'; |
1010 | 278 | 613 | ||
1011 | 279 | 614 | ||
1012 | 280 | COMMENT ON COLUMN bug.date_last_message IS 'When the last BugMessage was attached to this Bug. Maintained by a trigger on the BugMessage table.'; | 615 | COMMENT ON COLUMN public.bug.message_count IS 'The number of messages (currently just comments) on this bugbug, maintained by the set_bug_message_count_t trigger.'; |
1013 | 281 | 616 | ||
1014 | 282 | 617 | ||
1015 | 283 | COMMENT ON COLUMN bug.number_of_duplicates IS 'The number of bugs marked as duplicates of this bug, populated by a trigger after setting the duplicateof of bugs.'; | 618 | COMMENT ON COLUMN public.bug.users_affected_count IS 'The number of users affected by this bug, maintained by the set_bug_users_affected_count_t trigger.'; |
1016 | 284 | 619 | ||
1017 | 285 | 620 | ||
1018 | 286 | COMMENT ON COLUMN bug.message_count IS 'The number of messages (currently just comments) on this bugbug, maintained by the set_bug_message_count_t trigger.'; | 621 | COMMENT ON COLUMN public.bug.heat IS 'The relevance of this bug. This value is computed periodically using bug_affects_person and other bug values.'; |
1019 | 287 | 622 | ||
1020 | 288 | 623 | ||
1021 | 289 | COMMENT ON COLUMN bug.users_affected_count IS 'The number of users affected by this bug, maintained by the set_bug_users_affected_count_t trigger.'; | 624 | COMMENT ON COLUMN public.bug.heat_last_updated IS 'The time this bug''s heat was last updated, or NULL if the heat has never yet been updated.'; |
1022 | 290 | 625 | ||
1023 | 291 | 626 | ||
1024 | 292 | COMMENT ON COLUMN bug.heat IS 'The relevance of this bug. This value is computed periodically using bug_affects_person and other bug values.'; | 627 | COMMENT ON COLUMN public.bug.latest_patch_uploaded IS 'The time when the most recent patch has been attached to this bug or NULL if no patches are attached'; |
1025 | 293 | 628 | ||
1026 | 294 | 629 | ||
1027 | 295 | COMMENT ON COLUMN bug.heat_last_updated IS 'The time this bug''s heat was last updated, or NULL if the heat has never yet been updated.'; | 630 | COMMENT ON COLUMN public.bug.information_type IS 'Enum describing what type of information is stored, such as type of private or security related data, and used to determine how to apply an access policy.'; |
1028 | 296 | 631 | ||
1029 | 297 | 632 | ||
1030 | 298 | COMMENT ON COLUMN bug.latest_patch_uploaded IS 'The time when the most recent patch has been attached to this bug or NULL if no patches are attached'; | 633 | CREATE FUNCTION public.bug_row(bug_id integer) RETURNS public.bug |
994 | 299 | |||
995 | 300 | |||
996 | 301 | CREATE FUNCTION bug_row(bug_id integer) RETURNS bug | ||
1031 | 302 | LANGUAGE sql STABLE | 634 | LANGUAGE sql STABLE |
1032 | 303 | AS $_$ | 635 | AS $_$ |
1033 | 304 | SELECT * FROM Bug WHERE id=$1; | 636 | SELECT * FROM Bug WHERE id=$1; |
1034 | 305 | $_$; | 637 | $_$; |
1035 | 306 | 638 | ||
1036 | 307 | 639 | ||
1041 | 308 | COMMENT ON FUNCTION bug_row(bug_id integer) IS 'Helper for manually testing functions requiring a bug row as input. eg. SELECT * FROM bugsummary_tags(bug_row(1))'; | 640 | COMMENT ON FUNCTION public.bug_row(bug_id integer) IS 'Helper for manually testing functions requiring a bug row as input. eg. SELECT * FROM bugsummary_tags(bug_row(1))'; |
1042 | 309 | 641 | ||
1043 | 310 | 642 | ||
1044 | 311 | CREATE TABLE bugsummary ( | 643 | CREATE TABLE public.bugsummary ( |
1045 | 312 | id integer NOT NULL, | 644 | id integer NOT NULL, |
1046 | 313 | count integer DEFAULT 0 NOT NULL, | 645 | count integer DEFAULT 0 NOT NULL, |
1047 | 314 | product integer, | 646 | product integer, |
1048 | @@ -322,12 +654,28 @@ | |||
1049 | 322 | milestone integer, | 654 | milestone integer, |
1050 | 323 | importance integer NOT NULL, | 655 | importance integer NOT NULL, |
1051 | 324 | has_patch boolean NOT NULL, | 656 | has_patch boolean NOT NULL, |
1054 | 325 | fixed_upstream boolean NOT NULL, | 657 | access_policy integer, |
1055 | 326 | CONSTRAINT bugtask_assignment_checks CHECK (CASE WHEN (product IS NOT NULL) THEN ((((productseries IS NULL) AND (distribution IS NULL)) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) WHEN (productseries IS NOT NULL) THEN (((distribution IS NULL) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) WHEN (distribution IS NOT NULL) THEN (distroseries IS NULL) WHEN (distroseries IS NOT NULL) THEN true ELSE false END) | 658 | CONSTRAINT bugtask_assignment_checks CHECK ( |
1056 | 659 | CASE | ||
1057 | 660 | WHEN (product IS NOT NULL) THEN ((((productseries IS NULL) AND (distribution IS NULL)) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) | ||
1058 | 661 | WHEN (productseries IS NOT NULL) THEN (((distribution IS NULL) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) | ||
1059 | 662 | WHEN (distribution IS NOT NULL) THEN (distroseries IS NULL) | ||
1060 | 663 | WHEN (distroseries IS NOT NULL) THEN true | ||
1061 | 664 | ELSE false | ||
1062 | 665 | END) | ||
1063 | 327 | ); | 666 | ); |
1064 | 328 | 667 | ||
1065 | 329 | 668 | ||
1067 | 330 | CREATE FUNCTION bug_summary_dec(bugsummary) RETURNS void | 669 | COMMENT ON TABLE public.bugsummary IS 'A fact table for bug metadata aggregate queries. Each row represents the number of bugs that are in the system addressed by all the dimensions (e.g. product or productseries etc). '; |
1068 | 670 | |||
1069 | 671 | |||
1070 | 672 | COMMENT ON COLUMN public.bugsummary.sourcepackagename IS 'The sourcepackagename for the aggregate. Counting bugs in a distribution/distroseries requires selecting all rows by sourcepackagename. If this is too slow, add the bug to the NULL row and select with sourcepackagename is NULL to exclude them from the calculations'; | ||
1071 | 673 | |||
1072 | 674 | |||
1073 | 675 | COMMENT ON COLUMN public.bugsummary.milestone IS 'A milestone present on the bug. All bugs are also aggregated with a NULL entry for milestone to permit querying totals (because the milestone figures cannot be summed as many milestones can be on a single bug)'; | ||
1074 | 676 | |||
1075 | 677 | |||
1076 | 678 | CREATE FUNCTION public.bug_summary_dec(public.bugsummary) RETURNS void | ||
1077 | 331 | LANGUAGE sql | 679 | LANGUAGE sql |
1078 | 332 | AS $_$ | 680 | AS $_$ |
1079 | 333 | -- We own the row reference, so in the absence of bugs this cannot | 681 | -- We own the row reference, so in the absence of bugs this cannot |
1080 | @@ -353,34 +701,47 @@ | |||
1081 | 353 | OR milestone = $1.milestone) | 701 | OR milestone = $1.milestone) |
1082 | 354 | AND importance = $1.importance | 702 | AND importance = $1.importance |
1083 | 355 | AND has_patch = $1.has_patch | 703 | AND has_patch = $1.has_patch |
1085 | 356 | AND fixed_upstream = $1.fixed_upstream; | 704 | AND access_policy IS NOT DISTINCT FROM $1.access_policy; |
1086 | 357 | $_$; | 705 | $_$; |
1087 | 358 | 706 | ||
1088 | 359 | 707 | ||
1093 | 360 | COMMENT ON FUNCTION bug_summary_dec(bugsummary) IS 'UPSERT into bugsummary incrementing one row'; | 708 | COMMENT ON FUNCTION public.bug_summary_dec(public.bugsummary) IS 'UPSERT into bugsummary incrementing one row'; |
1094 | 361 | 709 | ||
1095 | 362 | 710 | ||
1096 | 363 | CREATE FUNCTION bug_summary_flush_temp_journal() RETURNS void | 711 | CREATE FUNCTION public.bug_summary_flush_temp_journal() RETURNS void |
1097 | 364 | LANGUAGE plpgsql | 712 | LANGUAGE plpgsql |
1098 | 365 | AS $$ | 713 | AS $$ |
1099 | 366 | DECLARE | 714 | DECLARE |
1100 | 367 | d bugsummary%ROWTYPE; | 715 | d bugsummary%ROWTYPE; |
1101 | 368 | BEGIN | 716 | BEGIN |
1104 | 369 | -- may get called even though no summaries were made (for simplicity in the | 717 | -- May get called even though no summaries were made (for simplicity in the |
1105 | 370 | -- callers) | 718 | -- callers). We sum the rows here to minimise the number of inserts |
1106 | 719 | -- into the persistent journal, as it's reasonably likely that we'll | ||
1107 | 720 | -- have -1s and +1s cancelling each other out. | ||
1108 | 371 | PERFORM ensure_bugsummary_temp_journal(); | 721 | PERFORM ensure_bugsummary_temp_journal(); |
1112 | 372 | FOR d IN SELECT * FROM bugsummary_temp_journal LOOP | 722 | INSERT INTO BugSummaryJournal( |
1113 | 373 | PERFORM bugsummary_journal_ins(d); | 723 | count, product, productseries, distribution, |
1114 | 374 | END LOOP; | 724 | distroseries, sourcepackagename, viewed_by, tag, |
1115 | 725 | status, milestone, importance, has_patch, access_policy) | ||
1116 | 726 | SELECT | ||
1117 | 727 | SUM(count), product, productseries, distribution, | ||
1118 | 728 | distroseries, sourcepackagename, viewed_by, tag, | ||
1119 | 729 | status, milestone, importance, has_patch, access_policy | ||
1120 | 730 | FROM bugsummary_temp_journal | ||
1121 | 731 | GROUP BY | ||
1122 | 732 | product, productseries, distribution, | ||
1123 | 733 | distroseries, sourcepackagename, viewed_by, tag, | ||
1124 | 734 | status, milestone, importance, has_patch, access_policy | ||
1125 | 735 | HAVING SUM(count) != 0; | ||
1126 | 375 | TRUNCATE bugsummary_temp_journal; | 736 | TRUNCATE bugsummary_temp_journal; |
1127 | 376 | END; | 737 | END; |
1128 | 377 | $$; | 738 | $$; |
1129 | 378 | 739 | ||
1130 | 379 | 740 | ||
1135 | 380 | COMMENT ON FUNCTION bug_summary_flush_temp_journal() IS 'flush the temporary bugsummary journal into the bugsummary table'; | 741 | COMMENT ON FUNCTION public.bug_summary_flush_temp_journal() IS 'flush the temporary bugsummary journal into the bugsummary table'; |
1136 | 381 | 742 | ||
1137 | 382 | 743 | ||
1138 | 383 | CREATE FUNCTION bug_summary_inc(d bugsummary) RETURNS void | 744 | CREATE FUNCTION public.bug_summary_inc(d public.bugsummary) RETURNS void |
1139 | 384 | LANGUAGE plpgsql | 745 | LANGUAGE plpgsql |
1140 | 385 | AS $_$ | 746 | AS $_$ |
1141 | 386 | BEGIN | 747 | BEGIN |
1142 | @@ -408,7 +769,7 @@ | |||
1143 | 408 | OR milestone = $1.milestone) | 769 | OR milestone = $1.milestone) |
1144 | 409 | AND importance = $1.importance | 770 | AND importance = $1.importance |
1145 | 410 | AND has_patch = $1.has_patch | 771 | AND has_patch = $1.has_patch |
1147 | 411 | AND fixed_upstream = $1.fixed_upstream; | 772 | AND access_policy IS NOT DISTINCT FROM $1.access_policy; |
1148 | 412 | IF found THEN | 773 | IF found THEN |
1149 | 413 | RETURN; | 774 | RETURN; |
1150 | 414 | END IF; | 775 | END IF; |
1151 | @@ -419,13 +780,12 @@ | |||
1152 | 419 | INSERT INTO BugSummary( | 780 | INSERT INTO BugSummary( |
1153 | 420 | count, product, productseries, distribution, | 781 | count, product, productseries, distribution, |
1154 | 421 | distroseries, sourcepackagename, viewed_by, tag, | 782 | distroseries, sourcepackagename, viewed_by, tag, |
1157 | 422 | status, milestone, | 783 | status, milestone, importance, has_patch, access_policy) |
1156 | 423 | importance, has_patch, fixed_upstream) | ||
1158 | 424 | VALUES ( | 784 | VALUES ( |
1159 | 425 | d.count, d.product, d.productseries, d.distribution, | 785 | d.count, d.product, d.productseries, d.distribution, |
1160 | 426 | d.distroseries, d.sourcepackagename, d.viewed_by, d.tag, | 786 | d.distroseries, d.sourcepackagename, d.viewed_by, d.tag, |
1163 | 427 | d.status, d.milestone, | 787 | d.status, d.milestone, d.importance, d.has_patch, |
1164 | 428 | d.importance, d.has_patch, d.fixed_upstream); | 788 | d.access_policy); |
1165 | 429 | RETURN; | 789 | RETURN; |
1166 | 430 | EXCEPTION WHEN unique_violation THEN | 790 | EXCEPTION WHEN unique_violation THEN |
1167 | 431 | -- do nothing, and loop to try the UPDATE again | 791 | -- do nothing, and loop to try the UPDATE again |
1168 | @@ -435,48 +795,12 @@ | |||
1169 | 435 | $_$; | 795 | $_$; |
1170 | 436 | 796 | ||
1171 | 437 | 797 | ||
1214 | 438 | COMMENT ON FUNCTION bug_summary_inc(d bugsummary) IS 'UPSERT into bugsummary incrementing one row'; | 798 | COMMENT ON FUNCTION public.bug_summary_inc(d public.bugsummary) IS 'UPSERT into bugsummary incrementing one row'; |
1215 | 439 | 799 | ||
1216 | 440 | 800 | ||
1217 | 441 | CREATE FUNCTION bug_summary_temp_journal_ins(d bugsummary) RETURNS void | 801 | CREATE FUNCTION public.bug_update_latest_patch_uploaded(integer) RETURNS void |
1218 | 442 | LANGUAGE plpgsql | 802 | LANGUAGE plpgsql SECURITY DEFINER |
1219 | 443 | AS $$ | 803 | SET search_path TO 'public' |
1178 | 444 | BEGIN | ||
1179 | 445 | INSERT INTO BugSummary_Temp_Journal( | ||
1180 | 446 | count, product, productseries, distribution, | ||
1181 | 447 | distroseries, sourcepackagename, viewed_by, tag, | ||
1182 | 448 | status, milestone, importance, has_patch, fixed_upstream) | ||
1183 | 449 | VALUES ( | ||
1184 | 450 | d.count, d.product, d.productseries, d.distribution, | ||
1185 | 451 | d.distroseries, d.sourcepackagename, d.viewed_by, d.tag, | ||
1186 | 452 | d.status, d.milestone, d.importance, d.has_patch, d.fixed_upstream); | ||
1187 | 453 | RETURN; | ||
1188 | 454 | END; | ||
1189 | 455 | $$; | ||
1190 | 456 | |||
1191 | 457 | |||
1192 | 458 | COMMENT ON FUNCTION bug_summary_temp_journal_ins(d bugsummary) IS 'Insert a BugSummary into the temporary journal'; | ||
1193 | 459 | |||
1194 | 460 | |||
1195 | 461 | CREATE FUNCTION bug_update_heat_copy_to_bugtask() RETURNS trigger | ||
1196 | 462 | LANGUAGE plpgsql SECURITY DEFINER | ||
1197 | 463 | SET search_path TO public | ||
1198 | 464 | AS $$ | ||
1199 | 465 | BEGIN | ||
1200 | 466 | IF NEW.heat != OLD.heat THEN | ||
1201 | 467 | UPDATE bugtask SET heat=NEW.heat WHERE bugtask.bug=NEW.id; | ||
1202 | 468 | END IF; | ||
1203 | 469 | RETURN NULL; -- Ignored - this is an AFTER trigger | ||
1204 | 470 | END; | ||
1205 | 471 | $$; | ||
1206 | 472 | |||
1207 | 473 | |||
1208 | 474 | COMMENT ON FUNCTION bug_update_heat_copy_to_bugtask() IS 'Copies bug heat to bugtasks when the bug is changed. Runs on UPDATE only because INSERTs do not have bugtasks at the point of insertion.'; | ||
1209 | 475 | |||
1210 | 476 | |||
1211 | 477 | CREATE FUNCTION bug_update_latest_patch_uploaded(integer) RETURNS void | ||
1212 | 478 | LANGUAGE plpgsql SECURITY DEFINER | ||
1213 | 479 | SET search_path TO public | ||
1220 | 480 | AS $_$ | 804 | AS $_$ |
1221 | 481 | BEGIN | 805 | BEGIN |
1222 | 482 | UPDATE bug SET latest_patch_uploaded = | 806 | UPDATE bug SET latest_patch_uploaded = |
1223 | @@ -490,9 +814,9 @@ | |||
1224 | 490 | $_$; | 814 | $_$; |
1225 | 491 | 815 | ||
1226 | 492 | 816 | ||
1228 | 493 | CREATE FUNCTION bug_update_latest_patch_uploaded_on_delete() RETURNS trigger | 817 | CREATE FUNCTION public.bug_update_latest_patch_uploaded_on_delete() RETURNS trigger |
1229 | 494 | LANGUAGE plpgsql SECURITY DEFINER | 818 | LANGUAGE plpgsql SECURITY DEFINER |
1231 | 495 | SET search_path TO public | 819 | SET search_path TO 'public' |
1232 | 496 | AS $$ | 820 | AS $$ |
1233 | 497 | BEGIN | 821 | BEGIN |
1234 | 498 | PERFORM bug_update_latest_patch_uploaded(OLD.bug); | 822 | PERFORM bug_update_latest_patch_uploaded(OLD.bug); |
1235 | @@ -501,9 +825,9 @@ | |||
1236 | 501 | $$; | 825 | $$; |
1237 | 502 | 826 | ||
1238 | 503 | 827 | ||
1240 | 504 | CREATE FUNCTION bug_update_latest_patch_uploaded_on_insert_update() RETURNS trigger | 828 | CREATE FUNCTION public.bug_update_latest_patch_uploaded_on_insert_update() RETURNS trigger |
1241 | 505 | LANGUAGE plpgsql SECURITY DEFINER | 829 | LANGUAGE plpgsql SECURITY DEFINER |
1243 | 506 | SET search_path TO public | 830 | SET search_path TO 'public' |
1244 | 507 | AS $$ | 831 | AS $$ |
1245 | 508 | BEGIN | 832 | BEGIN |
1246 | 509 | PERFORM bug_update_latest_patch_uploaded(NEW.bug); | 833 | PERFORM bug_update_latest_patch_uploaded(NEW.bug); |
1247 | @@ -512,9 +836,9 @@ | |||
1248 | 512 | $$; | 836 | $$; |
1249 | 513 | 837 | ||
1250 | 514 | 838 | ||
1252 | 515 | CREATE FUNCTION bugmessage_copy_owner_from_message() RETURNS trigger | 839 | CREATE FUNCTION public.bugmessage_copy_owner_from_message() RETURNS trigger |
1253 | 516 | LANGUAGE plpgsql SECURITY DEFINER | 840 | LANGUAGE plpgsql SECURITY DEFINER |
1255 | 517 | SET search_path TO public | 841 | SET search_path TO 'public' |
1256 | 518 | AS $$ | 842 | AS $$ |
1257 | 519 | BEGIN | 843 | BEGIN |
1258 | 520 | IF TG_OP = 'INSERT' THEN | 844 | IF TG_OP = 'INSERT' THEN |
1259 | @@ -537,145 +861,98 @@ | |||
1260 | 537 | $$; | 861 | $$; |
1261 | 538 | 862 | ||
1262 | 539 | 863 | ||
1358 | 540 | COMMENT ON FUNCTION bugmessage_copy_owner_from_message() IS 'Copies the message owner into bugmessage when bugmessage changes.'; | 864 | COMMENT ON FUNCTION public.bugmessage_copy_owner_from_message() IS 'Copies the message owner into bugmessage when bugmessage changes.'; |
1359 | 541 | 865 | ||
1360 | 542 | 866 | ||
1361 | 543 | CREATE FUNCTION bugsubscription_maintain_bug_summary() RETURNS trigger | 867 | CREATE FUNCTION public.bugsummary_journal_bug(bug_row public.bug, _count integer) RETURNS void |
1362 | 544 | LANGUAGE plpgsql SECURITY DEFINER | 868 | LANGUAGE plpgsql |
1363 | 545 | SET search_path TO public | 869 | AS $$ |
1364 | 546 | AS $$ | 870 | DECLARE |
1365 | 547 | BEGIN | 871 | btf_row bugtaskflat%ROWTYPE; |
1366 | 548 | -- This trigger only works if we are inserting, updating or deleting | 872 | BEGIN |
1367 | 549 | -- a single row per statement. | 873 | FOR btf_row IN SELECT * FROM bugtaskflat WHERE bug = bug_row.id |
1368 | 550 | IF TG_OP = 'INSERT' THEN | 874 | LOOP |
1369 | 551 | IF NOT (bug_row(NEW.bug)).private THEN | 875 | PERFORM bugsummary_journal_bugtaskflat(btf_row, _count); |
1370 | 552 | -- Public subscriptions are not aggregated. | 876 | END LOOP; |
1371 | 553 | RETURN NEW; | 877 | END; |
1372 | 554 | END IF; | 878 | $$; |
1373 | 555 | IF TG_WHEN = 'BEFORE' THEN | 879 | |
1374 | 556 | PERFORM unsummarise_bug(bug_row(NEW.bug)); | 880 | |
1375 | 557 | ELSE | 881 | CREATE TABLE public.bugtaskflat ( |
1376 | 558 | PERFORM summarise_bug(bug_row(NEW.bug)); | 882 | bugtask integer NOT NULL, |
1377 | 559 | END IF; | 883 | bug integer NOT NULL, |
1378 | 560 | PERFORM bug_summary_flush_temp_journal(); | 884 | datecreated timestamp without time zone, |
1379 | 561 | RETURN NEW; | 885 | duplicateof integer, |
1380 | 562 | ELSIF TG_OP = 'DELETE' THEN | 886 | bug_owner integer NOT NULL, |
1381 | 563 | IF NOT (bug_row(OLD.bug)).private THEN | 887 | fti public.ts2_tsvector, |
1382 | 564 | -- Public subscriptions are not aggregated. | 888 | information_type integer NOT NULL, |
1383 | 565 | RETURN OLD; | 889 | date_last_updated timestamp without time zone NOT NULL, |
1384 | 566 | END IF; | 890 | heat integer NOT NULL, |
1385 | 567 | IF TG_WHEN = 'BEFORE' THEN | 891 | product integer, |
1386 | 568 | PERFORM unsummarise_bug(bug_row(OLD.bug)); | 892 | productseries integer, |
1387 | 569 | ELSE | 893 | distribution integer, |
1388 | 570 | PERFORM summarise_bug(bug_row(OLD.bug)); | 894 | distroseries integer, |
1389 | 571 | END IF; | 895 | sourcepackagename integer, |
1390 | 572 | PERFORM bug_summary_flush_temp_journal(); | 896 | status integer NOT NULL, |
1391 | 573 | RETURN OLD; | 897 | importance integer NOT NULL, |
1392 | 574 | ELSE | 898 | assignee integer, |
1393 | 575 | IF (OLD.person IS DISTINCT FROM NEW.person | 899 | milestone integer, |
1394 | 576 | OR OLD.bug IS DISTINCT FROM NEW.bug) THEN | 900 | owner integer NOT NULL, |
1395 | 577 | IF TG_WHEN = 'BEFORE' THEN | 901 | active boolean NOT NULL, |
1396 | 578 | IF (bug_row(OLD.bug)).private THEN | 902 | access_policies integer[], |
1397 | 579 | -- Public subscriptions are not aggregated. | 903 | access_grants integer[], |
1398 | 580 | PERFORM unsummarise_bug(bug_row(OLD.bug)); | 904 | latest_patch_uploaded timestamp without time zone, |
1399 | 581 | END IF; | 905 | date_closed timestamp without time zone |
1400 | 582 | IF OLD.bug <> NEW.bug AND (bug_row(NEW.bug)).private THEN | 906 | ); |
1401 | 583 | -- Public subscriptions are not aggregated. | 907 | |
1402 | 584 | PERFORM unsummarise_bug(bug_row(NEW.bug)); | 908 | |
1403 | 585 | END IF; | 909 | CREATE FUNCTION public.bugsummary_journal_bugtaskflat(btf_row public.bugtaskflat, _count integer) RETURNS void |
1404 | 586 | ELSE | 910 | LANGUAGE plpgsql |
1405 | 587 | IF (bug_row(OLD.bug)).private THEN | 911 | AS $$ |
1406 | 588 | -- Public subscriptions are not aggregated. | 912 | BEGIN |
1407 | 589 | PERFORM summarise_bug(bug_row(OLD.bug)); | 913 | PERFORM ensure_bugsummary_temp_journal(); |
1408 | 590 | END IF; | 914 | INSERT INTO BugSummary_Temp_Journal( |
1409 | 591 | IF OLD.bug <> NEW.bug AND (bug_row(NEW.bug)).private THEN | 915 | count, product, productseries, distribution, |
1410 | 592 | -- Public subscriptions are not aggregated. | 916 | distroseries, sourcepackagename, viewed_by, tag, |
1411 | 593 | PERFORM summarise_bug(bug_row(NEW.bug)); | 917 | status, milestone, importance, has_patch, access_policy) |
1412 | 594 | END IF; | 918 | SELECT |
1413 | 595 | END IF; | 919 | _count, product, productseries, distribution, |
1414 | 596 | END IF; | 920 | distroseries, sourcepackagename, viewed_by, tag, |
1415 | 597 | PERFORM bug_summary_flush_temp_journal(); | 921 | status, milestone, importance, has_patch, access_policy |
1416 | 598 | RETURN NEW; | 922 | FROM bugsummary_locations(btf_row); |
1417 | 599 | END IF; | 923 | END; |
1418 | 600 | END; | 924 | $$; |
1419 | 601 | $$; | 925 | |
1420 | 602 | 926 | ||
1421 | 603 | 927 | CREATE FUNCTION public.bugsummary_locations(btf_row public.bugtaskflat) RETURNS SETOF public.bugsummary | |
1422 | 604 | COMMENT ON FUNCTION bugsubscription_maintain_bug_summary() IS 'AFTER trigger on bugsubscription maintaining the bugs summaries in bugsummary.'; | 928 | LANGUAGE plpgsql |
1423 | 605 | 929 | AS $$ | |
1424 | 606 | 930 | BEGIN | |
1425 | 607 | CREATE FUNCTION bugsummary_journal_ins(d bugsummary) RETURNS void | 931 | IF btf_row.duplicateof IS NOT NULL THEN |
1331 | 608 | LANGUAGE plpgsql | ||
1332 | 609 | AS $$ | ||
1333 | 610 | BEGIN | ||
1334 | 611 | IF d.count <> 0 THEN | ||
1335 | 612 | INSERT INTO BugSummaryJournal ( | ||
1336 | 613 | count, product, productseries, distribution, | ||
1337 | 614 | distroseries, sourcepackagename, viewed_by, tag, | ||
1338 | 615 | status, milestone, | ||
1339 | 616 | importance, has_patch, fixed_upstream) | ||
1340 | 617 | VALUES ( | ||
1341 | 618 | d.count, d.product, d.productseries, d.distribution, | ||
1342 | 619 | d.distroseries, d.sourcepackagename, d.viewed_by, d.tag, | ||
1343 | 620 | d.status, d.milestone, | ||
1344 | 621 | d.importance, d.has_patch, d.fixed_upstream); | ||
1345 | 622 | END IF; | ||
1346 | 623 | END; | ||
1347 | 624 | $$; | ||
1348 | 625 | |||
1349 | 626 | |||
1350 | 627 | COMMENT ON FUNCTION bugsummary_journal_ins(d bugsummary) IS 'Add an entry into BugSummaryJournal'; | ||
1351 | 628 | |||
1352 | 629 | |||
1353 | 630 | CREATE FUNCTION bugsummary_locations(bug_row bug) RETURNS SETOF bugsummary | ||
1354 | 631 | LANGUAGE plpgsql | ||
1355 | 632 | AS $$ | ||
1356 | 633 | BEGIN | ||
1357 | 634 | IF BUG_ROW.duplicateof IS NOT NULL THEN | ||
1426 | 635 | RETURN; | 932 | RETURN; |
1427 | 636 | END IF; | 933 | END IF; |
1428 | 637 | RETURN QUERY | 934 | RETURN QUERY |
1429 | 638 | SELECT | 935 | SELECT |
1430 | 639 | CAST(NULL AS integer) AS id, | 936 | CAST(NULL AS integer) AS id, |
1431 | 640 | CAST(1 AS integer) AS count, | 937 | CAST(1 AS integer) AS count, |
1460 | 641 | product, productseries, distribution, distroseries, | 938 | bug_targets.product, bug_targets.productseries, |
1461 | 642 | sourcepackagename, person AS viewed_by, tag, status, milestone, | 939 | bug_targets.distribution, bug_targets.distroseries, |
1462 | 643 | importance, | 940 | bug_targets.sourcepackagename, |
1463 | 644 | BUG_ROW.latest_patch_uploaded IS NOT NULL AS has_patch, | 941 | bug_viewers.viewed_by, bug_tags.tag, btf_row.status, |
1464 | 645 | (EXISTS ( | 942 | btf_row.milestone, btf_row.importance, |
1465 | 646 | SELECT TRUE FROM BugTask AS RBT | 943 | btf_row.latest_patch_uploaded IS NOT NULL AS has_patch, |
1466 | 647 | WHERE | 944 | bug_viewers.access_policy |
1467 | 648 | RBT.bug = tasks.bug | 945 | FROM |
1468 | 649 | -- This would just be 'RBT.id <> tasks.id', except | 946 | bugsummary_targets(btf_row) as bug_targets, |
1469 | 650 | -- that the records from tasks are summaries and not | 947 | bugsummary_tags(btf_row) AS bug_tags, |
1470 | 651 | -- real bugtasks, and do not have an id. | 948 | bugsummary_viewers(btf_row) AS bug_viewers; |
1443 | 652 | AND (RBT.product IS DISTINCT FROM tasks.product | ||
1444 | 653 | OR RBT.productseries | ||
1445 | 654 | IS DISTINCT FROM tasks.productseries | ||
1446 | 655 | OR RBT.distribution IS DISTINCT FROM tasks.distribution | ||
1447 | 656 | OR RBT.distroseries IS DISTINCT FROM tasks.distroseries | ||
1448 | 657 | OR RBT.sourcepackagename | ||
1449 | 658 | IS DISTINCT FROM tasks.sourcepackagename) | ||
1450 | 659 | -- Flagged as INVALID, FIXCOMMITTED or FIXRELEASED | ||
1451 | 660 | -- via a bugwatch, or FIXCOMMITTED or FIXRELEASED on | ||
1452 | 661 | -- the product. | ||
1453 | 662 | AND ((bugwatch IS NOT NULL AND status IN (17, 25, 30)) | ||
1454 | 663 | OR (bugwatch IS NULL AND product IS NOT NULL | ||
1455 | 664 | AND status IN (25, 30)))) | ||
1456 | 665 | )::boolean AS fixed_upstream | ||
1457 | 666 | FROM bugsummary_tasks(BUG_ROW) AS tasks | ||
1458 | 667 | JOIN bugsummary_tags(BUG_ROW) AS bug_tags ON TRUE | ||
1459 | 668 | LEFT OUTER JOIN bugsummary_viewers(BUG_ROW) AS bug_viewers ON TRUE; | ||
1471 | 669 | END; | 949 | END; |
1472 | 670 | $$; | 950 | $$; |
1473 | 671 | 951 | ||
1474 | 672 | 952 | ||
1479 | 673 | COMMENT ON FUNCTION bugsummary_locations(bug_row bug) IS 'Calculate what BugSummary rows should exist for a given Bug.'; | 953 | CREATE FUNCTION public.bugsummary_rollup_journal(batchsize integer DEFAULT NULL::integer) RETURNS void |
1476 | 674 | |||
1477 | 675 | |||
1478 | 676 | CREATE FUNCTION bugsummary_rollup_journal(batchsize integer DEFAULT NULL::integer) RETURNS void | ||
1480 | 677 | LANGUAGE plpgsql SECURITY DEFINER | 954 | LANGUAGE plpgsql SECURITY DEFINER |
1482 | 678 | SET search_path TO public | 955 | SET search_path TO 'public' |
1483 | 679 | AS $$ | 956 | AS $$ |
1484 | 680 | DECLARE | 957 | DECLARE |
1485 | 681 | d bugsummary%ROWTYPE; | 958 | d bugsummary%ROWTYPE; |
1486 | @@ -710,13 +987,13 @@ | |||
1487 | 710 | milestone, | 987 | milestone, |
1488 | 711 | importance, | 988 | importance, |
1489 | 712 | has_patch, | 989 | has_patch, |
1491 | 713 | fixed_upstream | 990 | access_policy |
1492 | 714 | FROM BugSummaryJournal | 991 | FROM BugSummaryJournal |
1493 | 715 | WHERE id <= max_id | 992 | WHERE id <= max_id |
1494 | 716 | GROUP BY | 993 | GROUP BY |
1495 | 717 | product, productseries, distribution, distroseries, | 994 | product, productseries, distribution, distroseries, |
1496 | 718 | sourcepackagename, viewed_by, tag, status, milestone, | 995 | sourcepackagename, viewed_by, tag, status, milestone, |
1498 | 719 | importance, has_patch, fixed_upstream | 996 | importance, has_patch, access_policy |
1499 | 720 | HAVING sum(count) <> 0 | 997 | HAVING sum(count) <> 0 |
1500 | 721 | LOOP | 998 | LOOP |
1501 | 722 | IF d.count < 0 THEN | 999 | IF d.count < 0 THEN |
1502 | @@ -734,10 +1011,10 @@ | |||
1503 | 734 | $$; | 1011 | $$; |
1504 | 735 | 1012 | ||
1505 | 736 | 1013 | ||
1510 | 737 | COMMENT ON FUNCTION bugsummary_rollup_journal(batchsize integer) IS 'Collate and migrate rows from BugSummaryJournal to BugSummary'; | 1014 | COMMENT ON FUNCTION public.bugsummary_rollup_journal(batchsize integer) IS 'Collate and migrate rows from BugSummaryJournal to BugSummary'; |
1511 | 738 | 1015 | ||
1512 | 739 | 1016 | ||
1513 | 740 | CREATE FUNCTION valid_name(text) RETURNS boolean | 1017 | CREATE FUNCTION public.valid_name(text) RETURNS boolean |
1514 | 741 | LANGUAGE plpythonu IMMUTABLE STRICT | 1018 | LANGUAGE plpythonu IMMUTABLE STRICT |
1515 | 742 | AS $$ | 1019 | AS $$ |
1516 | 743 | import re | 1020 | import re |
1517 | @@ -749,7 +1026,7 @@ | |||
1518 | 749 | $$; | 1026 | $$; |
1519 | 750 | 1027 | ||
1520 | 751 | 1028 | ||
1522 | 752 | COMMENT ON FUNCTION valid_name(text) IS 'validate a name. | 1029 | COMMENT ON FUNCTION public.valid_name(text) IS 'validate a name. |
1523 | 753 | 1030 | ||
1524 | 754 | Names must contain only lowercase letters, numbers, ., & -. They | 1031 | Names must contain only lowercase letters, numbers, ., & -. They |
1525 | 755 | must start with an alphanumeric. They are ASCII only. Names are useful | 1032 | must start with an alphanumeric. They are ASCII only. Names are useful |
1526 | @@ -760,446 +1037,347 @@ | |||
1527 | 760 | namespace conflict if URL traversal is possible by name as well as id.'; | 1037 | namespace conflict if URL traversal is possible by name as well as id.'; |
1528 | 761 | 1038 | ||
1529 | 762 | 1039 | ||
1531 | 763 | CREATE TABLE bugtag ( | 1040 | CREATE TABLE public.bugtag ( |
1532 | 764 | id integer NOT NULL, | 1041 | id integer NOT NULL, |
1533 | 765 | bug integer NOT NULL, | 1042 | bug integer NOT NULL, |
1534 | 766 | tag text NOT NULL, | 1043 | tag text NOT NULL, |
1971 | 767 | CONSTRAINT valid_tag CHECK (valid_name(tag)) | 1044 | CONSTRAINT valid_tag CHECK (public.valid_name(tag)) |
1972 | 768 | ); | 1045 | ); |
1973 | 769 | 1046 | ||
1974 | 770 | 1047 | ||
1975 | 771 | COMMENT ON TABLE bugtag IS 'Attaches simple text tags to a bug.'; | 1048 | COMMENT ON TABLE public.bugtag IS 'Attaches simple text tags to a bug.'; |
1976 | 772 | 1049 | ||
1977 | 773 | 1050 | ||
1978 | 774 | COMMENT ON COLUMN bugtag.bug IS 'The bug the tags is attached to.'; | 1051 | COMMENT ON COLUMN public.bugtag.bug IS 'The bug the tags is attached to.'; |
1979 | 775 | 1052 | ||
1980 | 776 | 1053 | ||
1981 | 777 | COMMENT ON COLUMN bugtag.tag IS 'The text representation of the tag.'; | 1054 | COMMENT ON COLUMN public.bugtag.tag IS 'The text representation of the tag.'; |
1982 | 778 | 1055 | ||
1983 | 779 | 1056 | ||
1984 | 780 | CREATE FUNCTION bugsummary_tags(bug_row bug) RETURNS SETOF bugtag | 1057 | CREATE FUNCTION public.bugsummary_tags(btf_row public.bugtaskflat) RETURNS SETOF public.bugtag |
1985 | 781 | LANGUAGE sql STABLE | 1058 | LANGUAGE sql STABLE |
1986 | 782 | AS $_$ | 1059 | AS $_$ |
1987 | 783 | SELECT * FROM BugTag WHERE BugTag.bug = $1.id | 1060 | SELECT * FROM BugTag WHERE BugTag.bug = $1.bug |
1988 | 784 | UNION ALL | 1061 | UNION ALL |
1989 | 785 | SELECT NULL::integer, $1.id, NULL::text; | 1062 | SELECT NULL::integer, $1.bug, NULL::text; |
1990 | 786 | $_$; | 1063 | $_$; |
1991 | 787 | 1064 | ||
1992 | 788 | 1065 | ||
1993 | 789 | COMMENT ON FUNCTION bugsummary_tags(bug_row bug) IS 'Return (bug, tag) for all tags + (bug, NULL::text)'; | 1066 | CREATE FUNCTION public.bugsummary_targets(btf_row public.bugtaskflat) RETURNS TABLE(product integer, productseries integer, distribution integer, distroseries integer, sourcepackagename integer) |
1994 | 790 | 1067 | LANGUAGE sql IMMUTABLE | |
1995 | 791 | 1068 | AS $_$ | |
1996 | 792 | CREATE TABLE bugtask ( | 1069 | -- Include a sourcepackagename-free task if this one has a |
1997 | 793 | id integer NOT NULL, | 1070 | -- sourcepackagename, so package tasks are also counted in their |
1998 | 794 | bug integer NOT NULL, | 1071 | -- distro/series. |
1999 | 795 | product integer, | 1072 | SELECT |
2000 | 796 | distribution integer, | 1073 | $1.product, $1.productseries, $1.distribution, |
2001 | 797 | distroseries integer, | 1074 | $1.distroseries, $1.sourcepackagename |
2002 | 798 | sourcepackagename integer, | 1075 | UNION -- Implicit DISTINCT |
2003 | 799 | binarypackagename integer, | 1076 | SELECT |
2004 | 800 | status integer NOT NULL, | 1077 | $1.product, $1.productseries, $1.distribution, |
2005 | 801 | importance integer DEFAULT 5 NOT NULL, | 1078 | $1.distroseries, NULL; |
2006 | 802 | assignee integer, | 1079 | $_$; |
2007 | 803 | date_assigned timestamp without time zone, | 1080 | |
2008 | 804 | datecreated timestamp without time zone DEFAULT timezone('UTC'::text, ('now'::text)::timestamp(6) with time zone), | 1081 | |
2009 | 805 | owner integer NOT NULL, | 1082 | CREATE FUNCTION public.bugsummary_viewers(btf_row public.bugtaskflat) RETURNS TABLE(viewed_by integer, access_policy integer) |
2010 | 806 | milestone integer, | 1083 | LANGUAGE sql IMMUTABLE |
2011 | 807 | bugwatch integer, | 1084 | AS $_$ |
2012 | 808 | fti ts2.tsvector, | 1085 | SELECT NULL::integer, NULL::integer WHERE $1.information_type IN (1, 2) |
2013 | 809 | targetnamecache text, | 1086 | UNION ALL |
2014 | 810 | date_confirmed timestamp without time zone, | 1087 | SELECT unnest($1.access_grants), NULL::integer |
2015 | 811 | date_inprogress timestamp without time zone, | 1088 | WHERE $1.information_type NOT IN (1, 2) |
2016 | 812 | date_closed timestamp without time zone, | 1089 | UNION ALL |
2017 | 813 | productseries integer, | 1090 | SELECT NULL::integer, unnest($1.access_policies) |
2018 | 814 | date_incomplete timestamp without time zone, | 1091 | WHERE $1.information_type NOT IN (1, 2); |
2019 | 815 | date_left_new timestamp without time zone, | 1092 | $_$; |
2020 | 816 | date_triaged timestamp without time zone, | 1093 | |
2021 | 817 | date_fix_committed timestamp without time zone, | 1094 | |
2022 | 818 | date_fix_released timestamp without time zone, | 1095 | CREATE FUNCTION public.bugtag_maintain_bug_summary() RETURNS trigger |
2023 | 819 | date_left_closed timestamp without time zone, | 1096 | LANGUAGE plpgsql SECURITY DEFINER |
2024 | 820 | heat_rank integer DEFAULT 0 NOT NULL, | 1097 | SET search_path TO 'public' |
2025 | 821 | date_milestone_set timestamp without time zone, | 1098 | AS $$ |
2026 | 822 | heat integer DEFAULT 0 NOT NULL, | 1099 | BEGIN |
2027 | 823 | CONSTRAINT bugtask_assignment_checks CHECK (CASE WHEN (product IS NOT NULL) THEN ((((productseries IS NULL) AND (distribution IS NULL)) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) WHEN (productseries IS NOT NULL) THEN (((distribution IS NULL) AND (distroseries IS NULL)) AND (sourcepackagename IS NULL)) WHEN (distribution IS NOT NULL) THEN (distroseries IS NULL) WHEN (distroseries IS NOT NULL) THEN true ELSE false END) | 1100 | IF TG_OP = 'INSERT' THEN |
2028 | 824 | ); | 1101 | IF TG_WHEN = 'BEFORE' THEN |
2029 | 825 | 1102 | PERFORM unsummarise_bug(NEW.bug); | |
2030 | 826 | 1103 | ELSE | |
2031 | 827 | COMMENT ON TABLE bugtask IS 'Links a given Bug to a particular (sourcepackagename, distro) or product.'; | 1104 | PERFORM summarise_bug(NEW.bug); |
2032 | 828 | 1105 | END IF; | |
2033 | 829 | 1106 | PERFORM bug_summary_flush_temp_journal(); | |
2034 | 830 | COMMENT ON COLUMN bugtask.bug IS 'The bug that is assigned to this (sourcepackagename, distro) or product.'; | 1107 | RETURN NEW; |
2035 | 831 | 1108 | ELSIF TG_OP = 'DELETE' THEN | |
2036 | 832 | 1109 | IF TG_WHEN = 'BEFORE' THEN | |
2037 | 833 | COMMENT ON COLUMN bugtask.product IS 'The product in which this bug shows up.'; | 1110 | PERFORM unsummarise_bug(OLD.bug); |
2038 | 834 | 1111 | ELSE | |
2039 | 835 | 1112 | PERFORM summarise_bug(OLD.bug); | |
2040 | 836 | COMMENT ON COLUMN bugtask.distribution IS 'The distro of the named sourcepackage.'; | 1113 | END IF; |
2041 | 837 | 1114 | PERFORM bug_summary_flush_temp_journal(); | |
2042 | 838 | 1115 | RETURN OLD; | |
2043 | 839 | COMMENT ON COLUMN bugtask.sourcepackagename IS 'The name of the sourcepackage in which this bug shows up.'; | 1116 | ELSE |
2044 | 840 | 1117 | IF TG_WHEN = 'BEFORE' THEN | |
2045 | 841 | 1118 | PERFORM unsummarise_bug(OLD.bug); | |
2046 | 842 | COMMENT ON COLUMN bugtask.binarypackagename IS 'The name of the binary package built from the source package. This column may only contain a value if this bug task is linked to a sourcepackage (not a product)'; | 1119 | IF OLD.bug <> NEW.bug THEN |
2047 | 843 | 1120 | PERFORM unsummarise_bug(NEW.bug); | |
2048 | 844 | 1121 | END IF; | |
2049 | 845 | COMMENT ON COLUMN bugtask.status IS 'The general health of the bug, e.g. Accepted, Rejected, etc.'; | 1122 | ELSE |
2050 | 846 | 1123 | PERFORM summarise_bug(OLD.bug); | |
2051 | 847 | 1124 | IF OLD.bug <> NEW.bug THEN | |
2052 | 848 | COMMENT ON COLUMN bugtask.importance IS 'The importance of fixing the bug.'; | 1125 | PERFORM summarise_bug(NEW.bug); |
2053 | 849 | 1126 | END IF; | |
2054 | 850 | 1127 | END IF; | |
2055 | 851 | COMMENT ON COLUMN bugtask.assignee IS 'The person who has been assigned to fix this bug in this product or (sourcepackagename, distro)'; | 1128 | PERFORM bug_summary_flush_temp_journal(); |
2056 | 852 | 1129 | RETURN NEW; | |
2057 | 853 | 1130 | END IF; | |
2058 | 854 | COMMENT ON COLUMN bugtask.date_assigned IS 'The date on which the bug in this (sourcepackagename, distro) or product was assigned to someone to fix'; | 1131 | END; |
2059 | 855 | 1132 | $$; | |
2060 | 856 | 1133 | ||
2061 | 857 | COMMENT ON COLUMN bugtask.datecreated IS 'A timestamp for the creation of this bug assignment. Note that this is not the date the bug was created (though it might be), it''s the date the bug was assigned to this product, which could have come later.'; | 1134 | |
2062 | 858 | 1135 | COMMENT ON FUNCTION public.bugtag_maintain_bug_summary() IS 'AFTER trigger on bugtag maintaining the bugs summaries in bugsummary.'; | |
2063 | 859 | 1136 | ||
2064 | 860 | COMMENT ON COLUMN bugtask.milestone IS 'A way to mark a bug for grouping purposes, e.g. to say it needs to be fixed by version 1.2'; | 1137 | |
2065 | 861 | 1138 | CREATE FUNCTION public.bugtask_flatten(task_id integer, check_only boolean) RETURNS boolean | |
2066 | 862 | 1139 | LANGUAGE plpgsql SECURITY DEFINER | |
2067 | 863 | COMMENT ON COLUMN bugtask.bugwatch IS 'This column allows us to link a bug | 1140 | SET search_path TO 'public' |
2068 | 864 | task to a bug watch. In other words, we are connecting the state of the task | 1141 | AS $$ |
2069 | 865 | to the state of the bug in a different bug tracking system. To the best of | 1142 | DECLARE |
2070 | 866 | our ability we''ll try and keep the bug task syncronised with the state of | 1143 | bug_row Bug%ROWTYPE; |
2071 | 867 | the remote bug watch.'; | 1144 | task_row BugTask%ROWTYPE; |
2072 | 868 | 1145 | old_flat_row BugTaskFlat%ROWTYPE; | |
2073 | 869 | 1146 | new_flat_row BugTaskFlat%ROWTYPE; | |
2074 | 870 | COMMENT ON COLUMN bugtask.targetnamecache IS 'A cached value of the target name of this bugtask, to make it easier to sort and search on the target name.'; | 1147 | _product_active boolean; |
2075 | 871 | 1148 | _access_policies integer[]; | |
2076 | 872 | 1149 | _access_grants integer[]; | |
2077 | 873 | COMMENT ON COLUMN bugtask.date_confirmed IS 'The date when this bug transitioned from an unconfirmed status to a confirmed one. If the state regresses to a one that logically occurs before Confirmed, e.g., Unconfirmed, this date is cleared.'; | 1150 | BEGIN |
2078 | 874 | 1151 | -- This is the master function to update BugTaskFlat, but there are | |
2079 | 875 | 1152 | -- maintenance triggers and jobs on the involved tables that update | |
2080 | 876 | COMMENT ON COLUMN bugtask.date_inprogress IS 'The date on which this bug transitioned from not being in progress to a state >= In Progress. If the status moves back to a pre-In Progress state, this date is cleared'; | 1153 | -- it directly. Any changes here probably require a corresponding |
2081 | 877 | 1154 | -- change in other trigger functions. | |
2082 | 878 | 1155 | ||
2083 | 879 | COMMENT ON COLUMN bugtask.date_closed IS 'The date when this bug transitioned to a resolved state, e.g., Rejected, Fix Released, etc. If the state changes back to a pre-closed state, this date is cleared'; | 1156 | SELECT * INTO task_row FROM BugTask WHERE id = task_id; |
2084 | 880 | 1157 | SELECT * INTO old_flat_row FROM BugTaskFlat WHERE bugtask = task_id; | |
2085 | 881 | 1158 | ||
2086 | 882 | COMMENT ON COLUMN bugtask.productseries IS 'The product series to which the bug is targeted'; | 1159 | -- If the task doesn't exist, ensure that there's no flat row. |
2087 | 883 | 1160 | IF task_row.id IS NULL THEN | |
2088 | 884 | 1161 | IF old_flat_row.bugtask IS NOT NULL THEN | |
2089 | 885 | COMMENT ON COLUMN bugtask.date_left_new IS 'The date when this bug first transitioned out of the NEW status.'; | 1162 | IF NOT check_only THEN |
2090 | 886 | 1163 | DELETE FROM BugTaskFlat WHERE bugtask = task_id; | |
2091 | 887 | 1164 | END IF; | |
2092 | 888 | COMMENT ON COLUMN bugtask.date_triaged IS 'The date when this bug transitioned to a status >= TRIAGED.'; | 1165 | RETURN FALSE; |
2093 | 889 | 1166 | ELSE | |
2094 | 890 | 1167 | RETURN TRUE; | |
2095 | 891 | COMMENT ON COLUMN bugtask.date_fix_committed IS 'The date when this bug transitioned to a status >= FIXCOMMITTED.'; | 1168 | END IF; |
2096 | 892 | 1169 | END IF; | |
2097 | 893 | 1170 | ||
2098 | 894 | COMMENT ON COLUMN bugtask.date_fix_released IS 'The date when this bug transitioned to a FIXRELEASED status.'; | 1171 | SELECT * FROM bug INTO bug_row WHERE id = task_row.bug; |
2099 | 895 | 1172 | ||
2100 | 896 | 1173 | -- If it's a product(series) task, we must consult the active flag. | |
2101 | 897 | COMMENT ON COLUMN bugtask.date_left_closed IS 'The date when this bug last transitioned out of a CLOSED status.'; | 1174 | IF task_row.product IS NOT NULL THEN |
2102 | 898 | 1175 | SELECT product.active INTO _product_active | |
2103 | 899 | 1176 | FROM product WHERE product.id = task_row.product LIMIT 1; | |
2104 | 900 | COMMENT ON COLUMN bugtask.heat_rank IS 'The heat bin in which this bugtask appears, as a value from the BugTaskHeatRank enumeration.'; | 1177 | ELSIF task_row.productseries IS NOT NULL THEN |
2105 | 901 | 1178 | SELECT product.active INTO _product_active | |
2106 | 902 | 1179 | FROM | |
2107 | 903 | COMMENT ON COLUMN bugtask.date_milestone_set IS 'The date when this bug was targed to the milestone that is currently set.'; | 1180 | product |
2108 | 904 | 1181 | JOIN productseries ON productseries.product = product.id | |
2109 | 905 | 1182 | WHERE productseries.id = task_row.productseries LIMIT 1; | |
2110 | 906 | CREATE FUNCTION bugsummary_tasks(bug_row bug) RETURNS SETOF bugtask | 1183 | END IF; |
2111 | 907 | LANGUAGE plpgsql STABLE | 1184 | |
2112 | 908 | AS $$ | 1185 | SELECT policies, grants |
2113 | 909 | DECLARE | 1186 | INTO _access_policies, _access_grants |
2114 | 910 | bt bugtask%ROWTYPE; | 1187 | FROM bug_build_access_cache(bug_row.id, bug_row.information_type) |
2115 | 911 | r record; | 1188 | AS (policies integer[], grants integer[]); |
2116 | 912 | BEGIN | 1189 | |
2117 | 913 | bt.bug = BUG_ROW.id; | 1190 | -- Compile the new flat row. |
2118 | 914 | 1191 | SELECT task_row.id, bug_row.id, task_row.datecreated, | |
2119 | 915 | -- One row only for each target permutation - need to ignore other fields | 1192 | bug_row.duplicateof, bug_row.owner, bug_row.fti, |
2120 | 916 | -- like date last modified to deal with conjoined masters and multiple | 1193 | bug_row.information_type, bug_row.date_last_updated, |
2121 | 917 | -- sourcepackage tasks in a distro. | 1194 | bug_row.heat, task_row.product, task_row.productseries, |
2122 | 918 | FOR r IN | 1195 | task_row.distribution, task_row.distroseries, |
2123 | 919 | SELECT | 1196 | task_row.sourcepackagename, task_row.status, |
2124 | 920 | product, productseries, distribution, distroseries, | 1197 | task_row.importance, task_row.assignee, |
2125 | 921 | sourcepackagename, status, milestone, importance, bugwatch | 1198 | task_row.milestone, task_row.owner, |
2126 | 922 | FROM BugTask WHERE bug=BUG_ROW.id | 1199 | COALESCE(_product_active, TRUE), |
2127 | 923 | UNION -- Implicit DISTINCT | 1200 | _access_policies, |
2128 | 924 | SELECT | 1201 | _access_grants, |
2129 | 925 | product, productseries, distribution, distroseries, | 1202 | bug_row.latest_patch_uploaded, task_row.date_closed |
2130 | 926 | NULL, status, milestone, importance, bugwatch | 1203 | INTO new_flat_row; |
2131 | 927 | FROM BugTask WHERE bug=BUG_ROW.id AND sourcepackagename IS NOT NULL | 1204 | |
2132 | 928 | LOOP | 1205 | -- Calculate the necessary updates. |
2133 | 929 | bt.product = r.product; | 1206 | IF old_flat_row.bugtask IS NULL THEN |
2134 | 930 | bt.productseries = r.productseries; | 1207 | IF NOT check_only THEN |
2135 | 931 | bt.distribution = r.distribution; | 1208 | INSERT INTO BugTaskFlat VALUES (new_flat_row.*); |
2136 | 932 | bt.distroseries = r.distroseries; | 1209 | END IF; |
2137 | 933 | bt.sourcepackagename = r.sourcepackagename; | 1210 | RETURN FALSE; |
2138 | 934 | bt.status = r.status; | 1211 | ELSIF new_flat_row != old_flat_row THEN |
2139 | 935 | bt.milestone = r.milestone; | 1212 | IF NOT check_only THEN |
2140 | 936 | bt.importance = r.importance; | 1213 | UPDATE BugTaskFlat SET |
2141 | 937 | bt.bugwatch = r.bugwatch; | 1214 | bug = new_flat_row.bug, |
2142 | 938 | RETURN NEXT bt; | 1215 | datecreated = new_flat_row.datecreated, |
2143 | 939 | END LOOP; | 1216 | duplicateof = new_flat_row.duplicateof, |
2144 | 940 | END; | 1217 | bug_owner = new_flat_row.bug_owner, |
2145 | 941 | $$; | 1218 | fti = new_flat_row.fti, |
2146 | 942 | 1219 | information_type = new_flat_row.information_type, | |
2147 | 943 | 1220 | date_last_updated = new_flat_row.date_last_updated, | |
2148 | 944 | COMMENT ON FUNCTION bugsummary_tasks(bug_row bug) IS 'Return all tasks for the bug + all sourcepackagename tasks again with the sourcepackagename squashed'; | 1221 | heat = new_flat_row.heat, |
2149 | 945 | 1222 | product = new_flat_row.product, | |
2150 | 946 | 1223 | productseries = new_flat_row.productseries, | |
2151 | 947 | CREATE TABLE bugsubscription ( | 1224 | distribution = new_flat_row.distribution, |
2152 | 948 | id integer NOT NULL, | 1225 | distroseries = new_flat_row.distroseries, |
2153 | 949 | person integer NOT NULL, | 1226 | sourcepackagename = new_flat_row.sourcepackagename, |
2154 | 950 | bug integer NOT NULL, | 1227 | status = new_flat_row.status, |
2155 | 951 | date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL, | 1228 | importance = new_flat_row.importance, |
2156 | 952 | subscribed_by integer NOT NULL, | 1229 | assignee = new_flat_row.assignee, |
2157 | 953 | bug_notification_level integer DEFAULT 40 NOT NULL | 1230 | milestone = new_flat_row.milestone, |
2158 | 954 | ); | 1231 | owner = new_flat_row.owner, |
2159 | 955 | 1232 | active = new_flat_row.active, | |
2160 | 956 | 1233 | access_policies = new_flat_row.access_policies, | |
2161 | 957 | COMMENT ON TABLE bugsubscription IS 'A subscription by a Person to a bug.'; | 1234 | access_grants = new_flat_row.access_grants, |
2162 | 958 | 1235 | date_closed = new_flat_row.date_closed, | |
2163 | 959 | 1236 | latest_patch_uploaded = new_flat_row.latest_patch_uploaded | |
2164 | 960 | COMMENT ON COLUMN bugsubscription.bug_notification_level IS 'The level of notifications which the Person will receive from this subscription.'; | 1237 | WHERE bugtask = new_flat_row.bugtask; |
2165 | 961 | 1238 | END IF; | |
2166 | 962 | 1239 | RETURN FALSE; | |
2167 | 963 | CREATE FUNCTION bugsummary_viewers(bug_row bug) RETURNS SETOF bugsubscription | 1240 | ELSE |
2168 | 964 | LANGUAGE sql STABLE | 1241 | RETURN TRUE; |
2169 | 965 | AS $_$ | 1242 | END IF; |
2170 | 966 | SELECT * | 1243 | END; |
2171 | 967 | FROM BugSubscription | 1244 | $$; |
2172 | 968 | WHERE | 1245 | |
2173 | 969 | bugsubscription.bug=$1.id | 1246 | |
2174 | 970 | AND $1.private IS TRUE; | 1247 | COMMENT ON FUNCTION public.bugtask_flatten(task_id integer, check_only boolean) IS 'Create or update a BugTaskFlat row from the source tables. Returns whether the row was up to date. If check_only is true, the row is not brought up to date.'; |
2175 | 971 | $_$; | 1248 | |
2176 | 972 | 1249 | ||
2177 | 973 | 1250 | CREATE FUNCTION public.bugtask_maintain_bugtaskflat_trig() RETURNS trigger | |
2178 | 974 | COMMENT ON FUNCTION bugsummary_viewers(bug_row bug) IS 'Return (bug, viewer) for all viewers if private, nothing otherwise'; | 1251 | LANGUAGE plpgsql SECURITY DEFINER |
2179 | 975 | 1252 | SET search_path TO 'public' | |
2180 | 976 | 1253 | AS $$ | |
2181 | 977 | CREATE FUNCTION bugtag_maintain_bug_summary() RETURNS trigger | 1254 | BEGIN |
2182 | 978 | LANGUAGE plpgsql SECURITY DEFINER | 1255 | IF TG_OP = 'INSERT' THEN |
2183 | 979 | SET search_path TO public | 1256 | PERFORM bugtask_flatten(NEW.id, FALSE); |
2184 | 980 | AS $$ | 1257 | ELSIF TG_OP = 'UPDATE' THEN |
2185 | 981 | BEGIN | 1258 | IF NEW.bug != OLD.bug THEN |
2186 | 982 | IF TG_OP = 'INSERT' THEN | 1259 | RAISE EXCEPTION 'cannot move bugtask to a different bug'; |
2187 | 983 | IF TG_WHEN = 'BEFORE' THEN | 1260 | ELSIF (NEW.product IS DISTINCT FROM OLD.product |
2188 | 984 | PERFORM unsummarise_bug(bug_row(NEW.bug)); | 1261 | OR NEW.productseries IS DISTINCT FROM OLD.productseries) THEN |
2189 | 985 | ELSE | 1262 | -- product.active may differ. Do a full update. |
2190 | 986 | PERFORM summarise_bug(bug_row(NEW.bug)); | 1263 | PERFORM bugtask_flatten(NEW.id, FALSE); |
2191 | 987 | END IF; | 1264 | ELSIF ( |
2192 | 988 | PERFORM bug_summary_flush_temp_journal(); | 1265 | NEW.datecreated IS DISTINCT FROM OLD.datecreated |
2193 | 989 | RETURN NEW; | 1266 | OR NEW.product IS DISTINCT FROM OLD.product |
2194 | 990 | ELSIF TG_OP = 'DELETE' THEN | 1267 | OR NEW.productseries IS DISTINCT FROM OLD.productseries |
2195 | 991 | IF TG_WHEN = 'BEFORE' THEN | 1268 | OR NEW.distribution IS DISTINCT FROM OLD.distribution |
2196 | 992 | PERFORM unsummarise_bug(bug_row(OLD.bug)); | 1269 | OR NEW.distroseries IS DISTINCT FROM OLD.distroseries |
2197 | 993 | ELSE | 1270 | OR NEW.sourcepackagename IS DISTINCT FROM OLD.sourcepackagename |
2198 | 994 | PERFORM summarise_bug(bug_row(OLD.bug)); | 1271 | OR NEW.status IS DISTINCT FROM OLD.status |
2199 | 995 | END IF; | 1272 | OR NEW.importance IS DISTINCT FROM OLD.importance |
2200 | 996 | PERFORM bug_summary_flush_temp_journal(); | 1273 | OR NEW.assignee IS DISTINCT FROM OLD.assignee |
2201 | 997 | RETURN OLD; | 1274 | OR NEW.milestone IS DISTINCT FROM OLD.milestone |
2202 | 998 | ELSE | 1275 | OR NEW.owner IS DISTINCT FROM OLD.owner |
2203 | 999 | IF TG_WHEN = 'BEFORE' THEN | 1276 | OR NEW.date_closed IS DISTINCT FROM OLD.date_closed) THEN |
2204 | 1000 | PERFORM unsummarise_bug(bug_row(OLD.bug)); | 1277 | -- Otherwise just update the columns from bugtask. |
2205 | 1001 | IF OLD.bug <> NEW.bug THEN | 1278 | -- Access policies and grants may have changed due to target |
2206 | 1002 | PERFORM unsummarise_bug(bug_row(NEW.bug)); | 1279 | -- transitions, but an earlier trigger will already have |
2207 | 1003 | END IF; | 1280 | -- mirrored them to all relevant flat tasks. |
2208 | 1004 | ELSE | 1281 | UPDATE BugTaskFlat SET |
2209 | 1005 | PERFORM summarise_bug(bug_row(OLD.bug)); | 1282 | datecreated = NEW.datecreated, |
2210 | 1006 | IF OLD.bug <> NEW.bug THEN | 1283 | product = NEW.product, |
2211 | 1007 | PERFORM summarise_bug(bug_row(NEW.bug)); | 1284 | productseries = NEW.productseries, |
2212 | 1008 | END IF; | 1285 | distribution = NEW.distribution, |
2213 | 1009 | END IF; | 1286 | distroseries = NEW.distroseries, |
2214 | 1010 | PERFORM bug_summary_flush_temp_journal(); | 1287 | sourcepackagename = NEW.sourcepackagename, |
2215 | 1011 | RETURN NEW; | 1288 | status = NEW.status, |
2216 | 1012 | END IF; | 1289 | importance = NEW.importance, |
2217 | 1013 | END; | 1290 | assignee = NEW.assignee, |
2218 | 1014 | $$; | 1291 | milestone = NEW.milestone, |
2219 | 1015 | 1292 | owner = NEW.owner, | |
2220 | 1016 | 1293 | date_closed = NEW.date_closed | |
2221 | 1017 | COMMENT ON FUNCTION bugtag_maintain_bug_summary() IS 'AFTER trigger on bugtag maintaining the bugs summaries in bugsummary.'; | 1294 | WHERE bugtask = NEW.id; |
2222 | 1018 | 1295 | END IF; | |
2223 | 1019 | 1296 | ELSIF TG_OP = 'DELETE' THEN | |
2224 | 1020 | CREATE FUNCTION bugtask_maintain_bug_summary() RETURNS trigger | 1297 | PERFORM bugtask_flatten(OLD.id, FALSE); |
2225 | 1021 | LANGUAGE plpgsql SECURITY DEFINER | 1298 | END IF; |
2226 | 1022 | SET search_path TO public | 1299 | RETURN NULL; |
2227 | 1023 | AS $$ | 1300 | END; |
2228 | 1024 | BEGIN | 1301 | $$; |
2229 | 1025 | -- This trigger only works if we are inserting, updating or deleting | 1302 | |
2230 | 1026 | -- a single row per statement. | 1303 | |
2231 | 1027 | 1304 | CREATE FUNCTION public.bugtaskflat_maintain_bug_summary() RETURNS trigger | |
2232 | 1028 | -- Unlike bug_maintain_bug_summary, this trigger does not have access | 1305 | LANGUAGE plpgsql SECURITY DEFINER |
2233 | 1029 | -- to the old bug when invoked as an AFTER trigger. To work around this | 1306 | SET search_path TO 'public' |
2234 | 1030 | -- we install this trigger as both a BEFORE and an AFTER trigger. | 1307 | AS $$ |
2235 | 1031 | IF TG_OP = 'INSERT' THEN | 1308 | BEGIN |
2236 | 1032 | IF TG_WHEN = 'BEFORE' THEN | 1309 | IF TG_OP = 'INSERT' THEN |
2237 | 1033 | PERFORM unsummarise_bug(bug_row(NEW.bug)); | 1310 | PERFORM bugsummary_journal_bugtaskflat(NEW, 1); |
2238 | 1034 | ELSE | 1311 | PERFORM bug_summary_flush_temp_journal(); |
2239 | 1035 | PERFORM summarise_bug(bug_row(NEW.bug)); | 1312 | ELSIF TG_OP = 'DELETE' THEN |
2240 | 1036 | END IF; | 1313 | PERFORM bugsummary_journal_bugtaskflat(OLD, -1); |
2241 | 1037 | PERFORM bug_summary_flush_temp_journal(); | 1314 | PERFORM bug_summary_flush_temp_journal(); |
2242 | 1038 | RETURN NEW; | 1315 | ELSIF |
2243 | 1039 | 1316 | NEW.product IS DISTINCT FROM OLD.product | |
2244 | 1040 | ELSIF TG_OP = 'DELETE' THEN | 1317 | OR NEW.productseries IS DISTINCT FROM OLD.productseries |
2245 | 1041 | IF TG_WHEN = 'BEFORE' THEN | 1318 | OR NEW.distribution IS DISTINCT FROM OLD.distribution |
2246 | 1042 | PERFORM unsummarise_bug(bug_row(OLD.bug)); | 1319 | OR NEW.distroseries IS DISTINCT FROM OLD.distroseries |
2247 | 1043 | ELSE | 1320 | OR NEW.sourcepackagename IS DISTINCT FROM OLD.sourcepackagename |
2248 | 1044 | PERFORM summarise_bug(bug_row(OLD.bug)); | 1321 | OR NEW.status IS DISTINCT FROM OLD.status |
2249 | 1045 | END IF; | 1322 | OR NEW.milestone IS DISTINCT FROM OLD.milestone |
2250 | 1046 | PERFORM bug_summary_flush_temp_journal(); | 1323 | OR NEW.importance IS DISTINCT FROM OLD.importance |
2251 | 1047 | RETURN OLD; | 1324 | OR NEW.latest_patch_uploaded IS DISTINCT FROM OLD.latest_patch_uploaded |
2252 | 1048 | 1325 | OR NEW.information_type IS DISTINCT FROM OLD.information_type | |
2253 | 1049 | ELSE | 1326 | OR NEW.access_grants IS DISTINCT FROM OLD.access_grants |
2254 | 1050 | IF (OLD.product IS DISTINCT FROM NEW.product | 1327 | OR NEW.access_policies IS DISTINCT FROM OLD.access_policies |
2255 | 1051 | OR OLD.productseries IS DISTINCT FROM NEW.productseries | 1328 | OR NEW.duplicateof IS DISTINCT FROM OLD.duplicateof |
2256 | 1052 | OR OLD.distribution IS DISTINCT FROM NEW.distribution | 1329 | THEN |
2257 | 1053 | OR OLD.distroseries IS DISTINCT FROM NEW.distroseries | 1330 | PERFORM bugsummary_journal_bugtaskflat(OLD, -1); |
2258 | 1054 | OR OLD.sourcepackagename IS DISTINCT FROM NEW.sourcepackagename | 1331 | PERFORM bugsummary_journal_bugtaskflat(NEW, 1); |
2259 | 1055 | OR OLD.status IS DISTINCT FROM NEW.status | 1332 | PERFORM bug_summary_flush_temp_journal(); |
2260 | 1056 | OR OLD.importance IS DISTINCT FROM NEW.importance | 1333 | END IF; |
2261 | 1057 | OR OLD.bugwatch IS DISTINCT FROM NEW.bugwatch | 1334 | RETURN NULL; |
2262 | 1058 | OR OLD.milestone IS DISTINCT FROM NEW.milestone) THEN | 1335 | END; |
2263 | 1059 | 1336 | $$; | |
2264 | 1060 | IF TG_WHEN = 'BEFORE' THEN | 1337 | |
2265 | 1061 | PERFORM unsummarise_bug(bug_row(OLD.bug)); | 1338 | |
2266 | 1062 | IF OLD.bug <> NEW.bug THEN | 1339 | CREATE FUNCTION public.build_access_cache(art_id integer, information_type integer) RETURNS record |
2267 | 1063 | PERFORM unsummarise_bug(bug_row(NEW.bug)); | 1340 | LANGUAGE plpgsql |
2268 | 1064 | END IF; | 1341 | AS $$ |
2269 | 1065 | ELSE | 1342 | DECLARE |
2270 | 1066 | PERFORM summarise_bug(bug_row(OLD.bug)); | 1343 | _policies integer[]; |
2271 | 1067 | IF OLD.bug <> NEW.bug THEN | 1344 | _grants integer[]; |
2272 | 1068 | PERFORM summarise_bug(bug_row(NEW.bug)); | 1345 | cache record; |
2273 | 1069 | END IF; | 1346 | BEGIN |
2274 | 1070 | END IF; | 1347 | -- If private, grab the access control information. |
2275 | 1071 | END IF; | 1348 | -- If public, access_policies and access_grants are NULL. |
2276 | 1072 | PERFORM bug_summary_flush_temp_journal(); | 1349 | -- 3 == PRIVATESECURITY, 4 == USERDATA, 5 == PROPRIETARY |
2277 | 1073 | RETURN NEW; | 1350 | -- 6 == EMBARGOED |
2278 | 1074 | END IF; | 1351 | IF information_type NOT IN (1, 2) THEN |
2279 | 1075 | END; | 1352 | SELECT COALESCE(array_agg(policy ORDER BY policy), ARRAY[]::integer[]) |
2280 | 1076 | $$; | 1353 | INTO _policies FROM accesspolicyartifact WHERE artifact = art_id; |
2281 | 1077 | 1354 | SELECT COALESCE(array_agg(grantee ORDER BY grantee), ARRAY[]::integer[]) | |
2282 | 1078 | 1355 | INTO _grants FROM accessartifactgrant WHERE artifact = art_id; | |
2283 | 1079 | COMMENT ON FUNCTION bugtask_maintain_bug_summary() IS 'Both BEFORE & AFTER trigger on bugtask maintaining the bugs summaries in bugsummary.'; | 1356 | END IF; |
2284 | 1080 | 1357 | cache := (_policies, _grants); | |
2285 | 1081 | 1358 | RETURN cache; | |
2286 | 1082 | CREATE FUNCTION calculate_bug_heat(bug_id integer) RETURNS integer | 1359 | END; |
2287 | 1083 | LANGUAGE plpythonu STABLE STRICT | 1360 | $$; |
2288 | 1084 | AS $$ | 1361 | |
2289 | 1085 | from datetime import datetime | 1362 | |
2290 | 1086 | 1363 | CREATE FUNCTION public.calculate_bug_heat(bug_id integer) RETURNS integer | |
2291 | 1087 | class BugHeatConstants: | 1364 | LANGUAGE sql STABLE STRICT |
2292 | 1088 | PRIVACY = 150 | 1365 | AS $_$ |
2293 | 1089 | SECURITY = 250 | 1366 | SELECT |
2294 | 1090 | DUPLICATE = 6 | 1367 | (CASE information_type WHEN 1 THEN 0 WHEN 2 THEN 250 |
2295 | 1091 | AFFECTED_USER = 4 | 1368 | WHEN 3 THEN 400 ELSE 150 END) |
2296 | 1092 | SUBSCRIBER = 2 | 1369 | + (number_of_duplicates * 6) |
2297 | 1093 | 1370 | + (users_affected_count * 4) | |
2298 | 1094 | def get_max_heat_for_bug(bug_id): | 1371 | + ( |
2299 | 1095 | results = plpy.execute(""" | 1372 | SELECT COUNT(DISTINCT person) * 2 |
2300 | 1096 | SELECT MAX( | 1373 | FROM BugSubscription |
2301 | 1097 | GREATEST(Product.max_bug_heat, | 1374 | JOIN Bug AS SubBug ON BugSubscription.bug = SubBug.id |
2302 | 1098 | DistributionSourcePackage.max_bug_heat)) | 1375 | WHERE SubBug.id = $1 OR SubBug.duplicateof = $1)::integer AS heat |
2303 | 1099 | AS max_heat | 1376 | FROM Bug WHERE Bug.id = $1; |
2304 | 1100 | FROM BugTask | 1377 | $_$; |
2305 | 1101 | LEFT OUTER JOIN ProductSeries ON | 1378 | |
2306 | 1102 | BugTask.productseries = ProductSeries.id | 1379 | |
2307 | 1103 | LEFT OUTER JOIN Product ON ( | 1380 | CREATE FUNCTION public.cursor_fetch(cur refcursor, n integer) RETURNS SETOF record |
1872 | 1104 | BugTask.product = Product.id | ||
1873 | 1105 | OR ProductSeries.product = Product.id) | ||
1874 | 1106 | LEFT OUTER JOIN DistroSeries ON | ||
1875 | 1107 | BugTask.distroseries = DistroSeries.id | ||
1876 | 1108 | LEFT OUTER JOIN Distribution ON ( | ||
1877 | 1109 | BugTask.distribution = Distribution.id | ||
1878 | 1110 | OR DistroSeries.distribution = Distribution.id) | ||
1879 | 1111 | LEFT OUTER JOIN DistributionSourcePackage ON ( | ||
1880 | 1112 | BugTask.sourcepackagename = | ||
1881 | 1113 | DistributionSourcePackage.sourcepackagename) | ||
1882 | 1114 | WHERE | ||
1883 | 1115 | BugTask.bug = %s""" % bug_id) | ||
1884 | 1116 | |||
1885 | 1117 | return results[0]['max_heat'] | ||
1886 | 1118 | |||
1887 | 1119 | # It would be nice to be able to just SELECT * here, but we need the | ||
1888 | 1120 | # timestamps to be in a format that datetime.fromtimestamp() will | ||
1889 | 1121 | # understand. | ||
1890 | 1122 | bug_data = plpy.execute(""" | ||
1891 | 1123 | SELECT | ||
1892 | 1124 | duplicateof, | ||
1893 | 1125 | private, | ||
1894 | 1126 | security_related, | ||
1895 | 1127 | number_of_duplicates, | ||
1896 | 1128 | users_affected_count, | ||
1897 | 1129 | EXTRACT(epoch from datecreated) | ||
1898 | 1130 | AS timestamp_date_created, | ||
1899 | 1131 | EXTRACT(epoch from date_last_updated) | ||
1900 | 1132 | AS timestamp_date_last_updated, | ||
1901 | 1133 | EXTRACT(epoch from date_last_message) | ||
1902 | 1134 | AS timestamp_date_last_message | ||
1903 | 1135 | FROM Bug WHERE id = %s""" % bug_id) | ||
1904 | 1136 | |||
1905 | 1137 | if bug_data.nrows() == 0: | ||
1906 | 1138 | raise Exception("Bug %s doesn't exist." % bug_id) | ||
1907 | 1139 | |||
1908 | 1140 | bug = bug_data[0] | ||
1909 | 1141 | if bug['duplicateof'] is not None: | ||
1910 | 1142 | return None | ||
1911 | 1143 | |||
1912 | 1144 | heat = {} | ||
1913 | 1145 | heat['dupes'] = ( | ||
1914 | 1146 | BugHeatConstants.DUPLICATE * bug['number_of_duplicates']) | ||
1915 | 1147 | heat['affected_users'] = ( | ||
1916 | 1148 | BugHeatConstants.AFFECTED_USER * | ||
1917 | 1149 | bug['users_affected_count']) | ||
1918 | 1150 | |||
1919 | 1151 | if bug['private']: | ||
1920 | 1152 | heat['privacy'] = BugHeatConstants.PRIVACY | ||
1921 | 1153 | if bug['security_related']: | ||
1922 | 1154 | heat['security'] = BugHeatConstants.SECURITY | ||
1923 | 1155 | |||
1924 | 1156 | # Get the heat from subscribers, both direct and via duplicates. | ||
1925 | 1157 | subs_from_dupes = plpy.execute(""" | ||
1926 | 1158 | SELECT COUNT(DISTINCT BugSubscription.person) AS sub_count | ||
1927 | 1159 | FROM BugSubscription, Bug | ||
1928 | 1160 | WHERE Bug.id = BugSubscription.bug | ||
1929 | 1161 | AND (Bug.id = %s OR Bug.duplicateof = %s)""" | ||
1930 | 1162 | % (bug_id, bug_id)) | ||
1931 | 1163 | |||
1932 | 1164 | heat['subcribers'] = ( | ||
1933 | 1165 | BugHeatConstants.SUBSCRIBER | ||
1934 | 1166 | * subs_from_dupes[0]['sub_count']) | ||
1935 | 1167 | |||
1936 | 1168 | total_heat = sum(heat.values()) | ||
1937 | 1169 | |||
1938 | 1170 | # Bugs decay over time. Every day the bug isn't touched its heat | ||
1939 | 1171 | # decreases by 1%. | ||
1940 | 1172 | date_last_updated = datetime.fromtimestamp( | ||
1941 | 1173 | bug['timestamp_date_last_updated']) | ||
1942 | 1174 | days_since_last_update = (datetime.utcnow() - date_last_updated).days | ||
1943 | 1175 | total_heat = int(total_heat * (0.99 ** days_since_last_update)) | ||
1944 | 1176 | |||
1945 | 1177 | if days_since_last_update > 0: | ||
1946 | 1178 | # Bug heat increases by a quarter of the maximum bug heat | ||
1947 | 1179 | # divided by the number of days since the bug's creation date. | ||
1948 | 1180 | date_created = datetime.fromtimestamp( | ||
1949 | 1181 | bug['timestamp_date_created']) | ||
1950 | 1182 | |||
1951 | 1183 | if bug['timestamp_date_last_message'] is not None: | ||
1952 | 1184 | date_last_message = datetime.fromtimestamp( | ||
1953 | 1185 | bug['timestamp_date_last_message']) | ||
1954 | 1186 | oldest_date = max(date_last_updated, date_last_message) | ||
1955 | 1187 | else: | ||
1956 | 1188 | date_last_message = None | ||
1957 | 1189 | oldest_date = date_last_updated | ||
1958 | 1190 | |||
1959 | 1191 | days_since_last_activity = (datetime.utcnow() - oldest_date).days | ||
1960 | 1192 | days_since_created = (datetime.utcnow() - date_created).days | ||
1961 | 1193 | max_heat = get_max_heat_for_bug(bug_id) | ||
1962 | 1194 | if max_heat is not None and days_since_created > 0: | ||
1963 | 1195 | total_heat = ( | ||
1964 | 1196 | total_heat + (max_heat * 0.25 / days_since_created)) | ||
1965 | 1197 | |||
1966 | 1198 | return int(total_heat) | ||
1967 | 1199 | $$; | ||
1968 | 1200 | |||
1969 | 1201 | |||
1970 | 1202 | CREATE FUNCTION cursor_fetch(cur refcursor, n integer) RETURNS SETOF record | ||
2308 | 1203 | LANGUAGE plpgsql | 1381 | LANGUAGE plpgsql |
2309 | 1204 | AS $$ | 1382 | AS $$ |
2310 | 1205 | DECLARE | 1383 | DECLARE |
2311 | @@ -1217,86 +1395,86 @@ | |||
2312 | 1217 | $$; | 1395 | $$; |
2313 | 1218 | 1396 | ||
2314 | 1219 | 1397 | ||
2319 | 1220 | COMMENT ON FUNCTION cursor_fetch(cur refcursor, n integer) IS 'Fetch the next n items from a cursor. Work around for not being able to use FETCH inside a SELECT statement.'; | 1398 | COMMENT ON FUNCTION public.cursor_fetch(cur refcursor, n integer) IS 'Fetch the next n items from a cursor. Work around for not being able to use FETCH inside a SELECT statement.'; |
2320 | 1221 | 1399 | ||
2321 | 1222 | 1400 | ||
2322 | 1223 | CREATE FUNCTION debversion(character) RETURNS debversion | 1401 | CREATE FUNCTION public.debversion(character) RETURNS public.debversion |
2323 | 1224 | LANGUAGE internal IMMUTABLE STRICT | 1402 | LANGUAGE internal IMMUTABLE STRICT |
2324 | 1225 | AS $$rtrim1$$; | 1403 | AS $$rtrim1$$; |
2325 | 1226 | 1404 | ||
2326 | 1227 | 1405 | ||
2328 | 1228 | CREATE FUNCTION debversion_cmp(version1 debversion, version2 debversion) RETURNS integer | 1406 | CREATE FUNCTION public.debversion_cmp(version1 public.debversion, version2 public.debversion) RETURNS integer |
2329 | 1229 | LANGUAGE c IMMUTABLE STRICT | 1407 | LANGUAGE c IMMUTABLE STRICT |
2330 | 1230 | AS '$libdir/debversion', 'debversion_cmp'; | 1408 | AS '$libdir/debversion', 'debversion_cmp'; |
2331 | 1231 | 1409 | ||
2332 | 1232 | 1410 | ||
2337 | 1233 | COMMENT ON FUNCTION debversion_cmp(version1 debversion, version2 debversion) IS 'Compare Debian versions'; | 1411 | COMMENT ON FUNCTION public.debversion_cmp(version1 public.debversion, version2 public.debversion) IS 'Compare Debian versions'; |
2338 | 1234 | 1412 | ||
2339 | 1235 | 1413 | ||
2340 | 1236 | CREATE FUNCTION debversion_eq(version1 debversion, version2 debversion) RETURNS boolean | 1414 | CREATE FUNCTION public.debversion_eq(version1 public.debversion, version2 public.debversion) RETURNS boolean |
2341 | 1237 | LANGUAGE c IMMUTABLE STRICT | 1415 | LANGUAGE c IMMUTABLE STRICT |
2342 | 1238 | AS '$libdir/debversion', 'debversion_eq'; | 1416 | AS '$libdir/debversion', 'debversion_eq'; |
2343 | 1239 | 1417 | ||
2344 | 1240 | 1418 | ||
2349 | 1241 | COMMENT ON FUNCTION debversion_eq(version1 debversion, version2 debversion) IS 'debversion equal'; | 1419 | COMMENT ON FUNCTION public.debversion_eq(version1 public.debversion, version2 public.debversion) IS 'debversion equal'; |
2350 | 1242 | 1420 | ||
2351 | 1243 | 1421 | ||
2352 | 1244 | CREATE FUNCTION debversion_ge(version1 debversion, version2 debversion) RETURNS boolean | 1422 | CREATE FUNCTION public.debversion_ge(version1 public.debversion, version2 public.debversion) RETURNS boolean |
2353 | 1245 | LANGUAGE c IMMUTABLE STRICT | 1423 | LANGUAGE c IMMUTABLE STRICT |
2354 | 1246 | AS '$libdir/debversion', 'debversion_ge'; | 1424 | AS '$libdir/debversion', 'debversion_ge'; |
2355 | 1247 | 1425 | ||
2356 | 1248 | 1426 | ||
2361 | 1249 | COMMENT ON FUNCTION debversion_ge(version1 debversion, version2 debversion) IS 'debversion greater-than-or-equal'; | 1427 | COMMENT ON FUNCTION public.debversion_ge(version1 public.debversion, version2 public.debversion) IS 'debversion greater-than-or-equal'; |
2362 | 1250 | 1428 | ||
2363 | 1251 | 1429 | ||
2364 | 1252 | CREATE FUNCTION debversion_gt(version1 debversion, version2 debversion) RETURNS boolean | 1430 | CREATE FUNCTION public.debversion_gt(version1 public.debversion, version2 public.debversion) RETURNS boolean |
2365 | 1253 | LANGUAGE c IMMUTABLE STRICT | 1431 | LANGUAGE c IMMUTABLE STRICT |
2366 | 1254 | AS '$libdir/debversion', 'debversion_gt'; | 1432 | AS '$libdir/debversion', 'debversion_gt'; |
2367 | 1255 | 1433 | ||
2368 | 1256 | 1434 | ||
2373 | 1257 | COMMENT ON FUNCTION debversion_gt(version1 debversion, version2 debversion) IS 'debversion greater-than'; | 1435 | COMMENT ON FUNCTION public.debversion_gt(version1 public.debversion, version2 public.debversion) IS 'debversion greater-than'; |
2374 | 1258 | 1436 | ||
2375 | 1259 | 1437 | ||
2376 | 1260 | CREATE FUNCTION debversion_hash(debversion) RETURNS integer | 1438 | CREATE FUNCTION public.debversion_hash(public.debversion) RETURNS integer |
2377 | 1261 | LANGUAGE c IMMUTABLE STRICT | 1439 | LANGUAGE c IMMUTABLE STRICT |
2378 | 1262 | AS '$libdir/debversion', 'debversion_hash'; | 1440 | AS '$libdir/debversion', 'debversion_hash'; |
2379 | 1263 | 1441 | ||
2380 | 1264 | 1442 | ||
2382 | 1265 | CREATE FUNCTION debversion_larger(version1 debversion, version2 debversion) RETURNS debversion | 1443 | CREATE FUNCTION public.debversion_larger(version1 public.debversion, version2 public.debversion) RETURNS public.debversion |
2383 | 1266 | LANGUAGE c IMMUTABLE STRICT | 1444 | LANGUAGE c IMMUTABLE STRICT |
2384 | 1267 | AS '$libdir/debversion', 'debversion_larger'; | 1445 | AS '$libdir/debversion', 'debversion_larger'; |
2385 | 1268 | 1446 | ||
2386 | 1269 | 1447 | ||
2388 | 1270 | CREATE FUNCTION debversion_le(version1 debversion, version2 debversion) RETURNS boolean | 1448 | CREATE FUNCTION public.debversion_le(version1 public.debversion, version2 public.debversion) RETURNS boolean |
2389 | 1271 | LANGUAGE c IMMUTABLE STRICT | 1449 | LANGUAGE c IMMUTABLE STRICT |
2390 | 1272 | AS '$libdir/debversion', 'debversion_le'; | 1450 | AS '$libdir/debversion', 'debversion_le'; |
2391 | 1273 | 1451 | ||
2392 | 1274 | 1452 | ||
2397 | 1275 | COMMENT ON FUNCTION debversion_le(version1 debversion, version2 debversion) IS 'debversion less-than-or-equal'; | 1453 | COMMENT ON FUNCTION public.debversion_le(version1 public.debversion, version2 public.debversion) IS 'debversion less-than-or-equal'; |
2398 | 1276 | 1454 | ||
2399 | 1277 | 1455 | ||
2400 | 1278 | CREATE FUNCTION debversion_lt(version1 debversion, version2 debversion) RETURNS boolean | 1456 | CREATE FUNCTION public.debversion_lt(version1 public.debversion, version2 public.debversion) RETURNS boolean |
2401 | 1279 | LANGUAGE c IMMUTABLE STRICT | 1457 | LANGUAGE c IMMUTABLE STRICT |
2402 | 1280 | AS '$libdir/debversion', 'debversion_lt'; | 1458 | AS '$libdir/debversion', 'debversion_lt'; |
2403 | 1281 | 1459 | ||
2404 | 1282 | 1460 | ||
2409 | 1283 | COMMENT ON FUNCTION debversion_lt(version1 debversion, version2 debversion) IS 'debversion less-than'; | 1461 | COMMENT ON FUNCTION public.debversion_lt(version1 public.debversion, version2 public.debversion) IS 'debversion less-than'; |
2410 | 1284 | 1462 | ||
2411 | 1285 | 1463 | ||
2412 | 1286 | CREATE FUNCTION debversion_ne(version1 debversion, version2 debversion) RETURNS boolean | 1464 | CREATE FUNCTION public.debversion_ne(version1 public.debversion, version2 public.debversion) RETURNS boolean |
2413 | 1287 | LANGUAGE c IMMUTABLE STRICT | 1465 | LANGUAGE c IMMUTABLE STRICT |
2414 | 1288 | AS '$libdir/debversion', 'debversion_ne'; | 1466 | AS '$libdir/debversion', 'debversion_ne'; |
2415 | 1289 | 1467 | ||
2416 | 1290 | 1468 | ||
2421 | 1291 | COMMENT ON FUNCTION debversion_ne(version1 debversion, version2 debversion) IS 'debversion not equal'; | 1469 | COMMENT ON FUNCTION public.debversion_ne(version1 public.debversion, version2 public.debversion) IS 'debversion not equal'; |
2422 | 1292 | 1470 | ||
2423 | 1293 | 1471 | ||
2424 | 1294 | CREATE FUNCTION debversion_smaller(version1 debversion, version2 debversion) RETURNS debversion | 1472 | CREATE FUNCTION public.debversion_smaller(version1 public.debversion, version2 public.debversion) RETURNS public.debversion |
2425 | 1295 | LANGUAGE c IMMUTABLE STRICT | 1473 | LANGUAGE c IMMUTABLE STRICT |
2426 | 1296 | AS '$libdir/debversion', 'debversion_smaller'; | 1474 | AS '$libdir/debversion', 'debversion_smaller'; |
2427 | 1297 | 1475 | ||
2428 | 1298 | 1476 | ||
2430 | 1299 | CREATE FUNCTION debversion_sort_key(version text) RETURNS text | 1477 | CREATE FUNCTION public.debversion_sort_key(version text) RETURNS text |
2431 | 1300 | LANGUAGE plpythonu IMMUTABLE STRICT | 1478 | LANGUAGE plpythonu IMMUTABLE STRICT |
2432 | 1301 | AS $_$ | 1479 | AS $_$ |
2433 | 1302 | # If this method is altered, then any functional indexes using it | 1480 | # If this method is altered, then any functional indexes using it |
2434 | @@ -1365,13 +1543,12 @@ | |||
2435 | 1365 | $_$; | 1543 | $_$; |
2436 | 1366 | 1544 | ||
2437 | 1367 | 1545 | ||
2442 | 1368 | COMMENT ON FUNCTION debversion_sort_key(version text) IS 'Return a string suitable for sorting debian version strings on'; | 1546 | COMMENT ON FUNCTION public.debversion_sort_key(version text) IS 'Return a string suitable for sorting debian version strings on'; |
2443 | 1369 | 1547 | ||
2444 | 1370 | 1548 | ||
2445 | 1371 | CREATE FUNCTION ensure_bugsummary_temp_journal() RETURNS void | 1549 | CREATE FUNCTION public.ensure_bugsummary_temp_journal() RETURNS void |
2446 | 1372 | LANGUAGE plpgsql | 1550 | LANGUAGE plpgsql |
2447 | 1373 | AS $$ | 1551 | AS $$ |
2448 | 1374 | DECLARE | ||
2449 | 1375 | BEGIN | 1552 | BEGIN |
2450 | 1376 | CREATE TEMPORARY TABLE bugsummary_temp_journal ( | 1553 | CREATE TEMPORARY TABLE bugsummary_temp_journal ( |
2451 | 1377 | LIKE bugsummary ) ON COMMIT DROP; | 1554 | LIKE bugsummary ) ON COMMIT DROP; |
2452 | @@ -1383,48 +1560,66 @@ | |||
2453 | 1383 | $$; | 1560 | $$; |
2454 | 1384 | 1561 | ||
2455 | 1385 | 1562 | ||
2460 | 1386 | COMMENT ON FUNCTION ensure_bugsummary_temp_journal() IS 'Create a temporary table bugsummary_temp_journal if it does not exist.'; | 1563 | COMMENT ON FUNCTION public.ensure_bugsummary_temp_journal() IS 'Create a temporary table bugsummary_temp_journal if it does not exist.'; |
2461 | 1387 | 1564 | ||
2462 | 1388 | 1565 | ||
2463 | 1389 | CREATE FUNCTION generate_openid_identifier() RETURNS text | 1566 | CREATE FUNCTION public.ftiupdate() RETURNS trigger |
2464 | 1390 | LANGUAGE plpythonu | 1567 | LANGUAGE plpythonu |
2500 | 1391 | AS $$ | 1568 | AS $_$ |
2501 | 1392 | from random import choice | 1569 | new = TD["new"] |
2502 | 1393 | 1570 | args = TD["args"][:] | |
2503 | 1394 | # Non display confusing characters. | 1571 | |
2504 | 1395 | chars = '34678bcdefhkmnprstwxyzABCDEFGHJKLMNPQRTWXY' | 1572 | # Short circuit if none of the relevant columns have been |
2505 | 1396 | 1573 | # modified and fti is not being set to NULL (setting the fti | |
2506 | 1397 | # Character length of tokens. Can be increased, decreased or even made | 1574 | # column to NULL is thus how we can force a rebuild of the fti |
2507 | 1398 | # random - Launchpad does not care. 7 means it takes 40 bytes to store | 1575 | # column). |
2508 | 1399 | # a null-terminated Launchpad identity URL on the current domain name. | 1576 | if TD["event"] == "UPDATE" and new["fti"] != None: |
2509 | 1400 | length=7 | 1577 | old = TD["old"] |
2510 | 1401 | 1578 | relevant_modification = False | |
2511 | 1402 | loop_count = 0 | 1579 | for column_name in args[::2]: |
2512 | 1403 | while loop_count < 20000: | 1580 | if new[column_name] != old[column_name]: |
2513 | 1404 | # Generate a random openid_identifier | 1581 | relevant_modification = True |
2514 | 1405 | oid = ''.join(choice(chars) for count in range(length)) | 1582 | break |
2515 | 1406 | 1583 | if not relevant_modification: | |
2516 | 1407 | # Check if the oid is already in the db, although this is pretty | 1584 | return "OK" |
2517 | 1408 | # unlikely | 1585 | |
2518 | 1409 | rv = plpy.execute(""" | 1586 | # Generate an SQL statement that turns the requested |
2519 | 1410 | SELECT COUNT(*) AS num FROM Account WHERE openid_identifier = '%s' | 1587 | # column values into a weighted tsvector |
2520 | 1411 | """ % oid, 1) | 1588 | sql = [] |
2521 | 1412 | if rv[0]['num'] == 0: | 1589 | for i in range(0, len(args), 2): |
2522 | 1413 | return oid | 1590 | sql.append( |
2523 | 1414 | loop_count += 1 | 1591 | "setweight(to_tsvector('default', coalesce(" |
2524 | 1415 | if loop_count == 1: | 1592 | "substring(ltrim($%d) from 1 for 2500),''))," |
2525 | 1416 | plpy.warning( | 1593 | "CAST($%d AS \"char\"))" % (i + 1, i + 2)) |
2526 | 1417 | 'Clash generating unique openid_identifier. ' | 1594 | args[i] = new[args[i]] |
2527 | 1418 | 'Increase length if you see this warning too much.') | 1595 | |
2528 | 1419 | plpy.error( | 1596 | sql = "SELECT %s AS fti" % "||".join(sql) |
2529 | 1420 | "Unable to generate unique openid_identifier. " | 1597 | |
2530 | 1421 | "Need to increase length of tokens.") | 1598 | # Execute and store in the fti column |
2531 | 1422 | $$; | 1599 | plan = plpy.prepare(sql, ["text", "char"] * (len(args)/2)) |
2532 | 1423 | 1600 | new["fti"] = plpy.execute(plan, args, 1)[0]["fti"] | |
2533 | 1424 | 1601 | ||
2534 | 1425 | CREATE FUNCTION getlocalnodeid() RETURNS integer | 1602 | # Tell PostgreSQL we have modified the data |
2535 | 1603 | return "MODIFY" | ||
2536 | 1604 | $_$; | ||
2537 | 1605 | |||
2538 | 1606 | |||
2539 | 1607 | COMMENT ON FUNCTION public.ftiupdate() IS 'Trigger function that keeps the fti tsvector column up to date.'; | ||
2540 | 1608 | |||
2541 | 1609 | |||
2542 | 1610 | CREATE FUNCTION public.ftq(text) RETURNS tsquery | ||
2543 | 1611 | LANGUAGE plpythonu IMMUTABLE STRICT | ||
2544 | 1612 | AS $_$ | ||
2545 | 1613 | p = plpy.prepare( | ||
2546 | 1614 | "SELECT to_tsquery('default', _ftq($1)) AS x", ["text"]) | ||
2547 | 1615 | query = plpy.execute(p, args, 1)[0]["x"] | ||
2548 | 1616 | return query or None | ||
2549 | 1617 | $_$; | ||
2550 | 1618 | |||
2551 | 1619 | |||
2552 | 1620 | CREATE FUNCTION public.getlocalnodeid() RETURNS integer | ||
2553 | 1426 | LANGUAGE plpgsql STABLE SECURITY DEFINER | 1621 | LANGUAGE plpgsql STABLE SECURITY DEFINER |
2555 | 1427 | SET search_path TO public | 1622 | SET search_path TO 'public' |
2556 | 1428 | AS $$ | 1623 | AS $$ |
2557 | 1429 | DECLARE | 1624 | DECLARE |
2558 | 1430 | v_node_id integer; | 1625 | v_node_id integer; |
2559 | @@ -1438,70 +1633,48 @@ | |||
2560 | 1438 | $$; | 1633 | $$; |
2561 | 1439 | 1634 | ||
2562 | 1440 | 1635 | ||
2567 | 1441 | COMMENT ON FUNCTION getlocalnodeid() IS 'Return the replication node id for this node, or NULL if not a replicated installation.'; | 1636 | COMMENT ON FUNCTION public.getlocalnodeid() IS 'Return the replication node id for this node, or NULL if not a replicated installation.'; |
2568 | 1442 | 1637 | ||
2569 | 1443 | 1638 | ||
2570 | 1444 | CREATE FUNCTION is_blacklisted_name(text, integer) RETURNS boolean | 1639 | CREATE FUNCTION public.gitrepository_denorm_access(gitrepository_id integer) RETURNS void |
2571 | 1640 | LANGUAGE sql SECURITY DEFINER | ||
2572 | 1641 | SET search_path TO 'public' | ||
2573 | 1642 | AS $_$ | ||
2574 | 1643 | UPDATE GitRepository | ||
2575 | 1644 | SET access_policy = policies[1], access_grants = grants | ||
2576 | 1645 | FROM | ||
2577 | 1646 | build_access_cache( | ||
2578 | 1647 | (SELECT id FROM accessartifact WHERE gitrepository = $1), | ||
2579 | 1648 | (SELECT information_type FROM gitrepository WHERE id = $1)) | ||
2580 | 1649 | AS (policies integer[], grants integer[]) | ||
2581 | 1650 | WHERE id = $1; | ||
2582 | 1651 | $_$; | ||
2583 | 1652 | |||
2584 | 1653 | |||
2585 | 1654 | CREATE FUNCTION public.gitrepository_maintain_access_cache_trig() RETURNS trigger | ||
2586 | 1655 | LANGUAGE plpgsql | ||
2587 | 1656 | AS $$ | ||
2588 | 1657 | BEGIN | ||
2589 | 1658 | PERFORM gitrepository_denorm_access(NEW.id); | ||
2590 | 1659 | RETURN NULL; | ||
2591 | 1660 | END; | ||
2592 | 1661 | $$; | ||
2593 | 1662 | |||
2594 | 1663 | |||
2595 | 1664 | CREATE FUNCTION public.is_blacklisted_name(text, integer) RETURNS boolean | ||
2596 | 1445 | LANGUAGE sql STABLE STRICT SECURITY DEFINER | 1665 | LANGUAGE sql STABLE STRICT SECURITY DEFINER |
2598 | 1446 | SET search_path TO public | 1666 | SET search_path TO 'public' |
2599 | 1447 | AS $_$ | 1667 | AS $_$ |
2600 | 1448 | SELECT COALESCE(name_blacklist_match($1, $2)::boolean, FALSE); | 1668 | SELECT COALESCE(name_blacklist_match($1, $2)::boolean, FALSE); |
2601 | 1449 | $_$; | 1669 | $_$; |
2602 | 1450 | 1670 | ||
2603 | 1451 | 1671 | ||
2655 | 1452 | COMMENT ON FUNCTION is_blacklisted_name(text, integer) IS 'Return TRUE if any regular expressions stored in the NameBlacklist table match the givenname, otherwise return FALSE.'; | 1672 | COMMENT ON FUNCTION public.is_blacklisted_name(text, integer) IS 'Return TRUE if any regular expressions stored in the NameBlacklist table match the givenname, otherwise return FALSE.'; |
2656 | 1453 | 1673 | ||
2657 | 1454 | 1674 | ||
2658 | 1455 | CREATE FUNCTION is_person(text) RETURNS boolean | 1675 | CREATE FUNCTION public.lp_mirror_account_ins() RETURNS trigger |
2608 | 1456 | LANGUAGE sql STABLE STRICT | ||
2609 | 1457 | AS $_$ | ||
2610 | 1458 | SELECT count(*)>0 FROM Person WHERE name=$1 AND teamowner IS NULL; | ||
2611 | 1459 | $_$; | ||
2612 | 1460 | |||
2613 | 1461 | |||
2614 | 1462 | COMMENT ON FUNCTION is_person(text) IS 'True if the given name identifies a person in the Person table'; | ||
2615 | 1463 | |||
2616 | 1464 | |||
2617 | 1465 | CREATE FUNCTION is_printable_ascii(text) RETURNS boolean | ||
2618 | 1466 | LANGUAGE plpythonu IMMUTABLE STRICT | ||
2619 | 1467 | AS $_$ | ||
2620 | 1468 | import re, string | ||
2621 | 1469 | try: | ||
2622 | 1470 | text = args[0].decode("ASCII") | ||
2623 | 1471 | except UnicodeError: | ||
2624 | 1472 | return False | ||
2625 | 1473 | if re.search(r"^[%s]*$" % re.escape(string.printable), text) is None: | ||
2626 | 1474 | return False | ||
2627 | 1475 | return True | ||
2628 | 1476 | $_$; | ||
2629 | 1477 | |||
2630 | 1478 | |||
2631 | 1479 | COMMENT ON FUNCTION is_printable_ascii(text) IS 'True if the string is pure printable US-ASCII'; | ||
2632 | 1480 | |||
2633 | 1481 | |||
2634 | 1482 | CREATE FUNCTION is_team(integer) RETURNS boolean | ||
2635 | 1483 | LANGUAGE sql STABLE STRICT | ||
2636 | 1484 | AS $_$ | ||
2637 | 1485 | SELECT count(*)>0 FROM Person WHERE id=$1 AND teamowner IS NOT NULL; | ||
2638 | 1486 | $_$; | ||
2639 | 1487 | |||
2640 | 1488 | |||
2641 | 1489 | COMMENT ON FUNCTION is_team(integer) IS 'True if the given id identifies a team in the Person table'; | ||
2642 | 1490 | |||
2643 | 1491 | |||
2644 | 1492 | CREATE FUNCTION is_team(text) RETURNS boolean | ||
2645 | 1493 | LANGUAGE sql STABLE STRICT | ||
2646 | 1494 | AS $_$ | ||
2647 | 1495 | SELECT count(*)>0 FROM Person WHERE name=$1 AND teamowner IS NOT NULL; | ||
2648 | 1496 | $_$; | ||
2649 | 1497 | |||
2650 | 1498 | |||
2651 | 1499 | COMMENT ON FUNCTION is_team(text) IS 'True if the given name identifies a team in the Person table'; | ||
2652 | 1500 | |||
2653 | 1501 | |||
2654 | 1502 | CREATE FUNCTION lp_mirror_account_ins() RETURNS trigger | ||
2659 | 1503 | LANGUAGE plpgsql SECURITY DEFINER | 1676 | LANGUAGE plpgsql SECURITY DEFINER |
2661 | 1504 | SET search_path TO public | 1677 | SET search_path TO 'public' |
2662 | 1505 | AS $$ | 1678 | AS $$ |
2663 | 1506 | BEGIN | 1679 | BEGIN |
2664 | 1507 | INSERT INTO lp_Account (id, openid_identifier) | 1680 | INSERT INTO lp_Account (id, openid_identifier) |
2665 | @@ -1511,9 +1684,9 @@ | |||
2666 | 1511 | $$; | 1684 | $$; |
2667 | 1512 | 1685 | ||
2668 | 1513 | 1686 | ||
2670 | 1514 | CREATE FUNCTION lp_mirror_account_upd() RETURNS trigger | 1687 | CREATE FUNCTION public.lp_mirror_account_upd() RETURNS trigger |
2671 | 1515 | LANGUAGE plpgsql SECURITY DEFINER | 1688 | LANGUAGE plpgsql SECURITY DEFINER |
2673 | 1516 | SET search_path TO public | 1689 | SET search_path TO 'public' |
2674 | 1517 | AS $$ | 1690 | AS $$ |
2675 | 1518 | BEGIN | 1691 | BEGIN |
2676 | 1519 | IF OLD.id <> NEW.id OR OLD.openid_identifier <> NEW.openid_identifier THEN | 1692 | IF OLD.id <> NEW.id OR OLD.openid_identifier <> NEW.openid_identifier THEN |
2677 | @@ -1526,9 +1699,9 @@ | |||
2678 | 1526 | $$; | 1699 | $$; |
2679 | 1527 | 1700 | ||
2680 | 1528 | 1701 | ||
2682 | 1529 | CREATE FUNCTION lp_mirror_del() RETURNS trigger | 1702 | CREATE FUNCTION public.lp_mirror_del() RETURNS trigger |
2683 | 1530 | LANGUAGE plpgsql SECURITY DEFINER | 1703 | LANGUAGE plpgsql SECURITY DEFINER |
2685 | 1531 | SET search_path TO public | 1704 | SET search_path TO 'public' |
2686 | 1532 | AS $$ | 1705 | AS $$ |
2687 | 1533 | BEGIN | 1706 | BEGIN |
2688 | 1534 | EXECUTE 'DELETE FROM lp_' || TG_TABLE_NAME || ' WHERE id=' || OLD.id; | 1707 | EXECUTE 'DELETE FROM lp_' || TG_TABLE_NAME || ' WHERE id=' || OLD.id; |
2689 | @@ -1537,9 +1710,9 @@ | |||
2690 | 1537 | $$; | 1710 | $$; |
2691 | 1538 | 1711 | ||
2692 | 1539 | 1712 | ||
2694 | 1540 | CREATE FUNCTION lp_mirror_openididentifier_del() RETURNS trigger | 1713 | CREATE FUNCTION public.lp_mirror_openididentifier_del() RETURNS trigger |
2695 | 1541 | LANGUAGE plpgsql SECURITY DEFINER | 1714 | LANGUAGE plpgsql SECURITY DEFINER |
2697 | 1542 | SET search_path TO public | 1715 | SET search_path TO 'public' |
2698 | 1543 | AS $$ | 1716 | AS $$ |
2699 | 1544 | DECLARE | 1717 | DECLARE |
2700 | 1545 | next_identifier text; | 1718 | next_identifier text; |
2701 | @@ -1562,9 +1735,9 @@ | |||
2702 | 1562 | $$; | 1735 | $$; |
2703 | 1563 | 1736 | ||
2704 | 1564 | 1737 | ||
2706 | 1565 | CREATE FUNCTION lp_mirror_openididentifier_ins() RETURNS trigger | 1738 | CREATE FUNCTION public.lp_mirror_openididentifier_ins() RETURNS trigger |
2707 | 1566 | LANGUAGE plpgsql SECURITY DEFINER | 1739 | LANGUAGE plpgsql SECURITY DEFINER |
2709 | 1567 | SET search_path TO public | 1740 | SET search_path TO 'public' |
2710 | 1568 | AS $$ | 1741 | AS $$ |
2711 | 1569 | BEGIN | 1742 | BEGIN |
2712 | 1570 | -- Support obsolete lp_Account.openid_identifier as best we can | 1743 | -- Support obsolete lp_Account.openid_identifier as best we can |
2713 | @@ -1584,9 +1757,9 @@ | |||
2714 | 1584 | $$; | 1757 | $$; |
2715 | 1585 | 1758 | ||
2716 | 1586 | 1759 | ||
2718 | 1587 | CREATE FUNCTION lp_mirror_openididentifier_upd() RETURNS trigger | 1760 | CREATE FUNCTION public.lp_mirror_openididentifier_upd() RETURNS trigger |
2719 | 1588 | LANGUAGE plpgsql SECURITY DEFINER | 1761 | LANGUAGE plpgsql SECURITY DEFINER |
2721 | 1589 | SET search_path TO public | 1762 | SET search_path TO 'public' |
2722 | 1590 | AS $$ | 1763 | AS $$ |
2723 | 1591 | BEGIN | 1764 | BEGIN |
2724 | 1592 | IF OLD.identifier <> NEW.identifier THEN | 1765 | IF OLD.identifier <> NEW.identifier THEN |
2725 | @@ -1604,9 +1777,9 @@ | |||
2726 | 1604 | $$; | 1777 | $$; |
2727 | 1605 | 1778 | ||
2728 | 1606 | 1779 | ||
2730 | 1607 | CREATE FUNCTION lp_mirror_person_ins() RETURNS trigger | 1780 | CREATE FUNCTION public.lp_mirror_person_ins() RETURNS trigger |
2731 | 1608 | LANGUAGE plpgsql SECURITY DEFINER | 1781 | LANGUAGE plpgsql SECURITY DEFINER |
2733 | 1609 | SET search_path TO public | 1782 | SET search_path TO 'public' |
2734 | 1610 | AS $$ | 1783 | AS $$ |
2735 | 1611 | BEGIN | 1784 | BEGIN |
2736 | 1612 | INSERT INTO lp_Person ( | 1785 | INSERT INTO lp_Person ( |
2737 | @@ -1634,9 +1807,9 @@ | |||
2738 | 1634 | $$; | 1807 | $$; |
2739 | 1635 | 1808 | ||
2740 | 1636 | 1809 | ||
2742 | 1637 | CREATE FUNCTION lp_mirror_person_upd() RETURNS trigger | 1810 | CREATE FUNCTION public.lp_mirror_person_upd() RETURNS trigger |
2743 | 1638 | LANGUAGE plpgsql SECURITY DEFINER | 1811 | LANGUAGE plpgsql SECURITY DEFINER |
2745 | 1639 | SET search_path TO public | 1812 | SET search_path TO 'public' |
2746 | 1640 | AS $$ | 1813 | AS $$ |
2747 | 1641 | BEGIN | 1814 | BEGIN |
2748 | 1642 | UPDATE lp_Person | 1815 | UPDATE lp_Person |
2749 | @@ -1676,9 +1849,9 @@ | |||
2750 | 1676 | $$; | 1849 | $$; |
2751 | 1677 | 1850 | ||
2752 | 1678 | 1851 | ||
2754 | 1679 | CREATE FUNCTION lp_mirror_personlocation_ins() RETURNS trigger | 1852 | CREATE FUNCTION public.lp_mirror_personlocation_ins() RETURNS trigger |
2755 | 1680 | LANGUAGE plpgsql SECURITY DEFINER | 1853 | LANGUAGE plpgsql SECURITY DEFINER |
2757 | 1681 | SET search_path TO public | 1854 | SET search_path TO 'public' |
2758 | 1682 | AS $$ | 1855 | AS $$ |
2759 | 1683 | BEGIN | 1856 | BEGIN |
2760 | 1684 | INSERT INTO lp_PersonLocation SELECT NEW.*; | 1857 | INSERT INTO lp_PersonLocation SELECT NEW.*; |
2761 | @@ -1687,9 +1860,9 @@ | |||
2762 | 1687 | $$; | 1860 | $$; |
2763 | 1688 | 1861 | ||
2764 | 1689 | 1862 | ||
2766 | 1690 | CREATE FUNCTION lp_mirror_personlocation_upd() RETURNS trigger | 1863 | CREATE FUNCTION public.lp_mirror_personlocation_upd() RETURNS trigger |
2767 | 1691 | LANGUAGE plpgsql SECURITY DEFINER | 1864 | LANGUAGE plpgsql SECURITY DEFINER |
2769 | 1692 | SET search_path TO public | 1865 | SET search_path TO 'public' |
2770 | 1693 | AS $$ | 1866 | AS $$ |
2771 | 1694 | BEGIN | 1867 | BEGIN |
2772 | 1695 | UPDATE lp_PersonLocation | 1868 | UPDATE lp_PersonLocation |
2773 | @@ -1709,9 +1882,9 @@ | |||
2774 | 1709 | $$; | 1882 | $$; |
2775 | 1710 | 1883 | ||
2776 | 1711 | 1884 | ||
2778 | 1712 | CREATE FUNCTION lp_mirror_teamparticipation_ins() RETURNS trigger | 1885 | CREATE FUNCTION public.lp_mirror_teamparticipation_ins() RETURNS trigger |
2779 | 1713 | LANGUAGE plpgsql SECURITY DEFINER | 1886 | LANGUAGE plpgsql SECURITY DEFINER |
2781 | 1714 | SET search_path TO public | 1887 | SET search_path TO 'public' |
2782 | 1715 | AS $$ | 1888 | AS $$ |
2783 | 1716 | BEGIN | 1889 | BEGIN |
2784 | 1717 | INSERT INTO lp_TeamParticipation SELECT NEW.*; | 1890 | INSERT INTO lp_TeamParticipation SELECT NEW.*; |
2785 | @@ -1720,9 +1893,9 @@ | |||
2786 | 1720 | $$; | 1893 | $$; |
2787 | 1721 | 1894 | ||
2788 | 1722 | 1895 | ||
2790 | 1723 | CREATE FUNCTION lp_mirror_teamparticipation_upd() RETURNS trigger | 1896 | CREATE FUNCTION public.lp_mirror_teamparticipation_upd() RETURNS trigger |
2791 | 1724 | LANGUAGE plpgsql SECURITY DEFINER | 1897 | LANGUAGE plpgsql SECURITY DEFINER |
2793 | 1725 | SET search_path TO public | 1898 | SET search_path TO 'public' |
2794 | 1726 | AS $$ | 1899 | AS $$ |
2795 | 1727 | BEGIN | 1900 | BEGIN |
2796 | 1728 | UPDATE lp_TeamParticipation | 1901 | UPDATE lp_TeamParticipation |
2797 | @@ -1735,28 +1908,9 @@ | |||
2798 | 1735 | $$; | 1908 | $$; |
2799 | 1736 | 1909 | ||
2800 | 1737 | 1910 | ||
2821 | 1738 | CREATE FUNCTION maintain_transitively_private() RETURNS trigger | 1911 | CREATE FUNCTION public.message_copy_owner_to_bugmessage() RETURNS trigger |
2802 | 1739 | LANGUAGE plpgsql | ||
2803 | 1740 | AS $$ | ||
2804 | 1741 | BEGIN | ||
2805 | 1742 | IF TG_OP = 'UPDATE' THEN | ||
2806 | 1743 | IF (NEW.stacked_on IS NOT DISTINCT FROM OLD.stacked_on | ||
2807 | 1744 | AND NEW.private IS NOT DISTINCT FROM OLD.private) THEN | ||
2808 | 1745 | RETURN NULL; | ||
2809 | 1746 | END IF; | ||
2810 | 1747 | END IF; | ||
2811 | 1748 | PERFORM update_transitively_private(NEW.id); | ||
2812 | 1749 | RETURN NULL; | ||
2813 | 1750 | END; | ||
2814 | 1751 | $$; | ||
2815 | 1752 | |||
2816 | 1753 | |||
2817 | 1754 | COMMENT ON FUNCTION maintain_transitively_private() IS 'Trigger maintaining the Branch transitively_private column'; | ||
2818 | 1755 | |||
2819 | 1756 | |||
2820 | 1757 | CREATE FUNCTION message_copy_owner_to_bugmessage() RETURNS trigger | ||
2822 | 1758 | LANGUAGE plpgsql SECURITY DEFINER | 1912 | LANGUAGE plpgsql SECURITY DEFINER |
2824 | 1759 | SET search_path TO public | 1913 | SET search_path TO 'public' |
2825 | 1760 | AS $$ | 1914 | AS $$ |
2826 | 1761 | BEGIN | 1915 | BEGIN |
2827 | 1762 | IF NEW.owner != OLD.owner THEN | 1916 | IF NEW.owner != OLD.owner THEN |
2828 | @@ -1770,12 +1924,12 @@ | |||
2829 | 1770 | $$; | 1924 | $$; |
2830 | 1771 | 1925 | ||
2831 | 1772 | 1926 | ||
2836 | 1773 | COMMENT ON FUNCTION message_copy_owner_to_bugmessage() IS 'Copies the message owner into bugmessage when message changes.'; | 1927 | COMMENT ON FUNCTION public.message_copy_owner_to_bugmessage() IS 'Copies the message owner into bugmessage when message changes.'; |
2837 | 1774 | 1928 | ||
2838 | 1775 | 1929 | ||
2839 | 1776 | CREATE FUNCTION message_copy_owner_to_questionmessage() RETURNS trigger | 1930 | CREATE FUNCTION public.message_copy_owner_to_questionmessage() RETURNS trigger |
2840 | 1777 | LANGUAGE plpgsql SECURITY DEFINER | 1931 | LANGUAGE plpgsql SECURITY DEFINER |
2842 | 1778 | SET search_path TO public | 1932 | SET search_path TO 'public' |
2843 | 1779 | AS $$ | 1933 | AS $$ |
2844 | 1780 | BEGIN | 1934 | BEGIN |
2845 | 1781 | IF NEW.owner != OLD.owner THEN | 1935 | IF NEW.owner != OLD.owner THEN |
2846 | @@ -1789,10 +1943,10 @@ | |||
2847 | 1789 | $$; | 1943 | $$; |
2848 | 1790 | 1944 | ||
2849 | 1791 | 1945 | ||
2854 | 1792 | COMMENT ON FUNCTION message_copy_owner_to_questionmessage() IS 'Copies the message owner into questionmessage when message changes.'; | 1946 | COMMENT ON FUNCTION public.message_copy_owner_to_questionmessage() IS 'Copies the message owner into questionmessage when message changes.'; |
2855 | 1793 | 1947 | ||
2856 | 1794 | 1948 | ||
2857 | 1795 | CREATE FUNCTION milestone_sort_key(dateexpected timestamp without time zone, name text) RETURNS text | 1949 | CREATE FUNCTION public.milestone_sort_key(dateexpected timestamp without time zone, name text) RETURNS text |
2858 | 1796 | LANGUAGE plpythonu IMMUTABLE | 1950 | LANGUAGE plpythonu IMMUTABLE |
2859 | 1797 | AS $$ | 1951 | AS $$ |
2860 | 1798 | # If this method is altered, then any functional indexes using it | 1952 | # If this method is altered, then any functional indexes using it |
2861 | @@ -1813,10 +1967,10 @@ | |||
2862 | 1813 | $$; | 1967 | $$; |
2863 | 1814 | 1968 | ||
2864 | 1815 | 1969 | ||
2869 | 1816 | COMMENT ON FUNCTION milestone_sort_key(dateexpected timestamp without time zone, name text) IS 'Sort by the Milestone dateexpected and name. If the dateexpected is NULL, then it is converted to a date far in the future, so it will be sorted as a milestone in the future.'; | 1970 | COMMENT ON FUNCTION public.milestone_sort_key(dateexpected timestamp without time zone, name text) IS 'Sort by the Milestone dateexpected and name. If the dateexpected is NULL, then it is converted to a date far in the future, so it will be sorted as a milestone in the future.'; |
2870 | 1817 | 1971 | ||
2871 | 1818 | 1972 | ||
2872 | 1819 | CREATE FUNCTION mv_branch_distribution_update() RETURNS trigger | 1973 | CREATE FUNCTION public.mv_branch_distribution_update() RETURNS trigger |
2873 | 1820 | LANGUAGE plpgsql | 1974 | LANGUAGE plpgsql |
2874 | 1821 | AS $$ | 1975 | AS $$ |
2875 | 1822 | BEGIN | 1976 | BEGIN |
2876 | @@ -1834,10 +1988,10 @@ | |||
2877 | 1834 | $$; | 1988 | $$; |
2878 | 1835 | 1989 | ||
2879 | 1836 | 1990 | ||
2884 | 1837 | COMMENT ON FUNCTION mv_branch_distribution_update() IS 'Maintain Branch name cache when Distribution is modified.'; | 1991 | COMMENT ON FUNCTION public.mv_branch_distribution_update() IS 'Maintain Branch name cache when Distribution is modified.'; |
2885 | 1838 | 1992 | ||
2886 | 1839 | 1993 | ||
2887 | 1840 | CREATE FUNCTION mv_branch_distroseries_update() RETURNS trigger | 1994 | CREATE FUNCTION public.mv_branch_distroseries_update() RETURNS trigger |
2888 | 1841 | LANGUAGE plpgsql | 1995 | LANGUAGE plpgsql |
2889 | 1842 | AS $$ | 1996 | AS $$ |
2890 | 1843 | BEGIN | 1997 | BEGIN |
2891 | @@ -1853,10 +2007,10 @@ | |||
2892 | 1853 | $$; | 2007 | $$; |
2893 | 1854 | 2008 | ||
2894 | 1855 | 2009 | ||
2899 | 1856 | COMMENT ON FUNCTION mv_branch_distroseries_update() IS 'Maintain Branch name cache when Distroseries is modified.'; | 2010 | COMMENT ON FUNCTION public.mv_branch_distroseries_update() IS 'Maintain Branch name cache when Distroseries is modified.'; |
2900 | 1857 | 2011 | ||
2901 | 1858 | 2012 | ||
2902 | 1859 | CREATE FUNCTION mv_branch_person_update() RETURNS trigger | 2013 | CREATE FUNCTION public.mv_branch_person_update() RETURNS trigger |
2903 | 1860 | LANGUAGE plpgsql | 2014 | LANGUAGE plpgsql |
2904 | 1861 | AS $$ | 2015 | AS $$ |
2905 | 1862 | DECLARE | 2016 | DECLARE |
2906 | @@ -1873,10 +2027,10 @@ | |||
2907 | 1873 | $$; | 2027 | $$; |
2908 | 1874 | 2028 | ||
2909 | 1875 | 2029 | ||
2914 | 1876 | COMMENT ON FUNCTION mv_branch_person_update() IS 'Maintain Branch name cache when Person is modified.'; | 2030 | COMMENT ON FUNCTION public.mv_branch_person_update() IS 'Maintain Branch name cache when Person is modified.'; |
2915 | 1877 | 2031 | ||
2916 | 1878 | 2032 | ||
2917 | 1879 | CREATE FUNCTION mv_branch_product_update() RETURNS trigger | 2033 | CREATE FUNCTION public.mv_branch_product_update() RETURNS trigger |
2918 | 1880 | LANGUAGE plpgsql | 2034 | LANGUAGE plpgsql |
2919 | 1881 | AS $$ | 2035 | AS $$ |
2920 | 1882 | DECLARE | 2036 | DECLARE |
2921 | @@ -1893,12 +2047,12 @@ | |||
2922 | 1893 | $$; | 2047 | $$; |
2923 | 1894 | 2048 | ||
2924 | 1895 | 2049 | ||
2929 | 1896 | COMMENT ON FUNCTION mv_branch_product_update() IS 'Maintain Branch name cache when Product is modified.'; | 2050 | COMMENT ON FUNCTION public.mv_branch_product_update() IS 'Maintain Branch name cache when Product is modified.'; |
2930 | 1897 | 2051 | ||
2931 | 1898 | 2052 | ||
2932 | 1899 | CREATE FUNCTION mv_pillarname_distribution() RETURNS trigger | 2053 | CREATE FUNCTION public.mv_pillarname_distribution() RETURNS trigger |
2933 | 1900 | LANGUAGE plpgsql SECURITY DEFINER | 2054 | LANGUAGE plpgsql SECURITY DEFINER |
2935 | 1901 | SET search_path TO public | 2055 | SET search_path TO 'public' |
2936 | 1902 | AS $$ | 2056 | AS $$ |
2937 | 1903 | BEGIN | 2057 | BEGIN |
2938 | 1904 | IF TG_OP = 'INSERT' THEN | 2058 | IF TG_OP = 'INSERT' THEN |
2939 | @@ -1912,12 +2066,12 @@ | |||
2940 | 1912 | $$; | 2066 | $$; |
2941 | 1913 | 2067 | ||
2942 | 1914 | 2068 | ||
2947 | 1915 | COMMENT ON FUNCTION mv_pillarname_distribution() IS 'Trigger maintaining the PillarName table'; | 2069 | COMMENT ON FUNCTION public.mv_pillarname_distribution() IS 'Trigger maintaining the PillarName table'; |
2948 | 1916 | 2070 | ||
2949 | 1917 | 2071 | ||
2950 | 1918 | CREATE FUNCTION mv_pillarname_product() RETURNS trigger | 2072 | CREATE FUNCTION public.mv_pillarname_product() RETURNS trigger |
2951 | 1919 | LANGUAGE plpgsql SECURITY DEFINER | 2073 | LANGUAGE plpgsql SECURITY DEFINER |
2953 | 1920 | SET search_path TO public | 2074 | SET search_path TO 'public' |
2954 | 1921 | AS $$ | 2075 | AS $$ |
2955 | 1922 | BEGIN | 2076 | BEGIN |
2956 | 1923 | IF TG_OP = 'INSERT' THEN | 2077 | IF TG_OP = 'INSERT' THEN |
2957 | @@ -1932,12 +2086,12 @@ | |||
2958 | 1932 | $$; | 2086 | $$; |
2959 | 1933 | 2087 | ||
2960 | 1934 | 2088 | ||
2965 | 1935 | COMMENT ON FUNCTION mv_pillarname_product() IS 'Trigger maintaining the PillarName table'; | 2089 | COMMENT ON FUNCTION public.mv_pillarname_product() IS 'Trigger maintaining the PillarName table'; |
2966 | 1936 | 2090 | ||
2967 | 1937 | 2091 | ||
2968 | 1938 | CREATE FUNCTION mv_pillarname_project() RETURNS trigger | 2092 | CREATE FUNCTION public.mv_pillarname_project() RETURNS trigger |
2969 | 1939 | LANGUAGE plpgsql SECURITY DEFINER | 2093 | LANGUAGE plpgsql SECURITY DEFINER |
2971 | 1940 | SET search_path TO public | 2094 | SET search_path TO 'public' |
2972 | 1941 | AS $$ | 2095 | AS $$ |
2973 | 1942 | BEGIN | 2096 | BEGIN |
2974 | 1943 | IF TG_OP = 'INSERT' THEN | 2097 | IF TG_OP = 'INSERT' THEN |
2975 | @@ -1952,221 +2106,47 @@ | |||
2976 | 1952 | $$; | 2106 | $$; |
2977 | 1953 | 2107 | ||
2978 | 1954 | 2108 | ||
3194 | 1955 | COMMENT ON FUNCTION mv_pillarname_project() IS 'Trigger maintaining the PillarName table'; | 2109 | COMMENT ON FUNCTION public.mv_pillarname_project() IS 'Trigger maintaining the PillarName table'; |
3195 | 1956 | 2110 | ||
3196 | 1957 | 2111 | ||
3197 | 1958 | CREATE FUNCTION mv_pofiletranslator_pomsgset() RETURNS trigger | 2112 | CREATE FUNCTION public.mv_pofiletranslator_translationmessage() RETURNS trigger |
3198 | 1959 | LANGUAGE plpgsql | 2113 | LANGUAGE plpgsql SECURITY DEFINER |
3199 | 1960 | AS $$ | 2114 | SET search_path TO 'public' |
3200 | 1961 | BEGIN | 2115 | AS $$ |
3201 | 1962 | IF TG_OP = 'DELETE' THEN | 2116 | BEGIN |
3202 | 1963 | RAISE EXCEPTION | 2117 | -- Update any existing entries. |
3203 | 1964 | 'Deletions from POMsgSet not supported by the POFileTranslator materialized view'; | 2118 | UPDATE POFileTranslator |
3204 | 1965 | ELSIF TG_OP = 'UPDATE' THEN | 2119 | SET date_last_touched = CURRENT_TIMESTAMP AT TIME ZONE 'UTC' |
3205 | 1966 | IF OLD.pofile != NEW.pofile THEN | 2120 | FROM POFile, TranslationTemplateItem |
3206 | 1967 | RAISE EXCEPTION | 2121 | WHERE person = NEW.submitter AND |
3207 | 1968 | 'Changing POMsgSet.pofile not supported by the POFileTranslator materialized view'; | 2122 | TranslationTemplateItem.potmsgset = NEW.potmsgset AND |
3208 | 1969 | END IF; | 2123 | TranslationTemplateItem.potemplate = POFile.potemplate AND |
3209 | 1970 | END IF; | 2124 | POFile.language = NEW.language AND |
3210 | 1971 | RETURN NEW; | 2125 | POFileTranslator.pofile = POFile.id; |
3211 | 1972 | END; | 2126 | |
3212 | 1973 | $$; | 2127 | -- Insert any missing entries. |
3213 | 1974 | 2128 | INSERT INTO POFileTranslator (person, pofile) | |
3214 | 1975 | 2129 | SELECT DISTINCT NEW.submitter, POFile.id | |
3215 | 1976 | COMMENT ON FUNCTION mv_pofiletranslator_pomsgset() IS 'Trigger enforing no POMsgSet deletions or POMsgSet.pofile changes'; | 2130 | FROM TranslationTemplateItem |
3216 | 1977 | 2131 | JOIN POFile ON | |
3217 | 1978 | 2132 | POFile.language = NEW.language AND | |
3218 | 1979 | CREATE FUNCTION mv_pofiletranslator_posubmission() RETURNS trigger | 2133 | POFile.potemplate = TranslationTemplateItem.potemplate |
3219 | 1980 | LANGUAGE plpgsql SECURITY DEFINER | 2134 | WHERE |
3220 | 1981 | AS $$ | 2135 | TranslationTemplateItem.potmsgset = NEW.potmsgset AND |
3221 | 1982 | DECLARE | 2136 | NOT EXISTS ( |
3222 | 1983 | v_pofile INTEGER; | 2137 | SELECT * |
3223 | 1984 | v_trash_old BOOLEAN; | 2138 | FROM POFileTranslator |
3224 | 1985 | BEGIN | 2139 | WHERE person = NEW.submitter AND pofile = POFile.id |
3225 | 1986 | -- If we are deleting a row, we need to remove the existing | 2140 | ); |
3226 | 1987 | -- POFileTranslator row and reinsert the historical data if it exists. | 2141 | RETURN NULL; |
3227 | 1988 | -- We also treat UPDATEs that change the key (person, pofile) the same | 2142 | END; |
3228 | 1989 | -- as deletes. UPDATEs that don't change these columns are treated like | 2143 | $$; |
3229 | 1990 | -- INSERTs below. | 2144 | |
3230 | 1991 | IF TG_OP = 'INSERT' THEN | 2145 | |
3231 | 1992 | v_trash_old := FALSE; | 2146 | COMMENT ON FUNCTION public.mv_pofiletranslator_translationmessage() IS 'Trigger maintaining the POFileTranslator table'; |
3232 | 1993 | ELSIF TG_OP = 'DELETE' THEN | 2147 | |
3233 | 1994 | v_trash_old := TRUE; | 2148 | |
3234 | 1995 | ELSE -- UPDATE | 2149 | CREATE FUNCTION public.mv_validpersonorteamcache_emailaddress() RETURNS trigger |
3020 | 1996 | v_trash_old = ( | ||
3021 | 1997 | OLD.person != NEW.person OR OLD.pomsgset != NEW.pomsgset | ||
3022 | 1998 | ); | ||
3023 | 1999 | END IF; | ||
3024 | 2000 | |||
3025 | 2001 | IF v_trash_old THEN | ||
3026 | 2002 | |||
3027 | 2003 | -- Delete the old record. | ||
3028 | 2004 | DELETE FROM POFileTranslator USING POMsgSet | ||
3029 | 2005 | WHERE POFileTranslator.pofile = POMsgSet.pofile | ||
3030 | 2006 | AND POFileTranslator.person = OLD.person | ||
3031 | 2007 | AND POMsgSet.id = OLD.pomsgset; | ||
3032 | 2008 | |||
3033 | 2009 | -- Insert a past record if there is one. | ||
3034 | 2010 | INSERT INTO POFileTranslator ( | ||
3035 | 2011 | person, pofile, latest_posubmission, date_last_touched | ||
3036 | 2012 | ) | ||
3037 | 2013 | SELECT DISTINCT ON (POSubmission.person, POMsgSet.pofile) | ||
3038 | 2014 | POSubmission.person, POMsgSet.pofile, | ||
3039 | 2015 | POSubmission.id, POSubmission.datecreated | ||
3040 | 2016 | FROM POSubmission, POMsgSet | ||
3041 | 2017 | WHERE POSubmission.pomsgset = POMsgSet.id | ||
3042 | 2018 | AND POSubmission.pomsgset = OLD.pomsgset | ||
3043 | 2019 | AND POSubmission.person = OLD.person | ||
3044 | 2020 | ORDER BY | ||
3045 | 2021 | POSubmission.person, POMsgSet.pofile, | ||
3046 | 2022 | POSubmission.datecreated DESC, POSubmission.id DESC; | ||
3047 | 2023 | |||
3048 | 2024 | -- No NEW with DELETE, so we can short circuit and leave. | ||
3049 | 2025 | IF TG_OP = 'DELETE' THEN | ||
3050 | 2026 | RETURN NULL; -- Ignored because this is an AFTER trigger | ||
3051 | 2027 | END IF; | ||
3052 | 2028 | END IF; | ||
3053 | 2029 | |||
3054 | 2030 | -- Get our new pofile id | ||
3055 | 2031 | SELECT INTO v_pofile POMsgSet.pofile FROM POMsgSet | ||
3056 | 2032 | WHERE POMsgSet.id = NEW.pomsgset; | ||
3057 | 2033 | |||
3058 | 2034 | -- Standard 'upsert' loop to avoid race conditions. | ||
3059 | 2035 | LOOP | ||
3060 | 2036 | UPDATE POFileTranslator | ||
3061 | 2037 | SET | ||
3062 | 2038 | date_last_touched = CURRENT_TIMESTAMP AT TIME ZONE 'UTC', | ||
3063 | 2039 | latest_posubmission = NEW.id | ||
3064 | 2040 | WHERE | ||
3065 | 2041 | person = NEW.person | ||
3066 | 2042 | AND pofile = v_pofile; | ||
3067 | 2043 | IF found THEN | ||
3068 | 2044 | RETURN NULL; -- Return value ignored as this is an AFTER trigger | ||
3069 | 2045 | END IF; | ||
3070 | 2046 | |||
3071 | 2047 | BEGIN | ||
3072 | 2048 | INSERT INTO POFileTranslator (person, pofile, latest_posubmission) | ||
3073 | 2049 | VALUES (NEW.person, v_pofile, NEW.id); | ||
3074 | 2050 | RETURN NULL; -- Return value ignored as this is an AFTER trigger | ||
3075 | 2051 | EXCEPTION WHEN unique_violation THEN | ||
3076 | 2052 | -- do nothing | ||
3077 | 2053 | END; | ||
3078 | 2054 | END LOOP; | ||
3079 | 2055 | END; | ||
3080 | 2056 | $$; | ||
3081 | 2057 | |||
3082 | 2058 | |||
3083 | 2059 | COMMENT ON FUNCTION mv_pofiletranslator_posubmission() IS 'Trigger maintaining the POFileTranslator table'; | ||
3084 | 2060 | |||
3085 | 2061 | |||
3086 | 2062 | CREATE FUNCTION mv_pofiletranslator_translationmessage() RETURNS trigger | ||
3087 | 2063 | LANGUAGE plpgsql SECURITY DEFINER | ||
3088 | 2064 | SET search_path TO public | ||
3089 | 2065 | AS $$ | ||
3090 | 2066 | DECLARE | ||
3091 | 2067 | v_trash_old BOOLEAN; | ||
3092 | 2068 | BEGIN | ||
3093 | 2069 | -- If we are deleting a row, we need to remove the existing | ||
3094 | 2070 | -- POFileTranslator row and reinsert the historical data if it exists. | ||
3095 | 2071 | -- We also treat UPDATEs that change the key (submitter) the same | ||
3096 | 2072 | -- as deletes. UPDATEs that don't change these columns are treated like | ||
3097 | 2073 | -- INSERTs below. | ||
3098 | 2074 | IF TG_OP = 'INSERT' THEN | ||
3099 | 2075 | v_trash_old := FALSE; | ||
3100 | 2076 | ELSIF TG_OP = 'DELETE' THEN | ||
3101 | 2077 | v_trash_old := TRUE; | ||
3102 | 2078 | ELSE -- UPDATE | ||
3103 | 2079 | v_trash_old = ( | ||
3104 | 2080 | OLD.submitter != NEW.submitter | ||
3105 | 2081 | ); | ||
3106 | 2082 | END IF; | ||
3107 | 2083 | |||
3108 | 2084 | IF v_trash_old THEN | ||
3109 | 2085 | -- Was this somebody's most-recently-changed message? | ||
3110 | 2086 | -- If so, delete the entry for that change. | ||
3111 | 2087 | DELETE FROM POFileTranslator | ||
3112 | 2088 | WHERE latest_message = OLD.id; | ||
3113 | 2089 | IF FOUND THEN | ||
3114 | 2090 | -- We deleted the entry for somebody's latest contribution. | ||
3115 | 2091 | -- Find that person's latest remaining contribution and | ||
3116 | 2092 | -- create a new record for that. | ||
3117 | 2093 | INSERT INTO POFileTranslator ( | ||
3118 | 2094 | person, pofile, latest_message, date_last_touched | ||
3119 | 2095 | ) | ||
3120 | 2096 | SELECT DISTINCT ON (person, pofile.id) | ||
3121 | 2097 | new_latest_message.submitter AS person, | ||
3122 | 2098 | pofile.id, | ||
3123 | 2099 | new_latest_message.id, | ||
3124 | 2100 | greatest(new_latest_message.date_created, | ||
3125 | 2101 | new_latest_message.date_reviewed) | ||
3126 | 2102 | FROM POFile | ||
3127 | 2103 | JOIN TranslationTemplateItem AS old_template_item | ||
3128 | 2104 | ON OLD.potmsgset = old_template_item.potmsgset AND | ||
3129 | 2105 | old_template_item.potemplate = pofile.potemplate AND | ||
3130 | 2106 | pofile.language = OLD.language | ||
3131 | 2107 | JOIN TranslationTemplateItem AS new_template_item | ||
3132 | 2108 | ON (old_template_item.potemplate = | ||
3133 | 2109 | new_template_item.potemplate) | ||
3134 | 2110 | JOIN TranslationMessage AS new_latest_message | ||
3135 | 2111 | ON new_latest_message.potmsgset = | ||
3136 | 2112 | new_template_item.potmsgset AND | ||
3137 | 2113 | new_latest_message.language = OLD.language | ||
3138 | 2114 | LEFT OUTER JOIN POfileTranslator AS ExistingEntry | ||
3139 | 2115 | ON ExistingEntry.person = OLD.submitter AND | ||
3140 | 2116 | ExistingEntry.pofile = POFile.id | ||
3141 | 2117 | WHERE | ||
3142 | 2118 | new_latest_message.submitter = OLD.submitter AND | ||
3143 | 2119 | ExistingEntry IS NULL | ||
3144 | 2120 | ORDER BY new_latest_message.submitter, pofile.id, | ||
3145 | 2121 | new_latest_message.date_created DESC, | ||
3146 | 2122 | new_latest_message.id DESC; | ||
3147 | 2123 | END IF; | ||
3148 | 2124 | |||
3149 | 2125 | -- No NEW with DELETE, so we can short circuit and leave. | ||
3150 | 2126 | IF TG_OP = 'DELETE' THEN | ||
3151 | 2127 | RETURN NULL; -- Ignored because this is an AFTER trigger | ||
3152 | 2128 | END IF; | ||
3153 | 2129 | END IF; | ||
3154 | 2130 | |||
3155 | 2131 | -- Standard 'upsert' loop to avoid race conditions. | ||
3156 | 2132 | LOOP | ||
3157 | 2133 | UPDATE POFileTranslator | ||
3158 | 2134 | SET | ||
3159 | 2135 | date_last_touched = CURRENT_TIMESTAMP AT TIME ZONE 'UTC', | ||
3160 | 2136 | latest_message = NEW.id | ||
3161 | 2137 | FROM POFile, TranslationTemplateItem | ||
3162 | 2138 | WHERE person = NEW.submitter AND | ||
3163 | 2139 | TranslationTemplateItem.potmsgset=NEW.potmsgset AND | ||
3164 | 2140 | TranslationTemplateItem.potemplate=pofile.potemplate AND | ||
3165 | 2141 | pofile.language=NEW.language AND | ||
3166 | 2142 | POFileTranslator.pofile = pofile.id; | ||
3167 | 2143 | IF found THEN | ||
3168 | 2144 | RETURN NULL; -- Return value ignored as this is an AFTER trigger | ||
3169 | 2145 | END IF; | ||
3170 | 2146 | |||
3171 | 2147 | BEGIN | ||
3172 | 2148 | INSERT INTO POFileTranslator (person, pofile, latest_message) | ||
3173 | 2149 | SELECT DISTINCT ON (NEW.submitter, pofile.id) | ||
3174 | 2150 | NEW.submitter, pofile.id, NEW.id | ||
3175 | 2151 | FROM TranslationTemplateItem | ||
3176 | 2152 | JOIN POFile | ||
3177 | 2153 | ON pofile.language = NEW.language AND | ||
3178 | 2154 | pofile.potemplate = translationtemplateitem.potemplate | ||
3179 | 2155 | WHERE | ||
3180 | 2156 | TranslationTemplateItem.potmsgset = NEW.potmsgset; | ||
3181 | 2157 | RETURN NULL; -- Return value ignored as this is an AFTER trigger | ||
3182 | 2158 | EXCEPTION WHEN unique_violation THEN | ||
3183 | 2159 | -- do nothing | ||
3184 | 2160 | END; | ||
3185 | 2161 | END LOOP; | ||
3186 | 2162 | END; | ||
3187 | 2163 | $$; | ||
3188 | 2164 | |||
3189 | 2165 | |||
3190 | 2166 | COMMENT ON FUNCTION mv_pofiletranslator_translationmessage() IS 'Trigger maintaining the POFileTranslator table'; | ||
3191 | 2167 | |||
3192 | 2168 | |||
3193 | 2169 | CREATE FUNCTION mv_validpersonorteamcache_emailaddress() RETURNS trigger | ||
3235 | 2170 | LANGUAGE plpythonu SECURITY DEFINER | 2150 | LANGUAGE plpythonu SECURITY DEFINER |
3236 | 2171 | AS $_$ | 2151 | AS $_$ |
3237 | 2172 | # This trigger function keeps the ValidPersonOrTeamCache materialized | 2152 | # This trigger function keeps the ValidPersonOrTeamCache materialized |
3238 | @@ -2258,10 +2238,10 @@ | |||
3239 | 2258 | $_$; | 2238 | $_$; |
3240 | 2259 | 2239 | ||
3241 | 2260 | 2240 | ||
3246 | 2261 | COMMENT ON FUNCTION mv_validpersonorteamcache_emailaddress() IS 'A trigger for maintaining the ValidPersonOrTeamCache eager materialized view when changes are made to the EmailAddress table'; | 2241 | COMMENT ON FUNCTION public.mv_validpersonorteamcache_emailaddress() IS 'A trigger for maintaining the ValidPersonOrTeamCache eager materialized view when changes are made to the EmailAddress table'; |
3247 | 2262 | 2242 | ||
3248 | 2263 | 2243 | ||
3249 | 2264 | CREATE FUNCTION mv_validpersonorteamcache_person() RETURNS trigger | 2244 | CREATE FUNCTION public.mv_validpersonorteamcache_person() RETURNS trigger |
3250 | 2265 | LANGUAGE plpythonu SECURITY DEFINER | 2245 | LANGUAGE plpythonu SECURITY DEFINER |
3251 | 2266 | AS $_$ | 2246 | AS $_$ |
3252 | 2267 | # This trigger function could be simplified by simply issuing | 2247 | # This trigger function could be simplified by simply issuing |
3253 | @@ -2322,12 +2302,12 @@ | |||
3254 | 2322 | $_$; | 2302 | $_$; |
3255 | 2323 | 2303 | ||
3256 | 2324 | 2304 | ||
3261 | 2325 | COMMENT ON FUNCTION mv_validpersonorteamcache_person() IS 'A trigger for maintaining the ValidPersonOrTeamCache eager materialized view when changes are made to the Person table'; | 2305 | COMMENT ON FUNCTION public.mv_validpersonorteamcache_person() IS 'A trigger for maintaining the ValidPersonOrTeamCache eager materialized view when changes are made to the Person table'; |
3262 | 2326 | 2306 | ||
3263 | 2327 | 2307 | ||
3264 | 2328 | CREATE FUNCTION name_blacklist_match(text, integer) RETURNS integer | 2308 | CREATE FUNCTION public.name_blacklist_match(text, integer) RETURNS integer |
3265 | 2329 | LANGUAGE plpythonu STABLE STRICT SECURITY DEFINER | 2309 | LANGUAGE plpythonu STABLE STRICT SECURITY DEFINER |
3267 | 2330 | SET search_path TO public | 2310 | SET search_path TO 'public' |
3268 | 2331 | AS $_$ | 2311 | AS $_$ |
3269 | 2332 | import re | 2312 | import re |
3270 | 2333 | name = args[0].decode("UTF-8") | 2313 | name = args[0].decode("UTF-8") |
3271 | @@ -2396,10 +2376,10 @@ | |||
3272 | 2396 | $_$; | 2376 | $_$; |
3273 | 2397 | 2377 | ||
3274 | 2398 | 2378 | ||
3279 | 2399 | COMMENT ON FUNCTION name_blacklist_match(text, integer) IS 'Return the id of the row in the NameBlacklist table that matches the given name, or NULL if no regexps in the NameBlacklist table match.'; | 2379 | COMMENT ON FUNCTION public.name_blacklist_match(text, integer) IS 'Return the id of the row in the NameBlacklist table that matches the given name, or NULL if no regexps in the NameBlacklist table match.'; |
3280 | 2400 | 2380 | ||
3281 | 2401 | 2381 | ||
3282 | 2402 | CREATE FUNCTION null_count(p_values anyarray) RETURNS integer | 2382 | CREATE FUNCTION public.null_count(p_values anyarray) RETURNS integer |
3283 | 2403 | LANGUAGE plpgsql IMMUTABLE STRICT | 2383 | LANGUAGE plpgsql IMMUTABLE STRICT |
3284 | 2404 | AS $$ | 2384 | AS $$ |
3285 | 2405 | DECLARE | 2385 | DECLARE |
3286 | @@ -2416,10 +2396,10 @@ | |||
3287 | 2416 | $$; | 2396 | $$; |
3288 | 2417 | 2397 | ||
3289 | 2418 | 2398 | ||
3294 | 2419 | COMMENT ON FUNCTION null_count(p_values anyarray) IS 'Return the number of NULLs in the first row of the given array.'; | 2399 | COMMENT ON FUNCTION public.null_count(p_values anyarray) IS 'Return the number of NULLs in the first row of the given array.'; |
3295 | 2420 | 2400 | ||
3296 | 2421 | 2401 | ||
3297 | 2422 | CREATE FUNCTION packageset_deleted_trig() RETURNS trigger | 2402 | CREATE FUNCTION public.packageset_deleted_trig() RETURNS trigger |
3298 | 2423 | LANGUAGE plpgsql | 2403 | LANGUAGE plpgsql |
3299 | 2424 | AS $$ | 2404 | AS $$ |
3300 | 2425 | BEGIN | 2405 | BEGIN |
3301 | @@ -2436,10 +2416,10 @@ | |||
3302 | 2436 | $$; | 2416 | $$; |
3303 | 2437 | 2417 | ||
3304 | 2438 | 2418 | ||
3309 | 2439 | COMMENT ON FUNCTION packageset_deleted_trig() IS 'Remove any DAG edges leading to/from the deleted package set.'; | 2419 | COMMENT ON FUNCTION public.packageset_deleted_trig() IS 'Remove any DAG edges leading to/from the deleted package set.'; |
3310 | 2440 | 2420 | ||
3311 | 2441 | 2421 | ||
3312 | 2442 | CREATE FUNCTION packageset_inserted_trig() RETURNS trigger | 2422 | CREATE FUNCTION public.packageset_inserted_trig() RETURNS trigger |
3313 | 2443 | LANGUAGE plpgsql | 2423 | LANGUAGE plpgsql |
3314 | 2444 | AS $$ | 2424 | AS $$ |
3315 | 2445 | BEGIN | 2425 | BEGIN |
3316 | @@ -2453,10 +2433,10 @@ | |||
3317 | 2453 | $$; | 2433 | $$; |
3318 | 2454 | 2434 | ||
3319 | 2455 | 2435 | ||
3324 | 2456 | COMMENT ON FUNCTION packageset_inserted_trig() IS 'Insert self-referencing DAG edge when a new package set is inserted.'; | 2436 | COMMENT ON FUNCTION public.packageset_inserted_trig() IS 'Insert self-referencing DAG edge when a new package set is inserted.'; |
3325 | 2457 | 2437 | ||
3326 | 2458 | 2438 | ||
3327 | 2459 | CREATE FUNCTION packagesetinclusion_deleted_trig() RETURNS trigger | 2439 | CREATE FUNCTION public.packagesetinclusion_deleted_trig() RETURNS trigger |
3328 | 2460 | LANGUAGE plpgsql | 2440 | LANGUAGE plpgsql |
3329 | 2461 | AS $$ | 2441 | AS $$ |
3330 | 2462 | BEGIN | 2442 | BEGIN |
3331 | @@ -2524,10 +2504,10 @@ | |||
3332 | 2524 | $$; | 2504 | $$; |
3333 | 2525 | 2505 | ||
3334 | 2526 | 2506 | ||
3339 | 2527 | COMMENT ON FUNCTION packagesetinclusion_deleted_trig() IS 'Maintain the transitive closure in the DAG when an edge leading to/from a package set is deleted.'; | 2507 | COMMENT ON FUNCTION public.packagesetinclusion_deleted_trig() IS 'Maintain the transitive closure in the DAG when an edge leading to/from a package set is deleted.'; |
3340 | 2528 | 2508 | ||
3341 | 2529 | 2509 | ||
3342 | 2530 | CREATE FUNCTION packagesetinclusion_inserted_trig() RETURNS trigger | 2510 | CREATE FUNCTION public.packagesetinclusion_inserted_trig() RETURNS trigger |
3343 | 2531 | LANGUAGE plpgsql | 2511 | LANGUAGE plpgsql |
3344 | 2532 | AS $$ | 2512 | AS $$ |
3345 | 2533 | BEGIN | 2513 | BEGIN |
3346 | @@ -2598,10 +2578,10 @@ | |||
3347 | 2598 | $$; | 2578 | $$; |
3348 | 2599 | 2579 | ||
3349 | 2600 | 2580 | ||
3354 | 2601 | COMMENT ON FUNCTION packagesetinclusion_inserted_trig() IS 'Maintain the transitive closure in the DAG for a newly inserted edge leading to/from a package set.'; | 2581 | COMMENT ON FUNCTION public.packagesetinclusion_inserted_trig() IS 'Maintain the transitive closure in the DAG for a newly inserted edge leading to/from a package set.'; |
3355 | 2602 | 2582 | ||
3356 | 2603 | 2583 | ||
3357 | 2604 | CREATE FUNCTION person_sort_key(displayname text, name text) RETURNS text | 2584 | CREATE FUNCTION public.person_sort_key(displayname text, name text) RETURNS text |
3358 | 2605 | LANGUAGE plpythonu IMMUTABLE STRICT | 2585 | LANGUAGE plpythonu IMMUTABLE STRICT |
3359 | 2606 | AS $$ | 2586 | AS $$ |
3360 | 2607 | # NB: If this implementation is changed, the person_sort_idx needs to be | 2587 | # NB: If this implementation is changed, the person_sort_idx needs to be |
3361 | @@ -2623,32 +2603,17 @@ | |||
3362 | 2623 | $$; | 2603 | $$; |
3363 | 2624 | 2604 | ||
3364 | 2625 | 2605 | ||
3379 | 2626 | COMMENT ON FUNCTION person_sort_key(displayname text, name text) IS 'Return a string suitable for sorting people on, generated by stripping noise out of displayname and concatenating name'; | 2606 | COMMENT ON FUNCTION public.person_sort_key(displayname text, name text) IS 'Return a string suitable for sorting people on, generated by stripping noise out of displayname and concatenating name'; |
3380 | 2627 | 2607 | ||
3381 | 2628 | 2608 | ||
3382 | 2629 | CREATE FUNCTION pgstattuple(text) RETURNS pgstattuple_type | 2609 | CREATE FUNCTION public.plpgsql_call_handler() RETURNS language_handler |
3369 | 2630 | LANGUAGE c STRICT | ||
3370 | 2631 | AS '$libdir/pgstattuple', 'pgstattuple'; | ||
3371 | 2632 | |||
3372 | 2633 | |||
3373 | 2634 | CREATE FUNCTION pgstattuple(oid) RETURNS pgstattuple_type | ||
3374 | 2635 | LANGUAGE c STRICT | ||
3375 | 2636 | AS '$libdir/pgstattuple', 'pgstattuplebyid'; | ||
3376 | 2637 | |||
3377 | 2638 | |||
3378 | 2639 | CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler | ||
3383 | 2640 | LANGUAGE c | 2610 | LANGUAGE c |
3384 | 2641 | AS '$libdir/plpgsql', 'plpgsql_call_handler'; | 2611 | AS '$libdir/plpgsql', 'plpgsql_call_handler'; |
3385 | 2642 | 2612 | ||
3386 | 2643 | 2613 | ||
3393 | 2644 | CREATE FUNCTION plpython_call_handler() RETURNS language_handler | 2614 | CREATE FUNCTION public.questionmessage_copy_owner_from_message() RETURNS trigger |
3388 | 2645 | LANGUAGE c | ||
3389 | 2646 | AS '$libdir/plpython', 'plpython_call_handler'; | ||
3390 | 2647 | |||
3391 | 2648 | |||
3392 | 2649 | CREATE FUNCTION questionmessage_copy_owner_from_message() RETURNS trigger | ||
3394 | 2650 | LANGUAGE plpgsql SECURITY DEFINER | 2615 | LANGUAGE plpgsql SECURITY DEFINER |
3396 | 2651 | SET search_path TO public | 2616 | SET search_path TO 'public' |
3397 | 2652 | AS $$ | 2617 | AS $$ |
3398 | 2653 | BEGIN | 2618 | BEGIN |
3399 | 2654 | IF TG_OP = 'INSERT' THEN | 2619 | IF TG_OP = 'INSERT' THEN |
3400 | @@ -2671,12 +2636,12 @@ | |||
3401 | 2671 | $$; | 2636 | $$; |
3402 | 2672 | 2637 | ||
3403 | 2673 | 2638 | ||
3408 | 2674 | COMMENT ON FUNCTION questionmessage_copy_owner_from_message() IS 'Copies the message owner into QuestionMessage when QuestionMessage changes.'; | 2639 | COMMENT ON FUNCTION public.questionmessage_copy_owner_from_message() IS 'Copies the message owner into QuestionMessage when QuestionMessage changes.'; |
3409 | 2675 | 2640 | ||
3410 | 2676 | 2641 | ||
3411 | 2677 | CREATE FUNCTION replication_lag() RETURNS interval | 2642 | CREATE FUNCTION public.replication_lag() RETURNS interval |
3412 | 2678 | LANGUAGE plpgsql STABLE SECURITY DEFINER | 2643 | LANGUAGE plpgsql STABLE SECURITY DEFINER |
3414 | 2679 | SET search_path TO public | 2644 | SET search_path TO 'public' |
3415 | 2680 | AS $$ | 2645 | AS $$ |
3416 | 2681 | DECLARE | 2646 | DECLARE |
3417 | 2682 | v_lag interval; | 2647 | v_lag interval; |
3418 | @@ -2693,12 +2658,12 @@ | |||
3419 | 2693 | $$; | 2658 | $$; |
3420 | 2694 | 2659 | ||
3421 | 2695 | 2660 | ||
3426 | 2696 | COMMENT ON FUNCTION replication_lag() IS 'Returns the worst lag time in our cluster, or NULL if not a replicated installation. Only returns meaningful results on the lpmain replication set master.'; | 2661 | COMMENT ON FUNCTION public.replication_lag() IS 'Returns the worst lag time in our cluster, or NULL if not a replicated installation. Only returns meaningful results on the lpmain replication set master.'; |
3427 | 2697 | 2662 | ||
3428 | 2698 | 2663 | ||
3429 | 2699 | CREATE FUNCTION replication_lag(node_id integer) RETURNS interval | 2664 | CREATE FUNCTION public.replication_lag(node_id integer) RETURNS interval |
3430 | 2700 | LANGUAGE plpgsql STABLE SECURITY DEFINER | 2665 | LANGUAGE plpgsql STABLE SECURITY DEFINER |
3432 | 2701 | SET search_path TO public | 2666 | SET search_path TO 'public' |
3433 | 2702 | AS $$ | 2667 | AS $$ |
3434 | 2703 | DECLARE | 2668 | DECLARE |
3435 | 2704 | v_lag interval; | 2669 | v_lag interval; |
3436 | @@ -2717,10 +2682,10 @@ | |||
3437 | 2717 | $$; | 2682 | $$; |
3438 | 2718 | 2683 | ||
3439 | 2719 | 2684 | ||
3444 | 2720 | COMMENT ON FUNCTION replication_lag(node_id integer) IS 'Returns the lag time of the lpmain replication set to the given node, or NULL if not a replicated installation. The node id parameter can be obtained by calling getlocalnodeid() on the relevant database. This function only returns meaningful results on the lpmain replication set master.'; | 2685 | COMMENT ON FUNCTION public.replication_lag(node_id integer) IS 'Returns the lag time of the lpmain replication set to the given node, or NULL if not a replicated installation. The node id parameter can be obtained by calling getlocalnodeid() on the relevant database. This function only returns meaningful results on the lpmain replication set master.'; |
3445 | 2721 | 2686 | ||
3446 | 2722 | 2687 | ||
3447 | 2723 | CREATE FUNCTION sane_version(text) RETURNS boolean | 2688 | CREATE FUNCTION public.sane_version(text) RETURNS boolean |
3448 | 2724 | LANGUAGE plpythonu IMMUTABLE STRICT | 2689 | LANGUAGE plpythonu IMMUTABLE STRICT |
3449 | 2725 | AS $_$ | 2690 | AS $_$ |
3450 | 2726 | import re | 2691 | import re |
3451 | @@ -2733,12 +2698,12 @@ | |||
3452 | 2733 | $_$; | 2698 | $_$; |
3453 | 2734 | 2699 | ||
3454 | 2735 | 2700 | ||
3459 | 2736 | COMMENT ON FUNCTION sane_version(text) IS 'A sane version number for use by ProductRelease and DistroRelease. We may make it less strict if required, but it would be nice if we can enforce simple version strings because we use them in URLs'; | 2701 | COMMENT ON FUNCTION public.sane_version(text) IS 'A sane version number for use by ProductRelease and DistroRelease. We may make it less strict if required, but it would be nice if we can enforce simple version strings because we use them in URLs'; |
3460 | 2737 | 2702 | ||
3461 | 2738 | 2703 | ||
3462 | 2739 | CREATE FUNCTION set_bug_date_last_message() RETURNS trigger | 2704 | CREATE FUNCTION public.set_bug_date_last_message() RETURNS trigger |
3463 | 2740 | LANGUAGE plpgsql SECURITY DEFINER | 2705 | LANGUAGE plpgsql SECURITY DEFINER |
3465 | 2741 | SET search_path TO public | 2706 | SET search_path TO 'public' |
3466 | 2742 | AS $$ | 2707 | AS $$ |
3467 | 2743 | BEGIN | 2708 | BEGIN |
3468 | 2744 | IF TG_OP = 'INSERT' THEN | 2709 | IF TG_OP = 'INSERT' THEN |
3469 | @@ -2763,10 +2728,10 @@ | |||
3470 | 2763 | $$; | 2728 | $$; |
3471 | 2764 | 2729 | ||
3472 | 2765 | 2730 | ||
3477 | 2766 | COMMENT ON FUNCTION set_bug_date_last_message() IS 'AFTER INSERT trigger on BugMessage maintaining the Bug.date_last_message column'; | 2731 | COMMENT ON FUNCTION public.set_bug_date_last_message() IS 'AFTER INSERT trigger on BugMessage maintaining the Bug.date_last_message column'; |
3478 | 2767 | 2732 | ||
3479 | 2768 | 2733 | ||
3480 | 2769 | CREATE FUNCTION set_bug_message_count() RETURNS trigger | 2734 | CREATE FUNCTION public.set_bug_message_count() RETURNS trigger |
3481 | 2770 | LANGUAGE plpgsql | 2735 | LANGUAGE plpgsql |
3482 | 2771 | AS $$ | 2736 | AS $$ |
3483 | 2772 | BEGIN | 2737 | BEGIN |
3484 | @@ -2791,10 +2756,10 @@ | |||
3485 | 2791 | $$; | 2756 | $$; |
3486 | 2792 | 2757 | ||
3487 | 2793 | 2758 | ||
3492 | 2794 | COMMENT ON FUNCTION set_bug_message_count() IS 'AFTER UPDATE trigger on BugAffectsPerson maintaining the Bug.users_affected_count column'; | 2759 | COMMENT ON FUNCTION public.set_bug_message_count() IS 'AFTER UPDATE trigger on BugAffectsPerson maintaining the Bug.users_affected_count column'; |
3493 | 2795 | 2760 | ||
3494 | 2796 | 2761 | ||
3495 | 2797 | CREATE FUNCTION set_bug_number_of_duplicates() RETURNS trigger | 2762 | CREATE FUNCTION public.set_bug_number_of_duplicates() RETURNS trigger |
3496 | 2798 | LANGUAGE plpgsql | 2763 | LANGUAGE plpgsql |
3497 | 2799 | AS $$ | 2764 | AS $$ |
3498 | 2800 | BEGIN | 2765 | BEGIN |
3499 | @@ -2826,10 +2791,10 @@ | |||
3500 | 2826 | $$; | 2791 | $$; |
3501 | 2827 | 2792 | ||
3502 | 2828 | 2793 | ||
3507 | 2829 | COMMENT ON FUNCTION set_bug_number_of_duplicates() IS 'AFTER UPDATE trigger on Bug maintaining the Bug.number_of_duplicates column'; | 2794 | COMMENT ON FUNCTION public.set_bug_number_of_duplicates() IS 'AFTER UPDATE trigger on Bug maintaining the Bug.number_of_duplicates column'; |
3508 | 2830 | 2795 | ||
3509 | 2831 | 2796 | ||
3510 | 2832 | CREATE FUNCTION set_bug_users_affected_count() RETURNS trigger | 2797 | CREATE FUNCTION public.set_bug_users_affected_count() RETURNS trigger |
3511 | 2833 | LANGUAGE plpgsql | 2798 | LANGUAGE plpgsql |
3512 | 2834 | AS $$ | 2799 | AS $$ |
3513 | 2835 | BEGIN | 2800 | BEGIN |
3514 | @@ -2878,7 +2843,7 @@ | |||
3515 | 2878 | $$; | 2843 | $$; |
3516 | 2879 | 2844 | ||
3517 | 2880 | 2845 | ||
3519 | 2881 | CREATE FUNCTION set_bugtask_date_milestone_set() RETURNS trigger | 2846 | CREATE FUNCTION public.set_bugtask_date_milestone_set() RETURNS trigger |
3520 | 2882 | LANGUAGE plpgsql | 2847 | LANGUAGE plpgsql |
3521 | 2883 | AS $$ | 2848 | AS $$ |
3522 | 2884 | BEGIN | 2849 | BEGIN |
3523 | @@ -2924,10 +2889,10 @@ | |||
3524 | 2924 | $$; | 2889 | $$; |
3525 | 2925 | 2890 | ||
3526 | 2926 | 2891 | ||
3531 | 2927 | COMMENT ON FUNCTION set_bugtask_date_milestone_set() IS 'Update BugTask.date_milestone_set when BugTask.milestone is changed.'; | 2892 | COMMENT ON FUNCTION public.set_bugtask_date_milestone_set() IS 'Update BugTask.date_milestone_set when BugTask.milestone is changed.'; |
3532 | 2928 | 2893 | ||
3533 | 2929 | 2894 | ||
3534 | 2930 | CREATE FUNCTION set_date_status_set() RETURNS trigger | 2895 | CREATE FUNCTION public.set_date_status_set() RETURNS trigger |
3535 | 2931 | LANGUAGE plpgsql | 2896 | LANGUAGE plpgsql |
3536 | 2932 | AS $$ | 2897 | AS $$ |
3537 | 2933 | BEGIN | 2898 | BEGIN |
3538 | @@ -2939,74 +2904,10 @@ | |||
3539 | 2939 | $$; | 2904 | $$; |
3540 | 2940 | 2905 | ||
3541 | 2941 | 2906 | ||
3610 | 2942 | COMMENT ON FUNCTION set_date_status_set() IS 'BEFORE UPDATE trigger on Account that maintains the Account.date_status_set column.'; | 2907 | COMMENT ON FUNCTION public.set_date_status_set() IS 'BEFORE UPDATE trigger on Account that maintains the Account.date_status_set column.'; |
3611 | 2943 | 2908 | ||
3612 | 2944 | 2909 | ||
3613 | 2945 | CREATE FUNCTION set_openid_identifier() RETURNS trigger | 2910 | CREATE FUNCTION public.sha1(text) RETURNS character |
3546 | 2946 | LANGUAGE plpythonu | ||
3547 | 2947 | AS $$ | ||
3548 | 2948 | # If someone is trying to explicitly set the openid_identifier, let them. | ||
3549 | 2949 | # This also causes openid_identifiers to be left alone if this is an | ||
3550 | 2950 | # UPDATE trigger. | ||
3551 | 2951 | if TD['new']['openid_identifier'] is not None: | ||
3552 | 2952 | return None | ||
3553 | 2953 | |||
3554 | 2954 | from random import choice | ||
3555 | 2955 | |||
3556 | 2956 | # Non display confusing characters | ||
3557 | 2957 | chars = '34678bcdefhkmnprstwxyzABCDEFGHJKLMNPQRTWXY' | ||
3558 | 2958 | |||
3559 | 2959 | # character length of tokens. Can be increased, decreased or even made | ||
3560 | 2960 | # random - Launchpad does not care. 7 means it takes 40 bytes to store | ||
3561 | 2961 | # a null-terminated Launchpad identity URL on the current domain name. | ||
3562 | 2962 | length=7 | ||
3563 | 2963 | |||
3564 | 2964 | loop_count = 0 | ||
3565 | 2965 | while loop_count < 20000: | ||
3566 | 2966 | # Generate a random openid_identifier | ||
3567 | 2967 | oid = ''.join(choice(chars) for count in range(length)) | ||
3568 | 2968 | |||
3569 | 2969 | # Check if the oid is already in the db, although this is pretty | ||
3570 | 2970 | # unlikely | ||
3571 | 2971 | rv = plpy.execute(""" | ||
3572 | 2972 | SELECT COUNT(*) AS num FROM Person WHERE openid_identifier = '%s' | ||
3573 | 2973 | """ % oid, 1) | ||
3574 | 2974 | if rv[0]['num'] == 0: | ||
3575 | 2975 | TD['new']['openid_identifier'] = oid | ||
3576 | 2976 | return "MODIFY" | ||
3577 | 2977 | loop_count += 1 | ||
3578 | 2978 | if loop_count == 1: | ||
3579 | 2979 | plpy.warning( | ||
3580 | 2980 | 'Clash generating unique openid_identifier. ' | ||
3581 | 2981 | 'Increase length if you see this warning too much.') | ||
3582 | 2982 | plpy.error( | ||
3583 | 2983 | "Unable to generate unique openid_identifier. " | ||
3584 | 2984 | "Need to increase length of tokens.") | ||
3585 | 2985 | $$; | ||
3586 | 2986 | |||
3587 | 2987 | |||
3588 | 2988 | CREATE FUNCTION set_shipit_normalized_address() RETURNS trigger | ||
3589 | 2989 | LANGUAGE plpgsql | ||
3590 | 2990 | AS $$ | ||
3591 | 2991 | BEGIN | ||
3592 | 2992 | NEW.normalized_address = | ||
3593 | 2993 | lower( | ||
3594 | 2994 | -- Strip off everything that's not alphanumeric | ||
3595 | 2995 | -- characters. | ||
3596 | 2996 | regexp_replace( | ||
3597 | 2997 | coalesce(NEW.addressline1, '') || ' ' || | ||
3598 | 2998 | coalesce(NEW.addressline2, '') || ' ' || | ||
3599 | 2999 | coalesce(NEW.city, ''), | ||
3600 | 3000 | '[^a-zA-Z0-9]+', '', 'g')); | ||
3601 | 3001 | RETURN NEW; | ||
3602 | 3002 | END; | ||
3603 | 3003 | $$; | ||
3604 | 3004 | |||
3605 | 3005 | |||
3606 | 3006 | COMMENT ON FUNCTION set_shipit_normalized_address() IS 'Store a normalized concatenation of the request''s address into the normalized_address column.'; | ||
3607 | 3007 | |||
3608 | 3008 | |||
3609 | 3009 | CREATE FUNCTION sha1(text) RETURNS character | ||
3614 | 3010 | LANGUAGE plpythonu IMMUTABLE STRICT | 2911 | LANGUAGE plpythonu IMMUTABLE STRICT |
3615 | 3011 | AS $$ | 2912 | AS $$ |
3616 | 3012 | import hashlib | 2913 | import hashlib |
3617 | @@ -3014,56 +2915,63 @@ | |||
3618 | 3014 | $$; | 2915 | $$; |
3619 | 3015 | 2916 | ||
3620 | 3016 | 2917 | ||
3643 | 3017 | COMMENT ON FUNCTION sha1(text) IS 'Return the SHA1 one way cryptographic hash as a string of 40 hex digits'; | 2918 | COMMENT ON FUNCTION public.sha1(text) IS 'Return the SHA1 one way cryptographic hash as a string of 40 hex digits'; |
3644 | 3018 | 2919 | ||
3645 | 3019 | 2920 | ||
3646 | 3020 | CREATE FUNCTION summarise_bug(bug_row bug) RETURNS void | 2921 | CREATE FUNCTION public.specification_denorm_access(spec_id integer) RETURNS void |
3647 | 3021 | LANGUAGE plpgsql | 2922 | LANGUAGE sql SECURITY DEFINER |
3648 | 3022 | AS $$ | 2923 | SET search_path TO 'public' |
3649 | 3023 | DECLARE | 2924 | AS $_$ |
3650 | 3024 | d bugsummary%ROWTYPE; | 2925 | UPDATE specification |
3651 | 3025 | BEGIN | 2926 | SET access_policy = policies[1], access_grants = grants |
3652 | 3026 | PERFORM ensure_bugsummary_temp_journal(); | 2927 | FROM |
3653 | 3027 | FOR d IN SELECT * FROM bugsummary_locations(BUG_ROW) LOOP | 2928 | build_access_cache( |
3654 | 3028 | d.count = 1; | 2929 | (SELECT id FROM accessartifact WHERE specification = $1), |
3655 | 3029 | PERFORM bug_summary_temp_journal_ins(d); | 2930 | (SELECT information_type FROM specification WHERE id = $1)) |
3656 | 3030 | END LOOP; | 2931 | AS (policies integer[], grants integer[]) |
3657 | 3031 | END; | 2932 | WHERE id = $1; |
3658 | 3032 | $$; | 2933 | $_$; |
3659 | 3033 | 2934 | ||
3660 | 3034 | 2935 | ||
3661 | 3035 | COMMENT ON FUNCTION summarise_bug(bug_row bug) IS 'AFTER summarise a bug row into bugsummary.'; | 2936 | CREATE FUNCTION public.specification_maintain_access_cache_trig() RETURNS trigger |
3662 | 3036 | 2937 | LANGUAGE plpgsql | |
3663 | 3037 | 2938 | AS $$ | |
3664 | 3038 | CREATE FUNCTION ulower(text) RETURNS text | 2939 | BEGIN |
3665 | 2940 | PERFORM specification_denorm_access(NEW.id); | ||
3666 | 2941 | RETURN NULL; | ||
3667 | 2942 | END; | ||
3668 | 2943 | $$; | ||
3669 | 2944 | |||
3670 | 2945 | |||
3671 | 2946 | CREATE FUNCTION public.summarise_bug(bug integer) RETURNS void | ||
3672 | 2947 | LANGUAGE plpgsql | ||
3673 | 2948 | AS $$ | ||
3674 | 2949 | BEGIN | ||
3675 | 2950 | PERFORM bugsummary_journal_bug(bug_row(bug), 1); | ||
3676 | 2951 | END; | ||
3677 | 2952 | $$; | ||
3678 | 2953 | |||
3679 | 2954 | |||
3680 | 2955 | CREATE FUNCTION public.ulower(text) RETURNS text | ||
3681 | 3039 | LANGUAGE plpythonu IMMUTABLE STRICT | 2956 | LANGUAGE plpythonu IMMUTABLE STRICT |
3682 | 3040 | AS $$ | 2957 | AS $$ |
3683 | 3041 | return args[0].decode('utf8').lower().encode('utf8') | 2958 | return args[0].decode('utf8').lower().encode('utf8') |
3684 | 3042 | $$; | 2959 | $$; |
3685 | 3043 | 2960 | ||
3686 | 3044 | 2961 | ||
3691 | 3045 | COMMENT ON FUNCTION ulower(text) IS 'Return the lower case version of a UTF-8 encoded string.'; | 2962 | COMMENT ON FUNCTION public.ulower(text) IS 'Return the lower case version of a UTF-8 encoded string.'; |
3692 | 3046 | 2963 | ||
3693 | 3047 | 2964 | ||
3694 | 3048 | CREATE FUNCTION unsummarise_bug(bug_row bug) RETURNS void | 2965 | CREATE FUNCTION public.unsummarise_bug(bug integer) RETURNS void |
3695 | 3049 | LANGUAGE plpgsql | 2966 | LANGUAGE plpgsql |
3696 | 3050 | AS $$ | 2967 | AS $$ |
3697 | 3051 | DECLARE | ||
3698 | 3052 | d bugsummary%ROWTYPE; | ||
3699 | 3053 | BEGIN | 2968 | BEGIN |
3705 | 3054 | PERFORM ensure_bugsummary_temp_journal(); | 2969 | PERFORM bugsummary_journal_bug(bug_row(bug), -1); |
3701 | 3055 | FOR d IN SELECT * FROM bugsummary_locations(BUG_ROW) LOOP | ||
3702 | 3056 | d.count = -1; | ||
3703 | 3057 | PERFORM bug_summary_temp_journal_ins(d); | ||
3704 | 3058 | END LOOP; | ||
3706 | 3059 | END; | 2970 | END; |
3707 | 3060 | $$; | 2971 | $$; |
3708 | 3061 | 2972 | ||
3709 | 3062 | 2973 | ||
3714 | 3063 | COMMENT ON FUNCTION unsummarise_bug(bug_row bug) IS 'AFTER unsummarise a bug row from bugsummary.'; | 2974 | CREATE FUNCTION public.update_branch_name_cache() RETURNS trigger |
3711 | 3064 | |||
3712 | 3065 | |||
3713 | 3066 | CREATE FUNCTION update_branch_name_cache() RETURNS trigger | ||
3715 | 3067 | LANGUAGE plpgsql | 2975 | LANGUAGE plpgsql |
3716 | 3068 | AS $$ | 2976 | AS $$ |
3717 | 3069 | DECLARE | 2977 | DECLARE |
3718 | @@ -3075,7 +2983,7 @@ | |||
3719 | 3075 | OR NEW.unique_name IS NULL | 2983 | OR NEW.unique_name IS NULL |
3720 | 3076 | OR OLD.owner_name <> NEW.owner_name | 2984 | OR OLD.owner_name <> NEW.owner_name |
3721 | 3077 | OR OLD.unique_name <> NEW.unique_name | 2985 | OR OLD.unique_name <> NEW.unique_name |
3723 | 3078 | OR (NEW.target_suffix IS NULL <> OLD.target_suffix IS NULL) | 2986 | OR ((NEW.target_suffix IS NULL) <> (OLD.target_suffix IS NULL)) |
3724 | 3079 | OR COALESCE(OLD.target_suffix, '') <> COALESCE(NEW.target_suffix, '') | 2987 | OR COALESCE(OLD.target_suffix, '') <> COALESCE(NEW.target_suffix, '') |
3725 | 3080 | OR OLD.name <> NEW.name | 2988 | OR OLD.name <> NEW.name |
3726 | 3081 | OR OLD.owner <> NEW.owner | 2989 | OR OLD.owner <> NEW.owner |
3727 | @@ -3111,12 +3019,12 @@ | |||
3728 | 3111 | $$; | 3019 | $$; |
3729 | 3112 | 3020 | ||
3730 | 3113 | 3021 | ||
3735 | 3114 | COMMENT ON FUNCTION update_branch_name_cache() IS 'Maintain the cached name columns in Branch.'; | 3022 | COMMENT ON FUNCTION public.update_branch_name_cache() IS 'Maintain the cached name columns in Branch.'; |
3736 | 3115 | 3023 | ||
3737 | 3116 | 3024 | ||
3738 | 3117 | CREATE FUNCTION update_database_disk_utilization() RETURNS void | 3025 | CREATE FUNCTION public.update_database_disk_utilization() RETURNS void |
3739 | 3118 | LANGUAGE sql SECURITY DEFINER | 3026 | LANGUAGE sql SECURITY DEFINER |
3741 | 3119 | SET search_path TO public | 3027 | SET search_path TO 'public' |
3742 | 3120 | AS $$ | 3028 | AS $$ |
3743 | 3121 | INSERT INTO DatabaseDiskUtilization | 3029 | INSERT INTO DatabaseDiskUtilization |
3744 | 3122 | SELECT | 3030 | SELECT |
3745 | @@ -3136,6 +3044,7 @@ | |||
3746 | 3136 | (stat).free_space, | 3044 | (stat).free_space, |
3747 | 3137 | (stat).free_percent | 3045 | (stat).free_percent |
3748 | 3138 | FROM ( | 3046 | FROM ( |
3749 | 3047 | -- Tables | ||
3750 | 3139 | SELECT | 3048 | SELECT |
3751 | 3140 | pg_namespace.nspname AS namespace, | 3049 | pg_namespace.nspname AS namespace, |
3752 | 3141 | pg_class.relname AS name, | 3050 | pg_class.relname AS name, |
3753 | @@ -3151,6 +3060,7 @@ | |||
3754 | 3151 | 3060 | ||
3755 | 3152 | UNION ALL | 3061 | UNION ALL |
3756 | 3153 | 3062 | ||
3757 | 3063 | -- Indexes | ||
3758 | 3154 | SELECT | 3064 | SELECT |
3759 | 3155 | pg_namespace_table.nspname AS namespace, | 3065 | pg_namespace_table.nspname AS namespace, |
3760 | 3156 | pg_class_table.relname AS name, | 3066 | pg_class_table.relname AS name, |
3761 | @@ -3163,12 +3073,15 @@ | |||
3762 | 3163 | pg_namespace AS pg_namespace_index, | 3073 | pg_namespace AS pg_namespace_index, |
3763 | 3164 | pg_class AS pg_class_table, | 3074 | pg_class AS pg_class_table, |
3764 | 3165 | pg_class AS pg_class_index, | 3075 | pg_class AS pg_class_index, |
3766 | 3166 | pg_index | 3076 | pg_index, |
3767 | 3077 | pg_am | ||
3768 | 3167 | WHERE | 3078 | WHERE |
3769 | 3168 | pg_class_index.relkind = 'i' | 3079 | pg_class_index.relkind = 'i' |
3770 | 3080 | AND pg_am.amname <> 'gin' -- pgstattuple doesn't support GIN | ||
3771 | 3169 | AND pg_table_is_visible(pg_class_table.oid) | 3081 | AND pg_table_is_visible(pg_class_table.oid) |
3772 | 3170 | AND pg_class_index.relnamespace = pg_namespace_index.oid | 3082 | AND pg_class_index.relnamespace = pg_namespace_index.oid |
3773 | 3171 | AND pg_class_table.relnamespace = pg_namespace_table.oid | 3083 | AND pg_class_table.relnamespace = pg_namespace_table.oid |
3774 | 3084 | AND pg_class_index.relam = pg_am.oid | ||
3775 | 3172 | AND pg_index.indexrelid = pg_class_index.oid | 3085 | AND pg_index.indexrelid = pg_class_index.oid |
3776 | 3173 | AND pg_index.indrelid = pg_class_table.oid | 3086 | AND pg_index.indrelid = pg_class_table.oid |
3777 | 3174 | 3087 | ||
3778 | @@ -3208,20 +3121,22 @@ | |||
3779 | 3208 | pg_namespace AS pg_namespace_index, | 3121 | pg_namespace AS pg_namespace_index, |
3780 | 3209 | pg_class AS pg_class_table, | 3122 | pg_class AS pg_class_table, |
3781 | 3210 | pg_class AS pg_class_index, | 3123 | pg_class AS pg_class_index, |
3783 | 3211 | pg_class AS pg_class_toast | 3124 | pg_class AS pg_class_toast, |
3784 | 3125 | pg_index | ||
3785 | 3212 | WHERE | 3126 | WHERE |
3786 | 3213 | pg_class_table.relnamespace = pg_namespace_table.oid | 3127 | pg_class_table.relnamespace = pg_namespace_table.oid |
3787 | 3214 | AND pg_table_is_visible(pg_class_table.oid) | 3128 | AND pg_table_is_visible(pg_class_table.oid) |
3788 | 3215 | AND pg_class_index.relnamespace = pg_namespace_index.oid | 3129 | AND pg_class_index.relnamespace = pg_namespace_index.oid |
3789 | 3216 | AND pg_class_table.reltoastrelid = pg_class_toast.oid | 3130 | AND pg_class_table.reltoastrelid = pg_class_toast.oid |
3791 | 3217 | AND pg_class_index.oid = pg_class_toast.reltoastidxid | 3131 | AND pg_class_index.oid = pg_index.indexrelid |
3792 | 3132 | AND pg_index.indrelid = pg_class_toast.oid | ||
3793 | 3218 | ) AS whatever; | 3133 | ) AS whatever; |
3794 | 3219 | $$; | 3134 | $$; |
3795 | 3220 | 3135 | ||
3796 | 3221 | 3136 | ||
3798 | 3222 | CREATE FUNCTION update_database_stats() RETURNS void | 3137 | CREATE FUNCTION public.update_database_stats() RETURNS void |
3799 | 3223 | LANGUAGE plpythonu SECURITY DEFINER | 3138 | LANGUAGE plpythonu SECURITY DEFINER |
3801 | 3224 | SET search_path TO public | 3139 | SET search_path TO 'public' |
3802 | 3225 | AS $_$ | 3140 | AS $_$ |
3803 | 3226 | import re | 3141 | import re |
3804 | 3227 | import subprocess | 3142 | import subprocess |
3805 | @@ -3306,12 +3221,12 @@ | |||
3806 | 3306 | $_$; | 3221 | $_$; |
3807 | 3307 | 3222 | ||
3808 | 3308 | 3223 | ||
3813 | 3309 | COMMENT ON FUNCTION update_database_stats() IS 'Copies rows from pg_stat_user_tables into DatabaseTableStats. We use a stored procedure because it is problematic for us to grant permissions on objects in the pg_catalog schema.'; | 3224 | COMMENT ON FUNCTION public.update_database_stats() IS 'Copies rows from pg_stat_user_tables into DatabaseTableStats. We use a stored procedure because it is problematic for us to grant permissions on objects in the pg_catalog schema.'; |
3814 | 3310 | 3225 | ||
3815 | 3311 | 3226 | ||
3816 | 3312 | CREATE FUNCTION update_replication_lag_cache() RETURNS boolean | 3227 | CREATE FUNCTION public.update_replication_lag_cache() RETURNS boolean |
3817 | 3313 | LANGUAGE plpgsql SECURITY DEFINER | 3228 | LANGUAGE plpgsql SECURITY DEFINER |
3819 | 3314 | SET search_path TO public | 3229 | SET search_path TO 'public' |
3820 | 3315 | AS $$ | 3230 | AS $$ |
3821 | 3316 | BEGIN | 3231 | BEGIN |
3822 | 3317 | DELETE FROM DatabaseReplicationLag; | 3232 | DELETE FROM DatabaseReplicationLag; |
3823 | @@ -3329,64 +3244,10 @@ | |||
3824 | 3329 | $$; | 3244 | $$; |
3825 | 3330 | 3245 | ||
3826 | 3331 | 3246 | ||
3885 | 3332 | COMMENT ON FUNCTION update_replication_lag_cache() IS 'Updates the DatabaseReplicationLag materialized view.'; | 3247 | COMMENT ON FUNCTION public.update_replication_lag_cache() IS 'Updates the DatabaseReplicationLag materialized view.'; |
3886 | 3333 | 3248 | ||
3887 | 3334 | 3249 | ||
3888 | 3335 | CREATE FUNCTION update_transitively_private(start_branch integer, _root_branch integer DEFAULT NULL::integer, _root_transitively_private boolean DEFAULT NULL::boolean) RETURNS void | 3250 | CREATE FUNCTION public.valid_absolute_url(text) RETURNS boolean |
3831 | 3336 | LANGUAGE plpgsql SECURITY DEFINER | ||
3832 | 3337 | SET search_path TO public | ||
3833 | 3338 | AS $$ | ||
3834 | 3339 | DECLARE | ||
3835 | 3340 | root_transitively_private boolean := _root_transitively_private; | ||
3836 | 3341 | root_branch int := _root_branch; | ||
3837 | 3342 | BEGIN | ||
3838 | 3343 | IF root_transitively_private IS NULL THEN | ||
3839 | 3344 | -- We can't just trust the transitively_private flag of the | ||
3840 | 3345 | -- branch we are stacked on, as if we are updating multiple | ||
3841 | 3346 | -- records they will be updated in an indeterminate order. | ||
3842 | 3347 | -- We need a recursive query. | ||
3843 | 3348 | UPDATE Branch SET transitively_private = ( | ||
3844 | 3349 | WITH RECURSIVE stacked_branches AS ( | ||
3845 | 3350 | SELECT | ||
3846 | 3351 | top_branch.id, top_branch.stacked_on, top_branch.private | ||
3847 | 3352 | FROM Branch AS top_branch | ||
3848 | 3353 | WHERE top_branch.id = start_branch | ||
3849 | 3354 | UNION ALL | ||
3850 | 3355 | SELECT | ||
3851 | 3356 | sub_branch.id, sub_branch.stacked_on, sub_branch.private | ||
3852 | 3357 | FROM stacked_branches, Branch AS sub_branch | ||
3853 | 3358 | WHERE | ||
3854 | 3359 | stacked_branches.stacked_on = sub_branch.id | ||
3855 | 3360 | AND stacked_branches.stacked_on != start_branch | ||
3856 | 3361 | -- Shortcircuit. No need to recurse if already private. | ||
3857 | 3362 | AND stacked_branches.private IS FALSE | ||
3858 | 3363 | ) | ||
3859 | 3364 | SELECT COUNT(*) > 0 | ||
3860 | 3365 | FROM stacked_branches | ||
3861 | 3366 | WHERE private IS TRUE) | ||
3862 | 3367 | WHERE Branch.id = start_branch | ||
3863 | 3368 | RETURNING transitively_private INTO root_transitively_private; | ||
3864 | 3369 | root_branch := start_branch; | ||
3865 | 3370 | ELSE | ||
3866 | 3371 | -- Now we have calculated the correct transitively_private flag | ||
3867 | 3372 | -- we can trust it. | ||
3868 | 3373 | UPDATE Branch SET | ||
3869 | 3374 | transitively_private = GREATEST(private, root_transitively_private) | ||
3870 | 3375 | WHERE id = root_branch; | ||
3871 | 3376 | END IF; | ||
3872 | 3377 | |||
3873 | 3378 | -- Recurse to branches stacked on this one. | ||
3874 | 3379 | PERFORM update_transitively_private( | ||
3875 | 3380 | start_branch, id, GREATEST(private, root_transitively_private)) | ||
3876 | 3381 | FROM Branch WHERE stacked_on = root_branch AND id != start_branch; | ||
3877 | 3382 | END; | ||
3878 | 3383 | $$; | ||
3879 | 3384 | |||
3880 | 3385 | |||
3881 | 3386 | COMMENT ON FUNCTION update_transitively_private(start_branch integer, _root_branch integer, _root_transitively_private boolean) IS 'A branch is transitively private if it is private or is stacked on any transitively private branches.'; | ||
3882 | 3387 | |||
3883 | 3388 | |||
3884 | 3389 | CREATE FUNCTION valid_absolute_url(text) RETURNS boolean | ||
3889 | 3390 | LANGUAGE plpythonu IMMUTABLE STRICT | 3251 | LANGUAGE plpythonu IMMUTABLE STRICT |
3890 | 3391 | AS $$ | 3252 | AS $$ |
3891 | 3392 | from urlparse import urlparse, uses_netloc | 3253 | from urlparse import urlparse, uses_netloc |
3892 | @@ -3403,10 +3264,10 @@ | |||
3893 | 3403 | $$; | 3264 | $$; |
3894 | 3404 | 3265 | ||
3895 | 3405 | 3266 | ||
3900 | 3406 | COMMENT ON FUNCTION valid_absolute_url(text) IS 'Ensure the given test is a valid absolute URL, containing both protocol and network location'; | 3267 | COMMENT ON FUNCTION public.valid_absolute_url(text) IS 'Ensure the given test is a valid absolute URL, containing both protocol and network location'; |
3901 | 3407 | 3268 | ||
3902 | 3408 | 3269 | ||
3903 | 3409 | CREATE FUNCTION valid_branch_name(text) RETURNS boolean | 3270 | CREATE FUNCTION public.valid_branch_name(text) RETURNS boolean |
3904 | 3410 | LANGUAGE plpythonu IMMUTABLE STRICT | 3271 | LANGUAGE plpythonu IMMUTABLE STRICT |
3905 | 3411 | AS $$ | 3272 | AS $$ |
3906 | 3412 | import re | 3273 | import re |
3907 | @@ -3418,27 +3279,27 @@ | |||
3908 | 3418 | $$; | 3279 | $$; |
3909 | 3419 | 3280 | ||
3910 | 3420 | 3281 | ||
3912 | 3421 | COMMENT ON FUNCTION valid_branch_name(text) IS 'validate a branch name. | 3282 | COMMENT ON FUNCTION public.valid_branch_name(text) IS 'validate a branch name. |
3913 | 3422 | 3283 | ||
3914 | 3423 | As per valid_name, except we allow uppercase and @'; | 3284 | As per valid_name, except we allow uppercase and @'; |
3915 | 3424 | 3285 | ||
3916 | 3425 | 3286 | ||
3918 | 3426 | CREATE FUNCTION valid_cve(text) RETURNS boolean | 3287 | CREATE FUNCTION public.valid_cve(text) RETURNS boolean |
3919 | 3427 | LANGUAGE plpythonu IMMUTABLE STRICT | 3288 | LANGUAGE plpythonu IMMUTABLE STRICT |
3920 | 3428 | AS $_$ | 3289 | AS $_$ |
3921 | 3429 | import re | 3290 | import re |
3922 | 3430 | name = args[0] | 3291 | name = args[0] |
3924 | 3431 | pat = r"^(19|20)\d{2}-\d{4}$" | 3292 | pat = r"^(19|20)\d{2}-\d{4,}$" |
3925 | 3432 | if re.match(pat, name): | 3293 | if re.match(pat, name): |
3926 | 3433 | return 1 | 3294 | return 1 |
3927 | 3434 | return 0 | 3295 | return 0 |
3928 | 3435 | $_$; | 3296 | $_$; |
3929 | 3436 | 3297 | ||
3930 | 3437 | 3298 | ||
3935 | 3438 | COMMENT ON FUNCTION valid_cve(text) IS 'validate a common vulnerability number as defined on www.cve.mitre.org, minus the CAN- or CVE- prefix.'; | 3299 | COMMENT ON FUNCTION public.valid_cve(text) IS 'validate a common vulnerability number as defined on www.cve.mitre.org, minus the CAN- or CVE- prefix.'; |
3936 | 3439 | 3300 | ||
3937 | 3440 | 3301 | ||
3938 | 3441 | CREATE FUNCTION valid_debian_version(text) RETURNS boolean | 3302 | CREATE FUNCTION public.valid_debian_version(text) RETURNS boolean |
3939 | 3442 | LANGUAGE plpythonu IMMUTABLE STRICT | 3303 | LANGUAGE plpythonu IMMUTABLE STRICT |
3940 | 3443 | AS $_$ | 3304 | AS $_$ |
3941 | 3444 | import re | 3305 | import re |
3942 | @@ -3462,10 +3323,10 @@ | |||
3943 | 3462 | $_$; | 3323 | $_$; |
3944 | 3463 | 3324 | ||
3945 | 3464 | 3325 | ||
3950 | 3465 | COMMENT ON FUNCTION valid_debian_version(text) IS 'validate a version number as per Debian Policy'; | 3326 | COMMENT ON FUNCTION public.valid_debian_version(text) IS 'validate a version number as per Debian Policy'; |
3951 | 3466 | 3327 | ||
3952 | 3467 | 3328 | ||
3953 | 3468 | CREATE FUNCTION valid_fingerprint(text) RETURNS boolean | 3329 | CREATE FUNCTION public.valid_fingerprint(text) RETURNS boolean |
3954 | 3469 | LANGUAGE plpythonu IMMUTABLE STRICT | 3330 | LANGUAGE plpythonu IMMUTABLE STRICT |
3955 | 3470 | AS $$ | 3331 | AS $$ |
3956 | 3471 | import re | 3332 | import re |
3957 | @@ -3476,10 +3337,27 @@ | |||
3958 | 3476 | $$; | 3337 | $$; |
3959 | 3477 | 3338 | ||
3960 | 3478 | 3339 | ||
3965 | 3479 | COMMENT ON FUNCTION valid_fingerprint(text) IS 'Returns true if passed a valid GPG fingerprint. Valid GPG fingerprints are a 40 character long hexadecimal number in uppercase.'; | 3340 | COMMENT ON FUNCTION public.valid_fingerprint(text) IS 'Returns true if passed a valid GPG fingerprint. Valid GPG fingerprints are a 40 character long hexadecimal number in uppercase.'; |
3966 | 3480 | 3341 | ||
3967 | 3481 | 3342 | ||
3968 | 3482 | CREATE FUNCTION valid_keyid(text) RETURNS boolean | 3343 | CREATE FUNCTION public.valid_git_repository_name(text) RETURNS boolean |
3969 | 3344 | LANGUAGE plpythonu IMMUTABLE STRICT | ||
3970 | 3345 | AS $$ | ||
3971 | 3346 | import re | ||
3972 | 3347 | name = args[0] | ||
3973 | 3348 | pat = r"^(?i)[a-z0-9][a-z0-9+\.\-@_]*\Z" | ||
3974 | 3349 | if not name.endswith(".git") and re.match(pat, name): | ||
3975 | 3350 | return 1 | ||
3976 | 3351 | return 0 | ||
3977 | 3352 | $$; | ||
3978 | 3353 | |||
3979 | 3354 | |||
3980 | 3355 | COMMENT ON FUNCTION public.valid_git_repository_name(text) IS 'validate a Git repository name. | ||
3981 | 3356 | |||
3982 | 3357 | As per valid_branch_name, except we disallow names ending in ".git".'; | ||
3983 | 3358 | |||
3984 | 3359 | |||
3985 | 3360 | CREATE FUNCTION public.valid_keyid(text) RETURNS boolean | ||
3986 | 3483 | LANGUAGE plpythonu IMMUTABLE STRICT | 3361 | LANGUAGE plpythonu IMMUTABLE STRICT |
3987 | 3484 | AS $$ | 3362 | AS $$ |
3988 | 3485 | import re | 3363 | import re |
3989 | @@ -3490,10 +3368,10 @@ | |||
3990 | 3490 | $$; | 3368 | $$; |
3991 | 3491 | 3369 | ||
3992 | 3492 | 3370 | ||
3997 | 3493 | COMMENT ON FUNCTION valid_keyid(text) IS 'Returns true if passed a valid GPG keyid. Valid GPG keyids are an 8 character long hexadecimal number in uppercase (in reality, they are 16 characters long but we are using the ''common'' definition.'; | 3371 | COMMENT ON FUNCTION public.valid_keyid(text) IS 'Returns true if passed a valid GPG keyid. Valid GPG keyids are an 8 character long hexadecimal number in uppercase (in reality, they are 16 characters long but we are using the ''common'' definition.'; |
3998 | 3494 | 3372 | ||
3999 | 3495 | 3373 | ||
4000 | 3496 | CREATE FUNCTION valid_regexp(text) RETURNS boolean | 3374 | CREATE FUNCTION public.valid_regexp(text) RETURNS boolean |
4001 | 3497 | LANGUAGE plpythonu IMMUTABLE STRICT | 3375 | LANGUAGE plpythonu IMMUTABLE STRICT |
4002 | 3498 | AS $$ | 3376 | AS $$ |
4003 | 3499 | import re | 3377 | import re |
4004 | @@ -3506,10 +3384,10 @@ | |||
4005 | 3506 | $$; | 3384 | $$; |
4006 | 3507 | 3385 | ||
4007 | 3508 | 3386 | ||
4012 | 3509 | COMMENT ON FUNCTION valid_regexp(text) IS 'Returns true if the input can be compiled as a regular expression.'; | 3387 | COMMENT ON FUNCTION public.valid_regexp(text) IS 'Returns true if the input can be compiled as a regular expression.'; |
4013 | 3510 | 3388 | ||
4014 | 3511 | 3389 | ||
4015 | 3512 | CREATE FUNCTION version_sort_key(version text) RETURNS text | 3390 | CREATE FUNCTION public.version_sort_key(version text) RETURNS text |
4016 | 3513 | LANGUAGE plpythonu IMMUTABLE STRICT | 3391 | LANGUAGE plpythonu IMMUTABLE STRICT |
4017 | 3514 | AS $$ | 3392 | AS $$ |
4018 | 3515 | # If this method is altered, then any functional indexes using it | 3393 | # If this method is altered, then any functional indexes using it |
4019 | @@ -3529,10 +3407,10 @@ | |||
4020 | 3529 | $$; | 3407 | $$; |
4021 | 3530 | 3408 | ||
4022 | 3531 | 3409 | ||
4027 | 3532 | COMMENT ON FUNCTION version_sort_key(version text) IS 'Sort a field as version numbers that do not necessarily conform to debian package versions (For example, when "2-2" should be considered greater than "1:1"). debversion_sort_key() should be used for debian versions. Numbers will be sorted after letters unlike typical ASCII, so that a descending sort will put the latest version number that starts with a number instead of a letter will be at the top. E.g. ascending is [a, z, 1, 9] and descending is [9, 1, z, a].'; | 3410 | COMMENT ON FUNCTION public.version_sort_key(version text) IS 'Sort a field as version numbers that do not necessarily conform to debian package versions (For example, when "2-2" should be considered greater than "1:1"). debversion_sort_key() should be used for debian versions. Numbers will be sorted after letters unlike typical ASCII, so that a descending sort will put the latest version number that starts with a number instead of a letter will be at the top. E.g. ascending is [a, z, 1, 9] and descending is [9, 1, z, a].'; |
4028 | 3533 | 3411 | ||
4029 | 3534 | 3412 | ||
4030 | 3535 | CREATE FUNCTION you_are_your_own_member() RETURNS trigger | 3413 | CREATE FUNCTION public.you_are_your_own_member() RETURNS trigger |
4031 | 3536 | LANGUAGE plpgsql | 3414 | LANGUAGE plpgsql |
4032 | 3537 | AS $$ | 3415 | AS $$ |
4033 | 3538 | BEGIN | 3416 | BEGIN |
4034 | @@ -3543,873 +3421,116 @@ | |||
4035 | 3543 | $$; | 3421 | $$; |
4036 | 3544 | 3422 | ||
4037 | 3545 | 3423 | ||
4905 | 3546 | COMMENT ON FUNCTION you_are_your_own_member() IS 'Trigger function to ensure that every row added to the Person table gets a corresponding row in the TeamParticipation table, as per the TeamParticipationUsage page on the Launchpad wiki'; | 3424 | COMMENT ON FUNCTION public.you_are_your_own_member() IS 'Trigger function to ensure that every row added to the Person table gets a corresponding row in the TeamParticipation table, as per the TeamParticipationUsage page on the Launchpad wiki'; |
4906 | 3547 | 3425 | ||
4907 | 3548 | 3426 | ||
4908 | 3549 | SET search_path = ts2, pg_catalog; | 3427 | CREATE OPERATOR public.> ( |
4909 | 3550 | 3428 | PROCEDURE = public.debversion_gt, | |
4910 | 3551 | CREATE FUNCTION _ftq(text) RETURNS text | 3429 | LEFTARG = public.debversion, |
4911 | 3552 | LANGUAGE plpythonu IMMUTABLE STRICT | 3430 | RIGHTARG = public.debversion, |
4912 | 3553 | AS $_$ | 3431 | COMMUTATOR = OPERATOR(public.<), |
4913 | 3554 | import re | 3432 | NEGATOR = OPERATOR(public.>=) |
4914 | 3555 | 3433 | ); | |
4915 | 3556 | # I think this method would be more robust if we used a real | 3434 | |
4916 | 3557 | # tokenizer and parser to generate the query string, but we need | 3435 | |
4917 | 3558 | # something suitable for use as a stored procedure which currently | 3436 | COMMENT ON OPERATOR public.> (public.debversion, public.debversion) IS 'debversion greater-than'; |
4918 | 3559 | # means no external dependancies. | 3437 | |
4919 | 3560 | 3438 | ||
4920 | 3561 | # Convert to Unicode | 3439 | CREATE AGGREGATE public.max(public.debversion) ( |
4921 | 3562 | query = args[0].decode('utf8') | 3440 | SFUNC = public.debversion_larger, |
4922 | 3563 | ## plpy.debug('1 query is %s' % repr(query)) | 3441 | STYPE = public.debversion, |
4923 | 3564 | 3442 | SORTOP = OPERATOR(public.>) | |
4924 | 3565 | # Normalize whitespace | 3443 | ); |
4925 | 3566 | query = re.sub("(?u)\s+"," ", query) | 3444 | |
4926 | 3567 | 3445 | ||
4927 | 3568 | # Convert AND, OR, NOT and - to tsearch2 punctuation | 3446 | CREATE OPERATOR public.< ( |
4928 | 3569 | query = re.sub(r"(?u)(?:^|\s)-([\w\(])", r" !\1", query) | 3447 | PROCEDURE = public.debversion_lt, |
4929 | 3570 | query = re.sub(r"(?u)\bAND\b", "&", query) | 3448 | LEFTARG = public.debversion, |
4930 | 3571 | query = re.sub(r"(?u)\bOR\b", "|", query) | 3449 | RIGHTARG = public.debversion, |
4931 | 3572 | query = re.sub(r"(?u)\bNOT\b", " !", query) | 3450 | COMMUTATOR = OPERATOR(public.>), |
4932 | 3573 | ## plpy.debug('2 query is %s' % repr(query)) | 3451 | NEGATOR = OPERATOR(public.>=) |
4933 | 3574 | 3452 | ); | |
4934 | 3575 | # Deal with unwanted punctuation. We convert strings of punctuation | 3453 | |
4935 | 3576 | # inside words to a '-' character for the hypenation handling below | 3454 | |
4936 | 3577 | # to deal with further. Outside of words we replace with whitespace. | 3455 | COMMENT ON OPERATOR public.< (public.debversion, public.debversion) IS 'debversion less-than'; |
4937 | 3578 | # We don't mess with -&|!()' as they are handled later. | 3456 | |
4938 | 3579 | #punctuation = re.escape(r'`~@#$%^*+=[]{}:;"<>,.?\/') | 3457 | |
4939 | 3580 | punctuation = r"[^\w\s\-\&\|\!\(\)']" | 3458 | CREATE AGGREGATE public.min(public.debversion) ( |
4940 | 3581 | query = re.sub(r"(?u)(\w)%s+(\w)" % (punctuation,), r"\1-\2", query) | 3459 | SFUNC = public.debversion_smaller, |
4941 | 3582 | query = re.sub(r"(?u)%s+" % (punctuation,), " ", query) | 3460 | STYPE = public.debversion, |
4942 | 3583 | ## plpy.debug('3 query is %s' % repr(query)) | 3461 | SORTOP = OPERATOR(public.<) |
4943 | 3584 | 3462 | ); | |
4944 | 3585 | # Strip ! characters inside and at the end of a word | 3463 | |
4945 | 3586 | query = re.sub(r"(?u)(?<=\w)[\!]+", " ", query) | 3464 | |
4946 | 3587 | 3465 | CREATE OPERATOR public.<= ( | |
4947 | 3588 | # Now that we have handle case sensitive booleans, convert to lowercase | 3466 | PROCEDURE = public.debversion_le, |
4948 | 3589 | query = query.lower() | 3467 | LEFTARG = public.debversion, |
4949 | 3590 | 3468 | RIGHTARG = public.debversion, | |
4950 | 3591 | # Convert foo-bar to ((foo&bar)|foobar) and foo-bar-baz to | 3469 | COMMUTATOR = OPERATOR(public.>=), |
4951 | 3592 | # ((foo&bar&baz)|foobarbaz) | 3470 | NEGATOR = OPERATOR(public.>) |
4952 | 3593 | def hyphen_repl(match): | 3471 | ); |
4953 | 3594 | bits = match.group(0).split("-") | 3472 | |
4954 | 3595 | return "((%s)|%s)" % ("&".join(bits), "".join(bits)) | 3473 | |
4955 | 3596 | query = re.sub(r"(?u)\b\w+-[\w\-]+\b", hyphen_repl, query) | 3474 | COMMENT ON OPERATOR public.<= (public.debversion, public.debversion) IS 'debversion less-than-or-equal'; |
4956 | 3597 | ## plpy.debug('4 query is %s' % repr(query)) | 3475 | |
4957 | 3598 | 3476 | ||
4958 | 3599 | # Any remaining - characters are spurious | 3477 | CREATE OPERATOR public.<> ( |
4959 | 3600 | query = query.replace('-','') | 3478 | PROCEDURE = public.debversion_ne, |
4960 | 3601 | 3479 | LEFTARG = public.debversion, | |
4961 | 3602 | # Remove unpartnered bracket on the left and right | 3480 | RIGHTARG = public.debversion, |
4962 | 3603 | query = re.sub(r"(?ux) ^ ( [^(]* ) \)", r"(\1)", query) | 3481 | COMMUTATOR = OPERATOR(public.<>), |
4963 | 3604 | query = re.sub(r"(?ux) \( ( [^)]* ) $", r"(\1)", query) | 3482 | NEGATOR = OPERATOR(public.=) |
4964 | 3605 | 3483 | ); | |
4965 | 3606 | # Remove spurious brackets | 3484 | |
4966 | 3607 | query = re.sub(r"(?u)\(([^\&\|]*?)\)", r" \1 ", query) | 3485 | |
4967 | 3608 | ## plpy.debug('5 query is %s' % repr(query)) | 3486 | COMMENT ON OPERATOR public.<> (public.debversion, public.debversion) IS 'debversion not equal'; |
4968 | 3609 | 3487 | ||
4969 | 3610 | # Insert & between tokens without an existing boolean operator | 3488 | |
4970 | 3611 | # ( not proceeded by (|&! | 3489 | CREATE OPERATOR public.= ( |
4971 | 3612 | query = re.sub(r"(?u)(?<![\(\|\&\!])\s*\(", "&(", query) | 3490 | PROCEDURE = public.debversion_eq, |
4972 | 3613 | ## plpy.debug('6 query is %s' % repr(query)) | 3491 | LEFTARG = public.debversion, |
4973 | 3614 | # ) not followed by )|& | 3492 | RIGHTARG = public.debversion, |
4974 | 3615 | query = re.sub(r"(?u)\)(?!\s*(\)|\||\&|\s*$))", ")&", query) | 3493 | COMMUTATOR = OPERATOR(public.=), |
4975 | 3616 | ## plpy.debug('6.1 query is %s' % repr(query)) | 3494 | NEGATOR = OPERATOR(public.<>) |
4976 | 3617 | # Whitespace not proceded by (|&! not followed by &| | 3495 | ); |
4977 | 3618 | query = re.sub(r"(?u)(?<![\(\|\&\!\s])\s+(?![\&\|\s])", "&", query) | 3496 | |
4978 | 3619 | ## plpy.debug('7 query is %s' % repr(query)) | 3497 | |
4979 | 3620 | 3498 | COMMENT ON OPERATOR public.= (public.debversion, public.debversion) IS 'debversion equal'; | |
4980 | 3621 | # Detect and repair syntax errors - we are lenient because | 3499 | |
4981 | 3622 | # this input is generally from users. | 3500 | |
4982 | 3623 | 3501 | CREATE OPERATOR public.>= ( | |
4983 | 3624 | # Fix unbalanced brackets | 3502 | PROCEDURE = public.debversion_ge, |
4984 | 3625 | openings = query.count("(") | 3503 | LEFTARG = public.debversion, |
4985 | 3626 | closings = query.count(")") | 3504 | RIGHTARG = public.debversion, |
4986 | 3627 | if openings > closings: | 3505 | COMMUTATOR = OPERATOR(public.<=), |
4987 | 3628 | query = query + " ) "*(openings-closings) | 3506 | NEGATOR = OPERATOR(public.<) |
4988 | 3629 | elif closings > openings: | 3507 | ); |
4989 | 3630 | query = " ( "*(closings-openings) + query | 3508 | |
4990 | 3631 | ## plpy.debug('8 query is %s' % repr(query)) | 3509 | |
4991 | 3632 | 3510 | COMMENT ON OPERATOR public.>= (public.debversion, public.debversion) IS 'debversion greater-than-or-equal'; | |
4992 | 3633 | # Strip ' character that do not have letters on both sides | 3511 | |
4993 | 3634 | query = re.sub(r"(?u)((?<!\w)'|'(?!\w))", "", query) | 3512 | |
4994 | 3635 | 3513 | CREATE OPERATOR FAMILY public.debversion_ops USING btree; | |
4995 | 3636 | # Brackets containing nothing but whitespace and booleans, recursive | 3514 | |
4996 | 3637 | last = "" | 3515 | |
4997 | 3638 | while last != query: | 3516 | CREATE OPERATOR CLASS public.debversion_ops |
4998 | 3639 | last = query | 3517 | DEFAULT FOR TYPE public.debversion USING btree FAMILY public.debversion_ops AS |
4999 | 3640 | query = re.sub(r"(?u)\([\s\&\|\!]*\)", "", query) | 3518 | OPERATOR 1 public.<(public.debversion,public.debversion) , |
5000 | 3641 | ## plpy.debug('9 query is %s' % repr(query)) | 3519 | OPERATOR 2 public.<=(public.debversion,public.debversion) , |
4134 | 3642 | |||
4135 | 3643 | # An & or | following a ( | ||
4136 | 3644 | query = re.sub(r"(?u)(?<=\()[\&\|\s]+", "", query) | ||
4137 | 3645 | ## plpy.debug('10 query is %s' % repr(query)) | ||
4138 | 3646 | |||
4139 | 3647 | # An &, | or ! immediatly before a ) | ||
4140 | 3648 | query = re.sub(r"(?u)[\&\|\!\s]*[\&\|\!]+\s*(?=\))", "", query) | ||
4141 | 3649 | ## plpy.debug('11 query is %s' % repr(query)) | ||
4142 | 3650 | |||
4143 | 3651 | # An &,| or ! followed by another boolean. | ||
4144 | 3652 | query = re.sub(r"(?ux) \s* ( [\&\|\!] ) [\s\&\|]+", r"\1", query) | ||
4145 | 3653 | ## plpy.debug('12 query is %s' % repr(query)) | ||
4146 | 3654 | |||
4147 | 3655 | # Leading & or | | ||
4148 | 3656 | query = re.sub(r"(?u)^[\s\&\|]+", "", query) | ||
4149 | 3657 | ## plpy.debug('13 query is %s' % repr(query)) | ||
4150 | 3658 | |||
4151 | 3659 | # Trailing &, | or ! | ||
4152 | 3660 | query = re.sub(r"(?u)[\&\|\!\s]+$", "", query) | ||
4153 | 3661 | ## plpy.debug('14 query is %s' % repr(query)) | ||
4154 | 3662 | |||
4155 | 3663 | # If we have nothing but whitespace and tsearch2 operators, | ||
4156 | 3664 | # return NULL. | ||
4157 | 3665 | if re.search(r"(?u)^[\&\|\!\s\(\)]*$", query) is not None: | ||
4158 | 3666 | return None | ||
4159 | 3667 | |||
4160 | 3668 | # Convert back to UTF-8 | ||
4161 | 3669 | query = query.encode('utf8') | ||
4162 | 3670 | ## plpy.debug('15 query is %s' % repr(query)) | ||
4163 | 3671 | |||
4164 | 3672 | return query or None | ||
4165 | 3673 | $_$; | ||
4166 | 3674 | |||
4167 | 3675 | |||
4168 | 3676 | CREATE FUNCTION _get_parser_from_curcfg() RETURNS text | ||
4169 | 3677 | LANGUAGE sql IMMUTABLE STRICT | ||
4170 | 3678 | AS $$select prsname::text from pg_catalog.pg_ts_parser p join pg_ts_config c on cfgparser = p.oid where c.oid = show_curcfg();$$; | ||
4171 | 3679 | |||
4172 | 3680 | |||
4173 | 3681 | CREATE FUNCTION concat(pg_catalog.tsvector, pg_catalog.tsvector) RETURNS pg_catalog.tsvector | ||
4174 | 3682 | LANGUAGE internal IMMUTABLE STRICT | ||
4175 | 3683 | AS $$tsvector_concat$$; | ||
4176 | 3684 | |||
4177 | 3685 | |||
4178 | 3686 | CREATE FUNCTION dex_init(internal) RETURNS internal | ||
4179 | 3687 | LANGUAGE c | ||
4180 | 3688 | AS '$libdir/tsearch2', 'tsa_dex_init'; | ||
4181 | 3689 | |||
4182 | 3690 | |||
4183 | 3691 | CREATE FUNCTION dex_lexize(internal, internal, integer) RETURNS internal | ||
4184 | 3692 | LANGUAGE c STRICT | ||
4185 | 3693 | AS '$libdir/tsearch2', 'tsa_dex_lexize'; | ||
4186 | 3694 | |||
4187 | 3695 | |||
4188 | 3696 | CREATE FUNCTION ftiupdate() RETURNS trigger | ||
4189 | 3697 | LANGUAGE plpythonu | ||
4190 | 3698 | AS $_$ | ||
4191 | 3699 | new = TD["new"] | ||
4192 | 3700 | args = TD["args"][:] | ||
4193 | 3701 | |||
4194 | 3702 | # Short circuit if none of the relevant columns have been | ||
4195 | 3703 | # modified and fti is not being set to NULL (setting the fti | ||
4196 | 3704 | # column to NULL is thus how we can force a rebuild of the fti | ||
4197 | 3705 | # column). | ||
4198 | 3706 | if TD["event"] == "UPDATE" and new["fti"] != None: | ||
4199 | 3707 | old = TD["old"] | ||
4200 | 3708 | relevant_modification = False | ||
4201 | 3709 | for column_name in args[::2]: | ||
4202 | 3710 | if new[column_name] != old[column_name]: | ||
4203 | 3711 | relevant_modification = True | ||
4204 | 3712 | break | ||
4205 | 3713 | if not relevant_modification: | ||
4206 | 3714 | return "OK" | ||
4207 | 3715 | |||
4208 | 3716 | # Generate an SQL statement that turns the requested | ||
4209 | 3717 | # column values into a weighted tsvector | ||
4210 | 3718 | sql = [] | ||
4211 | 3719 | for i in range(0, len(args), 2): | ||
4212 | 3720 | sql.append( | ||
4213 | 3721 | "ts2.setweight(ts2.to_tsvector('default', coalesce(" | ||
4214 | 3722 | "substring(ltrim($%d) from 1 for 2500),''))," | ||
4215 | 3723 | "CAST($%d AS \"char\"))" % (i + 1, i + 2)) | ||
4216 | 3724 | args[i] = new[args[i]] | ||
4217 | 3725 | |||
4218 | 3726 | sql = "SELECT %s AS fti" % "||".join(sql) | ||
4219 | 3727 | |||
4220 | 3728 | # Execute and store in the fti column | ||
4221 | 3729 | plan = plpy.prepare(sql, ["text", "char"] * (len(args)/2)) | ||
4222 | 3730 | new["fti"] = plpy.execute(plan, args, 1)[0]["fti"] | ||
4223 | 3731 | |||
4224 | 3732 | # Tell PostgreSQL we have modified the data | ||
4225 | 3733 | return "MODIFY" | ||
4226 | 3734 | $_$; | ||
4227 | 3735 | |||
4228 | 3736 | |||
4229 | 3737 | COMMENT ON FUNCTION ftiupdate() IS 'Trigger function that keeps the fti tsvector column up to date.'; | ||
4230 | 3738 | |||
4231 | 3739 | |||
4232 | 3740 | CREATE FUNCTION ftq(text) RETURNS pg_catalog.tsquery | ||
4233 | 3741 | LANGUAGE plpythonu IMMUTABLE STRICT | ||
4234 | 3742 | AS $_$ | ||
4235 | 3743 | import re | ||
4236 | 3744 | |||
4237 | 3745 | # I think this method would be more robust if we used a real | ||
4238 | 3746 | # tokenizer and parser to generate the query string, but we need | ||
4239 | 3747 | # something suitable for use as a stored procedure which currently | ||
4240 | 3748 | # means no external dependancies. | ||
4241 | 3749 | |||
4242 | 3750 | # Convert to Unicode | ||
4243 | 3751 | query = args[0].decode('utf8') | ||
4244 | 3752 | ## plpy.debug('1 query is %s' % repr(query)) | ||
4245 | 3753 | |||
4246 | 3754 | # Normalize whitespace | ||
4247 | 3755 | query = re.sub("(?u)\s+"," ", query) | ||
4248 | 3756 | |||
4249 | 3757 | # Convert AND, OR, NOT and - to tsearch2 punctuation | ||
4250 | 3758 | query = re.sub(r"(?u)(?:^|\s)-([\w\(])", r" !\1", query) | ||
4251 | 3759 | query = re.sub(r"(?u)\bAND\b", "&", query) | ||
4252 | 3760 | query = re.sub(r"(?u)\bOR\b", "|", query) | ||
4253 | 3761 | query = re.sub(r"(?u)\bNOT\b", " !", query) | ||
4254 | 3762 | ## plpy.debug('2 query is %s' % repr(query)) | ||
4255 | 3763 | |||
4256 | 3764 | # Deal with unwanted punctuation. We convert strings of punctuation | ||
4257 | 3765 | # inside words to a '-' character for the hypenation handling below | ||
4258 | 3766 | # to deal with further. Outside of words we replace with whitespace. | ||
4259 | 3767 | # We don't mess with -&|!()' as they are handled later. | ||
4260 | 3768 | #punctuation = re.escape(r'`~@#$%^*+=[]{}:;"<>,.?\/') | ||
4261 | 3769 | punctuation = r"[^\w\s\-\&\|\!\(\)']" | ||
4262 | 3770 | query = re.sub(r"(?u)(\w)%s+(\w)" % (punctuation,), r"\1-\2", query) | ||
4263 | 3771 | query = re.sub(r"(?u)%s+" % (punctuation,), " ", query) | ||
4264 | 3772 | ## plpy.debug('3 query is %s' % repr(query)) | ||
4265 | 3773 | |||
4266 | 3774 | # Strip ! characters inside and at the end of a word | ||
4267 | 3775 | query = re.sub(r"(?u)(?<=\w)[\!]+", " ", query) | ||
4268 | 3776 | |||
4269 | 3777 | # Now that we have handle case sensitive booleans, convert to lowercase | ||
4270 | 3778 | query = query.lower() | ||
4271 | 3779 | |||
4272 | 3780 | # Convert foo-bar to ((foo&bar)|foobar) and foo-bar-baz to | ||
4273 | 3781 | # ((foo&bar&baz)|foobarbaz) | ||
4274 | 3782 | def hyphen_repl(match): | ||
4275 | 3783 | bits = match.group(0).split("-") | ||
4276 | 3784 | return "((%s)|%s)" % ("&".join(bits), "".join(bits)) | ||
4277 | 3785 | query = re.sub(r"(?u)\b\w+-[\w\-]+\b", hyphen_repl, query) | ||
4278 | 3786 | ## plpy.debug('4 query is %s' % repr(query)) | ||
4279 | 3787 | |||
4280 | 3788 | # Any remaining - characters are spurious | ||
4281 | 3789 | query = query.replace('-','') | ||
4282 | 3790 | |||
4283 | 3791 | # Remove unpartnered bracket on the left and right | ||
4284 | 3792 | query = re.sub(r"(?ux) ^ ( [^(]* ) \)", r"(\1)", query) | ||
4285 | 3793 | query = re.sub(r"(?ux) \( ( [^)]* ) $", r"(\1)", query) | ||
4286 | 3794 | |||
4287 | 3795 | # Remove spurious brackets | ||
4288 | 3796 | query = re.sub(r"(?u)\(([^\&\|]*?)\)", r" \1 ", query) | ||
4289 | 3797 | ## plpy.debug('5 query is %s' % repr(query)) | ||
4290 | 3798 | |||
4291 | 3799 | # Insert & between tokens without an existing boolean operator | ||
4292 | 3800 | # ( not proceeded by (|&! | ||
4293 | 3801 | query = re.sub(r"(?u)(?<![\(\|\&\!])\s*\(", "&(", query) | ||
4294 | 3802 | ## plpy.debug('6 query is %s' % repr(query)) | ||
4295 | 3803 | # ) not followed by )|& | ||
4296 | 3804 | query = re.sub(r"(?u)\)(?!\s*(\)|\||\&|\s*$))", ")&", query) | ||
4297 | 3805 | ## plpy.debug('6.1 query is %s' % repr(query)) | ||
4298 | 3806 | # Whitespace not proceded by (|&! not followed by &| | ||
4299 | 3807 | query = re.sub(r"(?u)(?<![\(\|\&\!\s])\s+(?![\&\|\s])", "&", query) | ||
4300 | 3808 | ## plpy.debug('7 query is %s' % repr(query)) | ||
4301 | 3809 | |||
4302 | 3810 | # Detect and repair syntax errors - we are lenient because | ||
4303 | 3811 | # this input is generally from users. | ||
4304 | 3812 | |||
4305 | 3813 | # Fix unbalanced brackets | ||
4306 | 3814 | openings = query.count("(") | ||
4307 | 3815 | closings = query.count(")") | ||
4308 | 3816 | if openings > closings: | ||
4309 | 3817 | query = query + " ) "*(openings-closings) | ||
4310 | 3818 | elif closings > openings: | ||
4311 | 3819 | query = " ( "*(closings-openings) + query | ||
4312 | 3820 | ## plpy.debug('8 query is %s' % repr(query)) | ||
4313 | 3821 | |||
4314 | 3822 | # Strip ' character that do not have letters on both sides | ||
4315 | 3823 | query = re.sub(r"(?u)((?<!\w)'|'(?!\w))", "", query) | ||
4316 | 3824 | |||
4317 | 3825 | # Brackets containing nothing but whitespace and booleans, recursive | ||
4318 | 3826 | last = "" | ||
4319 | 3827 | while last != query: | ||
4320 | 3828 | last = query | ||
4321 | 3829 | query = re.sub(r"(?u)\([\s\&\|\!]*\)", "", query) | ||
4322 | 3830 | ## plpy.debug('9 query is %s' % repr(query)) | ||
4323 | 3831 | |||
4324 | 3832 | # An & or | following a ( | ||
4325 | 3833 | query = re.sub(r"(?u)(?<=\()[\&\|\s]+", "", query) | ||
4326 | 3834 | ## plpy.debug('10 query is %s' % repr(query)) | ||
4327 | 3835 | |||
4328 | 3836 | # An &, | or ! immediatly before a ) | ||
4329 | 3837 | query = re.sub(r"(?u)[\&\|\!\s]*[\&\|\!]+\s*(?=\))", "", query) | ||
4330 | 3838 | ## plpy.debug('11 query is %s' % repr(query)) | ||
4331 | 3839 | |||
4332 | 3840 | # An &,| or ! followed by another boolean. | ||
4333 | 3841 | query = re.sub(r"(?ux) \s* ( [\&\|\!] ) [\s\&\|]+", r"\1", query) | ||
4334 | 3842 | ## plpy.debug('12 query is %s' % repr(query)) | ||
4335 | 3843 | |||
4336 | 3844 | # Leading & or | | ||
4337 | 3845 | query = re.sub(r"(?u)^[\s\&\|]+", "", query) | ||
4338 | 3846 | ## plpy.debug('13 query is %s' % repr(query)) | ||
4339 | 3847 | |||
4340 | 3848 | # Trailing &, | or ! | ||
4341 | 3849 | query = re.sub(r"(?u)[\&\|\!\s]+$", "", query) | ||
4342 | 3850 | ## plpy.debug('14 query is %s' % repr(query)) | ||
4343 | 3851 | |||
4344 | 3852 | # If we have nothing but whitespace and tsearch2 operators, | ||
4345 | 3853 | # return NULL. | ||
4346 | 3854 | if re.search(r"(?u)^[\&\|\!\s\(\)]*$", query) is not None: | ||
4347 | 3855 | return None | ||
4348 | 3856 | |||
4349 | 3857 | # Convert back to UTF-8 | ||
4350 | 3858 | query = query.encode('utf8') | ||
4351 | 3859 | ## plpy.debug('15 query is %s' % repr(query)) | ||
4352 | 3860 | |||
4353 | 3861 | p = plpy.prepare("SELECT to_tsquery('default', $1) AS x", ["text"]) | ||
4354 | 3862 | query = plpy.execute(p, [query], 1)[0]["x"] | ||
4355 | 3863 | return query or None | ||
4356 | 3864 | $_$; | ||
4357 | 3865 | |||
4358 | 3866 | |||
4359 | 3867 | COMMENT ON FUNCTION ftq(text) IS 'Convert a string to an unparsed tsearch2 query'; | ||
4360 | 3868 | |||
4361 | 3869 | |||
4362 | 3870 | CREATE FUNCTION get_covers(pg_catalog.tsvector, pg_catalog.tsquery) RETURNS text | ||
4363 | 3871 | LANGUAGE c STRICT | ||
4364 | 3872 | AS '$libdir/tsearch2', 'tsa_get_covers'; | ||
4365 | 3873 | |||
4366 | 3874 | |||
4367 | 3875 | CREATE FUNCTION headline(oid, text, pg_catalog.tsquery, text) RETURNS text | ||
4368 | 3876 | LANGUAGE internal IMMUTABLE STRICT | ||
4369 | 3877 | AS $$ts_headline_byid_opt$$; | ||
4370 | 3878 | |||
4371 | 3879 | |||
4372 | 3880 | CREATE FUNCTION headline(oid, text, pg_catalog.tsquery) RETURNS text | ||
4373 | 3881 | LANGUAGE internal IMMUTABLE STRICT | ||
4374 | 3882 | AS $$ts_headline_byid$$; | ||
4375 | 3883 | |||
4376 | 3884 | |||
4377 | 3885 | CREATE FUNCTION headline(text, text, pg_catalog.tsquery, text) RETURNS text | ||
4378 | 3886 | LANGUAGE c IMMUTABLE STRICT | ||
4379 | 3887 | AS '$libdir/tsearch2', 'tsa_headline_byname'; | ||
4380 | 3888 | |||
4381 | 3889 | |||
4382 | 3890 | CREATE FUNCTION headline(text, text, pg_catalog.tsquery) RETURNS text | ||
4383 | 3891 | LANGUAGE c IMMUTABLE STRICT | ||
4384 | 3892 | AS '$libdir/tsearch2', 'tsa_headline_byname'; | ||
4385 | 3893 | |||
4386 | 3894 | |||
4387 | 3895 | CREATE FUNCTION headline(text, pg_catalog.tsquery, text) RETURNS text | ||
4388 | 3896 | LANGUAGE internal IMMUTABLE STRICT | ||
4389 | 3897 | AS $$ts_headline_opt$$; | ||
4390 | 3898 | |||
4391 | 3899 | |||
4392 | 3900 | CREATE FUNCTION headline(text, pg_catalog.tsquery) RETURNS text | ||
4393 | 3901 | LANGUAGE internal IMMUTABLE STRICT | ||
4394 | 3902 | AS $$ts_headline$$; | ||
4395 | 3903 | |||
4396 | 3904 | |||
4397 | 3905 | CREATE FUNCTION length(pg_catalog.tsvector) RETURNS integer | ||
4398 | 3906 | LANGUAGE internal IMMUTABLE STRICT | ||
4399 | 3907 | AS $$tsvector_length$$; | ||
4400 | 3908 | |||
4401 | 3909 | |||
4402 | 3910 | CREATE FUNCTION lexize(oid, text) RETURNS text[] | ||
4403 | 3911 | LANGUAGE internal STRICT | ||
4404 | 3912 | AS $$ts_lexize$$; | ||
4405 | 3913 | |||
4406 | 3914 | |||
4407 | 3915 | CREATE FUNCTION lexize(text, text) RETURNS text[] | ||
4408 | 3916 | LANGUAGE c STRICT | ||
4409 | 3917 | AS '$libdir/tsearch2', 'tsa_lexize_byname'; | ||
4410 | 3918 | |||
4411 | 3919 | |||
4412 | 3920 | CREATE FUNCTION lexize(text) RETURNS text[] | ||
4413 | 3921 | LANGUAGE c STRICT | ||
4414 | 3922 | AS '$libdir/tsearch2', 'tsa_lexize_bycurrent'; | ||
4415 | 3923 | |||
4416 | 3924 | |||
4417 | 3925 | CREATE FUNCTION numnode(pg_catalog.tsquery) RETURNS integer | ||
4418 | 3926 | LANGUAGE internal IMMUTABLE STRICT | ||
4419 | 3927 | AS $$tsquery_numnode$$; | ||
4420 | 3928 | |||
4421 | 3929 | |||
4422 | 3930 | CREATE FUNCTION parse(oid, text) RETURNS SETOF tokenout | ||
4423 | 3931 | LANGUAGE internal STRICT | ||
4424 | 3932 | AS $$ts_parse_byid$$; | ||
4425 | 3933 | |||
4426 | 3934 | |||
4427 | 3935 | CREATE FUNCTION parse(text, text) RETURNS SETOF tokenout | ||
4428 | 3936 | LANGUAGE internal STRICT | ||
4429 | 3937 | AS $$ts_parse_byname$$; | ||
4430 | 3938 | |||
4431 | 3939 | |||
4432 | 3940 | CREATE FUNCTION parse(text) RETURNS SETOF tokenout | ||
4433 | 3941 | LANGUAGE c STRICT | ||
4434 | 3942 | AS '$libdir/tsearch2', 'tsa_parse_current'; | ||
4435 | 3943 | |||
4436 | 3944 | |||
4437 | 3945 | CREATE FUNCTION plainto_tsquery(oid, text) RETURNS pg_catalog.tsquery | ||
4438 | 3946 | LANGUAGE internal IMMUTABLE STRICT | ||
4439 | 3947 | AS $$plainto_tsquery_byid$$; | ||
4440 | 3948 | |||
4441 | 3949 | |||
4442 | 3950 | CREATE FUNCTION plainto_tsquery(text, text) RETURNS pg_catalog.tsquery | ||
4443 | 3951 | LANGUAGE c IMMUTABLE STRICT | ||
4444 | 3952 | AS '$libdir/tsearch2', 'tsa_plainto_tsquery_name'; | ||
4445 | 3953 | |||
4446 | 3954 | |||
4447 | 3955 | CREATE FUNCTION plainto_tsquery(text) RETURNS pg_catalog.tsquery | ||
4448 | 3956 | LANGUAGE internal IMMUTABLE STRICT | ||
4449 | 3957 | AS $$plainto_tsquery$$; | ||
4450 | 3958 | |||
4451 | 3959 | |||
4452 | 3960 | CREATE FUNCTION prsd_end(internal) RETURNS void | ||
4453 | 3961 | LANGUAGE c | ||
4454 | 3962 | AS '$libdir/tsearch2', 'tsa_prsd_end'; | ||
4455 | 3963 | |||
4456 | 3964 | |||
4457 | 3965 | CREATE FUNCTION prsd_getlexeme(internal, internal, internal) RETURNS integer | ||
4458 | 3966 | LANGUAGE c | ||
4459 | 3967 | AS '$libdir/tsearch2', 'tsa_prsd_getlexeme'; | ||
4460 | 3968 | |||
4461 | 3969 | |||
4462 | 3970 | CREATE FUNCTION prsd_headline(internal, internal, internal) RETURNS internal | ||
4463 | 3971 | LANGUAGE c | ||
4464 | 3972 | AS '$libdir/tsearch2', 'tsa_prsd_headline'; | ||
4465 | 3973 | |||
4466 | 3974 | |||
4467 | 3975 | CREATE FUNCTION prsd_lextype(internal) RETURNS internal | ||
4468 | 3976 | LANGUAGE c | ||
4469 | 3977 | AS '$libdir/tsearch2', 'tsa_prsd_lextype'; | ||
4470 | 3978 | |||
4471 | 3979 | |||
4472 | 3980 | CREATE FUNCTION prsd_start(internal, integer) RETURNS internal | ||
4473 | 3981 | LANGUAGE c | ||
4474 | 3982 | AS '$libdir/tsearch2', 'tsa_prsd_start'; | ||
4475 | 3983 | |||
4476 | 3984 | |||
4477 | 3985 | CREATE FUNCTION querytree(pg_catalog.tsquery) RETURNS text | ||
4478 | 3986 | LANGUAGE internal STRICT | ||
4479 | 3987 | AS $$tsquerytree$$; | ||
4480 | 3988 | |||
4481 | 3989 | |||
4482 | 3990 | CREATE FUNCTION rank(real[], pg_catalog.tsvector, pg_catalog.tsquery) RETURNS real | ||
4483 | 3991 | LANGUAGE internal IMMUTABLE STRICT | ||
4484 | 3992 | AS $$ts_rank_wtt$$; | ||
4485 | 3993 | |||
4486 | 3994 | |||
4487 | 3995 | CREATE FUNCTION rank(real[], pg_catalog.tsvector, pg_catalog.tsquery, integer) RETURNS real | ||
4488 | 3996 | LANGUAGE internal IMMUTABLE STRICT | ||
4489 | 3997 | AS $$ts_rank_wttf$$; | ||
4490 | 3998 | |||
4491 | 3999 | |||
4492 | 4000 | CREATE FUNCTION rank(pg_catalog.tsvector, pg_catalog.tsquery) RETURNS real | ||
4493 | 4001 | LANGUAGE internal IMMUTABLE STRICT | ||
4494 | 4002 | AS $$ts_rank_tt$$; | ||
4495 | 4003 | |||
4496 | 4004 | |||
4497 | 4005 | CREATE FUNCTION rank(pg_catalog.tsvector, pg_catalog.tsquery, integer) RETURNS real | ||
4498 | 4006 | LANGUAGE internal IMMUTABLE STRICT | ||
4499 | 4007 | AS $$ts_rank_ttf$$; | ||
4500 | 4008 | |||
4501 | 4009 | |||
4502 | 4010 | CREATE FUNCTION rank_cd(real[], pg_catalog.tsvector, pg_catalog.tsquery) RETURNS real | ||
4503 | 4011 | LANGUAGE internal IMMUTABLE STRICT | ||
4504 | 4012 | AS $$ts_rankcd_wtt$$; | ||
4505 | 4013 | |||
4506 | 4014 | |||
4507 | 4015 | CREATE FUNCTION rank_cd(real[], pg_catalog.tsvector, pg_catalog.tsquery, integer) RETURNS real | ||
4508 | 4016 | LANGUAGE internal IMMUTABLE STRICT | ||
4509 | 4017 | AS $$ts_rankcd_wttf$$; | ||
4510 | 4018 | |||
4511 | 4019 | |||
4512 | 4020 | CREATE FUNCTION rank_cd(pg_catalog.tsvector, pg_catalog.tsquery) RETURNS real | ||
4513 | 4021 | LANGUAGE internal IMMUTABLE STRICT | ||
4514 | 4022 | AS $$ts_rankcd_tt$$; | ||
4515 | 4023 | |||
4516 | 4024 | |||
4517 | 4025 | CREATE FUNCTION rank_cd(pg_catalog.tsvector, pg_catalog.tsquery, integer) RETURNS real | ||
4518 | 4026 | LANGUAGE internal IMMUTABLE STRICT | ||
4519 | 4027 | AS $$ts_rankcd_ttf$$; | ||
4520 | 4028 | |||
4521 | 4029 | |||
4522 | 4030 | CREATE FUNCTION reset_tsearch() RETURNS void | ||
4523 | 4031 | LANGUAGE c STRICT | ||
4524 | 4032 | AS '$libdir/tsearch2', 'tsa_reset_tsearch'; | ||
4525 | 4033 | |||
4526 | 4034 | |||
4527 | 4035 | CREATE FUNCTION rewrite(pg_catalog.tsquery, text) RETURNS pg_catalog.tsquery | ||
4528 | 4036 | LANGUAGE internal IMMUTABLE STRICT | ||
4529 | 4037 | AS $$tsquery_rewrite_query$$; | ||
4530 | 4038 | |||
4531 | 4039 | |||
4532 | 4040 | CREATE FUNCTION rewrite(pg_catalog.tsquery, pg_catalog.tsquery, pg_catalog.tsquery) RETURNS pg_catalog.tsquery | ||
4533 | 4041 | LANGUAGE internal IMMUTABLE STRICT | ||
4534 | 4042 | AS $$tsquery_rewrite$$; | ||
4535 | 4043 | |||
4536 | 4044 | |||
4537 | 4045 | CREATE FUNCTION rewrite_accum(pg_catalog.tsquery, pg_catalog.tsquery[]) RETURNS pg_catalog.tsquery | ||
4538 | 4046 | LANGUAGE c | ||
4539 | 4047 | AS '$libdir/tsearch2', 'tsa_rewrite_accum'; | ||
4540 | 4048 | |||
4541 | 4049 | |||
4542 | 4050 | CREATE FUNCTION rewrite_finish(pg_catalog.tsquery) RETURNS pg_catalog.tsquery | ||
4543 | 4051 | LANGUAGE c | ||
4544 | 4052 | AS '$libdir/tsearch2', 'tsa_rewrite_finish'; | ||
4545 | 4053 | |||
4546 | 4054 | |||
4547 | 4055 | CREATE FUNCTION set_curcfg(integer) RETURNS void | ||
4548 | 4056 | LANGUAGE c STRICT | ||
4549 | 4057 | AS '$libdir/tsearch2', 'tsa_set_curcfg'; | ||
4550 | 4058 | |||
4551 | 4059 | |||
4552 | 4060 | CREATE FUNCTION set_curcfg(text) RETURNS void | ||
4553 | 4061 | LANGUAGE c STRICT | ||
4554 | 4062 | AS '$libdir/tsearch2', 'tsa_set_curcfg_byname'; | ||
4555 | 4063 | |||
4556 | 4064 | |||
4557 | 4065 | CREATE FUNCTION set_curdict(integer) RETURNS void | ||
4558 | 4066 | LANGUAGE c STRICT | ||
4559 | 4067 | AS '$libdir/tsearch2', 'tsa_set_curdict'; | ||
4560 | 4068 | |||
4561 | 4069 | |||
4562 | 4070 | CREATE FUNCTION set_curdict(text) RETURNS void | ||
4563 | 4071 | LANGUAGE c STRICT | ||
4564 | 4072 | AS '$libdir/tsearch2', 'tsa_set_curdict_byname'; | ||
4565 | 4073 | |||
4566 | 4074 | |||
4567 | 4075 | CREATE FUNCTION set_curprs(integer) RETURNS void | ||
4568 | 4076 | LANGUAGE c STRICT | ||
4569 | 4077 | AS '$libdir/tsearch2', 'tsa_set_curprs'; | ||
4570 | 4078 | |||
4571 | 4079 | |||
4572 | 4080 | CREATE FUNCTION set_curprs(text) RETURNS void | ||
4573 | 4081 | LANGUAGE c STRICT | ||
4574 | 4082 | AS '$libdir/tsearch2', 'tsa_set_curprs_byname'; | ||
4575 | 4083 | |||
4576 | 4084 | |||
4577 | 4085 | CREATE FUNCTION setweight(pg_catalog.tsvector, "char") RETURNS pg_catalog.tsvector | ||
4578 | 4086 | LANGUAGE internal IMMUTABLE STRICT | ||
4579 | 4087 | AS $$tsvector_setweight$$; | ||
4580 | 4088 | |||
4581 | 4089 | |||
4582 | 4090 | CREATE FUNCTION show_curcfg() RETURNS oid | ||
4583 | 4091 | LANGUAGE internal STABLE STRICT | ||
4584 | 4092 | AS $$get_current_ts_config$$; | ||
4585 | 4093 | |||
4586 | 4094 | |||
4587 | 4095 | CREATE FUNCTION snb_en_init(internal) RETURNS internal | ||
4588 | 4096 | LANGUAGE c | ||
4589 | 4097 | AS '$libdir/tsearch2', 'tsa_snb_en_init'; | ||
4590 | 4098 | |||
4591 | 4099 | |||
4592 | 4100 | CREATE FUNCTION snb_lexize(internal, internal, integer) RETURNS internal | ||
4593 | 4101 | LANGUAGE c STRICT | ||
4594 | 4102 | AS '$libdir/tsearch2', 'tsa_snb_lexize'; | ||
4595 | 4103 | |||
4596 | 4104 | |||
4597 | 4105 | CREATE FUNCTION snb_ru_init(internal) RETURNS internal | ||
4598 | 4106 | LANGUAGE c | ||
4599 | 4107 | AS '$libdir/tsearch2', 'tsa_snb_ru_init'; | ||
4600 | 4108 | |||
4601 | 4109 | |||
4602 | 4110 | CREATE FUNCTION snb_ru_init_koi8(internal) RETURNS internal | ||
4603 | 4111 | LANGUAGE c | ||
4604 | 4112 | AS '$libdir/tsearch2', 'tsa_snb_ru_init_koi8'; | ||
4605 | 4113 | |||
4606 | 4114 | |||
4607 | 4115 | CREATE FUNCTION snb_ru_init_utf8(internal) RETURNS internal | ||
4608 | 4116 | LANGUAGE c | ||
4609 | 4117 | AS '$libdir/tsearch2', 'tsa_snb_ru_init_utf8'; | ||
4610 | 4118 | |||
4611 | 4119 | |||
4612 | 4120 | CREATE FUNCTION spell_init(internal) RETURNS internal | ||
4613 | 4121 | LANGUAGE c | ||
4614 | 4122 | AS '$libdir/tsearch2', 'tsa_spell_init'; | ||
4615 | 4123 | |||
4616 | 4124 | |||
4617 | 4125 | CREATE FUNCTION spell_lexize(internal, internal, integer) RETURNS internal | ||
4618 | 4126 | LANGUAGE c STRICT | ||
4619 | 4127 | AS '$libdir/tsearch2', 'tsa_spell_lexize'; | ||
4620 | 4128 | |||
4621 | 4129 | |||
4622 | 4130 | CREATE FUNCTION stat(text) RETURNS SETOF statinfo | ||
4623 | 4131 | LANGUAGE internal STRICT | ||
4624 | 4132 | AS $$ts_stat1$$; | ||
4625 | 4133 | |||
4626 | 4134 | |||
4627 | 4135 | CREATE FUNCTION stat(text, text) RETURNS SETOF statinfo | ||
4628 | 4136 | LANGUAGE internal STRICT | ||
4629 | 4137 | AS $$ts_stat2$$; | ||
4630 | 4138 | |||
4631 | 4139 | |||
4632 | 4140 | CREATE FUNCTION strip(pg_catalog.tsvector) RETURNS pg_catalog.tsvector | ||
4633 | 4141 | LANGUAGE internal IMMUTABLE STRICT | ||
4634 | 4142 | AS $$tsvector_strip$$; | ||
4635 | 4143 | |||
4636 | 4144 | |||
4637 | 4145 | CREATE FUNCTION syn_init(internal) RETURNS internal | ||
4638 | 4146 | LANGUAGE c | ||
4639 | 4147 | AS '$libdir/tsearch2', 'tsa_syn_init'; | ||
4640 | 4148 | |||
4641 | 4149 | |||
4642 | 4150 | CREATE FUNCTION syn_lexize(internal, internal, integer) RETURNS internal | ||
4643 | 4151 | LANGUAGE c STRICT | ||
4644 | 4152 | AS '$libdir/tsearch2', 'tsa_syn_lexize'; | ||
4645 | 4153 | |||
4646 | 4154 | |||
4647 | 4155 | CREATE FUNCTION thesaurus_init(internal) RETURNS internal | ||
4648 | 4156 | LANGUAGE c | ||
4649 | 4157 | AS '$libdir/tsearch2', 'tsa_thesaurus_init'; | ||
4650 | 4158 | |||
4651 | 4159 | |||
4652 | 4160 | CREATE FUNCTION thesaurus_lexize(internal, internal, integer, internal) RETURNS internal | ||
4653 | 4161 | LANGUAGE c STRICT | ||
4654 | 4162 | AS '$libdir/tsearch2', 'tsa_thesaurus_lexize'; | ||
4655 | 4163 | |||
4656 | 4164 | |||
4657 | 4165 | CREATE FUNCTION to_tsquery(oid, text) RETURNS pg_catalog.tsquery | ||
4658 | 4166 | LANGUAGE internal IMMUTABLE STRICT | ||
4659 | 4167 | AS $$to_tsquery_byid$$; | ||
4660 | 4168 | |||
4661 | 4169 | |||
4662 | 4170 | CREATE FUNCTION to_tsquery(text, text) RETURNS pg_catalog.tsquery | ||
4663 | 4171 | LANGUAGE c IMMUTABLE STRICT | ||
4664 | 4172 | AS '$libdir/tsearch2', 'tsa_to_tsquery_name'; | ||
4665 | 4173 | |||
4666 | 4174 | |||
4667 | 4175 | CREATE FUNCTION to_tsquery(text) RETURNS pg_catalog.tsquery | ||
4668 | 4176 | LANGUAGE internal IMMUTABLE STRICT | ||
4669 | 4177 | AS $$to_tsquery$$; | ||
4670 | 4178 | |||
4671 | 4179 | |||
4672 | 4180 | CREATE FUNCTION to_tsvector(oid, text) RETURNS pg_catalog.tsvector | ||
4673 | 4181 | LANGUAGE internal IMMUTABLE STRICT | ||
4674 | 4182 | AS $$to_tsvector_byid$$; | ||
4675 | 4183 | |||
4676 | 4184 | |||
4677 | 4185 | CREATE FUNCTION to_tsvector(text, text) RETURNS pg_catalog.tsvector | ||
4678 | 4186 | LANGUAGE c IMMUTABLE STRICT | ||
4679 | 4187 | AS '$libdir/tsearch2', 'tsa_to_tsvector_name'; | ||
4680 | 4188 | |||
4681 | 4189 | |||
4682 | 4190 | CREATE FUNCTION to_tsvector(text) RETURNS pg_catalog.tsvector | ||
4683 | 4191 | LANGUAGE internal IMMUTABLE STRICT | ||
4684 | 4192 | AS $$to_tsvector$$; | ||
4685 | 4193 | |||
4686 | 4194 | |||
4687 | 4195 | CREATE FUNCTION token_type(integer) RETURNS SETOF tokentype | ||
4688 | 4196 | LANGUAGE internal STRICT ROWS 16 | ||
4689 | 4197 | AS $$ts_token_type_byid$$; | ||
4690 | 4198 | |||
4691 | 4199 | |||
4692 | 4200 | CREATE FUNCTION token_type(text) RETURNS SETOF tokentype | ||
4693 | 4201 | LANGUAGE internal STRICT ROWS 16 | ||
4694 | 4202 | AS $$ts_token_type_byname$$; | ||
4695 | 4203 | |||
4696 | 4204 | |||
4697 | 4205 | CREATE FUNCTION token_type() RETURNS SETOF tokentype | ||
4698 | 4206 | LANGUAGE c STRICT ROWS 16 | ||
4699 | 4207 | AS '$libdir/tsearch2', 'tsa_token_type_current'; | ||
4700 | 4208 | |||
4701 | 4209 | |||
4702 | 4210 | CREATE FUNCTION ts_debug(text) RETURNS SETOF tsdebug | ||
4703 | 4211 | LANGUAGE sql STRICT | ||
4704 | 4212 | AS $_$ | ||
4705 | 4213 | select | ||
4706 | 4214 | (select c.cfgname::text from pg_catalog.pg_ts_config as c | ||
4707 | 4215 | where c.oid = show_curcfg()), | ||
4708 | 4216 | t.alias as tok_type, | ||
4709 | 4217 | t.descr as description, | ||
4710 | 4218 | p.token, | ||
4711 | 4219 | ARRAY ( SELECT m.mapdict::pg_catalog.regdictionary::pg_catalog.text | ||
4712 | 4220 | FROM pg_catalog.pg_ts_config_map AS m | ||
4713 | 4221 | WHERE m.mapcfg = show_curcfg() AND m.maptokentype = p.tokid | ||
4714 | 4222 | ORDER BY m.mapseqno ) | ||
4715 | 4223 | AS dict_name, | ||
4716 | 4224 | strip(to_tsvector(p.token)) as tsvector | ||
4717 | 4225 | from | ||
4718 | 4226 | parse( _get_parser_from_curcfg(), $1 ) as p, | ||
4719 | 4227 | token_type() as t | ||
4720 | 4228 | where | ||
4721 | 4229 | t.tokid = p.tokid | ||
4722 | 4230 | $_$; | ||
4723 | 4231 | |||
4724 | 4232 | |||
4725 | 4233 | CREATE FUNCTION tsearch2() RETURNS trigger | ||
4726 | 4234 | LANGUAGE c | ||
4727 | 4235 | AS '$libdir/tsearch2', 'tsa_tsearch2'; | ||
4728 | 4236 | |||
4729 | 4237 | |||
4730 | 4238 | CREATE FUNCTION tsq_mcontained(pg_catalog.tsquery, pg_catalog.tsquery) RETURNS boolean | ||
4731 | 4239 | LANGUAGE internal IMMUTABLE STRICT | ||
4732 | 4240 | AS $$tsq_mcontained$$; | ||
4733 | 4241 | |||
4734 | 4242 | |||
4735 | 4243 | CREATE FUNCTION tsq_mcontains(pg_catalog.tsquery, pg_catalog.tsquery) RETURNS boolean | ||
4736 | 4244 | LANGUAGE internal IMMUTABLE STRICT | ||
4737 | 4245 | AS $$tsq_mcontains$$; | ||
4738 | 4246 | |||
4739 | 4247 | |||
4740 | 4248 | CREATE FUNCTION tsquery_and(pg_catalog.tsquery, pg_catalog.tsquery) RETURNS pg_catalog.tsquery | ||
4741 | 4249 | LANGUAGE internal IMMUTABLE STRICT | ||
4742 | 4250 | AS $$tsquery_and$$; | ||
4743 | 4251 | |||
4744 | 4252 | |||
4745 | 4253 | CREATE FUNCTION tsquery_not(pg_catalog.tsquery) RETURNS pg_catalog.tsquery | ||
4746 | 4254 | LANGUAGE internal IMMUTABLE STRICT | ||
4747 | 4255 | AS $$tsquery_not$$; | ||
4748 | 4256 | |||
4749 | 4257 | |||
4750 | 4258 | CREATE FUNCTION tsquery_or(pg_catalog.tsquery, pg_catalog.tsquery) RETURNS pg_catalog.tsquery | ||
4751 | 4259 | LANGUAGE internal IMMUTABLE STRICT | ||
4752 | 4260 | AS $$tsquery_or$$; | ||
4753 | 4261 | |||
4754 | 4262 | |||
4755 | 4263 | SET search_path = public, pg_catalog; | ||
4756 | 4264 | |||
4757 | 4265 | CREATE OPERATOR > ( | ||
4758 | 4266 | PROCEDURE = debversion_gt, | ||
4759 | 4267 | LEFTARG = debversion, | ||
4760 | 4268 | RIGHTARG = debversion, | ||
4761 | 4269 | COMMUTATOR = <, | ||
4762 | 4270 | NEGATOR = >= | ||
4763 | 4271 | ); | ||
4764 | 4272 | |||
4765 | 4273 | |||
4766 | 4274 | COMMENT ON OPERATOR > (debversion, debversion) IS 'debversion greater-than'; | ||
4767 | 4275 | |||
4768 | 4276 | |||
4769 | 4277 | CREATE AGGREGATE max(debversion) ( | ||
4770 | 4278 | SFUNC = debversion_larger, | ||
4771 | 4279 | STYPE = debversion, | ||
4772 | 4280 | SORTOP = > | ||
4773 | 4281 | ); | ||
4774 | 4282 | |||
4775 | 4283 | |||
4776 | 4284 | CREATE OPERATOR < ( | ||
4777 | 4285 | PROCEDURE = debversion_lt, | ||
4778 | 4286 | LEFTARG = debversion, | ||
4779 | 4287 | RIGHTARG = debversion, | ||
4780 | 4288 | COMMUTATOR = >, | ||
4781 | 4289 | NEGATOR = >= | ||
4782 | 4290 | ); | ||
4783 | 4291 | |||
4784 | 4292 | |||
4785 | 4293 | COMMENT ON OPERATOR < (debversion, debversion) IS 'debversion less-than'; | ||
4786 | 4294 | |||
4787 | 4295 | |||
4788 | 4296 | CREATE AGGREGATE min(debversion) ( | ||
4789 | 4297 | SFUNC = debversion_smaller, | ||
4790 | 4298 | STYPE = debversion, | ||
4791 | 4299 | SORTOP = < | ||
4792 | 4300 | ); | ||
4793 | 4301 | |||
4794 | 4302 | |||
4795 | 4303 | SET search_path = ts2, pg_catalog; | ||
4796 | 4304 | |||
4797 | 4305 | CREATE AGGREGATE rewrite(pg_catalog.tsquery[]) ( | ||
4798 | 4306 | SFUNC = rewrite_accum, | ||
4799 | 4307 | STYPE = pg_catalog.tsquery, | ||
4800 | 4308 | FINALFUNC = rewrite_finish | ||
4801 | 4309 | ); | ||
4802 | 4310 | |||
4803 | 4311 | |||
4804 | 4312 | SET search_path = public, pg_catalog; | ||
4805 | 4313 | |||
4806 | 4314 | CREATE OPERATOR <= ( | ||
4807 | 4315 | PROCEDURE = debversion_le, | ||
4808 | 4316 | LEFTARG = debversion, | ||
4809 | 4317 | RIGHTARG = debversion, | ||
4810 | 4318 | COMMUTATOR = >=, | ||
4811 | 4319 | NEGATOR = > | ||
4812 | 4320 | ); | ||
4813 | 4321 | |||
4814 | 4322 | |||
4815 | 4323 | COMMENT ON OPERATOR <= (debversion, debversion) IS 'debversion less-than-or-equal'; | ||
4816 | 4324 | |||
4817 | 4325 | |||
4818 | 4326 | CREATE OPERATOR <> ( | ||
4819 | 4327 | PROCEDURE = debversion_ne, | ||
4820 | 4328 | LEFTARG = debversion, | ||
4821 | 4329 | RIGHTARG = debversion, | ||
4822 | 4330 | COMMUTATOR = <>, | ||
4823 | 4331 | NEGATOR = = | ||
4824 | 4332 | ); | ||
4825 | 4333 | |||
4826 | 4334 | |||
4827 | 4335 | COMMENT ON OPERATOR <> (debversion, debversion) IS 'debversion not equal'; | ||
4828 | 4336 | |||
4829 | 4337 | |||
4830 | 4338 | CREATE OPERATOR = ( | ||
4831 | 4339 | PROCEDURE = debversion_eq, | ||
4832 | 4340 | LEFTARG = debversion, | ||
4833 | 4341 | RIGHTARG = debversion, | ||
4834 | 4342 | COMMUTATOR = =, | ||
4835 | 4343 | NEGATOR = <> | ||
4836 | 4344 | ); | ||
4837 | 4345 | |||
4838 | 4346 | |||
4839 | 4347 | COMMENT ON OPERATOR = (debversion, debversion) IS 'debversion equal'; | ||
4840 | 4348 | |||
4841 | 4349 | |||
4842 | 4350 | CREATE OPERATOR >= ( | ||
4843 | 4351 | PROCEDURE = debversion_ge, | ||
4844 | 4352 | LEFTARG = debversion, | ||
4845 | 4353 | RIGHTARG = debversion, | ||
4846 | 4354 | COMMUTATOR = <=, | ||
4847 | 4355 | NEGATOR = < | ||
4848 | 4356 | ); | ||
4849 | 4357 | |||
4850 | 4358 | |||
4851 | 4359 | COMMENT ON OPERATOR >= (debversion, debversion) IS 'debversion greater-than-or-equal'; | ||
4852 | 4360 | |||
4853 | 4361 | |||
4854 | 4362 | CREATE OPERATOR FAMILY debversion_ops USING btree; | ||
4855 | 4363 | |||
4856 | 4364 | |||
4857 | 4365 | CREATE OPERATOR CLASS debversion_ops | ||
4858 | 4366 | DEFAULT FOR TYPE debversion USING btree AS | ||
4859 | 4367 | OPERATOR 1 <(debversion,debversion) , | ||
4860 | 4368 | OPERATOR 2 <=(debversion,debversion) , | ||
4861 | 4369 | OPERATOR 3 =(debversion,debversion) , | ||
4862 | 4370 | OPERATOR 4 >=(debversion,debversion) , | ||
4863 | 4371 | OPERATOR 5 >(debversion,debversion) , | ||
4864 | 4372 | FUNCTION 1 debversion_cmp(debversion,debversion); | ||
4865 | 4373 | |||
4866 | 4374 | |||
4867 | 4375 | CREATE OPERATOR FAMILY debversion_ops USING hash; | ||
4868 | 4376 | |||
4869 | 4377 | |||
4870 | 4378 | CREATE OPERATOR CLASS debversion_ops | ||
4871 | 4379 | DEFAULT FOR TYPE debversion USING hash AS | ||
4872 | 4380 | OPERATOR 1 =(debversion,debversion) , | ||
4873 | 4381 | FUNCTION 1 debversion_hash(debversion); | ||
4874 | 4382 | |||
4875 | 4383 | |||
4876 | 4384 | SET search_path = ts2, pg_catalog; | ||
4877 | 4385 | |||
4878 | 4386 | CREATE OPERATOR FAMILY tsquery_ops USING btree; | ||
4879 | 4387 | |||
4880 | 4388 | |||
4881 | 4389 | CREATE OPERATOR CLASS tsquery_ops | ||
4882 | 4390 | FOR TYPE pg_catalog.tsquery USING btree AS | ||
4883 | 4391 | OPERATOR 1 <(pg_catalog.tsquery,pg_catalog.tsquery) , | ||
4884 | 4392 | OPERATOR 2 <=(pg_catalog.tsquery,pg_catalog.tsquery) , | ||
4885 | 4393 | OPERATOR 3 =(pg_catalog.tsquery,pg_catalog.tsquery) , | ||
4886 | 4394 | OPERATOR 4 >=(pg_catalog.tsquery,pg_catalog.tsquery) , | ||
4887 | 4395 | OPERATOR 5 >(pg_catalog.tsquery,pg_catalog.tsquery) , | ||
4888 | 4396 | FUNCTION 1 tsquery_cmp(pg_catalog.tsquery,pg_catalog.tsquery); | ||
4889 | 4397 | |||
4890 | 4398 | |||
4891 | 4399 | CREATE OPERATOR FAMILY tsvector_ops USING btree; | ||
4892 | 4400 | |||
4893 | 4401 | |||
4894 | 4402 | CREATE OPERATOR CLASS tsvector_ops | ||
4895 | 4403 | FOR TYPE pg_catalog.tsvector USING btree AS | ||
4896 | 4404 | OPERATOR 1 <(pg_catalog.tsvector,pg_catalog.tsvector) , | ||
4897 | 4405 | OPERATOR 2 <=(pg_catalog.tsvector,pg_catalog.tsvector) , | ||
4898 | 4406 | OPERATOR 3 =(pg_catalog.tsvector,pg_catalog.tsvector) , | ||
4899 | 4407 | OPERATOR 4 >=(pg_catalog.tsvector,pg_catalog.tsvector) , | ||
4900 | 4408 | OPERATOR 5 >(pg_catalog.tsvector,pg_catalog.tsvector) , | ||
4901 | 4409 | FUNCTION 1 tsvector_cmp(pg_catalog.tsvector,pg_catalog.tsvector); | ||
4902 | 4410 | |||
4903 | 4411 | |||
4904 | 4412 | SET search_path = pg_catalog; |
The diff has been truncated for viewing.
Yup