mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	By project convention, these names should include "P" when dealing with a pointer type; that is, if the result of a GETARG macro is of type FOO *, it should be called PG_GETARG_FOO_P not just PG_GETARG_FOO. Some newer types such as JSONB and ranges had not followed the convention, and a number of contrib modules hadn't gotten that memo either. Rename the offending macros to improve consistency. In passing, fix a few places that thought PG_DETOAST_DATUM() returns a Datum; it does not, it returns "struct varlena *". Applying DatumGetPointer to that happens not to cause any bad effects today, but it's formally wrong. Also, adjust an ltree macro that was designed without any thought for what pgindent would do with it. This is all cosmetic and shouldn't have any impact on generated code. Mark Dilger, some further tweaks by me Discussion: https://postgr.es/m/EA5676F4-766F-4F38-8348-ECC7DB427C6A@gmail.com
		
			
				
	
	
		
			326 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * contrib/ltree/_ltree_op.c
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * op function for ltree[]
 | 
						|
 * Teodor Sigaev <teodor@stack.net>
 | 
						|
 */
 | 
						|
#include "postgres.h"
 | 
						|
 | 
						|
#include <ctype.h>
 | 
						|
 | 
						|
#include "ltree.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();
 | 
						|
}
 |