1 /*
2  * contrib/intarray/_int_op.c
3  */
4 #include "postgres.h"
5 
6 
7 #include "_int.h"
8 
9 PG_MODULE_MAGIC;
10 
11 PG_FUNCTION_INFO_V1(_int_different);
12 PG_FUNCTION_INFO_V1(_int_same);
13 PG_FUNCTION_INFO_V1(_int_contains);
14 PG_FUNCTION_INFO_V1(_int_contained);
15 PG_FUNCTION_INFO_V1(_int_overlap);
16 PG_FUNCTION_INFO_V1(_int_union);
17 PG_FUNCTION_INFO_V1(_int_inter);
18 
19 Datum
_int_contained(PG_FUNCTION_ARGS)20 _int_contained(PG_FUNCTION_ARGS)
21 {
22 	/* just reverse the operands and call _int_contains */
23 	return DirectFunctionCall2(_int_contains,
24 							   PG_GETARG_DATUM(1),
25 							   PG_GETARG_DATUM(0));
26 }
27 
28 Datum
_int_contains(PG_FUNCTION_ARGS)29 _int_contains(PG_FUNCTION_ARGS)
30 {
31 	/* Force copy so we can modify the arrays in-place */
32 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
33 	ArrayType  *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
34 	bool		res;
35 
36 	CHECKARRVALID(a);
37 	CHECKARRVALID(b);
38 	PREPAREARR(a);
39 	PREPAREARR(b);
40 	res = inner_int_contains(a, b);
41 	pfree(a);
42 	pfree(b);
43 	PG_RETURN_BOOL(res);
44 }
45 
46 Datum
_int_different(PG_FUNCTION_ARGS)47 _int_different(PG_FUNCTION_ARGS)
48 {
49 	PG_RETURN_BOOL(!DatumGetBool(
50 								 DirectFunctionCall2(
51 													 _int_same,
52 													 PointerGetDatum(PG_GETARG_POINTER(0)),
53 													 PointerGetDatum(PG_GETARG_POINTER(1))
54 													 )
55 								 ));
56 }
57 
58 Datum
_int_same(PG_FUNCTION_ARGS)59 _int_same(PG_FUNCTION_ARGS)
60 {
61 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
62 	ArrayType  *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
63 	int			na,
64 				nb;
65 	int			n;
66 	int		   *da,
67 			   *db;
68 	bool		result;
69 
70 	CHECKARRVALID(a);
71 	CHECKARRVALID(b);
72 	na = ARRNELEMS(a);
73 	nb = ARRNELEMS(b);
74 	da = ARRPTR(a);
75 	db = ARRPTR(b);
76 
77 	result = FALSE;
78 
79 	if (na == nb)
80 	{
81 		SORT(a);
82 		SORT(b);
83 		result = TRUE;
84 
85 		for (n = 0; n < na; n++)
86 		{
87 			if (da[n] != db[n])
88 			{
89 				result = FALSE;
90 				break;
91 			}
92 		}
93 	}
94 
95 	pfree(a);
96 	pfree(b);
97 
98 	PG_RETURN_BOOL(result);
99 }
100 
101 /*	_int_overlap -- does a overlap b?
102  */
103 Datum
_int_overlap(PG_FUNCTION_ARGS)104 _int_overlap(PG_FUNCTION_ARGS)
105 {
106 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
107 	ArrayType  *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
108 	bool		result;
109 
110 	CHECKARRVALID(a);
111 	CHECKARRVALID(b);
112 	if (ARRISEMPTY(a) || ARRISEMPTY(b))
113 		return FALSE;
114 
115 	SORT(a);
116 	SORT(b);
117 
118 	result = inner_int_overlap(a, b);
119 
120 	pfree(a);
121 	pfree(b);
122 
123 	PG_RETURN_BOOL(result);
124 }
125 
126 Datum
_int_union(PG_FUNCTION_ARGS)127 _int_union(PG_FUNCTION_ARGS)
128 {
129 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
130 	ArrayType  *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
131 	ArrayType  *result;
132 
133 	CHECKARRVALID(a);
134 	CHECKARRVALID(b);
135 
136 	SORT(a);
137 	SORT(b);
138 
139 	result = inner_int_union(a, b);
140 
141 	pfree(a);
142 	pfree(b);
143 
144 	PG_RETURN_POINTER(result);
145 }
146 
147 Datum
_int_inter(PG_FUNCTION_ARGS)148 _int_inter(PG_FUNCTION_ARGS)
149 {
150 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
151 	ArrayType  *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
152 	ArrayType  *result;
153 
154 	CHECKARRVALID(a);
155 	CHECKARRVALID(b);
156 
157 	SORT(a);
158 	SORT(b);
159 
160 	result = inner_int_inter(a, b);
161 
162 	pfree(a);
163 	pfree(b);
164 
165 	PG_RETURN_POINTER(result);
166 }
167 
168 
169 PG_FUNCTION_INFO_V1(intset);
170 PG_FUNCTION_INFO_V1(icount);
171 PG_FUNCTION_INFO_V1(sort);
172 PG_FUNCTION_INFO_V1(sort_asc);
173 PG_FUNCTION_INFO_V1(sort_desc);
174 PG_FUNCTION_INFO_V1(uniq);
175 PG_FUNCTION_INFO_V1(idx);
176 PG_FUNCTION_INFO_V1(subarray);
177 PG_FUNCTION_INFO_V1(intarray_push_elem);
178 PG_FUNCTION_INFO_V1(intarray_push_array);
179 PG_FUNCTION_INFO_V1(intarray_del_elem);
180 PG_FUNCTION_INFO_V1(intset_union_elem);
181 PG_FUNCTION_INFO_V1(intset_subtract);
182 
183 Datum
intset(PG_FUNCTION_ARGS)184 intset(PG_FUNCTION_ARGS)
185 {
186 	PG_RETURN_POINTER(int_to_intset(PG_GETARG_INT32(0)));
187 }
188 
189 Datum
icount(PG_FUNCTION_ARGS)190 icount(PG_FUNCTION_ARGS)
191 {
192 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P(0);
193 	int32		count = ARRNELEMS(a);
194 
195 	PG_FREE_IF_COPY(a, 0);
196 	PG_RETURN_INT32(count);
197 }
198 
199 Datum
sort(PG_FUNCTION_ARGS)200 sort(PG_FUNCTION_ARGS)
201 {
202 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
203 	text	   *dirstr = (fcinfo->nargs == 2) ? PG_GETARG_TEXT_PP(1) : NULL;
204 	int32		dc = (dirstr) ? VARSIZE_ANY_EXHDR(dirstr) : 0;
205 	char	   *d = (dirstr) ? VARDATA_ANY(dirstr) : NULL;
206 	int			dir = -1;
207 
208 	CHECKARRVALID(a);
209 	if (ARRNELEMS(a) < 2)
210 		PG_RETURN_POINTER(a);
211 
212 	if (dirstr == NULL || (dc == 3
213 						   && (d[0] == 'A' || d[0] == 'a')
214 						   && (d[1] == 'S' || d[1] == 's')
215 						   && (d[2] == 'C' || d[2] == 'c')))
216 		dir = 1;
217 	else if (dc == 4
218 			 && (d[0] == 'D' || d[0] == 'd')
219 			 && (d[1] == 'E' || d[1] == 'e')
220 			 && (d[2] == 'S' || d[2] == 's')
221 			 && (d[3] == 'C' || d[3] == 'c'))
222 		dir = 0;
223 	if (dir == -1)
224 		ereport(ERROR,
225 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
226 				 errmsg("second parameter must be \"ASC\" or \"DESC\"")));
227 	QSORT(a, dir);
228 	PG_RETURN_POINTER(a);
229 }
230 
231 Datum
sort_asc(PG_FUNCTION_ARGS)232 sort_asc(PG_FUNCTION_ARGS)
233 {
234 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
235 
236 	CHECKARRVALID(a);
237 	QSORT(a, 1);
238 	PG_RETURN_POINTER(a);
239 }
240 
241 Datum
sort_desc(PG_FUNCTION_ARGS)242 sort_desc(PG_FUNCTION_ARGS)
243 {
244 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
245 
246 	CHECKARRVALID(a);
247 	QSORT(a, 0);
248 	PG_RETURN_POINTER(a);
249 }
250 
251 Datum
uniq(PG_FUNCTION_ARGS)252 uniq(PG_FUNCTION_ARGS)
253 {
254 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
255 
256 	CHECKARRVALID(a);
257 	if (ARRNELEMS(a) < 2)
258 		PG_RETURN_POINTER(a);
259 	a = _int_unique(a);
260 	PG_RETURN_POINTER(a);
261 }
262 
263 Datum
idx(PG_FUNCTION_ARGS)264 idx(PG_FUNCTION_ARGS)
265 {
266 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P(0);
267 	int32		result;
268 
269 	CHECKARRVALID(a);
270 	result = ARRNELEMS(a);
271 	if (result)
272 		result = intarray_match_first(a, PG_GETARG_INT32(1));
273 	PG_FREE_IF_COPY(a, 0);
274 	PG_RETURN_INT32(result);
275 }
276 
277 Datum
subarray(PG_FUNCTION_ARGS)278 subarray(PG_FUNCTION_ARGS)
279 {
280 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P(0);
281 	int32		start = PG_GETARG_INT32(1);
282 	int32		len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
283 	int32		end = 0;
284 	int32		c;
285 	ArrayType  *result;
286 
287 	start = (start > 0) ? start - 1 : start;
288 
289 	CHECKARRVALID(a);
290 	if (ARRISEMPTY(a))
291 	{
292 		PG_FREE_IF_COPY(a, 0);
293 		PG_RETURN_POINTER(new_intArrayType(0));
294 	}
295 
296 	c = ARRNELEMS(a);
297 
298 	if (start < 0)
299 		start = c + start;
300 
301 	if (len < 0)
302 		end = c + len;
303 	else if (len == 0)
304 		end = c;
305 	else
306 		end = start + len;
307 
308 	if (end > c)
309 		end = c;
310 
311 	if (start < 0)
312 		start = 0;
313 
314 	if (start >= end || end <= 0)
315 	{
316 		PG_FREE_IF_COPY(a, 0);
317 		PG_RETURN_POINTER(new_intArrayType(0));
318 	}
319 
320 	result = new_intArrayType(end - start);
321 	if (end - start > 0)
322 		memcpy(ARRPTR(result), ARRPTR(a) + start, (end - start) * sizeof(int32));
323 	PG_FREE_IF_COPY(a, 0);
324 	PG_RETURN_POINTER(result);
325 }
326 
327 Datum
intarray_push_elem(PG_FUNCTION_ARGS)328 intarray_push_elem(PG_FUNCTION_ARGS)
329 {
330 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P(0);
331 	ArrayType  *result;
332 
333 	result = intarray_add_elem(a, PG_GETARG_INT32(1));
334 	PG_FREE_IF_COPY(a, 0);
335 	PG_RETURN_POINTER(result);
336 }
337 
338 Datum
intarray_push_array(PG_FUNCTION_ARGS)339 intarray_push_array(PG_FUNCTION_ARGS)
340 {
341 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P(0);
342 	ArrayType  *b = PG_GETARG_ARRAYTYPE_P(1);
343 	ArrayType  *result;
344 
345 	result = intarray_concat_arrays(a, b);
346 	PG_FREE_IF_COPY(a, 0);
347 	PG_FREE_IF_COPY(b, 1);
348 	PG_RETURN_POINTER(result);
349 }
350 
351 Datum
intarray_del_elem(PG_FUNCTION_ARGS)352 intarray_del_elem(PG_FUNCTION_ARGS)
353 {
354 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
355 	int32		elem = PG_GETARG_INT32(1);
356 	int32		c;
357 	int32	   *aa;
358 	int32		n = 0,
359 				i;
360 
361 	CHECKARRVALID(a);
362 	if (!ARRISEMPTY(a))
363 	{
364 		c = ARRNELEMS(a);
365 		aa = ARRPTR(a);
366 		for (i = 0; i < c; i++)
367 		{
368 			if (aa[i] != elem)
369 			{
370 				if (i > n)
371 					aa[n++] = aa[i];
372 				else
373 					n++;
374 			}
375 		}
376 		a = resize_intArrayType(a, n);
377 	}
378 	PG_RETURN_POINTER(a);
379 }
380 
381 Datum
intset_union_elem(PG_FUNCTION_ARGS)382 intset_union_elem(PG_FUNCTION_ARGS)
383 {
384 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P(0);
385 	ArrayType  *result;
386 
387 	result = intarray_add_elem(a, PG_GETARG_INT32(1));
388 	PG_FREE_IF_COPY(a, 0);
389 	QSORT(result, 1);
390 	PG_RETURN_POINTER(_int_unique(result));
391 }
392 
393 Datum
intset_subtract(PG_FUNCTION_ARGS)394 intset_subtract(PG_FUNCTION_ARGS)
395 {
396 	ArrayType  *a = PG_GETARG_ARRAYTYPE_P_COPY(0);
397 	ArrayType  *b = PG_GETARG_ARRAYTYPE_P_COPY(1);
398 	ArrayType  *result;
399 	int32		ca;
400 	int32		cb;
401 	int32	   *aa,
402 			   *bb,
403 			   *r;
404 	int32		n = 0,
405 				i = 0,
406 				k = 0;
407 
408 	CHECKARRVALID(a);
409 	CHECKARRVALID(b);
410 
411 	QSORT(a, 1);
412 	a = _int_unique(a);
413 	ca = ARRNELEMS(a);
414 	QSORT(b, 1);
415 	b = _int_unique(b);
416 	cb = ARRNELEMS(b);
417 	result = new_intArrayType(ca);
418 	aa = ARRPTR(a);
419 	bb = ARRPTR(b);
420 	r = ARRPTR(result);
421 	while (i < ca)
422 	{
423 		if (k == cb || aa[i] < bb[k])
424 			r[n++] = aa[i++];
425 		else if (aa[i] == bb[k])
426 		{
427 			i++;
428 			k++;
429 		}
430 		else
431 			k++;
432 	}
433 	result = resize_intArrayType(result, n);
434 	pfree(a);
435 	pfree(b);
436 	PG_RETURN_POINTER(result);
437 }
438