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