diff options
Diffstat (limited to 'contrib/intarray/_int_op.c')
-rw-r--r-- | contrib/intarray/_int_op.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/contrib/intarray/_int_op.c b/contrib/intarray/_int_op.c new file mode 100644 index 0000000..5b164f6 --- /dev/null +++ b/contrib/intarray/_int_op.c @@ -0,0 +1,432 @@ +/* + * contrib/intarray/_int_op.c + */ +#include "postgres.h" + +#include "_int.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(_int_different); +PG_FUNCTION_INFO_V1(_int_same); +PG_FUNCTION_INFO_V1(_int_contains); +PG_FUNCTION_INFO_V1(_int_contained); +PG_FUNCTION_INFO_V1(_int_overlap); +PG_FUNCTION_INFO_V1(_int_union); +PG_FUNCTION_INFO_V1(_int_inter); + +Datum +_int_contained(PG_FUNCTION_ARGS) +{ + /* just reverse the operands and call _int_contains */ + return DirectFunctionCall2(_int_contains, + PG_GETARG_DATUM(1), + PG_GETARG_DATUM(0)); +} + +Datum +_int_contains(PG_FUNCTION_ARGS) +{ + /* Force copy so we can modify the arrays in-place */ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); + bool res; + + CHECKARRVALID(a); + CHECKARRVALID(b); + PREPAREARR(a); + PREPAREARR(b); + res = inner_int_contains(a, b); + pfree(a); + pfree(b); + PG_RETURN_BOOL(res); +} + +Datum +_int_different(PG_FUNCTION_ARGS) +{ + PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(_int_same, + PointerGetDatum(PG_GETARG_POINTER(0)), + PointerGetDatum(PG_GETARG_POINTER(1))))); +} + +Datum +_int_same(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); + int na, + nb; + int n; + int *da, + *db; + bool result; + + CHECKARRVALID(a); + CHECKARRVALID(b); + na = ARRNELEMS(a); + nb = ARRNELEMS(b); + da = ARRPTR(a); + db = ARRPTR(b); + + result = false; + + if (na == nb) + { + SORT(a); + SORT(b); + result = true; + + for (n = 0; n < na; n++) + { + if (da[n] != db[n]) + { + result = false; + break; + } + } + } + + pfree(a); + pfree(b); + + PG_RETURN_BOOL(result); +} + +/* _int_overlap -- does a overlap b? + */ +Datum +_int_overlap(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); + bool result; + + CHECKARRVALID(a); + CHECKARRVALID(b); + if (ARRISEMPTY(a) || ARRISEMPTY(b)) + return false; + + SORT(a); + SORT(b); + + result = inner_int_overlap(a, b); + + pfree(a); + pfree(b); + + PG_RETURN_BOOL(result); +} + +Datum +_int_union(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); + ArrayType *result; + + CHECKARRVALID(a); + CHECKARRVALID(b); + + SORT(a); + SORT(b); + + result = inner_int_union(a, b); + + pfree(a); + pfree(b); + + PG_RETURN_POINTER(result); +} + +Datum +_int_inter(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); + ArrayType *result; + + CHECKARRVALID(a); + CHECKARRVALID(b); + + SORT(a); + SORT(b); + + result = inner_int_inter(a, b); + + pfree(a); + pfree(b); + + PG_RETURN_POINTER(result); +} + + +PG_FUNCTION_INFO_V1(intset); +PG_FUNCTION_INFO_V1(icount); +PG_FUNCTION_INFO_V1(sort); +PG_FUNCTION_INFO_V1(sort_asc); +PG_FUNCTION_INFO_V1(sort_desc); +PG_FUNCTION_INFO_V1(uniq); +PG_FUNCTION_INFO_V1(idx); +PG_FUNCTION_INFO_V1(subarray); +PG_FUNCTION_INFO_V1(intarray_push_elem); +PG_FUNCTION_INFO_V1(intarray_push_array); +PG_FUNCTION_INFO_V1(intarray_del_elem); +PG_FUNCTION_INFO_V1(intset_union_elem); +PG_FUNCTION_INFO_V1(intset_subtract); + +Datum +intset(PG_FUNCTION_ARGS) +{ + PG_RETURN_POINTER(int_to_intset(PG_GETARG_INT32(0))); +} + +Datum +icount(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); + int32 count = ARRNELEMS(a); + + PG_FREE_IF_COPY(a, 0); + PG_RETURN_INT32(count); +} + +Datum +sort(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + text *dirstr = (fcinfo->nargs == 2) ? PG_GETARG_TEXT_PP(1) : NULL; + int32 dc = (dirstr) ? VARSIZE_ANY_EXHDR(dirstr) : 0; + char *d = (dirstr) ? VARDATA_ANY(dirstr) : NULL; + int dir = -1; + + CHECKARRVALID(a); + if (ARRNELEMS(a) < 2) + PG_RETURN_POINTER(a); + + if (dirstr == NULL || (dc == 3 + && (d[0] == 'A' || d[0] == 'a') + && (d[1] == 'S' || d[1] == 's') + && (d[2] == 'C' || d[2] == 'c'))) + dir = 1; + else if (dc == 4 + && (d[0] == 'D' || d[0] == 'd') + && (d[1] == 'E' || d[1] == 'e') + && (d[2] == 'S' || d[2] == 's') + && (d[3] == 'C' || d[3] == 'c')) + dir = 0; + if (dir == -1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("second parameter must be \"ASC\" or \"DESC\""))); + QSORT(a, dir); + PG_RETURN_POINTER(a); +} + +Datum +sort_asc(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + + CHECKARRVALID(a); + QSORT(a, 1); + PG_RETURN_POINTER(a); +} + +Datum +sort_desc(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + + CHECKARRVALID(a); + QSORT(a, 0); + PG_RETURN_POINTER(a); +} + +Datum +uniq(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + + CHECKARRVALID(a); + if (ARRNELEMS(a) < 2) + PG_RETURN_POINTER(a); + a = _int_unique(a); + PG_RETURN_POINTER(a); +} + +Datum +idx(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); + int32 result; + + CHECKARRVALID(a); + result = ARRNELEMS(a); + if (result) + result = intarray_match_first(a, PG_GETARG_INT32(1)); + PG_FREE_IF_COPY(a, 0); + PG_RETURN_INT32(result); +} + +Datum +subarray(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); + int32 start = PG_GETARG_INT32(1); + int32 len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0; + int32 end = 0; + int32 c; + ArrayType *result; + + start = (start > 0) ? start - 1 : start; + + CHECKARRVALID(a); + if (ARRISEMPTY(a)) + { + PG_FREE_IF_COPY(a, 0); + PG_RETURN_POINTER(new_intArrayType(0)); + } + + c = ARRNELEMS(a); + + if (start < 0) + start = c + start; + + if (len < 0) + end = c + len; + else if (len == 0) + end = c; + else + end = start + len; + + if (end > c) + end = c; + + if (start < 0) + start = 0; + + if (start >= end || end <= 0) + { + PG_FREE_IF_COPY(a, 0); + PG_RETURN_POINTER(new_intArrayType(0)); + } + + result = new_intArrayType(end - start); + if (end - start > 0) + memcpy(ARRPTR(result), ARRPTR(a) + start, (end - start) * sizeof(int32)); + PG_FREE_IF_COPY(a, 0); + PG_RETURN_POINTER(result); +} + +Datum +intarray_push_elem(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); + ArrayType *result; + + result = intarray_add_elem(a, PG_GETARG_INT32(1)); + PG_FREE_IF_COPY(a, 0); + PG_RETURN_POINTER(result); +} + +Datum +intarray_push_array(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P(1); + ArrayType *result; + + result = intarray_concat_arrays(a, b); + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_POINTER(result); +} + +Datum +intarray_del_elem(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + int32 elem = PG_GETARG_INT32(1); + int32 c; + int32 *aa; + int32 n = 0, + i; + + CHECKARRVALID(a); + if (!ARRISEMPTY(a)) + { + c = ARRNELEMS(a); + aa = ARRPTR(a); + for (i = 0; i < c; i++) + { + if (aa[i] != elem) + { + if (i > n) + aa[n++] = aa[i]; + else + n++; + } + } + a = resize_intArrayType(a, n); + } + PG_RETURN_POINTER(a); +} + +Datum +intset_union_elem(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P(0); + ArrayType *result; + + result = intarray_add_elem(a, PG_GETARG_INT32(1)); + PG_FREE_IF_COPY(a, 0); + QSORT(result, 1); + PG_RETURN_POINTER(_int_unique(result)); +} + +Datum +intset_subtract(PG_FUNCTION_ARGS) +{ + ArrayType *a = PG_GETARG_ARRAYTYPE_P_COPY(0); + ArrayType *b = PG_GETARG_ARRAYTYPE_P_COPY(1); + ArrayType *result; + int32 ca; + int32 cb; + int32 *aa, + *bb, + *r; + int32 n = 0, + i = 0, + k = 0; + + CHECKARRVALID(a); + CHECKARRVALID(b); + + QSORT(a, 1); + a = _int_unique(a); + ca = ARRNELEMS(a); + QSORT(b, 1); + b = _int_unique(b); + cb = ARRNELEMS(b); + result = new_intArrayType(ca); + aa = ARRPTR(a); + bb = ARRPTR(b); + r = ARRPTR(result); + while (i < ca) + { + if (k == cb || aa[i] < bb[k]) + r[n++] = aa[i++]; + else if (aa[i] == bb[k]) + { + i++; + k++; + } + else + k++; + } + result = resize_intArrayType(result, n); + pfree(a); + pfree(b); + PG_RETURN_POINTER(result); +} |