Пример #1
0
/*
 * cmsketch_agg transition function -
 *
 * 	adds the given element to the transition cmsketch using the given value for p and n
 */
Datum
cmsketch_agg_transp(PG_FUNCTION_ARGS)
{
	MemoryContext old;
	MemoryContext context;
	CountMinSketch *state;
	Datum incoming = PG_GETARG_DATUM(1);
	float8 eps = PG_GETARG_FLOAT8(2);
	float8 p = PG_GETARG_FLOAT8(3);

	if (!AggCheckCallContext(fcinfo, &context))
		elog(ERROR, "cmsketch_agg_transp called in non-aggregate context");

	old = MemoryContextSwitchTo(context);

	if (PG_ARGISNULL(0))
		state = cmsketch_startup(fcinfo, eps, p);
	else
		state = (CountMinSketch *) PG_GETARG_VARLENA_P(0);

	state = cmsketch_add_datum(fcinfo, state, incoming, 1);

	MemoryContextSwitchTo(old);

	PG_RETURN_POINTER(state);
}
Пример #2
0
/*
 * cmsketch_merge_agg transition function -
 *
 * 	returns the merge of the transition state and the given cmsketch
 */
Datum
cmsketch_merge_agg_trans(PG_FUNCTION_ARGS)
{
	MemoryContext old;
	MemoryContext context;
	CountMinSketch *state;
	CountMinSketch *incoming = (CountMinSketch *) PG_GETARG_VARLENA_P(1);

	if (!AggCheckCallContext(fcinfo, &context))
		elog(ERROR, "cmsketch_merge_agg_trans called in non-aggregate context");

	old = MemoryContextSwitchTo(context);

	if (PG_ARGISNULL(0))
	{
		state = CountMinSketchCopy(incoming);
		PG_RETURN_POINTER(state);
	}

	state = (CountMinSketch *) PG_GETARG_VARLENA_P(0);
	state = CountMinSketchMerge(state, incoming);

	MemoryContextSwitchTo(old);

	PG_RETURN_POINTER(state);
}
Пример #3
0
Datum anyold_finalfn(PG_FUNCTION_ARGS)
{
	/* cannot be called directly because of internal-type argument */
	Assert(AggCheckCallContext(fcinfo, NULL));
	
	if (PG_ARGISNULL(0))
		PG_RETURN_NULL();
		
	PG_RETURN_DATUM(PG_GETARG_DATUM(0));
}
Пример #4
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);
}
Пример #5
0
Datum hll_sum(PG_FUNCTION_ARGS) {
	MemoryContext aggctx;
    MemoryContext tmpcontext;
    MemoryContext oldcontext;

	dmerge_state *state;
	uint32_t     *value;
    uLongf dest_size = HLL_LEN * 4;
	int unpack_res;
	int count;
	int i;

	bytea    *data = PG_GETARG_BYTEA_P(1);

	if (!AggCheckCallContext(fcinfo, &aggctx))
        ereport(ERROR,
                (errcode(ERRCODE_DATA_EXCEPTION),
                 errmsg("hll_sum outside transition context")));


	if ( PG_ARGISNULL(0) ) {
		tmpcontext = AllocSetContextCreate(aggctx,
		                                   "hll_sum",
		                                   ALLOCSET_DEFAULT_MINSIZE,
		                                   ALLOCSET_DEFAULT_INITSIZE,
		                                   ALLOCSET_DEFAULT_MAXSIZE);

	    oldcontext = MemoryContextSwitchTo(tmpcontext);
		state = (dmerge_state *) palloc(sizeof(dmerge_state));
	    MemoryContextSwitchTo(oldcontext);

		value = state->state;
	} else {
		state = (dmerge_state *) PG_GETARG_POINTER(0);
		value = state->value;
	}

    unpack_res = uncompress((Bytef *) value, &dest_size, (Bytef *) VARDATA(data), VARSIZE(data));
    if ( unpack_res != Z_OK ) {
		ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("can't decode value")));
    }

    count = dest_size / 4;
    for(i = 0; i < count; i++) {
    	value[i] = ntohl(value[i]);
    }

	if ( !PG_ARGISNULL(0) ) {
		merge_sets(1 << state->state[0], value + 2, state->state + 2);
	}

	PG_RETURN_POINTER(state);
}
Пример #6
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;
}
Пример #7
0
Datum argm_finalfn(PG_FUNCTION_ARGS)
{
	ArgmState *state;

	/* cannot be called directly because of internal-type argument */
	Assert(AggCheckCallContext(fcinfo, NULL));

	state = (ArgmState *) PG_GETARG_POINTER(0);
	
	if (state->keys[0].is_null)
		PG_RETURN_NULL();
	
	PG_RETURN_DATUM(state->keys[0].value);
}
Пример #8
0
/*
 * keyed_min_max_combine_internal
 */
static Datum
keyed_min_max_combine_internal(FunctionCallInfo fcinfo, int sign)
{
	KeyedAggState *kas;
	KeyValue *state;
	KeyValue *incoming = (KeyValue *) PG_GETARG_VARLENA_P(1);
	MemoryContext old;
	MemoryContext context;
	int cmp;
	bool isnull;

	if (!AggCheckCallContext(fcinfo, &context))
		elog(ERROR, "keyed_min_combine_internal called in non-aggregate context");

	if (PG_ARGISNULL(0))
	{
		/*
		 * We can't use the startup function that the aggregate uses because
		 * the combiner Aggref doesn't have all of the original arguments.
		 */
		old = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
		kas = palloc0(sizeof(KeyedAggState));
		kas->key_type = lookup_type_cache(incoming->key_type, TYPECACHE_CMP_PROC_FINFO);
		kas->value_type = lookup_type_cache(incoming->value_type, 0);
		fcinfo->flinfo->fn_extra = kas;
		MemoryContextSwitchTo(old);

		old = MemoryContextSwitchTo(context);
		state = copy_kv(kas, incoming);
		MemoryContextSwitchTo(old);

		PG_RETURN_POINTER(state);
	}

	old = MemoryContextSwitchTo(context);

	state = (KeyValue *) PG_GETARG_VARLENA_P(0);
	kas = (KeyedAggState *) fcinfo->flinfo->fn_extra;
	incoming = point_to_self(kas, (struct varlena *) incoming);

	cmp = sign * compare_keys(kas, state, incoming->key,
			KV_KEY_IS_NULL(incoming), state->key_collation, &isnull);

	if (!isnull && cmp <= 0)
		state = copy_kv(kas, incoming);

	MemoryContextSwitchTo(old);

	PG_RETURN_POINTER(state);
}
Пример #9
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);
}
Пример #10
0
static BoolAggState *
makeBoolAggState(FunctionCallInfo fcinfo)
{
	BoolAggState *state;
	MemoryContext agg_context;

	if (!AggCheckCallContext(fcinfo, &agg_context))
		elog(ERROR, "aggregate function called in non-aggregate context");

	state = (BoolAggState *) MemoryContextAlloc(agg_context,
												sizeof(BoolAggState));
	state->aggcount = 0;
	state->aggtrue = 0;

	return state;
}
Пример #11
0
Datum
pgstrom_numeric_var_accum(PG_FUNCTION_ARGS)
{
	int32			nrows = PG_GETARG_INT32(1);
	MemoryContext	aggcxt;
	MemoryContext	oldcxt;
	numeric_agg_state *state;

	if (!AggCheckCallContext(fcinfo, &aggcxt))
		elog(ERROR, "aggregate function called in non-aggregate context");

	if (PG_ARGISNULL(1))
		nrows = 0;
	else if (nrows < 0)
		elog(ERROR, "Bug? negative nrows were given");

	/* make a state object and update it */
	oldcxt = MemoryContextSwitchTo(aggcxt);
	state = PG_ARGISNULL(0) ? NULL : (numeric_agg_state *)PG_GETARG_POINTER(0);
	if (!state)
	{
		state = palloc0(sizeof(numeric_agg_state));
		state->N = 0;
		state->sumX = DirectFunctionCall3(numeric_in,
										  CStringGetDatum("0"),
										  ObjectIdGetDatum(0),
										  Int32GetDatum(-1));
		state->sumX2 = DirectFunctionCall3(numeric_in,
										   CStringGetDatum("0"),
										   ObjectIdGetDatum(0),
										   Int32GetDatum(-1));
	}

	if (nrows > 0 && !PG_ARGISNULL(2) && !PG_ARGISNULL(3))
	{
		state->N += nrows;
		state->sumX = DirectFunctionCall2(numeric_add,
										  state->sumX,
										  PG_GETARG_DATUM(2));
		state->sumX2 = DirectFunctionCall2(numeric_add,
										   state->sumX2,
										   PG_GETARG_DATUM(3));
	}
	MemoryContextSwitchTo(oldcxt);

	PG_RETURN_POINTER(state);
}
Пример #12
0
Datum
pgstrom_final_avg_numeric_accum(PG_FUNCTION_ARGS)
{
	MemoryContext	aggcxt;
	MemoryContext	oldcxt;
	ArrayType	   *xarray;
	ArrayType	   *yarray;
	Datum			x0, x1;
	Datum			y0, y1;
	Datum			items[2];
	bool			isnull[4];

	if (!AggCheckCallContext(fcinfo, &aggcxt))
		elog(ERROR, "aggregate function called in non-aggregate context");
	if (PG_ARGISNULL(1))
		elog(ERROR, "Null state was supplied");

	if (PG_ARGISNULL(0))
	{
		oldcxt = MemoryContextSwitchTo(aggcxt);
		xarray = PG_GETARG_ARRAYTYPE_P_COPY(1);
		MemoryContextSwitchTo(oldcxt);
	}
	else
	{
		xarray = PG_GETARG_ARRAYTYPE_P(0);
		yarray = PG_GETARG_ARRAYTYPE_P(1);

		x0 = numeric_array_ref(xarray, 1, &isnull[0]);
		x1 = numeric_array_ref(xarray, 2, &isnull[1]);
		y0 = numeric_array_ref(yarray, 1, &isnull[2]);
		y1 = numeric_array_ref(yarray, 2, &isnull[3]);

		if (isnull[0] || isnull[1] || isnull[2] || isnull[3])
			elog(ERROR, "unexpected internal state");

		items[0] = DirectFunctionCall2(numeric_add, x0, y0);
		items[1] = DirectFunctionCall2(numeric_add, x1, y1);

		oldcxt = MemoryContextSwitchTo(aggcxt);
		xarray = construct_array(items, 2, NUMERICOID,
								 -1, false, 'i');
		MemoryContextSwitchTo(oldcxt);
	}
	PG_RETURN_POINTER(xarray);
}
Пример #13
0
/*
 * json_agg final function
 */
Datum
json_agg_finalfn(PG_FUNCTION_ARGS)
{
	StringInfo	state;

	/* cannot be called directly because of internal-type argument */
	Assert(AggCheckCallContext(fcinfo, NULL));

	state = PG_ARGISNULL(0) ? NULL : (StringInfo) PG_GETARG_POINTER(0);

	if (state == NULL)
		PG_RETURN_NULL();

	appendStringInfoChar(state, ']');

	PG_RETURN_TEXT_P(cstring_to_text(state->data));
}
Пример #14
0
Datum
_float4_weighted_stddev_samp_intermediate(PG_FUNCTION_ARGS)
{
	float	   *state;
	float		value,
				weight,
				w_v,
				w_v2;
	MemoryContext	aggcontext,
					oldcontext;

	if (!AggCheckCallContext(fcinfo, &aggcontext))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("_float4_weighted_stddev_samp_intermediate called in non-aggregate context")));

	if (PG_ARGISNULL(0))
	{
		oldcontext = MemoryContextSwitchTo(aggcontext);
		state = (float *) (palloc(4 * sizeof(float))); /* s_2, s_1, s_0, n_prime */
		state[0] = 0.0;
		state[1] = 0.0;
		state[2] = 0.0;
		state[3] = 0.0;
		MemoryContextSwitchTo(oldcontext);
	}
	else
		state = (float *) PG_GETARG_POINTER(0);

	/* Skip NULLs and zero weights */
	if (PG_ARGISNULL(1) || PG_ARGISNULL(2) || PG_GETARG_FLOAT4(2) == 0.0)
		PG_RETURN_POINTER(state);

	value = PG_GETARG_FLOAT4(1);
	weight = PG_GETARG_FLOAT4(2);
	w_v = weight * value;
	w_v2 = w_v * value;

	state[0] += w_v2;
	state[1] += w_v;
	state[2] += weight;
	state[3] += 1.0;

	PG_RETURN_POINTER(state);
}
Пример #15
0
/*
 * ARRAY_AGG(anynonarray) 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")));

	/*
	 * Note: we do not need a run-time check about whether arg1_typeid is a
	 * valid array element type, because the parser would have verified that
	 * while resolving the input/result types of this polymorphic aggregate.
	 */

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

	if (PG_ARGISNULL(0))
		state = initArrayResult(arg1_typeid, aggcontext, false);
	else
		state = (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);
}
Пример #16
0
Datum
int8inc(PG_FUNCTION_ARGS)
{
    /*
     * When int8 is pass-by-reference, we provide this special case to avoid
     * palloc overhead for COUNT(): when called as an aggregate, we know that
     * the argument is modifiable local storage, so just update it in-place.
     * (If int8 is pass-by-value, then of course this is useless as well as
     * incorrect, so just ifdef it out.)
     */
#ifndef USE_FLOAT8_BYVAL		/* controls int8 too */
    if (AggCheckCallContext(fcinfo, NULL))
    {
        int64	   *arg = (int64 *) PG_GETARG_POINTER(0);
        int64		result;

        result = *arg + 1;
        /* Overflow check */
        if (result < 0 && *arg > 0)
            ereport(ERROR,
                    (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                     errmsg("bigint out of range")));

        *arg = result;
        PG_RETURN_POINTER(arg);
    }
    else
#endif
    {
        /* Not called as an aggregate, so just do it the dumb way */
        int64		arg = PG_GETARG_INT64(0);
        int64		result;

        result = arg + 1;
        /* Overflow check */
        if (result < 0 && arg > 0)
            ereport(ERROR,
                    (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                     errmsg("bigint out of range")));

        PG_RETURN_INT64(result);
    }
}
Пример #17
0
/*
 * variance and stddev - mathmatical compatible result can be lead using
 * nrows, psum(X) and psum(X*X). So, we track these variables.
 */
Datum
pgstrom_variance_float8_accum(PG_FUNCTION_ARGS)
{
	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
	int32		nrows = PG_GETARG_INT32(1);
	float8		psumX = PG_GETARG_FLOAT8(2);
	float8		psumX2 = PG_GETARG_FLOAT8(3);
	float8	   *transvalues;
	float8		newN;
	float8		newSumX;
	float8		newSumX2;

	transvalues = check_float8_array(transarray, 3);
	newN = transvalues[0] + (float8) nrows;
	newSumX = transvalues[1] + psumX;
	check_float8_valid(newSumX, isinf(transvalues[1]) || isinf(psumX), true);
	newSumX2 = transvalues[2] + psumX2;
	check_float8_valid(newSumX2, isinf(transvalues[2]) || isinf(psumX2), true);

	if (AggCheckCallContext(fcinfo, NULL))
	{
		transvalues[0] = newN;
		transvalues[1] = newSumX;
		transvalues[2] = newSumX2;

		PG_RETURN_ARRAYTYPE_P(transarray);
	}
	else
	{
		Datum		transdatums[3];
		ArrayType  *result;

		transdatums[0] = Float8GetDatumFast(newN);
		transdatums[1] = Float8GetDatumFast(newSumX);
		transdatums[2] = Float8GetDatumFast(newSumX2);

		result = construct_array(transdatums, 3,
								 FLOAT8OID,
								 sizeof(float8), FLOAT8PASSBYVAL, 'd');
		PG_RETURN_ARRAYTYPE_P(result);
	}
}
Пример #18
0
static StringInfo makeJsonAggState( FunctionCallInfo fcinfo )
{
	StringInfo  state;
	MemoryContext aggcontext;
	MemoryContext oldcontext;

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

	/*
	 * Create state in aggregate context.  It'll stay there across subsequent
	 * calls.
	 */
	oldcontext = MemoryContextSwitchTo(aggcontext);
	state = makeStringInfo();
	MemoryContextSwitchTo(oldcontext);

	return state;
}
Пример #19
0
/*
 * keyed_min_trans_internal
 */
static Datum
keyed_min_max_trans_internal(FunctionCallInfo fcinfo, int sign)
{
	KeyValue *kv;
	Datum incoming_key = PG_GETARG_DATUM(1);
	Datum incoming_value = PG_GETARG_DATUM(2);
	KeyedAggState *state;
	MemoryContext old;
	MemoryContext context;
	bool isnull;
	int cmp;

	if (!AggCheckCallContext(fcinfo, &context))
		elog(ERROR, "keyed_min_max_trans_internal called in non-aggregate context");

	old = MemoryContextSwitchTo(context);

	if (PG_ARGISNULL(0))
	{
		kv = keyed_trans_startup(fcinfo);
		MemoryContextSwitchTo(old);
		PG_RETURN_POINTER(kv);
	}

	state = (KeyedAggState *) fcinfo->flinfo->fn_extra;
	kv = point_to_self(state, PG_GETARG_BYTEA_P(0));

	cmp = sign * compare_keys(state, kv, incoming_key,
			PG_ARGISNULL(1), PG_GET_COLLATION(), &isnull);

	if (!isnull && cmp <= 0)
		kv = set_kv(state, kv, incoming_key, PG_ARGISNULL(1), incoming_value, PG_ARGISNULL(2));

	MemoryContextSwitchTo(old);


	PG_RETURN_POINTER(kv);
}
Пример #20
0
/*
 * tdigest_agg transition function -
 * 	adds the given element to the transition tdigest
 */
Datum
tdigest_agg_trans(PG_FUNCTION_ARGS)
{
	MemoryContext old;
	MemoryContext context;
	TDigest *state;
	float8 incoming = PG_GETARG_FLOAT8(1);

	if (!AggCheckCallContext(fcinfo, &context))
		elog(ERROR, "tdigest_agg_trans called in non-aggregate context");

	old = MemoryContextSwitchTo(context);

	if (PG_ARGISNULL(0))
		state = tdigest_startup(fcinfo, 0);
	else
		state = (TDigest *) PG_GETARG_POINTER(0);

	TDigestAdd(state, incoming, 1);

	MemoryContextSwitchTo(old);

	PG_RETURN_POINTER(state);
}
Пример #21
0
/*
 * tdigest_merge_agg transition function -
 *
 * 	returns the union of the transition state and the given tdigest
 */
Datum
tdigest_merge_agg_trans(PG_FUNCTION_ARGS)
{
	MemoryContext old;
	MemoryContext context;
	TDigest *state;
	TDigest *incoming = tdigest_unpack(PG_GETARG_BYTEA_P(1));

	if (!AggCheckCallContext(fcinfo, &context))
		elog(ERROR, "tdigest_merge_agg_trans called in non-aggregate context");

	old = MemoryContextSwitchTo(context);

	if (PG_ARGISNULL(0))
		state = TDigestCreateWithCompression(incoming->compression);
	else
		state = (TDigest *) PG_GETARG_POINTER(0);

	TDigestMerge(state, incoming);

	MemoryContextSwitchTo(old);

	PG_RETURN_POINTER(state);
}
Пример #22
0
/*
 * bloom_agg transition function -
 * 	adds the given element to the transition Bloom filter
 */
Datum
bloom_agg_trans(PG_FUNCTION_ARGS)
{
	MemoryContext old;
	MemoryContext context;
	BloomFilter *state;

	if (!AggCheckCallContext(fcinfo, &context))
		elog(ERROR, "bloom_agg_trans called in non-aggregate context");

	old = MemoryContextSwitchTo(context);

	if (PG_ARGISNULL(0))
		state = bloom_startup(fcinfo, 0, 0);
	else
		state = (BloomFilter *) PG_GETARG_VARLENA_P(0);

	if (!PG_ARGISNULL(1))
		state = bloom_add_datum(fcinfo, state, PG_GETARG_DATUM(1));

	MemoryContextSwitchTo(old);

	PG_RETURN_POINTER(state);
}
Пример #23
0
/*
 * hll_agg transition function -
 * 	adds the given element to the transition HLL
 */
Datum
hll_agg_trans(PG_FUNCTION_ARGS)
{
	MemoryContext old;
	MemoryContext context;
	HyperLogLog *state;
	Datum incoming = PG_GETARG_DATUM(1);

	if (!AggCheckCallContext(fcinfo, &context))
		elog(ERROR, "hll_agg_trans called in non-aggregate context");

	old = MemoryContextSwitchTo(context);

	if (PG_ARGISNULL(0))
		state = hll_startup(fcinfo, 0);
	else
		state = (HyperLogLog *) PG_GETARG_VARLENA_P(0);

	state = hll_add_datum(fcinfo, state, incoming);

	MemoryContextSwitchTo(old);

	PG_RETURN_POINTER(state);
}
Пример #24
0
Datum
array_agg_finalfn(PG_FUNCTION_ARGS)
{
	Datum		result;
	ArrayBuildState *state;
	int			dims[1];
	int			lbs[1];

	/*
	 * Test for null before Asserting we are in right context.	This is to
	 * avoid possible Assert failure in 8.4beta installations, where it is
	 * possible for users to create NULL constants of type internal.
	 */
	if (PG_ARGISNULL(0))
		PG_RETURN_NULL();		/* returns null iff no input values */

	/* cannot be called directly because of internal-type argument */
	Assert(AggCheckCallContext(fcinfo, NULL));

	state = (ArrayBuildState *) PG_GETARG_POINTER(0);

	dims[0] = state->nelems;
	lbs[0] = 1;

	/*
	 * Make the result.  We cannot release the ArrayBuildState because
	 * sometimes aggregate final functions are re-executed.  Rather, it is
	 * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
	 * so.
	 */
	result = makeMdArrayResult(state, 1, dims, lbs,
							   CurrentMemoryContext,
							   false);

	PG_RETURN_DATUM(result);
}
Пример #25
0
Datum
array_agg_array_finalfn(PG_FUNCTION_ARGS)
{
	Datum		result;
	ArrayBuildStateArr *state;

	/* cannot be called directly because of internal-type argument */
	Assert(AggCheckCallContext(fcinfo, NULL));

	state = PG_ARGISNULL(0) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(0);

	if (state == NULL)
		PG_RETURN_NULL();		/* returns null iff no input values */

	/*
	 * Make the result.  We cannot release the ArrayBuildStateArr because
	 * sometimes aggregate final functions are re-executed.  Rather, it is
	 * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
	 * so.
	 */
	result = makeArrayResultArr(state, CurrentMemoryContext, false);

	PG_RETURN_DATUM(result);
}
Пример #26
0
inline
void *
AbstractionLayer::Allocator::internalAllocate(void *inPtr, const size_t inSize) const {
    // Avoid warning that inPtr is not used if R == NewAllocation
    (void) inPtr;
    
    void *ptr;
    bool errorOccurred = false;
    MemoryContext oldContext = NULL;
    MemoryContext aggContext = NULL;

    if (F == dbal::ReturnNULL) {
        /*
         * HOLD_INTERRUPTS() and RESUME_INTERRUPTS() only change the value of a
         * global variable but have no other side effects. In particular, they
         * do not call CHECK_INTERRUPTS(). Hence, we are save to use these
         * macros outside of a PG_TRY() block.
         */
        HOLD_INTERRUPTS();
    }
        
    PG_TRY(); {
        if (MC == dbal::AggregateContext) {
            if (!AggCheckCallContext(fcinfo, &aggContext))
                errorOccurred = true;
            else {
                oldContext = MemoryContextSwitchTo(aggContext);
                ptr = (R == Reallocation) ? internalRePalloc<ZM>(inPtr, inSize)
                                          : internalPalloc<ZM>(inSize);
                MemoryContextSwitchTo(oldContext);
            }
        } else {
            ptr = R ? internalRePalloc<ZM>(inPtr, inSize)
                    : internalPalloc<ZM>(inSize);
        }
    } PG_CATCH(); {
        if (F == dbal::ReturnNULL) {
            /*
             * This cannot be due to an interrupt, so it's reasonably safe
             * to assume that the PG exception was a pure memory-allocation
             * issue. We ignore the error and flush the error state.
             * Flushing is necessary for leaving the error state (e.g., the memory
             * context is restored).
             */
            FlushErrorState();
            ptr = NULL;
        } else {
            /*
             * PostgreSQL error messages can be stacked. So, it doesn't hurt to add
             * our own message. After unwinding the C++ stack, the PostgreSQL
             * exception will be re-thrown into the PostgreSQL C code.
             *
             * Throwing C++ exceptions inside a PG_CATCH block is not problematic
             * per se, but it is good practise to keep the exception mechanisms clearly
             * separated.
             */

            errorOccurred = true;
        }
    } PG_END_TRY();

    if (errorOccurred) {
        PG_TRY(); {
            // Clean up after ourselves
            if (oldContext != NULL)
                MemoryContextSwitchTo(oldContext);
        } PG_CATCH(); {
            if (F == dbal::ReturnNULL) {
                // We tried to clean up after ourselves. If this fails, we can
                // only ignore the issue.
                FlushErrorState();
            } 
            // Else do nothing. We will add a bad-allocation exception on top of
            // the existing PostgreSQL exception stack.
        } PG_END_TRY();
    }
    
    if (errorOccurred || !ptr)
        // We do not want to interleave PG exceptions and C++ exceptions.
        throw std::bad_alloc();

    if (F == dbal::ReturnNULL) {
        RESUME_INTERRUPTS();
    }
   
    return ptr;
}
Пример #27
0
Datum
tsa_rewrite_accum(PG_FUNCTION_ARGS)
{
	TSQuery		acc;
	ArrayType  *qa;
	TSQuery		q;
	QTNode	   *qex = NULL,
			   *subs = NULL,
			   *acctree = NULL;
	bool		isfind = false;
	Datum	   *elemsp;
	int			nelemsp;
	MemoryContext aggcontext;
	MemoryContext oldcontext;

	if (!AggCheckCallContext(fcinfo, &aggcontext))
		elog(ERROR, "tsa_rewrite_accum called in non-aggregate context");

	if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
	{
		acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ);
		SET_VARSIZE(acc, HDRSIZETQ);
		acc->size = 0;
	}
	else
		acc = PG_GETARG_TSQUERY(0);

	if (PG_ARGISNULL(1) || PG_GETARG_POINTER(1) == NULL)
		PG_RETURN_TSQUERY(acc);
	else
		qa = PG_GETARG_ARRAYTYPE_P_COPY(1);

	if (ARR_NDIM(qa) != 1)
		elog(ERROR, "array must be one-dimensional, not %d dimensions",
			 ARR_NDIM(qa));
	if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3)
		elog(ERROR, "array must have three elements");
	if (ARR_ELEMTYPE(qa) != TSQUERYOID)
		elog(ERROR, "array must contain tsquery elements");

	deconstruct_array(qa, TSQUERYOID, -1, false, 'i', &elemsp, NULL, &nelemsp);

	q = DatumGetTSQuery(elemsp[0]);
	if (q->size == 0)
	{
		pfree(elemsp);
		PG_RETURN_POINTER(acc);
	}

	if (!acc->size)
	{
		if (VARSIZE(acc) > HDRSIZETQ)
		{
			pfree(elemsp);
			PG_RETURN_POINTER(acc);
		}
		else
			acctree = QT2QTN(GETQUERY(q), GETOPERAND(q));
	}
	else
		acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc));

	QTNTernary(acctree);
	QTNSort(acctree);

	q = DatumGetTSQuery(elemsp[1]);
	if (q->size == 0)
	{
		pfree(elemsp);
		PG_RETURN_POINTER(acc);
	}
	qex = QT2QTN(GETQUERY(q), GETOPERAND(q));
	QTNTernary(qex);
	QTNSort(qex);

	q = DatumGetTSQuery(elemsp[2]);
	if (q->size)
		subs = QT2QTN(GETQUERY(q), GETOPERAND(q));

	acctree = findsubquery(acctree, qex, subs, &isfind);

	if (isfind || !acc->size)
	{
		/* pfree( acc ); do not pfree(p), because nodeAgg.c will */
		if (acctree)
		{
			QTNBinary(acctree);
			oldcontext = MemoryContextSwitchTo(aggcontext);
			acc = QTN2QT(acctree);
			MemoryContextSwitchTo(oldcontext);
		}
		else
		{
			acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ);
			SET_VARSIZE(acc, HDRSIZETQ);
			acc->size = 0;
		}
	}

	pfree(elemsp);
	QTNFree(qex);
	QTNFree(subs);
	QTNFree(acctree);

	PG_RETURN_TSQUERY(acc);
}
Пример #28
0
/*
 * json_agg transition function
 */
Datum
json_agg_transfn(PG_FUNCTION_ARGS)
{
	Oid			val_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
	MemoryContext aggcontext,
				oldcontext;
	StringInfo	state;
	Datum		val;
	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")));

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

	if (PG_ARGISNULL(0))
	{
		/*
		 * Make this StringInfo in a context where it will persist for the
		 * duration off the aggregate call. It's only needed for this initial
		 * piece, as the StringInfo routines make sure they use the right
		 * context to enlarge the object if necessary.
		 */
		oldcontext = MemoryContextSwitchTo(aggcontext);
		state = makeStringInfo();
		MemoryContextSwitchTo(oldcontext);

		appendStringInfoChar(state, '[');
	}
	else
	{
		state = (StringInfo) PG_GETARG_POINTER(0);
		appendStringInfoString(state, ", ");
	}

	/* fast path for NULLs */
	if (PG_ARGISNULL(1))
	{
		val = (Datum) 0;
		datum_to_json(val, true, state, 0, InvalidOid);
		PG_RETURN_POINTER(state);
	}

	val = PG_GETARG_DATUM(1);

	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);

	if (!PG_ARGISNULL(0) &&
	  (tcategory == TYPCATEGORY_ARRAY || tcategory == TYPCATEGORY_COMPOSITE))
	{
		appendStringInfoString(state, "\n ");
	}

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

	/*
	 * 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);
}
Пример #29
0
/**
 * @brief Return the n-th element from a composite value
 *
 * To the user, AnyType is a fully recursive type: Each AnyType object can be a
 * composite object and be composed of a number of other AnyType objects.
 * Function written using the C++ abstraction layer have a single logical
 * argument of type AnyType.
 */
inline
AnyType
AnyType::operator[](uint16_t inID) const {
    consistencyCheck();

    if (isNull()) {
        // Handle case mContent == NULL
        throw std::invalid_argument("Invalid type conversion. "
                                    "Null where not expected.");
    }
    if (!isComposite()) {
        // Handle case mContent == Scalar
        throw std::invalid_argument("Invalid type conversion. "
                                    "Composite type where not expected.");
    }

    if (mContent == ReturnComposite)
        return mChildren[inID];

    // It holds now that mContent is either FunctionComposite or NativeComposite
    // In this case, it is guaranteed that fcinfo != NULL
    Oid typeID = 0;
    bool isMutable = false;
    Datum datum = 0;

    if (mContent == FunctionComposite) {
        // This AnyType object represents to composite value consisting of all
        // function arguments

        if (inID >= size_t(PG_NARGS()))
            throw std::out_of_range("Invalid type conversion. Access behind "
                                    "end of argument list.");

        if (PG_ARGISNULL(inID))
            return AnyType();

        typeID = mSysInfo->functionInformation(fcinfo->flinfo->fn_oid)
                 ->getArgumentType(inID, fcinfo->flinfo);
        if (inID == 0) {
            // 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

            // BACKEND: AggCheckCallContext currently will never raise an
            // exception
            isMutable = AggCheckCallContext(fcinfo, NULL);
        }
        datum = PG_GETARG_DATUM(inID);
    } else { /* if (mContent == NativeComposite) */
        // This AnyType objects represents a tuple that was passed from the
        // backend

        TupleDesc tupdesc = mSysInfo
                            ->typeInformation(HeapTupleHeaderGetTypeId(mTupleHeader))
                            ->getTupleDesc(HeapTupleHeaderGetTypMod(mTupleHeader));

        if (inID >= tupdesc->natts)
            throw std::out_of_range("Invalid type conversion. Access behind "
                                    "end of composite object.");

        typeID = tupdesc->attrs[inID]->atttypid;
        bool isNull = false;
        datum = madlib_GetAttributeByNum(mTupleHeader, inID, &isNull);
        if (isNull)
            return AnyType();
    }

    if (typeID == InvalidOid)
        throw std::invalid_argument("Backend returned invalid type ID.");

    return mSysInfo->typeInformation(typeID)->isCompositeType()
           ? AnyType(mSysInfo, madlib_DatumGetHeapTupleHeader(datum), datum,
                     typeID)
           : AnyType(mSysInfo, datum, typeID, isMutable);
}
Пример #30
0
Datum
hvault_table_count_step(PG_FUNCTION_ARGS)
{
    MemoryContext aggmemctx, oldmemctx;
    ArrayType * ctx;
    ArrayType * idx_array;
    int i, pos_idx;
    int32_t * ctx_data;
    
    if (!AggCheckCallContext(fcinfo, &aggmemctx))
        elog(ERROR, "hvault_table_group_step called in non-aggregate context");

    
    ctx = PG_ARGISNULL(0) ? NULL : PG_GETARG_ARRAYTYPE_P(0);
    if (ctx == NULL)
    {
        int ndim;
        int32_t * bounds_data;
        int dims[MAXDIM];
        int lbs[MAXDIM]; 
        ArrayType * bounds_array;

        oldmemctx = MemoryContextSwitchTo(aggmemctx);

        if (PG_ARGISNULL(2))
            elog(ERROR, "bounds array must not be null");

//        if (!get_fn_expr_arg_stable(fcinfo->flinfo, 2))
//            elog(ERROR, "bounds array must be const");

        bounds_array = PG_GETARG_ARRAYTYPE_P(2);
        Assert(bounds_array != NULL);
        Assert(bounds_array->elemtype == INT4OID);

        if (bounds_array->ndim != 2 || ARR_DIMS(bounds_array)[1] != 2)
            elog(ERROR, "bounds array size is invalid");

        if (ARR_HASNULL(bounds_array))
        {
            int size = ARR_DIMS(bounds_array)[0] * ARR_DIMS(bounds_array)[1]; 
            for (i = 0; i < (size + 7) / 8; i++)
                if (ARR_NULLBITMAP(bounds_array)[i] != 0)
                    elog(ERROR, "bounds array must not contain NULLs");
        }

        ndim = ARR_DIMS(bounds_array)[0]; 
        if (ndim > MAXDIM)
            elog(ERROR, "too many dimensions, max supported is %d", MAXDIM);

        bounds_data = (int32_t *) ARR_DATA_PTR(bounds_array);
        for (i = 0; i < ndim; i++) 
        {
            int ubs;

            lbs[i] = bounds_data[2*i];
            ubs = bounds_data[2*i+1];
            dims[i] = ubs - lbs[i];
        }

        ctx = intArrayInit(ndim, dims, lbs);
        MemoryContextSwitchTo(oldmemctx);
    }
    
    Assert(!ARR_HASNULL(ctx));
    Assert(ctx->elemtype == INT4OID);
    
    if (PG_ARGISNULL(1))
        elog(ERROR, "group index array must not be null");

    idx_array = PG_GETARG_ARRAYTYPE_P(1);
    Assert(idx_array != NULL);
    Assert(idx_array->elemtype == INT4OID);

    if (idx_array->ndim != 1)
        elog(ERROR, "group index array must have single dimension");

    if (ARR_DIMS(idx_array)[0] != ctx->ndim)
        elog(ERROR, "group index array length is inconsistent");

    if (ARR_HASNULL(idx_array))
    {
        int size = ARR_DIMS(idx_array)[0];
        for (i = 0; i < (size + 7) / 8; i++)
            /* Skip elements with nulls */
            if (ARR_NULLBITMAP(idx_array)[i] != 0)
            {
                elog(WARNING, "index array contains NULL, skipping");
                PG_RETURN_ARRAYTYPE_P(ctx); 
            }
    }
    

    pos_idx = intArrayIdx(ctx, (int *) ARR_DATA_PTR(idx_array), true);
    if (pos_idx != -1)
    {
        Assert(pos_idx >= 0);
        if (ARR_SIZE(ctx) - ARR_DATA_OFFSET(ctx) <= pos_idx * 4)
        {
            elog(ERROR, "Array out of bounds access: %ld %d", 
                 ARR_SIZE(ctx) - ARR_DATA_OFFSET(ctx), pos_idx * 4);
        }
        ctx_data = (int32_t *) ARR_DATA_PTR(ctx);
        ctx_data[pos_idx]++;
    }
    
    PG_RETURN_ARRAYTYPE_P(ctx);
}