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 6 : PG_FUNCTION_INFO_V1(_ltree_isparent);
16 4 : PG_FUNCTION_INFO_V1(_ltree_r_isparent);
17 6 : PG_FUNCTION_INFO_V1(_ltree_risparent);
18 4 : PG_FUNCTION_INFO_V1(_ltree_r_risparent);
19 6 : PG_FUNCTION_INFO_V1(_ltq_regex);
20 4 : PG_FUNCTION_INFO_V1(_ltq_rregex);
21 6 : PG_FUNCTION_INFO_V1(_lt_q_regex);
22 4 : PG_FUNCTION_INFO_V1(_lt_q_rregex);
23 6 : PG_FUNCTION_INFO_V1(_ltxtq_exec);
24 4 : PG_FUNCTION_INFO_V1(_ltxtq_rexec);
25 :
26 6 : PG_FUNCTION_INFO_V1(_ltree_extract_isparent);
27 6 : PG_FUNCTION_INFO_V1(_ltree_extract_risparent);
28 6 : PG_FUNCTION_INFO_V1(_ltq_extract_regex);
29 6 : PG_FUNCTION_INFO_V1(_ltxtq_extract_exec);
30 :
31 6 : 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 40646 : array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found)
39 : {
40 40646 : int num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la));
41 40646 : ltree *item = (ltree *) ARR_DATA_PTR(la);
42 :
43 40646 : if (ARR_NDIM(la) > 1)
44 0 : ereport(ERROR,
45 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
46 : errmsg("array must be one-dimensional")));
47 40646 : 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 40646 : if (found)
53 12 : *found = NULL;
54 183564 : while (num > 0)
55 : {
56 145014 : if (DatumGetBool(DirectFunctionCall2(callback,
57 : PointerGetDatum(item), PointerGetDatum(param))))
58 : {
59 :
60 2096 : if (found)
61 8 : *found = item;
62 2096 : return true;
63 : }
64 142918 : num--;
65 142918 : item = NEXTVAL(item);
66 : }
67 :
68 38550 : return false;
69 : }
70 :
71 : Datum
72 6024 : _ltree_isparent(PG_FUNCTION_ARGS)
73 : {
74 6024 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
75 6024 : ltree *query = PG_GETARG_LTREE_P(1);
76 6024 : bool res = array_iterator(la, ltree_isparent, (void *) query, NULL);
77 :
78 6024 : PG_FREE_IF_COPY(la, 0);
79 6024 : PG_FREE_IF_COPY(query, 1);
80 6024 : 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 4620 : _ltree_risparent(PG_FUNCTION_ARGS)
94 : {
95 4620 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
96 4620 : ltree *query = PG_GETARG_LTREE_P(1);
97 4620 : bool res = array_iterator(la, ltree_risparent, (void *) query, NULL);
98 :
99 4620 : PG_FREE_IF_COPY(la, 0);
100 4620 : PG_FREE_IF_COPY(query, 1);
101 4620 : 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 19150 : _ltq_regex(PG_FUNCTION_ARGS)
115 : {
116 19150 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
117 19150 : lquery *query = PG_GETARG_LQUERY_P(1);
118 19150 : bool res = array_iterator(la, ltq_regex, (void *) query, NULL);
119 :
120 19150 : PG_FREE_IF_COPY(la, 0);
121 19150 : PG_FREE_IF_COPY(query, 1);
122 19150 : 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 3736 : _lt_q_regex(PG_FUNCTION_ARGS)
136 : {
137 3736 : ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0);
138 3736 : ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
139 3736 : lquery *query = (lquery *) ARR_DATA_PTR(_query);
140 3736 : bool res = false;
141 3736 : int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
142 :
143 3736 : if (ARR_NDIM(_query) > 1)
144 0 : ereport(ERROR,
145 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
146 : errmsg("array must be one-dimensional")));
147 3736 : 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 11048 : while (num > 0)
153 : {
154 7404 : if (array_iterator(_tree, ltq_regex, (void *) query, NULL))
155 : {
156 92 : res = true;
157 92 : break;
158 : }
159 7312 : num--;
160 7312 : query = (lquery *) NEXTVAL(query);
161 : }
162 :
163 3736 : PG_FREE_IF_COPY(_tree, 0);
164 3736 : PG_FREE_IF_COPY(_query, 1);
165 3736 : 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 3436 : _ltxtq_exec(PG_FUNCTION_ARGS)
180 : {
181 3436 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
182 3436 : ltxtquery *query = PG_GETARG_LTXTQUERY_P(1);
183 3436 : bool res = array_iterator(la, ltxtq_exec, (void *) query, NULL);
184 :
185 3436 : PG_FREE_IF_COPY(la, 0);
186 3436 : PG_FREE_IF_COPY(query, 1);
187 3436 : 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 4 : _ltree_extract_isparent(PG_FUNCTION_ARGS)
202 : {
203 4 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
204 4 : ltree *query = PG_GETARG_LTREE_P(1);
205 : ltree *found,
206 : *item;
207 :
208 4 : if (!array_iterator(la, ltree_isparent, (void *) query, &found))
209 : {
210 2 : PG_FREE_IF_COPY(la, 0);
211 2 : PG_FREE_IF_COPY(query, 1);
212 2 : PG_RETURN_NULL();
213 : }
214 :
215 2 : item = (ltree *) palloc0(VARSIZE(found));
216 2 : memcpy(item, found, VARSIZE(found));
217 :
218 2 : PG_FREE_IF_COPY(la, 0);
219 2 : PG_FREE_IF_COPY(query, 1);
220 2 : PG_RETURN_POINTER(item);
221 : }
222 :
223 : Datum
224 4 : _ltree_extract_risparent(PG_FUNCTION_ARGS)
225 : {
226 4 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
227 4 : ltree *query = PG_GETARG_LTREE_P(1);
228 : ltree *found,
229 : *item;
230 :
231 4 : if (!array_iterator(la, ltree_risparent, (void *) query, &found))
232 : {
233 2 : PG_FREE_IF_COPY(la, 0);
234 2 : PG_FREE_IF_COPY(query, 1);
235 2 : PG_RETURN_NULL();
236 : }
237 :
238 2 : item = (ltree *) palloc0(VARSIZE(found));
239 2 : memcpy(item, found, VARSIZE(found));
240 :
241 2 : PG_FREE_IF_COPY(la, 0);
242 2 : PG_FREE_IF_COPY(query, 1);
243 2 : PG_RETURN_POINTER(item);
244 : }
245 :
246 : Datum
247 2 : _ltq_extract_regex(PG_FUNCTION_ARGS)
248 : {
249 2 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
250 2 : lquery *query = PG_GETARG_LQUERY_P(1);
251 : ltree *found,
252 : *item;
253 :
254 2 : if (!array_iterator(la, ltq_regex, (void *) 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 2 : item = (ltree *) palloc0(VARSIZE(found));
262 2 : memcpy(item, found, VARSIZE(found));
263 :
264 2 : PG_FREE_IF_COPY(la, 0);
265 2 : PG_FREE_IF_COPY(query, 1);
266 2 : PG_RETURN_POINTER(item);
267 : }
268 :
269 : Datum
270 2 : _ltxtq_extract_exec(PG_FUNCTION_ARGS)
271 : {
272 2 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
273 2 : ltxtquery *query = PG_GETARG_LTXTQUERY_P(1);
274 : ltree *found,
275 : *item;
276 :
277 2 : if (!array_iterator(la, ltxtq_exec, (void *) 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 2 : item = (ltree *) palloc0(VARSIZE(found));
285 2 : memcpy(item, found, VARSIZE(found));
286 :
287 2 : PG_FREE_IF_COPY(la, 0);
288 2 : PG_FREE_IF_COPY(query, 1);
289 2 : PG_RETURN_POINTER(item);
290 : }
291 :
292 : Datum
293 16 : _lca(PG_FUNCTION_ARGS)
294 : {
295 16 : ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
296 16 : int num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la));
297 16 : ltree *item = (ltree *) ARR_DATA_PTR(la);
298 : ltree **a,
299 : *res;
300 :
301 16 : if (ARR_NDIM(la) > 1)
302 0 : ereport(ERROR,
303 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
304 : errmsg("array must be one-dimensional")));
305 16 : 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 16 : a = (ltree **) palloc(sizeof(ltree *) * num);
311 40 : while (num > 0)
312 : {
313 24 : num--;
314 24 : a[num] = item;
315 24 : item = NEXTVAL(item);
316 : }
317 16 : res = lca_inner(a, ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la)));
318 16 : pfree(a);
319 :
320 16 : PG_FREE_IF_COPY(la, 0);
321 :
322 16 : if (res)
323 12 : PG_RETURN_POINTER(res);
324 : else
325 4 : PG_RETURN_NULL();
326 : }
|