postgresql/contrib/ltree/_ltree_op.c
Tom Lane 5cabcfccce Modify array operations to include array's element type OID in the
array header, and to compute sizing and alignment of array elements
the same way normal tuple access operations do --- viz, using the
tupmacs.h macros att_addlength and att_align.  This makes the world
safe for arrays of cstrings or intervals, and should make it much
easier to write array-type-polymorphic functions; as examples see
the cleanups of array_out and contrib/array_iterator.  By Joe Conway
and Tom Lane.
2002-08-26 17:54:02 +00:00

239 lines
5.5 KiB
C

/*
* op function for ltree[]
* Teodor Sigaev <teodor@stack.net>
*/
#include "ltree.h"
#include <ctype.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(_ltxtq_exec);
PG_FUNCTION_INFO_V1(_ltxtq_rexec);
Datum _ltree_r_isparent(PG_FUNCTION_ARGS);
Datum _ltree_r_risparent(PG_FUNCTION_ARGS);
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);
Datum _ltree_extract_isparent(PG_FUNCTION_ARGS);
Datum _ltree_extract_risparent(PG_FUNCTION_ARGS);
Datum _ltq_extract_regex(PG_FUNCTION_ARGS);
Datum _ltxtq_extract_exec(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(_lca);
Datum _lca(PG_FUNCTION_ARGS);
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 )
elog(ERROR,"Dimension of array != 1");
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(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(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(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
_ltxtq_exec(PG_FUNCTION_ARGS) {
ArrayType *la = PG_GETARG_ARRAYTYPE_P(0);
ltxtquery *query = PG_GETARG_LTXTQUERY(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(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*)palloc( found->len );
memcpy( item, found, found->len );
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(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*)palloc( found->len );
memcpy( item, found, found->len );
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(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*)palloc( found->len );
memcpy( item, found, found->len );
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(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*)palloc( found->len );
memcpy( item, found, found->len );
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;
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();
}