TLA Line data Source code
1 : /*
2 : * contrib/ltree/_ltree_op.c
3 : *
4 : *
5 : * op function for ltree[]
6 : * Teodor Sigaev <teodor@stack.net>
7 : */
8 : #include "postgres.h"
9 :
10 : #include <ctype.h>
11 :
12 : #include "ltree.h"
13 : #include "utils/array.h"
14 :
15 GIC 3 : PG_FUNCTION_INFO_V1(_ltree_isparent);
16 CBC 2 : PG_FUNCTION_INFO_V1(_ltree_r_isparent);
17 3 : PG_FUNCTION_INFO_V1(_ltree_risparent);
18 2 : PG_FUNCTION_INFO_V1(_ltree_r_risparent);
19 3 : PG_FUNCTION_INFO_V1(_ltq_regex);
20 2 : PG_FUNCTION_INFO_V1(_ltq_rregex);
21 3 : PG_FUNCTION_INFO_V1(_lt_q_regex);
22 2 : PG_FUNCTION_INFO_V1(_lt_q_rregex);
23 3 : PG_FUNCTION_INFO_V1(_ltxtq_exec);
24 2 : PG_FUNCTION_INFO_V1(_ltxtq_rexec);
25 ECB :
26 GIC 3 : PG_FUNCTION_INFO_V1(_ltree_extract_isparent);
27 CBC 3 : PG_FUNCTION_INFO_V1(_ltree_extract_risparent);
28 3 : PG_FUNCTION_INFO_V1(_ltq_extract_regex);
29 3 : PG_FUNCTION_INFO_V1(_ltxtq_extract_exec);
30 ECB :
31 GIC 3 : PG_FUNCTION_INFO_V1(_lca);
32 ECB :
33 : typedef Datum (*PGCALL2) (PG_FUNCTION_ARGS);
34 :
35 : #define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
36 :
37 : static bool
38 GIC 20323 : array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
39 ECB : {
40 GIC 20323 : int num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la));
41 CBC 20323 : ltree *item = (ltree *) ARR_DATA_PTR(la);
42 ECB :
43 GIC 20323 : if (ARR_NDIM(la) > 1)
44 LBC 0 : ereport(ERROR,
45 EUB : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
46 : errmsg("array must be one-dimensional")));
47 GIC 20323 : if (array_contains_nulls(la))
48 LBC 0 : ereport(ERROR,
49 EUB : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
50 : errmsg("array must not contain nulls")));
51 :
52 GIC 20323 : if (found)
53 CBC 6 : *found = NULL;
54 91782 : while (num > 0)
55 ECB : {
56 GIC 72507 : if (DatumGetBool(DirectFunctionCall2(callback,
57 ECB : PointerGetDatum(item), PointerGetDatum(param))))
58 : {
59 :
60 GIC 1048 : if (found)
61 CBC 4 : *found = item;
62 1048 : return true;
63 ECB : }
64 GIC 71459 : num--;
65 CBC 71459 : item = NEXTVAL(item);
66 ECB : }
67 :
68 GIC 19275 : return false;
69 ECB : }
70 :
71 : Datum
72 GIC 3012 : _ltree_isparent(PG_FUNCTION_ARGS)
73 ECB : {
74 GIC 3012 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
75 CBC 3012 : ltree *query = PG_GETARG_LTREE_P(1);
76 3012 : bool res = array_iterator(la, ltree_isparent, (void *) query, NULL);
77 ECB :
78 GIC 3012 : PG_FREE_IF_COPY(la, 0);
79 CBC 3012 : PG_FREE_IF_COPY(query, 1);
80 3012 : PG_RETURN_BOOL(res);
81 ECB : }
82 :
83 : Datum
84 UIC 0 : _ltree_r_isparent(PG_FUNCTION_ARGS)
85 EUB : {
86 UIC 0 : PG_RETURN_DATUM(DirectFunctionCall2(_ltree_isparent,
87 EUB : PG_GETARG_DATUM(1),
88 : PG_GETARG_DATUM(0)
89 : ));
90 : }
91 :
92 : Datum
93 GIC 2310 : _ltree_risparent(PG_FUNCTION_ARGS)
94 ECB : {
95 GIC 2310 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
96 CBC 2310 : ltree *query = PG_GETARG_LTREE_P(1);
97 2310 : bool res = array_iterator(la, ltree_risparent, (void *) query, NULL);
98 ECB :
99 GIC 2310 : PG_FREE_IF_COPY(la, 0);
100 CBC 2310 : PG_FREE_IF_COPY(query, 1);
101 2310 : PG_RETURN_BOOL(res);
102 ECB : }
103 :
104 : Datum
105 UIC 0 : _ltree_r_risparent(PG_FUNCTION_ARGS)
106 EUB : {
107 UIC 0 : PG_RETURN_DATUM(DirectFunctionCall2(_ltree_risparent,
108 EUB : PG_GETARG_DATUM(1),
109 : PG_GETARG_DATUM(0)
110 : ));
111 : }
112 :
113 : Datum
114 GIC 9575 : _ltq_regex(PG_FUNCTION_ARGS)
115 ECB : {
116 GIC 9575 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
117 CBC 9575 : lquery *query = PG_GETARG_LQUERY_P(1);
118 9575 : bool res = array_iterator(la, ltq_regex, (void *) query, NULL);
119 ECB :
120 GIC 9575 : PG_FREE_IF_COPY(la, 0);
121 CBC 9575 : PG_FREE_IF_COPY(query, 1);
122 9575 : PG_RETURN_BOOL(res);
123 ECB : }
124 :
125 : Datum
126 UIC 0 : _ltq_rregex(PG_FUNCTION_ARGS)
127 EUB : {
128 UIC 0 : PG_RETURN_DATUM(DirectFunctionCall2(_ltq_regex,
129 EUB : PG_GETARG_DATUM(1),
130 : PG_GETARG_DATUM(0)
131 : ));
132 : }
133 :
134 : Datum
135 GIC 1868 : _lt_q_regex(PG_FUNCTION_ARGS)
136 ECB : {
137 GIC 1868 : ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0);
138 CBC 1868 : ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
139 1868 : lquery *query = (lquery *) ARR_DATA_PTR(_query);
140 1868 : bool res = false;
141 1868 : int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
142 ECB :
143 GIC 1868 : if (ARR_NDIM(_query) > 1)
144 LBC 0 : ereport(ERROR,
145 EUB : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
146 : errmsg("array must be one-dimensional")));
147 GIC 1868 : if (array_contains_nulls(_query))
148 LBC 0 : ereport(ERROR,
149 EUB : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
150 : errmsg("array must not contain nulls")));
151 :
152 GIC 5524 : while (num > 0)
153 ECB : {
154 GIC 3702 : if (array_iterator(_tree, ltq_regex, (void *) query, NULL))
155 ECB : {
156 GIC 46 : res = true;
157 CBC 46 : break;
158 ECB : }
159 GIC 3656 : num--;
160 CBC 3656 : query = (lquery *) NEXTVAL(query);
161 ECB : }
162 :
163 GIC 1868 : PG_FREE_IF_COPY(_tree, 0);
164 CBC 1868 : PG_FREE_IF_COPY(_query, 1);
165 1868 : PG_RETURN_BOOL(res);
166 ECB : }
167 :
168 : Datum
169 UIC 0 : _lt_q_rregex(PG_FUNCTION_ARGS)
170 EUB : {
171 UIC 0 : PG_RETURN_DATUM(DirectFunctionCall2(_lt_q_regex,
172 EUB : PG_GETARG_DATUM(1),
173 : PG_GETARG_DATUM(0)
174 : ));
175 : }
176 :
177 :
178 : Datum
179 GIC 1718 : _ltxtq_exec(PG_FUNCTION_ARGS)
180 ECB : {
181 GIC 1718 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
182 CBC 1718 : ltxtquery *query = PG_GETARG_LTXTQUERY_P(1);
183 1718 : bool res = array_iterator(la, ltxtq_exec, (void *) query, NULL);
184 ECB :
185 GIC 1718 : PG_FREE_IF_COPY(la, 0);
186 CBC 1718 : PG_FREE_IF_COPY(query, 1);
187 1718 : PG_RETURN_BOOL(res);
188 ECB : }
189 :
190 : Datum
191 UIC 0 : _ltxtq_rexec(PG_FUNCTION_ARGS)
192 EUB : {
193 UIC 0 : PG_RETURN_DATUM(DirectFunctionCall2(_ltxtq_exec,
194 EUB : PG_GETARG_DATUM(1),
195 : PG_GETARG_DATUM(0)
196 : ));
197 : }
198 :
199 :
200 : Datum
201 GIC 2 : _ltree_extract_isparent(PG_FUNCTION_ARGS)
202 ECB : {
203 GIC 2 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
204 CBC 2 : ltree *query = PG_GETARG_LTREE_P(1);
205 ECB : ltree *found,
206 : *item;
207 :
208 GIC 2 : if (!array_iterator(la, ltree_isparent, (void *) query, &found))
209 ECB : {
210 GIC 1 : PG_FREE_IF_COPY(la, 0);
211 CBC 1 : PG_FREE_IF_COPY(query, 1);
212 1 : PG_RETURN_NULL();
213 ECB : }
214 :
215 GIC 1 : item = (ltree *) palloc0(VARSIZE(found));
216 CBC 1 : memcpy(item, found, VARSIZE(found));
217 ECB :
218 GIC 1 : PG_FREE_IF_COPY(la, 0);
219 CBC 1 : PG_FREE_IF_COPY(query, 1);
220 1 : PG_RETURN_POINTER(item);
221 ECB : }
222 :
223 : Datum
224 GIC 2 : _ltree_extract_risparent(PG_FUNCTION_ARGS)
225 ECB : {
226 GIC 2 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
227 CBC 2 : ltree *query = PG_GETARG_LTREE_P(1);
228 ECB : ltree *found,
229 : *item;
230 :
231 GIC 2 : if (!array_iterator(la, ltree_risparent, (void *) query, &found))
232 ECB : {
233 GIC 1 : PG_FREE_IF_COPY(la, 0);
234 CBC 1 : PG_FREE_IF_COPY(query, 1);
235 1 : PG_RETURN_NULL();
236 ECB : }
237 :
238 GIC 1 : item = (ltree *) palloc0(VARSIZE(found));
239 CBC 1 : memcpy(item, found, VARSIZE(found));
240 ECB :
241 GIC 1 : PG_FREE_IF_COPY(la, 0);
242 CBC 1 : PG_FREE_IF_COPY(query, 1);
243 1 : PG_RETURN_POINTER(item);
244 ECB : }
245 :
246 : Datum
247 GIC 1 : _ltq_extract_regex(PG_FUNCTION_ARGS)
248 ECB : {
249 GIC 1 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
250 CBC 1 : lquery *query = PG_GETARG_LQUERY_P(1);
251 ECB : ltree *found,
252 : *item;
253 :
254 GIC 1 : if (!array_iterator(la, ltq_regex, (void *) query, &found))
255 ECB : {
256 UIC 0 : PG_FREE_IF_COPY(la, 0);
257 UBC 0 : PG_FREE_IF_COPY(query, 1);
258 0 : PG_RETURN_NULL();
259 EUB : }
260 :
261 GIC 1 : item = (ltree *) palloc0(VARSIZE(found));
262 CBC 1 : memcpy(item, found, VARSIZE(found));
263 ECB :
264 GIC 1 : PG_FREE_IF_COPY(la, 0);
265 CBC 1 : PG_FREE_IF_COPY(query, 1);
266 1 : PG_RETURN_POINTER(item);
267 ECB : }
268 :
269 : Datum
270 GIC 1 : _ltxtq_extract_exec(PG_FUNCTION_ARGS)
271 ECB : {
272 GIC 1 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
273 CBC 1 : ltxtquery *query = PG_GETARG_LTXTQUERY_P(1);
274 ECB : ltree *found,
275 : *item;
276 :
277 GIC 1 : if (!array_iterator(la, ltxtq_exec, (void *) query, &found))
278 ECB : {
279 UIC 0 : PG_FREE_IF_COPY(la, 0);
280 UBC 0 : PG_FREE_IF_COPY(query, 1);
281 0 : PG_RETURN_NULL();
282 EUB : }
283 :
284 GIC 1 : item = (ltree *) palloc0(VARSIZE(found));
285 CBC 1 : memcpy(item, found, VARSIZE(found));
286 ECB :
287 GIC 1 : PG_FREE_IF_COPY(la, 0);
288 CBC 1 : PG_FREE_IF_COPY(query, 1);
289 1 : PG_RETURN_POINTER(item);
290 ECB : }
291 :
292 : Datum
293 GIC 8 : _lca(PG_FUNCTION_ARGS)
294 ECB : {
295 GIC 8 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
296 CBC 8 : int num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la));
297 8 : ltree *item = (ltree *) ARR_DATA_PTR(la);
298 ECB : ltree **a,
299 : *res;
300 :
301 GIC 8 : if (ARR_NDIM(la) > 1)
302 LBC 0 : ereport(ERROR,
303 EUB : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
304 : errmsg("array must be one-dimensional")));
305 GIC 8 : if (array_contains_nulls(la))
306 LBC 0 : ereport(ERROR,
307 EUB : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
308 : errmsg("array must not contain nulls")));
309 :
310 GIC 8 : a = (ltree **) palloc(sizeof(ltree *) * num);
311 CBC 20 : while (num > 0)
312 ECB : {
313 GIC 12 : num--;
314 CBC 12 : a[num] = item;
315 12 : item = NEXTVAL(item);
316 ECB : }
317 GIC 8 : res = lca_inner(a, ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la)));
318 CBC 8 : pfree(a);
319 ECB :
320 GIC 8 : PG_FREE_IF_COPY(la, 0);
321 ECB :
322 GIC 8 : if (res)
323 CBC 6 : PG_RETURN_POINTER(res);
324 ECB : else
325 GIC 2 : PG_RETURN_NULL();
326 ECB : }
|