diff options
Diffstat (limited to 'contrib/ltree/_ltree_op.c')
-rw-r--r-- | contrib/ltree/_ltree_op.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/contrib/ltree/_ltree_op.c b/contrib/ltree/_ltree_op.c new file mode 100644 index 0000000..2fdb5ea --- /dev/null +++ b/contrib/ltree/_ltree_op.c @@ -0,0 +1,326 @@ +/* + * contrib/ltree/_ltree_op.c + * + * + * op function for ltree[] + * Teodor Sigaev <teodor@stack.net> + */ +#include "postgres.h" + +#include <ctype.h> + +#include "ltree.h" +#include "utils/array.h" + +PG_FUNCTION_INFO_V1(_ltree_isparent); +PG_FUNCTION_INFO_V1(_ltree_r_isparent); +PG_FUNCTION_INFO_V1(_ltree_risparent); +PG_FUNCTION_INFO_V1(_ltree_r_risparent); +PG_FUNCTION_INFO_V1(_ltq_regex); +PG_FUNCTION_INFO_V1(_ltq_rregex); +PG_FUNCTION_INFO_V1(_lt_q_regex); +PG_FUNCTION_INFO_V1(_lt_q_rregex); +PG_FUNCTION_INFO_V1(_ltxtq_exec); +PG_FUNCTION_INFO_V1(_ltxtq_rexec); + +PG_FUNCTION_INFO_V1(_ltree_extract_isparent); +PG_FUNCTION_INFO_V1(_ltree_extract_risparent); +PG_FUNCTION_INFO_V1(_ltq_extract_regex); +PG_FUNCTION_INFO_V1(_ltxtq_extract_exec); + +PG_FUNCTION_INFO_V1(_lca); + +typedef Datum (*PGCALL2) (PG_FUNCTION_ARGS); + +#define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) + +static bool +array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree **found) +{ + int num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la)); + ltree *item = (ltree *) ARR_DATA_PTR(la); + + if (ARR_NDIM(la) > 1) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("array must be one-dimensional"))); + if (array_contains_nulls(la)) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("array must not contain nulls"))); + + if (found) + *found = NULL; + while (num > 0) + { + if (DatumGetBool(DirectFunctionCall2(callback, + PointerGetDatum(item), PointerGetDatum(param)))) + { + + if (found) + *found = item; + return true; + } + num--; + item = NEXTVAL(item); + } + + return false; +} + +Datum +_ltree_isparent(PG_FUNCTION_ARGS) +{ + ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); + ltree *query = PG_GETARG_LTREE_P(1); + bool res = array_iterator(la, ltree_isparent, (void *) query, NULL); + + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_BOOL(res); +} + +Datum +_ltree_r_isparent(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(DirectFunctionCall2(_ltree_isparent, + PG_GETARG_DATUM(1), + PG_GETARG_DATUM(0) + )); +} + +Datum +_ltree_risparent(PG_FUNCTION_ARGS) +{ + ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); + ltree *query = PG_GETARG_LTREE_P(1); + bool res = array_iterator(la, ltree_risparent, (void *) query, NULL); + + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_BOOL(res); +} + +Datum +_ltree_r_risparent(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(DirectFunctionCall2(_ltree_risparent, + PG_GETARG_DATUM(1), + PG_GETARG_DATUM(0) + )); +} + +Datum +_ltq_regex(PG_FUNCTION_ARGS) +{ + ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); + lquery *query = PG_GETARG_LQUERY_P(1); + bool res = array_iterator(la, ltq_regex, (void *) query, NULL); + + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_BOOL(res); +} + +Datum +_ltq_rregex(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(DirectFunctionCall2(_ltq_regex, + PG_GETARG_DATUM(1), + PG_GETARG_DATUM(0) + )); +} + +Datum +_lt_q_regex(PG_FUNCTION_ARGS) +{ + ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0); + ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1); + lquery *query = (lquery *) ARR_DATA_PTR(_query); + bool res = false; + int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); + + if (ARR_NDIM(_query) > 1) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("array must be one-dimensional"))); + if (array_contains_nulls(_query)) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("array must not contain nulls"))); + + while (num > 0) + { + if (array_iterator(_tree, ltq_regex, (void *) query, NULL)) + { + res = true; + break; + } + num--; + query = (lquery *) NEXTVAL(query); + } + + PG_FREE_IF_COPY(_tree, 0); + PG_FREE_IF_COPY(_query, 1); + PG_RETURN_BOOL(res); +} + +Datum +_lt_q_rregex(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(DirectFunctionCall2(_lt_q_regex, + PG_GETARG_DATUM(1), + PG_GETARG_DATUM(0) + )); +} + + +Datum +_ltxtq_exec(PG_FUNCTION_ARGS) +{ + ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); + ltxtquery *query = PG_GETARG_LTXTQUERY_P(1); + bool res = array_iterator(la, ltxtq_exec, (void *) query, NULL); + + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_BOOL(res); +} + +Datum +_ltxtq_rexec(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(DirectFunctionCall2(_ltxtq_exec, + PG_GETARG_DATUM(1), + PG_GETARG_DATUM(0) + )); +} + + +Datum +_ltree_extract_isparent(PG_FUNCTION_ARGS) +{ + ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); + ltree *query = PG_GETARG_LTREE_P(1); + ltree *found, + *item; + + if (!array_iterator(la, ltree_isparent, (void *) query, &found)) + { + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_NULL(); + } + + item = (ltree *) palloc0(VARSIZE(found)); + memcpy(item, found, VARSIZE(found)); + + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_POINTER(item); +} + +Datum +_ltree_extract_risparent(PG_FUNCTION_ARGS) +{ + ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); + ltree *query = PG_GETARG_LTREE_P(1); + ltree *found, + *item; + + if (!array_iterator(la, ltree_risparent, (void *) query, &found)) + { + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_NULL(); + } + + item = (ltree *) palloc0(VARSIZE(found)); + memcpy(item, found, VARSIZE(found)); + + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_POINTER(item); +} + +Datum +_ltq_extract_regex(PG_FUNCTION_ARGS) +{ + ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); + lquery *query = PG_GETARG_LQUERY_P(1); + ltree *found, + *item; + + if (!array_iterator(la, ltq_regex, (void *) query, &found)) + { + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_NULL(); + } + + item = (ltree *) palloc0(VARSIZE(found)); + memcpy(item, found, VARSIZE(found)); + + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_POINTER(item); +} + +Datum +_ltxtq_extract_exec(PG_FUNCTION_ARGS) +{ + ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); + ltxtquery *query = PG_GETARG_LTXTQUERY_P(1); + ltree *found, + *item; + + if (!array_iterator(la, ltxtq_exec, (void *) query, &found)) + { + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_NULL(); + } + + item = (ltree *) palloc0(VARSIZE(found)); + memcpy(item, found, VARSIZE(found)); + + PG_FREE_IF_COPY(la, 0); + PG_FREE_IF_COPY(query, 1); + PG_RETURN_POINTER(item); +} + +Datum +_lca(PG_FUNCTION_ARGS) +{ + ArrayType *la = PG_GETARG_ARRAYTYPE_P(0); + int num = ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la)); + ltree *item = (ltree *) ARR_DATA_PTR(la); + ltree **a, + *res; + + if (ARR_NDIM(la) > 1) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("array must be one-dimensional"))); + if (array_contains_nulls(la)) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("array must not contain nulls"))); + + a = (ltree **) palloc(sizeof(ltree *) * num); + while (num > 0) + { + num--; + a[num] = item; + item = NEXTVAL(item); + } + res = lca_inner(a, ArrayGetNItems(ARR_NDIM(la), ARR_DIMS(la))); + pfree(a); + + PG_FREE_IF_COPY(la, 0); + + if (res) + PG_RETURN_POINTER(res); + else + PG_RETURN_NULL(); +} |