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 : }
|