@oliphaunt/extension-pgtap-linux-arm64-gnu 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +6 -0
- package/THIRD_PARTY_NOTICES.md +20 -0
- package/extension-contract.json +31 -0
- package/package.json +49 -0
- package/runtime/share/licenses/pgtap/README.md +153 -0
- package/runtime/share/postgresql/extension/pgtap--0.90.0--0.91.0.sql +29 -0
- package/runtime/share/postgresql/extension/pgtap--0.91.0--0.92.0.sql +1650 -0
- package/runtime/share/postgresql/extension/pgtap--0.92.0--0.93.0.sql +679 -0
- package/runtime/share/postgresql/extension/pgtap--0.93.0--0.94.0.sql +193 -0
- package/runtime/share/postgresql/extension/pgtap--0.94.0--0.95.0.sql +639 -0
- package/runtime/share/postgresql/extension/pgtap--0.95.0--0.96.0.sql +415 -0
- package/runtime/share/postgresql/extension/pgtap--0.96.0--0.97.0.sql +375 -0
- package/runtime/share/postgresql/extension/pgtap--0.97.0--0.98.0.sql +441 -0
- package/runtime/share/postgresql/extension/pgtap--0.98.0--0.99.0.sql +209 -0
- package/runtime/share/postgresql/extension/pgtap--0.99.0--1.0.0.sql +737 -0
- package/runtime/share/postgresql/extension/pgtap--1.0.0--1.1.0.sql +186 -0
- package/runtime/share/postgresql/extension/pgtap--1.1.0--1.2.0.sql +889 -0
- package/runtime/share/postgresql/extension/pgtap--1.2.0--1.3.0.sql +495 -0
- package/runtime/share/postgresql/extension/pgtap--1.3.0--1.3.1.sql +229 -0
- package/runtime/share/postgresql/extension/pgtap--1.3.1--1.3.2.sql +34 -0
- package/runtime/share/postgresql/extension/pgtap--1.3.2--1.3.3.sql +42 -0
- package/runtime/share/postgresql/extension/pgtap--1.3.3--1.3.4.sql +89 -0
- package/runtime/share/postgresql/extension/pgtap--1.3.4--1.3.5.sql +1 -0
- package/runtime/share/postgresql/extension/pgtap--1.3.5.sql +11520 -0
- package/runtime/share/postgresql/extension/pgtap--unpackaged--0.91.0.sql +714 -0
- package/runtime/share/postgresql/extension/pgtap-core--1.3.5.sql +4390 -0
- package/runtime/share/postgresql/extension/pgtap-core.sql +4390 -0
- package/runtime/share/postgresql/extension/pgtap-schema--1.3.5.sql +6764 -0
- package/runtime/share/postgresql/extension/pgtap-schema.sql +6764 -0
- package/runtime/share/postgresql/extension/pgtap.control +6 -0
- package/runtime/share/postgresql/extension/pgtap.sql +11520 -0
- package/runtime/share/postgresql/extension/uninstall_pgtap.sql +1088 -0
- package/share/licenses/pgtap/README.md +153 -0
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
CREATE OR REPLACE FUNCTION pgtap_version()
|
|
2
|
+
RETURNS NUMERIC AS 'SELECT 1.0;'
|
|
3
|
+
LANGUAGE SQL IMMUTABLE;
|
|
4
|
+
|
|
5
|
+
CREATE OR REPLACE FUNCTION _array_to_sorted_string( name[], text )
|
|
6
|
+
RETURNS text AS $$
|
|
7
|
+
SELECT array_to_string(ARRAY(
|
|
8
|
+
SELECT $1[i]
|
|
9
|
+
FROM generate_series(1, array_upper($1, 1)) s(i)
|
|
10
|
+
ORDER BY $1[i]
|
|
11
|
+
), $2);
|
|
12
|
+
$$ LANGUAGE SQL immutable;
|
|
13
|
+
|
|
14
|
+
-- policies_are( schema, table, policies[], description )
|
|
15
|
+
CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[], TEXT )
|
|
16
|
+
RETURNS TEXT AS $$
|
|
17
|
+
SELECT _are(
|
|
18
|
+
'policies',
|
|
19
|
+
ARRAY(
|
|
20
|
+
SELECT p.polname
|
|
21
|
+
FROM pg_catalog.pg_policy p
|
|
22
|
+
JOIN pg_catalog.pg_class c ON c.oid = p.polrelid
|
|
23
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
24
|
+
WHERE n.nspname = $1
|
|
25
|
+
AND c.relname = $2
|
|
26
|
+
EXCEPT
|
|
27
|
+
SELECT $3[i]
|
|
28
|
+
FROM generate_series(1, array_upper($3, 1)) s(i)
|
|
29
|
+
),
|
|
30
|
+
ARRAY(
|
|
31
|
+
SELECT $3[i]
|
|
32
|
+
FROM generate_series(1, array_upper($3, 1)) s(i)
|
|
33
|
+
EXCEPT
|
|
34
|
+
SELECT p.polname
|
|
35
|
+
FROM pg_catalog.pg_policy p
|
|
36
|
+
JOIN pg_catalog.pg_class c ON c.oid = p.polrelid
|
|
37
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
38
|
+
WHERE n.nspname = $1
|
|
39
|
+
AND c.relname = $2
|
|
40
|
+
),
|
|
41
|
+
$4
|
|
42
|
+
);
|
|
43
|
+
$$ LANGUAGE SQL;
|
|
44
|
+
|
|
45
|
+
-- policies_are( schema, table, policies[] )
|
|
46
|
+
CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[] )
|
|
47
|
+
RETURNS TEXT AS $$
|
|
48
|
+
SELECT policies_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct policies' );
|
|
49
|
+
$$ LANGUAGE SQL;
|
|
50
|
+
|
|
51
|
+
-- policies_are( table, policies[], description )
|
|
52
|
+
CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[], TEXT )
|
|
53
|
+
RETURNS TEXT AS $$
|
|
54
|
+
SELECT _are(
|
|
55
|
+
'policies',
|
|
56
|
+
ARRAY(
|
|
57
|
+
SELECT p.polname
|
|
58
|
+
FROM pg_catalog.pg_policy p
|
|
59
|
+
JOIN pg_catalog.pg_class c ON c.oid = p.polrelid
|
|
60
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
61
|
+
WHERE c.relname = $1
|
|
62
|
+
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
63
|
+
EXCEPT
|
|
64
|
+
SELECT $2[i]
|
|
65
|
+
FROM generate_series(1, array_upper($2, 1)) s(i)
|
|
66
|
+
),
|
|
67
|
+
ARRAY(
|
|
68
|
+
SELECT $2[i]
|
|
69
|
+
FROM generate_series(1, array_upper($2, 1)) s(i)
|
|
70
|
+
EXCEPT
|
|
71
|
+
SELECT p.polname
|
|
72
|
+
FROM pg_catalog.pg_policy p
|
|
73
|
+
JOIN pg_catalog.pg_class c ON c.oid = p.polrelid
|
|
74
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
75
|
+
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
76
|
+
),
|
|
77
|
+
$3
|
|
78
|
+
);
|
|
79
|
+
$$ LANGUAGE SQL;
|
|
80
|
+
|
|
81
|
+
-- policies_are( table, policies[] )
|
|
82
|
+
CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[] )
|
|
83
|
+
RETURNS TEXT AS $$
|
|
84
|
+
SELECT policies_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct policies' );
|
|
85
|
+
$$ LANGUAGE SQL;
|
|
86
|
+
|
|
87
|
+
-- policy_roles_are( schema, table, policy, roles[], description )
|
|
88
|
+
CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[], TEXT )
|
|
89
|
+
RETURNS TEXT AS $$
|
|
90
|
+
SELECT _are(
|
|
91
|
+
'policy roles',
|
|
92
|
+
ARRAY(
|
|
93
|
+
SELECT pr.rolname
|
|
94
|
+
FROM pg_catalog.pg_policy AS pp
|
|
95
|
+
JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles)
|
|
96
|
+
JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid
|
|
97
|
+
JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace
|
|
98
|
+
WHERE pn.nspname = $1
|
|
99
|
+
AND pc.relname = $2
|
|
100
|
+
AND pp.polname = $3
|
|
101
|
+
EXCEPT
|
|
102
|
+
SELECT $4[i]
|
|
103
|
+
FROM generate_series(1, array_upper($4, 1)) s(i)
|
|
104
|
+
),
|
|
105
|
+
ARRAY(
|
|
106
|
+
SELECT $4[i]
|
|
107
|
+
FROM generate_series(1, array_upper($4, 1)) s(i)
|
|
108
|
+
EXCEPT
|
|
109
|
+
SELECT pr.rolname
|
|
110
|
+
FROM pg_catalog.pg_policy AS pp
|
|
111
|
+
JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles)
|
|
112
|
+
JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid
|
|
113
|
+
JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace
|
|
114
|
+
WHERE pn.nspname = $1
|
|
115
|
+
AND pc.relname = $2
|
|
116
|
+
AND pp.polname = $3
|
|
117
|
+
),
|
|
118
|
+
$5
|
|
119
|
+
);
|
|
120
|
+
$$ LANGUAGE SQL;
|
|
121
|
+
|
|
122
|
+
-- policy_roles_are( schema, table, policy, roles[] )
|
|
123
|
+
CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[] )
|
|
124
|
+
RETURNS TEXT AS $$
|
|
125
|
+
SELECT policy_roles_are( $1, $2, $3, $4, 'Policy ' || quote_ident($3) || ' for table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct roles' );
|
|
126
|
+
$$ LANGUAGE SQL;
|
|
127
|
+
|
|
128
|
+
-- policy_roles_are( table, policy, roles[], description )
|
|
129
|
+
CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[], TEXT )
|
|
130
|
+
RETURNS TEXT AS $$
|
|
131
|
+
SELECT _are(
|
|
132
|
+
'policy roles',
|
|
133
|
+
ARRAY(
|
|
134
|
+
SELECT pr.rolname
|
|
135
|
+
FROM pg_catalog.pg_policy AS pp
|
|
136
|
+
JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles)
|
|
137
|
+
JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid
|
|
138
|
+
JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace
|
|
139
|
+
WHERE pc.relname = $1
|
|
140
|
+
AND pp.polname = $2
|
|
141
|
+
AND pn.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
142
|
+
EXCEPT
|
|
143
|
+
SELECT $3[i]
|
|
144
|
+
FROM generate_series(1, array_upper($3, 1)) s(i)
|
|
145
|
+
),
|
|
146
|
+
ARRAY(
|
|
147
|
+
SELECT $3[i]
|
|
148
|
+
FROM generate_series(1, array_upper($3, 1)) s(i)
|
|
149
|
+
EXCEPT
|
|
150
|
+
SELECT pr.rolname
|
|
151
|
+
FROM pg_catalog.pg_policy AS pp
|
|
152
|
+
JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles)
|
|
153
|
+
JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid
|
|
154
|
+
JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace
|
|
155
|
+
WHERE pc.relname = $1
|
|
156
|
+
AND pp.polname = $2
|
|
157
|
+
AND pn.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
158
|
+
),
|
|
159
|
+
$4
|
|
160
|
+
);
|
|
161
|
+
$$ LANGUAGE SQL;
|
|
162
|
+
|
|
163
|
+
-- policy_roles_are( table, policy, roles[] )
|
|
164
|
+
CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[] )
|
|
165
|
+
RETURNS TEXT AS $$
|
|
166
|
+
SELECT policy_roles_are( $1, $2, $3, 'Policy ' || quote_ident($2) || ' for table ' || quote_ident($1) || ' should have the correct roles' );
|
|
167
|
+
$$ LANGUAGE SQL;
|
|
168
|
+
|
|
169
|
+
-- policy_cmd_is( schema, table, policy, command, description )
|
|
170
|
+
CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text, text )
|
|
171
|
+
RETURNS TEXT AS $$
|
|
172
|
+
DECLARE
|
|
173
|
+
cmd text;
|
|
174
|
+
BEGIN
|
|
175
|
+
SELECT
|
|
176
|
+
CASE pp.polcmd WHEN 'r' THEN 'SELECT'
|
|
177
|
+
WHEN 'a' THEN 'INSERT'
|
|
178
|
+
WHEN 'w' THEN 'UPDATE'
|
|
179
|
+
WHEN 'd' THEN 'DELETE'
|
|
180
|
+
ELSE 'ALL'
|
|
181
|
+
END
|
|
182
|
+
FROM pg_catalog.pg_policy AS pp
|
|
183
|
+
JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid
|
|
184
|
+
JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace
|
|
185
|
+
WHERE pn.nspname = $1
|
|
186
|
+
AND pc.relname = $2
|
|
187
|
+
AND pp.polname = $3
|
|
188
|
+
INTO cmd;
|
|
189
|
+
|
|
190
|
+
RETURN is( cmd, upper($4), $5 );
|
|
191
|
+
END;
|
|
192
|
+
$$ LANGUAGE plpgsql;
|
|
193
|
+
|
|
194
|
+
-- policy_cmd_is( schema, table, policy, command )
|
|
195
|
+
CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text )
|
|
196
|
+
RETURNS TEXT AS $$
|
|
197
|
+
SELECT policy_cmd_is(
|
|
198
|
+
$1, $2, $3, $4,
|
|
199
|
+
'Policy ' || quote_ident($3)
|
|
200
|
+
|| ' for table ' || quote_ident($1) || '.' || quote_ident($2)
|
|
201
|
+
|| ' should apply to ' || upper($4) || ' command'
|
|
202
|
+
);
|
|
203
|
+
$$ LANGUAGE sql;
|
|
204
|
+
|
|
205
|
+
-- policy_cmd_is( table, policy, command, description )
|
|
206
|
+
CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text, text )
|
|
207
|
+
RETURNS TEXT AS $$
|
|
208
|
+
DECLARE
|
|
209
|
+
cmd text;
|
|
210
|
+
BEGIN
|
|
211
|
+
SELECT
|
|
212
|
+
CASE pp.polcmd WHEN 'r' THEN 'SELECT'
|
|
213
|
+
WHEN 'a' THEN 'INSERT'
|
|
214
|
+
WHEN 'w' THEN 'UPDATE'
|
|
215
|
+
WHEN 'd' THEN 'DELETE'
|
|
216
|
+
ELSE 'ALL'
|
|
217
|
+
END
|
|
218
|
+
FROM pg_catalog.pg_policy AS pp
|
|
219
|
+
JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid
|
|
220
|
+
JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace
|
|
221
|
+
WHERE pc.relname = $1
|
|
222
|
+
AND pp.polname = $2
|
|
223
|
+
AND pn.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
224
|
+
INTO cmd;
|
|
225
|
+
|
|
226
|
+
RETURN is( cmd, upper($3), $4 );
|
|
227
|
+
END;
|
|
228
|
+
$$ LANGUAGE plpgsql;
|
|
229
|
+
|
|
230
|
+
-- policy_cmd_is( table, policy, command )
|
|
231
|
+
CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text )
|
|
232
|
+
RETURNS TEXT AS $$
|
|
233
|
+
SELECT policy_cmd_is(
|
|
234
|
+
$1, $2, $3,
|
|
235
|
+
'Policy ' || quote_ident($2)
|
|
236
|
+
|| ' for table ' || quote_ident($1)
|
|
237
|
+
|| ' should apply to ' || upper($3) || ' command'
|
|
238
|
+
);
|
|
239
|
+
$$ LANGUAGE sql;
|
|
240
|
+
|
|
241
|
+
CREATE OR REPLACE FUNCTION _funkargs ( NAME[] )
|
|
242
|
+
RETURNS TEXT AS $$
|
|
243
|
+
BEGIN
|
|
244
|
+
RETURN array_to_string($1::regtype[], ',');
|
|
245
|
+
EXCEPTION WHEN undefined_object THEN
|
|
246
|
+
RETURN array_to_string($1, ',');
|
|
247
|
+
END;
|
|
248
|
+
$$ LANGUAGE PLPGSQL STABLE;
|
|
249
|
+
|
|
250
|
+
CREATE OR REPLACE FUNCTION _got_func ( NAME, NAME, NAME[] )
|
|
251
|
+
RETURNS BOOLEAN AS $$
|
|
252
|
+
SELECT EXISTS(
|
|
253
|
+
SELECT TRUE
|
|
254
|
+
FROM tap_funky
|
|
255
|
+
WHERE schema = $1
|
|
256
|
+
AND name = $2
|
|
257
|
+
AND args = _funkargs($3)
|
|
258
|
+
);
|
|
259
|
+
$$ LANGUAGE SQL;
|
|
260
|
+
|
|
261
|
+
CREATE OR REPLACE FUNCTION _got_func ( NAME, NAME[] )
|
|
262
|
+
RETURNS BOOLEAN AS $$
|
|
263
|
+
SELECT EXISTS(
|
|
264
|
+
SELECT TRUE
|
|
265
|
+
FROM tap_funky
|
|
266
|
+
WHERE name = $1
|
|
267
|
+
AND args = _funkargs($2)
|
|
268
|
+
AND is_visible
|
|
269
|
+
);
|
|
270
|
+
$$ LANGUAGE SQL;
|
|
271
|
+
|
|
272
|
+
/*
|
|
273
|
+
* Internal function to test whether the specified table in the specified schema
|
|
274
|
+
* has an inheritance chain. Returns true or false.
|
|
275
|
+
*/
|
|
276
|
+
CREATE OR REPLACE FUNCTION _inherited( NAME, NAME )
|
|
277
|
+
RETURNS BOOLEAN AS $$
|
|
278
|
+
SELECT EXISTS(
|
|
279
|
+
SELECT true
|
|
280
|
+
FROM pg_catalog.pg_namespace n
|
|
281
|
+
JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace
|
|
282
|
+
WHERE c.relkind = 'r'
|
|
283
|
+
AND n.nspname = $1
|
|
284
|
+
AND c.relname = $2
|
|
285
|
+
AND c.relhassubclass = true
|
|
286
|
+
);
|
|
287
|
+
$$ LANGUAGE SQL;
|
|
288
|
+
|
|
289
|
+
/*
|
|
290
|
+
* Internal function to test whether a specific table in the search_path has an
|
|
291
|
+
* inheritance chain. Returns true or false.
|
|
292
|
+
*/
|
|
293
|
+
CREATE OR REPLACE FUNCTION _inherited( NAME )
|
|
294
|
+
RETURNS BOOLEAN AS $$
|
|
295
|
+
SELECT EXISTS(
|
|
296
|
+
SELECT true
|
|
297
|
+
FROM pg_catalog.pg_class c
|
|
298
|
+
WHERE c.relkind = 'r'
|
|
299
|
+
AND pg_catalog.pg_table_is_visible( c.oid )
|
|
300
|
+
AND c.relname = $1
|
|
301
|
+
AND c.relhassubclass = true
|
|
302
|
+
);
|
|
303
|
+
$$ LANGUAGE SQL;
|
|
304
|
+
|
|
305
|
+
-- has_inherited_tables( schema, table, description )
|
|
306
|
+
CREATE OR REPLACE FUNCTION has_inherited_tables( NAME, NAME, TEXT )
|
|
307
|
+
RETURNS TEXT AS $$
|
|
308
|
+
SELECT ok( _inherited( $1, $2 ), $3);
|
|
309
|
+
$$ LANGUAGE SQL;
|
|
310
|
+
|
|
311
|
+
-- has_inherited_tables( schema, table )
|
|
312
|
+
CREATE OR REPLACE FUNCTION has_inherited_tables( NAME, NAME )
|
|
313
|
+
RETURNS TEXT AS $$
|
|
314
|
+
SELECT ok(
|
|
315
|
+
_inherited( $1, $2 ),
|
|
316
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should have descendents'
|
|
317
|
+
);
|
|
318
|
+
$$ LANGUAGE SQL;
|
|
319
|
+
|
|
320
|
+
-- has_inherited_tables( table, description )
|
|
321
|
+
CREATE OR REPLACE FUNCTION has_inherited_tables( NAME, TEXT )
|
|
322
|
+
RETURNS TEXT AS $$
|
|
323
|
+
SELECT ok( _inherited( $1 ), $2 );
|
|
324
|
+
$$ LANGUAGE SQL;
|
|
325
|
+
|
|
326
|
+
-- has_inherited_tables( table )
|
|
327
|
+
CREATE OR REPLACE FUNCTION has_inherited_tables( NAME )
|
|
328
|
+
RETURNS TEXT AS $$
|
|
329
|
+
SELECT ok(
|
|
330
|
+
_inherited( $1 ),
|
|
331
|
+
'Table ' || quote_ident( $1 ) || ' should have descendents'
|
|
332
|
+
);
|
|
333
|
+
$$ LANGUAGE SQL;
|
|
334
|
+
|
|
335
|
+
-- hasnt_inherited_tables( schema, table, description )
|
|
336
|
+
CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME, NAME, TEXT )
|
|
337
|
+
RETURNS TEXT AS $$
|
|
338
|
+
SELECT ok( NOT _inherited( $1, $2 ), $3 );
|
|
339
|
+
$$ LANGUAGE SQL;
|
|
340
|
+
|
|
341
|
+
-- hasnt_inherited_tables( schema, table )
|
|
342
|
+
CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME, NAME )
|
|
343
|
+
RETURNS TEXT AS $$
|
|
344
|
+
SELECT ok(
|
|
345
|
+
NOT _inherited( $1, $2 ),
|
|
346
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not have descendents'
|
|
347
|
+
);
|
|
348
|
+
$$ LANGUAGE SQL;
|
|
349
|
+
|
|
350
|
+
-- hasnt_inherited_tables( table, description )
|
|
351
|
+
CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME, TEXT )
|
|
352
|
+
RETURNS TEXT AS $$
|
|
353
|
+
SELECT ok( NOT _inherited( $1 ), $2 );
|
|
354
|
+
$$ LANGUAGE SQL;
|
|
355
|
+
|
|
356
|
+
-- hasnt_inherited_tables( table )
|
|
357
|
+
CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME )
|
|
358
|
+
RETURNS TEXT AS $$
|
|
359
|
+
SELECT ok(
|
|
360
|
+
NOT _inherited( $1 ),
|
|
361
|
+
'Table ' || quote_ident( $1 ) || ' should not have descendents'
|
|
362
|
+
);
|
|
363
|
+
$$ LANGUAGE SQL;
|
|
364
|
+
|
|
365
|
+
/*
|
|
366
|
+
* Internal function to test whether the schema-qualified table is an ancestor of
|
|
367
|
+
* the other schema-qualified table. The integer value is the length of the
|
|
368
|
+
* inheritance chain: a direct ancestor has has a chain length of 1.
|
|
369
|
+
*/
|
|
370
|
+
CREATE OR REPLACE FUNCTION _ancestor_of( NAME, NAME, NAME, NAME, INT )
|
|
371
|
+
RETURNS BOOLEAN AS $$
|
|
372
|
+
WITH RECURSIVE inheritance_chain AS (
|
|
373
|
+
-- select the ancestor tuple
|
|
374
|
+
SELECT i.inhrelid AS descendent_id, 1 AS inheritance_level
|
|
375
|
+
FROM pg_catalog.pg_inherits i
|
|
376
|
+
WHERE i.inhparent = (
|
|
377
|
+
SELECT c1.oid
|
|
378
|
+
FROM pg_catalog.pg_class c1
|
|
379
|
+
JOIN pg_catalog.pg_namespace n1
|
|
380
|
+
ON c1.relnamespace = n1.oid
|
|
381
|
+
WHERE c1.relname = $2
|
|
382
|
+
AND n1.nspname = $1
|
|
383
|
+
)
|
|
384
|
+
UNION
|
|
385
|
+
-- select the descendents
|
|
386
|
+
SELECT i.inhrelid AS descendent_id,
|
|
387
|
+
p.inheritance_level + 1 AS inheritance_level
|
|
388
|
+
FROM pg_catalog.pg_inherits i
|
|
389
|
+
JOIN inheritance_chain p
|
|
390
|
+
ON p.descendent_id = i.inhparent
|
|
391
|
+
WHERE i.inhrelid = (
|
|
392
|
+
SELECT c1.oid
|
|
393
|
+
FROM pg_catalog.pg_class c1
|
|
394
|
+
JOIN pg_catalog.pg_namespace n1
|
|
395
|
+
ON c1.relnamespace = n1.oid
|
|
396
|
+
WHERE c1.relname = $4
|
|
397
|
+
AND n1.nspname = $3
|
|
398
|
+
)
|
|
399
|
+
)
|
|
400
|
+
SELECT EXISTS(
|
|
401
|
+
SELECT true
|
|
402
|
+
FROM inheritance_chain
|
|
403
|
+
WHERE inheritance_level = COALESCE($5, inheritance_level)
|
|
404
|
+
AND descendent_id = (
|
|
405
|
+
SELECT c1.oid
|
|
406
|
+
FROM pg_catalog.pg_class c1
|
|
407
|
+
JOIN pg_catalog.pg_namespace n1
|
|
408
|
+
ON c1.relnamespace = n1.oid
|
|
409
|
+
WHERE c1.relname = $4
|
|
410
|
+
AND n1.nspname = $3
|
|
411
|
+
)
|
|
412
|
+
);
|
|
413
|
+
$$ LANGUAGE SQL;
|
|
414
|
+
|
|
415
|
+
/*
|
|
416
|
+
* Internal function to check if not-qualified tables
|
|
417
|
+
* within the search_path are connected by an inheritance chain.
|
|
418
|
+
*/
|
|
419
|
+
CREATE OR REPLACE FUNCTION _ancestor_of( NAME, NAME, INT )
|
|
420
|
+
RETURNS BOOLEAN AS $$
|
|
421
|
+
WITH RECURSIVE inheritance_chain AS (
|
|
422
|
+
-- select the ancestor tuple
|
|
423
|
+
SELECT i.inhrelid AS descendent_id, 1 AS inheritance_level
|
|
424
|
+
FROM pg_catalog.pg_inherits i
|
|
425
|
+
WHERE i.inhparent = (
|
|
426
|
+
SELECT c1.oid
|
|
427
|
+
FROM pg_catalog.pg_class c1
|
|
428
|
+
JOIN pg_catalog.pg_namespace n1
|
|
429
|
+
ON c1.relnamespace = n1.oid
|
|
430
|
+
WHERE c1.relname = $1
|
|
431
|
+
AND pg_catalog.pg_table_is_visible( c1.oid )
|
|
432
|
+
)
|
|
433
|
+
UNION
|
|
434
|
+
-- select the descendents
|
|
435
|
+
SELECT i.inhrelid AS descendent_id,
|
|
436
|
+
p.inheritance_level + 1 AS inheritance_level
|
|
437
|
+
FROM pg_catalog.pg_inherits i
|
|
438
|
+
JOIN inheritance_chain p
|
|
439
|
+
ON p.descendent_id = i.inhparent
|
|
440
|
+
WHERE i.inhrelid = (
|
|
441
|
+
SELECT c1.oid
|
|
442
|
+
FROM pg_catalog.pg_class c1
|
|
443
|
+
JOIN pg_catalog.pg_namespace n1
|
|
444
|
+
ON c1.relnamespace = n1.oid
|
|
445
|
+
WHERE c1.relname = $2
|
|
446
|
+
AND pg_catalog.pg_table_is_visible( c1.oid )
|
|
447
|
+
)
|
|
448
|
+
)
|
|
449
|
+
SELECT EXISTS(
|
|
450
|
+
SELECT true
|
|
451
|
+
FROM inheritance_chain
|
|
452
|
+
WHERE inheritance_level = COALESCE($3, inheritance_level)
|
|
453
|
+
AND descendent_id = (
|
|
454
|
+
SELECT c1.oid
|
|
455
|
+
FROM pg_catalog.pg_class c1
|
|
456
|
+
JOIN pg_catalog.pg_namespace n1
|
|
457
|
+
ON c1.relnamespace = n1.oid
|
|
458
|
+
WHERE c1.relname = $2
|
|
459
|
+
AND pg_catalog.pg_table_is_visible( c1.oid )
|
|
460
|
+
)
|
|
461
|
+
);
|
|
462
|
+
$$ LANGUAGE SQL;
|
|
463
|
+
|
|
464
|
+
-- is_ancestor_of( schema, table, schema, table, depth, description )
|
|
465
|
+
CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME, INT, TEXT )
|
|
466
|
+
RETURNS TEXT AS $$
|
|
467
|
+
SELECT ok( _ancestor_of( $1, $2, $3, $4, $5 ), $6 );
|
|
468
|
+
$$ LANGUAGE SQL;
|
|
469
|
+
|
|
470
|
+
-- is_ancestor_of( schema, table, schema, table, depth )
|
|
471
|
+
CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME, INT )
|
|
472
|
+
RETURNS TEXT AS $$
|
|
473
|
+
SELECT ok(
|
|
474
|
+
_ancestor_of( $1, $2, $3, $4, $5 ),
|
|
475
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 )
|
|
476
|
+
|| ' should be ancestor ' || $5 || ' for '
|
|
477
|
+
|| quote_ident( $3 ) || '.' || quote_ident( $4 )
|
|
478
|
+
);
|
|
479
|
+
$$ LANGUAGE SQL;
|
|
480
|
+
|
|
481
|
+
-- is_ancestor_of( schema, table, schema, table, description )
|
|
482
|
+
CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME, TEXT )
|
|
483
|
+
RETURNS TEXT AS $$
|
|
484
|
+
SELECT ok( _ancestor_of( $1, $2, $3, $4, NULL ), $5 );
|
|
485
|
+
$$ LANGUAGE SQL;
|
|
486
|
+
|
|
487
|
+
-- is_ancestor_of( schema, table, schema, table )
|
|
488
|
+
CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME )
|
|
489
|
+
RETURNS TEXT AS $$
|
|
490
|
+
SELECT ok(
|
|
491
|
+
_ancestor_of( $1, $2, $3, $4, NULL ),
|
|
492
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 )
|
|
493
|
+
|| ' should be an ancestor of '
|
|
494
|
+
|| quote_ident( $3 ) || '.' || quote_ident( $4 )
|
|
495
|
+
);
|
|
496
|
+
$$ LANGUAGE SQL;
|
|
497
|
+
|
|
498
|
+
-- is_ancestor_of( table, table, depth, description )
|
|
499
|
+
CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, INT, TEXT )
|
|
500
|
+
RETURNS TEXT AS $$
|
|
501
|
+
SELECT ok( _ancestor_of( $1, $2, $3 ), $4 );
|
|
502
|
+
$$ LANGUAGE SQL;
|
|
503
|
+
|
|
504
|
+
-- is_ancestor_of( table, table, depth )
|
|
505
|
+
CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, INT )
|
|
506
|
+
RETURNS TEXT AS $$
|
|
507
|
+
SELECT ok(
|
|
508
|
+
_ancestor_of( $1, $2, $3 ),
|
|
509
|
+
'Table ' || quote_ident( $1 ) || ' should be ancestor ' || $3 || ' of ' || quote_ident( $2)
|
|
510
|
+
);
|
|
511
|
+
$$ LANGUAGE SQL;
|
|
512
|
+
|
|
513
|
+
-- is_ancestor_of( table, table, description )
|
|
514
|
+
CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, TEXT )
|
|
515
|
+
RETURNS TEXT AS $$
|
|
516
|
+
SELECT ok( _ancestor_of( $1, $2, NULL ), $3 );
|
|
517
|
+
$$ LANGUAGE SQL;
|
|
518
|
+
|
|
519
|
+
-- is_ancestor_of( table, table )
|
|
520
|
+
CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME )
|
|
521
|
+
RETURNS TEXT AS $$
|
|
522
|
+
SELECT ok(
|
|
523
|
+
_ancestor_of( $1, $2, NULL ),
|
|
524
|
+
'Table ' || quote_ident( $1 ) || ' should be an ancestor of ' || quote_ident( $2)
|
|
525
|
+
);
|
|
526
|
+
$$ LANGUAGE SQL;
|
|
527
|
+
|
|
528
|
+
-- isnt_ancestor_of( schema, table, schema, table, depth, description )
|
|
529
|
+
CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME, INT, TEXT )
|
|
530
|
+
RETURNS TEXT AS $$
|
|
531
|
+
SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, $5 ), $6 );
|
|
532
|
+
$$ LANGUAGE SQL;
|
|
533
|
+
|
|
534
|
+
-- isnt_ancestor_of( schema, table, schema, table, depth )
|
|
535
|
+
CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME, INT )
|
|
536
|
+
RETURNS TEXT AS $$
|
|
537
|
+
SELECT ok(
|
|
538
|
+
NOT _ancestor_of( $1, $2, $3, $4, $5 ),
|
|
539
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 )
|
|
540
|
+
|| ' should not be ancestor ' || $5 || ' for '
|
|
541
|
+
|| quote_ident( $3 ) || '.' || quote_ident( $4 )
|
|
542
|
+
);
|
|
543
|
+
$$ LANGUAGE SQL;
|
|
544
|
+
|
|
545
|
+
-- isnt_ancestor_of( schema, table, schema, table, description )
|
|
546
|
+
CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME, TEXT )
|
|
547
|
+
RETURNS TEXT AS $$
|
|
548
|
+
SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, NULL ), $5 );
|
|
549
|
+
$$ LANGUAGE SQL;
|
|
550
|
+
|
|
551
|
+
-- isnt_ancestor_of( schema, table, schema, table )
|
|
552
|
+
CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME )
|
|
553
|
+
RETURNS TEXT AS $$
|
|
554
|
+
SELECT ok(
|
|
555
|
+
NOT _ancestor_of( $1, $2, $3, $4, NULL ),
|
|
556
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 )
|
|
557
|
+
|| ' should not be an ancestor of '
|
|
558
|
+
|| quote_ident( $3 ) || '.' || quote_ident( $4 )
|
|
559
|
+
);
|
|
560
|
+
$$ LANGUAGE SQL;
|
|
561
|
+
|
|
562
|
+
-- isnt_ancestor_of( table, table, depth, description )
|
|
563
|
+
CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, INT, TEXT )
|
|
564
|
+
RETURNS TEXT AS $$
|
|
565
|
+
SELECT ok( NOT _ancestor_of( $1, $2, $3 ), $4 );
|
|
566
|
+
$$ LANGUAGE SQL;
|
|
567
|
+
|
|
568
|
+
-- isnt_ancestor_of( table, table, depth )
|
|
569
|
+
CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, INT )
|
|
570
|
+
RETURNS TEXT AS $$
|
|
571
|
+
SELECT ok(
|
|
572
|
+
NOT _ancestor_of( $1, $2, $3 ),
|
|
573
|
+
'Table ' || quote_ident( $1 ) || ' should not be ancestor ' || $3 || ' of ' || quote_ident( $2)
|
|
574
|
+
);
|
|
575
|
+
$$ LANGUAGE SQL;
|
|
576
|
+
|
|
577
|
+
-- isnt_ancestor_of( table, table, description )
|
|
578
|
+
CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, TEXT )
|
|
579
|
+
RETURNS TEXT AS $$
|
|
580
|
+
SELECT ok( NOT _ancestor_of( $1, $2, NULL ), $3 );
|
|
581
|
+
$$ LANGUAGE SQL;
|
|
582
|
+
|
|
583
|
+
-- isnt_ancestor_of( table, table )
|
|
584
|
+
CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME )
|
|
585
|
+
RETURNS TEXT AS $$
|
|
586
|
+
SELECT ok(
|
|
587
|
+
NOT _ancestor_of( $1, $2, NULL ),
|
|
588
|
+
'Table ' || quote_ident( $1 ) || ' should not be an ancestor of ' || quote_ident( $2)
|
|
589
|
+
);
|
|
590
|
+
$$ LANGUAGE SQL;
|
|
591
|
+
|
|
592
|
+
-- is_descendent_of( schema, table, schema, table, depth, description )
|
|
593
|
+
CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME, INT, TEXT )
|
|
594
|
+
RETURNS TEXT AS $$
|
|
595
|
+
SELECT ok( _ancestor_of( $3, $4, $1, $2, $5 ), $6 );
|
|
596
|
+
$$ LANGUAGE SQL;
|
|
597
|
+
|
|
598
|
+
-- is_descendent_of( schema, table, schema, table, depth )
|
|
599
|
+
CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME, INT )
|
|
600
|
+
RETURNS TEXT AS $$
|
|
601
|
+
SELECT ok(
|
|
602
|
+
_ancestor_of( $3, $4, $1, $2, $5 ),
|
|
603
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 )
|
|
604
|
+
|| ' should be descendent ' || $5 || ' from '
|
|
605
|
+
|| quote_ident( $3 ) || '.' || quote_ident( $4 )
|
|
606
|
+
);
|
|
607
|
+
$$ LANGUAGE SQL;
|
|
608
|
+
|
|
609
|
+
-- is_descendent_of( schema, table, schema, table, description )
|
|
610
|
+
CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME, TEXT )
|
|
611
|
+
RETURNS TEXT AS $$
|
|
612
|
+
SELECT ok( _ancestor_of( $3, $4, $1, $2, NULL ), $5 );
|
|
613
|
+
$$ LANGUAGE SQL;
|
|
614
|
+
|
|
615
|
+
-- is_descendent_of( schema, table, schema, table )
|
|
616
|
+
CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME )
|
|
617
|
+
RETURNS TEXT AS $$
|
|
618
|
+
SELECT ok(
|
|
619
|
+
_ancestor_of( $3, $4, $1, $2, NULL ),
|
|
620
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 )
|
|
621
|
+
|| ' should be a descendent of '
|
|
622
|
+
|| quote_ident( $3 ) || '.' || quote_ident( $4 )
|
|
623
|
+
);
|
|
624
|
+
$$ LANGUAGE SQL;
|
|
625
|
+
|
|
626
|
+
-- is_descendent_of( table, table, depth, description )
|
|
627
|
+
CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, INT, TEXT )
|
|
628
|
+
RETURNS TEXT AS $$
|
|
629
|
+
SELECT ok( _ancestor_of( $2, $1, $3 ), $4 );
|
|
630
|
+
$$ LANGUAGE SQL;
|
|
631
|
+
|
|
632
|
+
-- is_descendent_of( table, table, depth )
|
|
633
|
+
CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, INT )
|
|
634
|
+
RETURNS TEXT AS $$
|
|
635
|
+
SELECT ok(
|
|
636
|
+
_ancestor_of( $2, $1, $3 ),
|
|
637
|
+
'Table ' || quote_ident( $1 ) || ' should be descendent ' || $3 || ' from ' || quote_ident( $2)
|
|
638
|
+
);
|
|
639
|
+
$$ LANGUAGE SQL;
|
|
640
|
+
|
|
641
|
+
-- is_descendent_of( table, table, description )
|
|
642
|
+
CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, TEXT )
|
|
643
|
+
RETURNS TEXT AS $$
|
|
644
|
+
SELECT ok( _ancestor_of( $2, $1, NULL ), $3 );
|
|
645
|
+
$$ LANGUAGE SQL;
|
|
646
|
+
|
|
647
|
+
-- is_descendent_of( table, table )
|
|
648
|
+
CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME )
|
|
649
|
+
RETURNS TEXT AS $$
|
|
650
|
+
SELECT ok(
|
|
651
|
+
_ancestor_of( $2, $1, NULL ),
|
|
652
|
+
'Table ' || quote_ident( $1 ) || ' should be a descendent of ' || quote_ident( $2)
|
|
653
|
+
);
|
|
654
|
+
$$ LANGUAGE SQL;
|
|
655
|
+
|
|
656
|
+
-- isnt_descendent_of( schema, table, schema, table, depth, description )
|
|
657
|
+
CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME, INT, TEXT )
|
|
658
|
+
RETURNS TEXT AS $$
|
|
659
|
+
SELECT ok(NOT _ancestor_of( $3, $4, $1, $2, $5 ), $6 );
|
|
660
|
+
$$ LANGUAGE SQL;
|
|
661
|
+
|
|
662
|
+
-- isnt_descendent_of( schema, table, schema, table, depth )
|
|
663
|
+
CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME, INT )
|
|
664
|
+
RETURNS TEXT AS $$
|
|
665
|
+
SELECT ok(
|
|
666
|
+
NOT _ancestor_of( $3, $4, $1, $2, $5 ),
|
|
667
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 )
|
|
668
|
+
|| ' should not be descendent ' || $5 || ' from '
|
|
669
|
+
|| quote_ident( $3 ) || '.' || quote_ident( $4 )
|
|
670
|
+
);
|
|
671
|
+
$$ LANGUAGE SQL;
|
|
672
|
+
|
|
673
|
+
-- isnt_descendent_of( schema, table, schema, table, description )
|
|
674
|
+
CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME, TEXT )
|
|
675
|
+
RETURNS TEXT AS $$
|
|
676
|
+
SELECT ok(NOT _ancestor_of( $3, $4, $1, $2, NULL ), $5 );
|
|
677
|
+
$$ LANGUAGE SQL;
|
|
678
|
+
|
|
679
|
+
-- isnt_descendent_of( schema, table, schema, table )
|
|
680
|
+
CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME )
|
|
681
|
+
RETURNS TEXT AS $$
|
|
682
|
+
SELECT ok(
|
|
683
|
+
NOT _ancestor_of( $3, $4, $1, $2, NULL ),
|
|
684
|
+
'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 )
|
|
685
|
+
|| ' should not be a descendent of '
|
|
686
|
+
|| quote_ident( $3 ) || '.' || quote_ident( $4 )
|
|
687
|
+
);
|
|
688
|
+
$$ LANGUAGE SQL;
|
|
689
|
+
|
|
690
|
+
-- isnt_descendent_of( table, table, depth, description )
|
|
691
|
+
CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, INT, TEXT )
|
|
692
|
+
RETURNS TEXT AS $$
|
|
693
|
+
SELECT ok(NOT _ancestor_of( $2, $1, $3 ), $4 );
|
|
694
|
+
$$ LANGUAGE SQL;
|
|
695
|
+
|
|
696
|
+
-- isnt_descendent_of( table, table, depth )
|
|
697
|
+
CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, INT )
|
|
698
|
+
RETURNS TEXT AS $$
|
|
699
|
+
SELECT ok(
|
|
700
|
+
NOT _ancestor_of( $2, $1, $3 ),
|
|
701
|
+
'Table ' || quote_ident( $1 ) || ' should not be descendent ' || $3 || ' from ' || quote_ident( $2)
|
|
702
|
+
);
|
|
703
|
+
$$ LANGUAGE SQL;
|
|
704
|
+
|
|
705
|
+
-- isnt_descendent_of( table, table, description )
|
|
706
|
+
CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, TEXT )
|
|
707
|
+
RETURNS TEXT AS $$
|
|
708
|
+
SELECT ok(NOT _ancestor_of( $2, $1, NULL ), $3 );
|
|
709
|
+
$$ LANGUAGE SQL;
|
|
710
|
+
|
|
711
|
+
-- isnt_descendent_of( table, table )
|
|
712
|
+
CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME )
|
|
713
|
+
RETURNS TEXT AS $$
|
|
714
|
+
SELECT ok(
|
|
715
|
+
NOT _ancestor_of( $2, $1, NULL ),
|
|
716
|
+
'Table ' || quote_ident( $1 ) || ' should not be a descendent of ' || quote_ident( $2)
|
|
717
|
+
);
|
|
718
|
+
$$ LANGUAGE SQL;
|
|
719
|
+
|
|
720
|
+
CREATE OR REPLACE FUNCTION _def_is( TEXT, TEXT, anyelement, TEXT )
|
|
721
|
+
RETURNS TEXT AS $$
|
|
722
|
+
DECLARE
|
|
723
|
+
thing text;
|
|
724
|
+
BEGIN
|
|
725
|
+
-- Function or special SQL syntax.
|
|
726
|
+
IF $1 ~ '^[^'']+[(]' OR $1 = ANY('{CURRENT_CATALOG,CURRENT_ROLE,CURRENT_SCHEMA,CURRENT_USER,SESSION_USER,USER}') THEN
|
|
727
|
+
RETURN is( $1, $3, $4 );
|
|
728
|
+
END IF;
|
|
729
|
+
|
|
730
|
+
EXECUTE 'SELECT is('
|
|
731
|
+
|| COALESCE($1, 'NULL' || '::' || $2) || '::' || $2 || ', '
|
|
732
|
+
|| COALESCE(quote_literal($3), 'NULL') || '::' || $2 || ', '
|
|
733
|
+
|| COALESCE(quote_literal($4), 'NULL')
|
|
734
|
+
|| ')' INTO thing;
|
|
735
|
+
RETURN thing;
|
|
736
|
+
END;
|
|
737
|
+
$$ LANGUAGE plpgsql;
|