/* * contrib/ltree/_ltree_op.c * * * op function for ltree[] * Teodor Sigaev */ #include "postgres.h" #include #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(); }