Esempio n. 1
0
/*
 * Find 'findelem' within array 'v'. Returns -1 if not found in an array
 * without any NULL elements, NULL if not found but one or more NULLs appeared
 * in the array.
 *
 * Declared STRICT, must not be called with NULL input(s).
 */
Datum
array_idx(PG_FUNCTION_ARGS)
{
    Datum        findelem = PG_GETARG_DATUM(0);
    ArrayType    *v = PG_GETARG_ARRAYTYPE_P(1);

    Oid          arg0_typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
    Oid          arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
    Oid          arg0_elemid;
    Oid          arg1_elemid;
    Oid          element_type;

    int16        typlen;
    bool         typbyval;
    char         typalign;

    Datum        *elems;
    bool         *nulls;
    int          nelems;

    Datum        cur_elem;
    bool         has_nulls;

    int i;
    

    if (ARR_NDIM(v) == 0)
        PG_RETURN_NULL();
    else if (ARR_NDIM(v) != 1)
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
             errmsg("idx(...) only makes sense for one-dimensional arrays, not %i", ARR_NDIM(v))));

    element_type = ARR_ELEMTYPE(v);
    /* For optimal performance we'd get this from a syscache or cache it in the function
     * call context; see array_push in src/backend/utils/adt/array_userfuncs.c */
    get_typlenbyvalalign(element_type,
                         &typlen,
                         &typbyval,
                         &typalign);
    
    deconstruct_array(v, element_type, typlen, typbyval, typalign, &elems, &nulls, &nelems);

    has_nulls = false;
    for (i = 0; i < nelems; i++)
    {
        has_nulls |= nulls[i];
        cur_elem = elems[i];
        /* Compare find_elem for equality against cur_elem */
        PG_RETURN_INT(i+1);
    }
   
    if (has_nulls)
        PG_RETURN_NULL();
    else
        PG_RETURN_INT(-1);
}
Esempio n. 2
0
/**
 * @brief Internal function for determining the type of a function argument
 *
 * @param inID Number of function argument
 * @param[out] outTypeID PostgreSQL OID of the function argument's type
 * @param[out] outIsMutable True if the data structure of this function argument
 *     can be safely modified. For objects passed by reference (like arrays)
 *     this is only true when passed as the first argument of a transition
 *     function.
 *
 * @internal
 *     Having this as separate function isolates the PG_TRY block. Otherwise,
 *     the compiler might warn that the longjmp could clobber local variables.
 */
inline
void
AbstractionLayer::AnyType::backendGetTypeIDForFunctionArg(uint16_t inID,
    Oid &outTypeID, bool &outIsMutable) const {
    
    madlib_assert(mContent == FunctionComposite, std::logic_error(
        "Inconsistency detected while converting from PostgreSQL to C++ types."));
    
    bool exceptionOccurred = false;

    PG_TRY(); {
        outTypeID = get_fn_expr_argtype(fcinfo->flinfo, inID);    

        // If we are called as an aggregate function, the first argument is the
        // transition state. In that case, we are free to modify the data.
        // In fact, for performance reasons, we *should* even do all modifications
        // in-place. In all other cases, directly modifying memory is dangerous.
        // See warning at:
        // http://www.postgresql.org/docs/current/static/xfunc-c.html#XFUNC-C-BASETYPE
        outIsMutable = (inID == 0 && AggCheckCallContext(fcinfo, NULL));
    } PG_CATCH(); {
        exceptionOccurred = true;
    } PG_END_TRY();
    
    if (exceptionOccurred)
        throw PGException();
}
Esempio n. 3
0
/*
 * ARRAY_AGG aggregate function
 */
Datum
array_agg_transfn(PG_FUNCTION_ARGS)
{
	Oid			arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
	MemoryContext aggcontext;
	ArrayBuildState *state;
	Datum		elem;

	if (arg1_typeid == InvalidOid)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("could not determine input data type")));

	if (!AggCheckCallContext(fcinfo, &aggcontext))
	{
		/* cannot be called directly because of internal-type argument */
		elog(ERROR, "array_agg_transfn called in non-aggregate context");
	}

	state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
	elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
	state = accumArrayResult(state,
							 elem,
							 PG_ARGISNULL(1),
							 arg1_typeid,
							 aggcontext);

	/*
	 * The transition type for array_agg() is declared to be "internal", which
	 * is a pass-by-value type the same size as a pointer.	So we can safely
	 * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
	 */
	PG_RETURN_POINTER(state);
}
Esempio n. 4
0
/*
 * ARRAY_AGG aggregate function
 */
datum_t array_agg_transfn(PG_FUNC_ARGS)
{
	oid_t arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
	struct mctx * aggcontext;
	array_build_s *state;
	datum_t elem;

	if (arg1_typeid == INVALID_OID)
		ereport(ERROR, (
		errcode(E_INVALID_PARAMETER_VALUE),
		errmsg("could not determine input data type")));

	if (!AggCheckCallContext(fcinfo, &aggcontext)) {
		/* cannot be called directly because of internal-type argument */
		elog(ERROR, "array_agg_transfn called in non-aggregate context");
	}

	state = PG_ARG_ISNULL(0) ? NULL : (array_build_s *) ARG_POINTER(0);
	elem = PG_ARG_ISNULL(1) ? (datum_t) 0 : ARG_DATUM(1);
	state = accum_array_result(state, elem, PG_ARG_ISNULL(1), arg1_typeid, aggcontext);

	/*
	 * The transition type for array_agg() is declared to be "internal", which
	 * is a pass-by-value type the same size as a pointer.  So we can safely
	 * pass the array_build_s pointer through nodeAgg.c's machinations.
	 */
	RET_POINTER(state);
}
Esempio n. 5
0
static bool
assert_equals_base(FunctionCallInfo fcinfo)
{
	Datum 		value1 = PG_GETARG_DATUM(0);
	Datum		value2 = PG_GETARG_DATUM(1);
	Oid		*ptr;

	ptr = (Oid *) fcinfo->flinfo->fn_extra;
	if (ptr == NULL)
	{
		Oid	  valtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
		Oid eqopfcid;

		if (!OidIsValid(valtype))
	    		elog(ERROR, "could not determine data type of input");

		eqopfcid = equality_oper_funcid(valtype);

		if (!OidIsValid(eqopfcid))
			ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				errmsg("unknown equal operand for datatype")));

    		/* First time calling for current query: allocate storage */
        	fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
            						                    sizeof(Oid));
                ptr = (Oid *) fcinfo->flinfo->fn_extra;
                *ptr = eqopfcid;
        }

	return DatumGetBool(OidFunctionCall2(*ptr, value1, value2));
}
Esempio n. 6
0
/*
 * Returns whether the Bloom filter contains the item or not
 */
Datum
bloom_contains(PG_FUNCTION_ARGS)
{
	BloomFilter *bloom;
	Datum elem = PG_GETARG_DATUM(1);
	bool contains = false;
	Oid	val_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
	TypeCacheEntry *typ;
	StringInfo buf;

	if (val_type == InvalidOid)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("could not determine input data type")));

	if (PG_ARGISNULL(0))
		PG_RETURN_BOOL(contains);

	bloom = (BloomFilter *) PG_GETARG_VARLENA_P(0);
	typ = lookup_type_cache(val_type, 0);

	buf = makeStringInfo();
	DatumToBytes(elem, typ, buf);

	contains = BloomFilterContains(bloom, buf->data, buf->len);

	pfree(buf->data);
	pfree(buf);

	PG_RETURN_BOOL(contains);
}
Esempio n. 7
0
Datum
variant_cast_in(PG_FUNCTION_ARGS)
{
    VariantInt			vi = palloc0(sizeof(*vi));

    vi->isnull = PG_ARGISNULL(0);
    vi->typid = get_fn_expr_argtype(fcinfo->flinfo, 0);
    vi->typmod = get_fn_expr_argtypmod(fcinfo->flinfo, 0);

    Assert(!fcinfo->flinfo->fn_strict); /* Must be callable on NULL input */

    if (!OidIsValid(vi->typid))
        elog(ERROR, "could not determine data type of input");

    /* Validate that we're casting to a registered variant */
    if( PG_ARGISNULL(1) )
        elog( ERROR, "Target typemod must not be NULL" );
    variant_get_variant_name(PG_GETARG_INT32(1), vi->typid, false);

    if( !vi->isnull )
        vi->data = PG_GETARG_DATUM(0);

    /* Since we're casting in, we'll call for INFunc_input, even though we don't need it */
    PG_RETURN_VARIANT( make_variant(vi, fcinfo, IOFunc_input) );
}
Esempio n. 8
0
static BloomFilter *
bloom_operation(FunctionCallInfo fcinfo, bool intersection)
{
	Oid bf_type = LookupTypeNameOid(NULL, SystemTypeName("bloom"), false);
	BloomFilter *result = NULL;
	int i;

	for (i = 0; i < PG_NARGS(); i++)
	{
		BloomFilter *bf;
		if (PG_ARGISNULL(i))
			continue;

		if (get_fn_expr_argtype(fcinfo->flinfo, i) != bf_type)
			elog(ERROR, "argument %d is not of type \"bloom\"", i + 1);

		bf = (BloomFilter *) PG_GETARG_VARLENA_P(i);

		if (result)
		{
			if (bf->m != result->m)
				elog(ERROR, "bloom filters must have the same p");
			else if (bf->k != result->k)
				elog(ERROR, "bloom filters must have the same n");
		}
		if (result == NULL)
			result = bf;
		else if (intersection)
			result = BloomFilterIntersection(result, bf);
		else
			result = BloomFilterUnion(result, bf);
	}

	return result;
}
Esempio n. 9
0
/*
 * worker_hash returns the hashed value of the given value.
 */
Datum
worker_hash(PG_FUNCTION_ARGS)
{
	Datum valueDatum = PG_GETARG_DATUM(0);
	Datum hashedValueDatum = 0;
	TypeCacheEntry *typeEntry = NULL;
	FmgrInfo *hashFunction = NULL;
	Oid valueDataType = InvalidOid;

	/* figure out hash function from the data type */
	valueDataType = get_fn_expr_argtype(fcinfo->flinfo, 0);
	typeEntry = lookup_type_cache(valueDataType, TYPECACHE_HASH_PROC_FINFO);

	if (typeEntry->hash_proc_finfo.fn_oid == InvalidOid)
	{
		ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						errmsg("cannot find a hash function for the input type"),
						errhint("Cast input to a data type with a hash function.")));
	}

	hashFunction = palloc0(sizeof(FmgrInfo));
	fmgr_info_copy(hashFunction, &(typeEntry->hash_proc_finfo), CurrentMemoryContext);

	/* calculate hash value */
	hashedValueDatum = FunctionCall1(hashFunction, valueDatum);

	PG_RETURN_INT32(hashedValueDatum);
}
Esempio n. 10
0
Datum
enum_last(PG_FUNCTION_ARGS)
{
	Oid			enumtypoid;
	Oid			max;

	/*
	 * We rely on being able to get the specific enum type from the calling
	 * expression tree.  Notice that the actual value of the argument isn't
	 * examined at all; in particular it might be NULL.
	 */
	enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
	if (enumtypoid == InvalidOid)
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("could not determine actual enum type")));

	/* Get the OID using the index */
	max = enum_endpoint(enumtypoid, BackwardScanDirection);

	if (!OidIsValid(max))
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("enum %s contains no values",
						format_type_be(enumtypoid))));

	PG_RETURN_OID(max);
}
Esempio n. 11
0
/*
 * Returns the estimate normalized frequency of the item
 */
Datum
cmsketch_norm_frequency(PG_FUNCTION_ARGS)
{
	CountMinSketch *cms;
	Datum elem = PG_GETARG_DATUM(1);
	float8 freq = 0;
	Oid	val_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
	TypeCacheEntry *typ;
	StringInfo buf;

	if (val_type == InvalidOid)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("could not determine input data type")));

	if (PG_ARGISNULL(0))
		PG_RETURN_FLOAT8(freq);

	cms = (CountMinSketch *) PG_GETARG_VARLENA_P(0);
	typ = lookup_type_cache(val_type, 0);

	buf = makeStringInfo();
	DatumToBytes(elem, typ, buf);

	freq = CountMinSketchEstimateNormFrequency(cms, buf->data, buf->len);

	pfree(buf->data);
	pfree(buf);

	PG_RETURN_FLOAT8(freq);
}
Esempio n. 12
0
/* 2-argument variant of enum_range */
Datum
enum_range_bounds(PG_FUNCTION_ARGS)
{
	Oid			lower;
	Oid			upper;
	Oid			enumtypoid;

	if (PG_ARGISNULL(0))
		lower = InvalidOid;
	else
		lower = PG_GETARG_OID(0);
	if (PG_ARGISNULL(1))
		upper = InvalidOid;
	else
		upper = PG_GETARG_OID(1);

	/*
	 * We rely on being able to get the specific enum type from the calling
	 * expression tree.  The generic type mechanism should have ensured that
	 * both are of the same type.
	 */
	enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
	if (enumtypoid == InvalidOid)
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("could not determine actual enum type")));

	PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid, lower, upper));
}
Esempio n. 13
0
/*
 * cms_topn_frequency is a user-facing UDF which returns the estimated frequency
 * of an item. The first parameter is for CmsTopn and second is for the item to
 * return the frequency.
 */
Datum
cms_topn_frequency(PG_FUNCTION_ARGS)
{
	CmsTopn *cmsTopn = (CmsTopn *) PG_GETARG_VARLENA_P(0);
	ArrayType *topnArray = TopnArray(cmsTopn);
	Datum item = PG_GETARG_DATUM(1);
	Oid itemType = get_fn_expr_argtype(fcinfo->flinfo, 1);
	TypeCacheEntry *itemTypeCacheEntry = NULL;
	Frequency frequency = 0;

	if (itemType == InvalidOid)
	{
		ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
		                errmsg("could not determine input data types")));
	}

	if (topnArray != NULL && itemType != ARR_ELEMTYPE(topnArray))
	{
		ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
		                errmsg("Not proper type for this cms_topn")));
	}

	itemTypeCacheEntry = lookup_type_cache(itemType, 0);
	frequency = CmsTopnEstimateItemFrequency(cmsTopn, item, itemTypeCacheEntry);

	PG_RETURN_INT32(frequency);
}
Esempio n. 14
0
/*
 * Returns the estimate count of the item
 */
Datum
cmsketch_count(PG_FUNCTION_ARGS)
{
	CountMinSketch *cms;
	Datum elem = PG_GETARG_DATUM(1);
	uint32_t count = false;
	Oid	val_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
	TypeCacheEntry *typ;
	Size size;

	if (val_type == InvalidOid)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("could not determine input data type")));

	if (PG_ARGISNULL(0))
		PG_RETURN_INT32(count);

	cms = (CountMinSketch *) PG_GETARG_VARLENA_P(0);
	typ = lookup_type_cache(val_type, 0);
	size = datumGetSize(elem, typ->typbyval, typ->typlen);

	if (typ->typbyval)
		count = CountMinSketchEstimateCount(cms, (char *) &elem, size);
	else
		count = CountMinSketchEstimateCount(cms, DatumGetPointer(elem), size);

	PG_RETURN_INT32(count);
}
Esempio n. 15
0
Datum Function_invoke(Function self, PG_FUNCTION_ARGS)
{
	Datum retVal;
	int32 top;
	jvalue* args;
	Type  invokerType;

	fcinfo->isnull = false;
	currentInvocation->function = self;

	if(self->isUDT)
		return self->func.udt.udtFunction(self->func.udt.udt, fcinfo);

	if(self->func.nonudt.isMultiCall && SRF_IS_FIRSTCALL())
		Invocation_assertDisconnect();

	top = self->func.nonudt.numParams;
	
	/* Leave room for one extra parameter. Functions that returns unmapped
	 * composite types must have a single row ResultSet as an OUT parameter.
	 */
	args  = (jvalue*)palloc((top + 1) * sizeof(jvalue));
	invokerType = self->func.nonudt.returnType;

	if(top > 0)
	{
		int32 idx;
		Type* types = self->func.nonudt.paramTypes;

		/* a class loader or other mechanism might have connected already. This
		 * connection must be dropped since its parent context is wrong.
		 */
		if(Type_isDynamic(invokerType))
			invokerType = Type_getRealType(invokerType, get_fn_expr_rettype(fcinfo->flinfo), self->func.nonudt.typeMap);

		for(idx = 0; idx < top; ++idx)
		{
			if(PG_ARGISNULL(idx))
				/*
				 * Set this argument to zero (or null in case of object)
				 */
				args[idx].j = 0L;
			else
			{
				Type paramType = types[idx];
				if(Type_isDynamic(paramType))
					paramType = Type_getRealType(paramType, get_fn_expr_argtype(fcinfo->flinfo, idx), self->func.nonudt.typeMap);
				args[idx] = Type_coerceDatum(paramType, PG_GETARG_DATUM(idx));
			}
		}
	}

	retVal = self->func.nonudt.isMultiCall
		? Type_invokeSRF(invokerType, self->clazz, self->func.nonudt.method, args, fcinfo)
		: Type_invoke(invokerType, self->clazz, self->func.nonudt.method, args, fcinfo);

	pfree(args);
	return retVal;
}
Esempio n. 16
0
Datum
cmsketch_add(PG_FUNCTION_ARGS)
{
	CountMinSketch *cms = (CountMinSketch *) PG_GETARG_VARLENA_P(0);
	fcinfo->flinfo->fn_extra = lookup_type_cache(get_fn_expr_argtype(fcinfo->flinfo, 1), 0);
	cms = cmsketch_add_datum(fcinfo, cms, PG_GETARG_DATUM(1));
	PG_RETURN_POINTER(cms);
}
Esempio n. 17
0
Datum
orafce_dump(PG_FUNCTION_ARGS)
{
	Oid		valtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
	List	*args;
	int16	typlen;
	bool	typbyval;
	Size	length;
	Datum	value;
	int		format;
	StringInfoData	str;

	if (!fcinfo->flinfo || !fcinfo->flinfo->fn_expr)
		elog(ERROR, "function is called from invalid context");

	if (PG_ARGISNULL(0))
		elog(ERROR, "argument is NULL");

	value = PG_GETARG_DATUM(0);
	format = PG_GETARG_IF_EXISTS(1, INT32, 10);

	args = ((FuncExpr *) fcinfo->flinfo->fn_expr)->args;
	valtype = exprType((Node *) list_nth(args, 0));

	get_typlenbyval(valtype, &typlen, &typbyval);
	length = datumGetSize(value, typbyval, typlen);

	initStringInfo(&str);
	appendStringInfo(&str, "Typ=%d Len=%d: ", valtype, (int) length);

	if (!typbyval)
	{
		appendDatum(&str, DatumGetPointer(value), length, format);
	}
	else if (length <= 1)
	{
		char	v = DatumGetChar(value);
		appendDatum(&str, &v, sizeof(char), format);
	}
	else if (length <= 2)
	{
		int16	v = DatumGetInt16(value);
		appendDatum(&str, &v, sizeof(int16), format);
	}
	else if (length <= 4)
	{
		int32	v = DatumGetInt32(value);
		appendDatum(&str, &v, sizeof(int32), format);
	}
	else
	{
		int64	v = DatumGetInt64(value);
		appendDatum(&str, &v, sizeof(int64), format);
	}

	PG_RETURN_TEXT_P(cstring_to_text(str.data));
}
Esempio n. 18
0
/*
 * cms_topn_add_agg_with_parameters is a aggregate function to add items. It
 * allows to specify parameters of created CmsTopn structure. In addition to
 * cms_topn_add_agg function, it takes error bound and confidence interval
 * parameters as the forth and fifth parameters.
 */
Datum
cms_topn_add_agg_with_parameters(PG_FUNCTION_ARGS)
{
	CmsTopn *currentCmsTopn = NULL;
	CmsTopn *updatedCmsTopn = NULL;
	uint32 topnItemCount = PG_GETARG_UINT32(2);
	float8 errorBound = PG_GETARG_FLOAT8(3);
	float8 confidenceInterval = PG_GETARG_FLOAT8(4);
	Datum newItem = 0;
	TypeCacheEntry *newItemTypeCacheEntry = NULL;
	Oid newItemType = InvalidOid;

	if (!AggCheckCallContext(fcinfo, NULL))
	{
		ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
		                errmsg("cms_topn_add_agg_with_parameters called in "
		                       "non-aggregate context")));
	}

	/* check whether cms_topn is null and create if it is */
	if (PG_ARGISNULL(0))
	{
		currentCmsTopn = CreateCmsTopn(topnItemCount, errorBound, confidenceInterval);
	}
	else
	{
		currentCmsTopn = (CmsTopn *) PG_GETARG_VARLENA_P(0);
	}

	/* if new item is null, return current CmsTopn */
	if (PG_ARGISNULL(1))
	{
		PG_RETURN_POINTER(currentCmsTopn);
	}

	/*
	 * Keep type cache entry between subsequent calls in order to get rid of
	 * cache lookup overhead.
	 */
	newItem = PG_GETARG_DATUM(1);
	if (fcinfo->flinfo->fn_extra == NULL)
	{
		newItemType = get_fn_expr_argtype(fcinfo->flinfo, 1);
		newItemTypeCacheEntry = lookup_type_cache(newItemType, 0);
		fcinfo->flinfo->fn_extra = newItemTypeCacheEntry;
	}
	else
	{
		newItemTypeCacheEntry = fcinfo->flinfo->fn_extra;
	}

	updatedCmsTopn = UpdateCmsTopn(currentCmsTopn, newItem, newItemTypeCacheEntry);

	PG_RETURN_POINTER(updatedCmsTopn);
}
Esempio n. 19
0
Datum
count_distinct_append(PG_FUNCTION_ARGS)
{
    element_set_t  *eset;

    /* info for anyelement */
    Oid         element_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    Datum       element = PG_GETARG_DATUM(1);

    /* memory contexts */
    MemoryContext oldcontext;
    MemoryContext aggcontext;

    /*
     * If the new value is NULL, we simply return the current aggregate state
     * (it might be NULL, so check it).
     */
    if (PG_ARGISNULL(1) && PG_ARGISNULL(0))
        PG_RETURN_NULL();
    else if (PG_ARGISNULL(1))
        PG_RETURN_DATUM(PG_GETARG_DATUM(0));

    /* from now on we know the new value is not NULL */

    /* switch to the per-group hash-table memory context */
    GET_AGG_CONTEXT("count_distinct_append", fcinfo, aggcontext);

    oldcontext = MemoryContextSwitchTo(aggcontext);

    /* init the hash table, if needed */
    if (PG_ARGISNULL(0))
    {
        int16       typlen;
        bool        typbyval;
        char        typalign;

        /* get type information for the second parameter (anyelement item) */
        get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);

        /* we can't handle varlena types yet or values passed by reference */
        if ((typlen < 0) || (! typbyval))
            elog(ERROR, "count_distinct handles only fixed-length types passed by value");

        eset = init_set(typlen, typalign, aggcontext);
    } else
        eset = (element_set_t *)PG_GETARG_POINTER(0);

    /* add the value into the set */
    add_element(eset, (char*)&element);

    MemoryContextSwitchTo(oldcontext);

    PG_RETURN_POINTER(eset);
}
Esempio n. 20
0
Datum
pgis_geometry_accum_transfn(PG_FUNCTION_ARGS)
{
	Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
	MemoryContext aggcontext;
	ArrayBuildState *state;
	pgis_abs *p;
	Datum elem;

	if (arg1_typeid == InvalidOid)
		ereport(ERROR,
		        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
		         errmsg("could not determine input data type")));

	if (fcinfo->context && IsA(fcinfo->context, AggState))
		aggcontext = ((AggState *) fcinfo->context)->aggcontext;
#if POSTGIS_PGSQL_VERSION == 84

	else if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
		aggcontext = ((WindowAggState *) fcinfo->context)->wincontext;
#endif
#if POSTGIS_PGSQL_VERSION > 84

	else if (fcinfo->context && IsA(fcinfo->context, WindowAggState))
		aggcontext = ((WindowAggState *) fcinfo->context)->aggcontext;
#endif

	else
	{
		/* cannot be called directly because of dummy-type argument */
		elog(ERROR, "array_agg_transfn called in non-aggregate context");
		aggcontext = NULL;  /* keep compiler quiet */
	}

	if ( PG_ARGISNULL(0) )
	{
		p = (pgis_abs*) palloc(sizeof(pgis_abs));
		p->a = NULL;
	}
	else
	{
		p = (pgis_abs*) PG_GETARG_POINTER(0);
	}
	state = p->a;
	elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
	state = accumArrayResult(state,
	                         elem,
	                         PG_ARGISNULL(1),
	                         arg1_typeid,
	                         aggcontext);
	p->a = state;

	PG_RETURN_POINTER(p);
}
Esempio n. 21
0
/*
 * SQL function to_json(anyvalue)
 */
Datum
to_json(PG_FUNCTION_ARGS)
{
	Datum		val = PG_GETARG_DATUM(0);
	Oid			val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
	StringInfo	result;
	TYPCATEGORY tcategory;
	Oid			typoutput;
	bool		typisvarlena;
	Oid			castfunc = InvalidOid;

	if (val_type == InvalidOid)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("could not determine input data type")));

	result = makeStringInfo();

	getTypeOutputInfo(val_type, &typoutput, &typisvarlena);

	if (val_type > FirstNormalObjectId)
	{
		HeapTuple	tuple;
		Form_pg_cast castForm;

		tuple = SearchSysCache2(CASTSOURCETARGET,
								ObjectIdGetDatum(val_type),
								ObjectIdGetDatum(JSONOID));
		if (HeapTupleIsValid(tuple))
		{
			castForm = (Form_pg_cast) GETSTRUCT(tuple);

			if (castForm->castmethod == COERCION_METHOD_FUNCTION)
				castfunc = typoutput = castForm->castfunc;

			ReleaseSysCache(tuple);
		}
	}

	if (castfunc != InvalidOid)
		tcategory = TYPCATEGORY_JSON_CAST;
	else if (val_type == RECORDARRAYOID)
		tcategory = TYPCATEGORY_ARRAY;
	else if (val_type == RECORDOID)
		tcategory = TYPCATEGORY_COMPOSITE;
	else if (val_type == JSONOID)
		tcategory = TYPCATEGORY_JSON;
	else
		tcategory = TypeCategory(val_type);

	datum_to_json(val, false, result, tcategory, typoutput);

	PG_RETURN_TEXT_P(cstring_to_text(result->data));
}
Esempio n. 22
0
Datum
int8_add(PG_FUNCTION_ARGS)
{
	int64   state1;
	int64   state2;

	/*
	 * GUARD against an incorrectly defined SQL function by verifying
	 * that the parameters are the types we are expecting:
	 *    int8_add(int64, int64) => int64
	 */
	if (PG_NARGS() != 2)
	{
		elog(ERROR, "%s defined with %d arguments, expected 2",
			 add_str, PG_NARGS() );
	}
	if (get_fn_expr_argtype(fcinfo->flinfo, 0) != INT8OID ||
		get_fn_expr_argtype(fcinfo->flinfo, 1) != INT8OID)
	{
		elog(ERROR, "%s defined with invalid types, expected (int8, int8)",
			 add_str );
	}
	if (get_fn_expr_rettype(fcinfo->flinfo) != INT8OID)
	{
		elog(ERROR, "%s defined with invalid return type, expected int8",
			 add_str );
	}

	/*
	 * GUARD against NULL input:
	 *  - IF both are null return NULL
	 *  - otherwise treat NULL as a zero value
	 */
	if (PG_ARGISNULL(0) && PG_ARGISNULL(1))
		PG_RETURN_NULL();
	state1 = PG_ARGISNULL(0) ? 0 : PG_GETARG_INT64(0);
	state2 = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT64(1);

	/* Do the math and return the result */
	PG_RETURN_INT64(state1 + state2);
}
Esempio n. 23
0
/*
 * Checks if range overlaps with existing partitions.
 * Returns TRUE if overlaps and FALSE otherwise.
 */
Datum
check_overlap(PG_FUNCTION_ARGS)
{
	int parent_oid = DatumGetInt32(PG_GETARG_DATUM(0));
	Datum p1 = PG_GETARG_DATUM(1);
	Oid	  p1_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
	Datum p2 = PG_GETARG_DATUM(2);
	Oid	  p2_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
	PartRelationInfo *prel;
	RangeRelation	 *rangerel;
	RangeEntry		 *ranges;
	FmgrInfo		  cmp_func_1;
	FmgrInfo		  cmp_func_2;
	int i;
	bool byVal;

	prel = get_pathman_relation_info(parent_oid, NULL);
	rangerel = get_pathman_range_relation(parent_oid, NULL);

	if (!prel || !rangerel || prel->parttype != PT_RANGE)
		PG_RETURN_NULL();

	/* comparison functions */
	cmp_func_1 = *get_cmp_func(p1_type, prel->atttype);
	cmp_func_2 = *get_cmp_func(p2_type, prel->atttype);

	byVal = rangerel->by_val;
	ranges = (RangeEntry *) dsm_array_get_pointer(&rangerel->ranges);
	for (i=0; i<rangerel->ranges.length; i++)
	{
		int c1 = FunctionCall2(&cmp_func_1, p1,
								PATHMAN_GET_DATUM(ranges[i].max, byVal));
		int c2 = FunctionCall2(&cmp_func_2, p2,
								PATHMAN_GET_DATUM(ranges[i].min, byVal));

		if (c1 < 0 && c2 > 0)
			PG_RETURN_BOOL(true);
	}

	PG_RETURN_BOOL(false);
}
Esempio n. 24
0
/*
 * fetch_array_arg_replace_nulls
 *
 * Fetch an array-valued argument in expanded form; if it's null, construct an
 * empty array value of the proper data type.  Also cache basic element type
 * information in fn_extra.
 *
 * Caution: if the input is a read/write pointer, this returns the input
 * argument; so callers must be sure that their changes are "safe", that is
 * they cannot leave the array in a corrupt state.
 *
 * If we're being called as an aggregate function, make sure any newly-made
 * expanded array is allocated in the aggregate state context, so as to save
 * copying operations.
 */
static ExpandedArrayHeader *
fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno)
{
	ExpandedArrayHeader *eah;
	Oid			element_type;
	ArrayMetaState *my_extra;
	MemoryContext resultcxt;

	/* If first time through, create datatype cache struct */
	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
	if (my_extra == NULL)
	{
		my_extra = (ArrayMetaState *)
			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
							   sizeof(ArrayMetaState));
		my_extra->element_type = InvalidOid;
		fcinfo->flinfo->fn_extra = my_extra;
	}

	/* Figure out which context we want the result in */
	if (!AggCheckCallContext(fcinfo, &resultcxt))
		resultcxt = CurrentMemoryContext;

	/* Now collect the array value */
	if (!PG_ARGISNULL(argno))
	{
		MemoryContext oldcxt = MemoryContextSwitchTo(resultcxt);

		eah = PG_GETARG_EXPANDED_ARRAYX(argno, my_extra);
		MemoryContextSwitchTo(oldcxt);
	}
	else
	{
		/* We have to look up the array type and element type */
		Oid			arr_typeid = get_fn_expr_argtype(fcinfo->flinfo, argno);

		if (!OidIsValid(arr_typeid))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("could not determine input data type")));
		element_type = get_element_type(arr_typeid);
		if (!OidIsValid(element_type))
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
					 errmsg("input data type is not an array")));

		eah = construct_empty_expanded_array(element_type,
											 resultcxt,
											 my_extra);
	}

	return eah;
}
Esempio n. 25
0
/*
 * fetch_array_arg_replace_nulls
 *
 * Fetch an array-valued argument; if it's null, construct an empty array
 * value of the proper data type.  Also cache basic element type information
 * in fn_extra.
 */
static ArrayType *
fetch_array_arg_replace_nulls(FunctionCallInfo fcinfo, int argno)
{
	ArrayType  *v;
	Oid			element_type;
	ArrayMetaState *my_extra;

	/* First collect the array value */
	if (!PG_ARGISNULL(argno))
	{
		v = PG_GETARG_ARRAYTYPE_P(argno);
		element_type = ARR_ELEMTYPE(v);
	}
	else
	{
		/* We have to look up the array type and element type */
		Oid			arr_typeid = get_fn_expr_argtype(fcinfo->flinfo, argno);

		if (!OidIsValid(arr_typeid))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("could not determine input data type")));
		element_type = get_element_type(arr_typeid);
		if (!OidIsValid(element_type))
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
					 errmsg("input data type is not an array")));

		v = construct_empty_array(element_type);
	}

	/* Now cache required info, which might change from call to call */
	my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
	if (my_extra == NULL)
	{
		my_extra = (ArrayMetaState *)
			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
							   sizeof(ArrayMetaState));
		my_extra->element_type = InvalidOid;
		fcinfo->flinfo->fn_extra = my_extra;
	}

	if (my_extra->element_type != element_type)
	{
		get_typlenbyvalalign(element_type,
							 &my_extra->typlen,
							 &my_extra->typbyval,
							 &my_extra->typalign);
		my_extra->element_type = element_type;
	}

	return v;
}
Esempio n. 26
0
Datum
rank_cd(PG_FUNCTION_ARGS)
{
	ArrayType  *win;
	tsvector   *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
	QUERYTYPE  *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(2));
	int			method = DEF_NORM_METHOD;
	float4		res;

	/*
	 * Pre-8.2, rank_cd took just a plain int as its first argument.
	 * It was a mistake to keep the same C function name while changing the
	 * signature, but it's too late to fix that.  Instead, do a runtime test
	 * to make sure the expected datatype has been passed.  This is needed
	 * to prevent core dumps if tsearch2 function definitions from an old
	 * database are loaded into an 8.2 server.
	 */
	if (get_fn_expr_argtype(fcinfo->flinfo, 0) != FLOAT4ARRAYOID)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("rank_cd() now takes real[] as its first argument, not integer")));

	/* now safe to dereference the first arg */
	win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));

	if (ARR_NDIM(win) != 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array of weight must be one-dimensional")));

	if (ARRNELEMS(win) < lengthof(weights))
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("array of weight is too short")));

	if (ARR_HASNULL(win))
		ereport(ERROR,
				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
				 errmsg("array of weight must not contain nulls")));

	if (PG_NARGS() == 4)
		method = PG_GETARG_INT32(3);

	res = calc_rank_cd((float4 *) ARR_DATA_PTR(win), txt, query, method);

	PG_FREE_IF_COPY(win, 0);
	PG_FREE_IF_COPY(txt, 1);
	PG_FREE_IF_COPY(query, 2);

	PG_RETURN_FLOAT4(res);
}
Esempio n. 27
0
Datum
array_agg_distinct_type_by_element(PG_FUNCTION_ARGS)
{
    /* get element type for the dummy second parameter (anynonarray item) */
    Oid element_type = get_fn_expr_argtype(fcinfo->flinfo, 1);

    CHECK_AGG_CONTEXT("count_distinct", fcinfo);

    /* return empty array if the state was not initialized */
    if (PG_ARGISNULL(0))
        PG_RETURN_DATUM(PointerGetDatum(construct_empty_array(element_type)));

    return build_array((element_set_t *)PG_GETARG_POINTER(0), element_type);
}
Esempio n. 28
0
Datum
bloom_add(PG_FUNCTION_ARGS)
{
	BloomFilter *bloom;

	if (PG_ARGISNULL(0))
		bloom = BloomFilterCreate();
	else
		bloom = (BloomFilter *) PG_GETARG_VARLENA_P(0);

	fcinfo->flinfo->fn_extra = lookup_type_cache(get_fn_expr_argtype(fcinfo->flinfo, 1), 0);
	bloom = bloom_add_datum(fcinfo, bloom, PG_GETARG_DATUM(1));
	PG_RETURN_POINTER(bloom);
}
Esempio n. 29
0
Datum anyold_transfn(PG_FUNCTION_ARGS)
{
	Oid           type;
	Datum         state;
	MemoryContext aggcontext,
	              oldcontext;
	int16         typlen;
	bool          typbyval;
	char          typalign;
	
	if (!AggCheckCallContext(fcinfo, &aggcontext))
	{
		/* cannot be called directly because of internal-type argument */
		elog(ERROR, "anyold_transfn called in non-aggregate context");
	}
	
	if (PG_ARGISNULL(0))
	{
		if (PG_ARGISNULL(1))
			PG_RETURN_NULL();
		/* First non-null value --- initialize */
		oldcontext = MemoryContextSwitchTo(aggcontext);
		
		type = get_fn_expr_argtype(fcinfo->flinfo, 1);
		if (type == InvalidOid)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("could not determine input data type")));
		get_typlenbyvalalign(type,
							&typlen,
							&typbyval,
							&typalign);

		/* Copy initial value */
		if (typlen == -1)
			state = PointerGetDatum(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)));
		else
			state = datumCopy(PG_GETARG_DATUM(1), typbyval, typlen);

		MemoryContextSwitchTo(oldcontext);
	}
	else
	{
		state = PG_GETARG_DATUM(0);
	}
	
	PG_RETURN_DATUM(state);
}
Datum
adaptive_add_item_agg2(PG_FUNCTION_ARGS)
{

    AdaptiveCounter acounter;

    /* info for anyelement */
    Oid         element_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    Datum       element = PG_GETARG_DATUM(1);
    int16       typlen;
    bool        typbyval;
    char        typalign;

    /* is the counter created (if not, create it with default parameters) */
    if (PG_ARGISNULL(0)) {
      acounter = ac_init(DEFAULT_ERROR, DEFAULT_NDISTINCT);
    } else {
      acounter = (AdaptiveCounter)PG_GETARG_BYTEA_P(0);
    }

    /* add the item to the estimator */
    if (! PG_ARGISNULL(1)) {

        /* TODO The requests for type info shouldn't be a problem (thanks to lsyscache),
        * but if it turns out to have a noticeable impact it's possible to cache that
        * between the calls (in the estimator). */

        /* get type information for the second parameter (anyelement item) */
        get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);

        /* it this a varlena type, passed by reference or by value ? */
        if (typlen == -1) {
            /* varlena */
            ac_add_item(acounter, VARDATA(element), VARSIZE(element) - VARHDRSZ);
        } else if (typbyval) {
            /* fixed-length, passed by value */
            ac_add_item(acounter, (char*)&element, typlen);
        } else {
            /* fixed-length, passed by reference */
            ac_add_item(acounter, (char*)element, typlen);
        }

    }

    /* return the updated bytea */
    PG_RETURN_BYTEA_P(acounter);

}