Пример #1
0
/*
 * nth_value
 * return the value of VE evaluated on the n-th row from the first
 * row of the window frame, per spec.
 */
datum_t window_nth_value(PG_FUNC_ARGS)
{
	winobj_s* winobj = PG_WINOBJ();
	bool const_offset;
	datum_t result;
	bool isnull;
	int32 nth;

	nth = D_TO_INT32(winfunc_get_arg_current(winobj, 1, &isnull));
	if (isnull)
		RET_NULL();

	const_offset = get_fn_expr_arg_stable(fcinfo->flinfo, 1);

	if (nth <= 0)
		ereport(ERROR, (
		errcode(E_INVALID_ARGUMENT_FOR_NTH_VALUE),
		errmsg("argument of nth_value must be greater than zero")));

	result = winfunc_get_arg_in_frame(
		winobj,
		0,
		nth - 1,
		WINDOW_SEEK_HEAD,
		const_offset, 
		&isnull,
		NULL);
	if (isnull)
		RET_NULL();

	RET_DATUM(result);
}
Пример #2
0
/*
 * nth_value
 * return the value of VE evaluated on the n-th row from the first
 * row of the window frame, per spec.
 */
Datum
window_nth_value(PG_FUNCTION_ARGS)
{
	WindowObject winobj = PG_WINDOW_OBJECT();
	bool		const_offset;
	Datum		result;
	bool		isnull;
	int32		nth;

	nth = DatumGetInt32(WinGetFuncArgCurrent(winobj, 1, &isnull));
	if (isnull)
		PG_RETURN_NULL();
	const_offset = get_fn_expr_arg_stable(fcinfo->flinfo, 1);

	if (nth <= 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_NTH_VALUE),
				 errmsg("argument of nth_value must be greater than zero")));

	result = WinGetFuncArgInFrame(winobj, 0,
								  nth - 1, WINDOW_SEEK_HEAD, const_offset,
								  &isnull, NULL);
	if (isnull)
		PG_RETURN_NULL();

	PG_RETURN_DATUM(result);
}
Пример #3
0
/*
 * leadlag_common
 * common operation of lead() and lag()
 * For lead() forward is true, whereas for lag() it is false.
 * withoffset indicates we have an offset second argument.
 * withdefault indicates we have a default third argument.
 */
static Datum
leadlag_common(FunctionCallInfo fcinfo,
			   bool forward, bool withoffset, bool withdefault)
{
	WindowObject winobj = PG_WINDOW_OBJECT();
	int32		offset;
	bool		const_offset;
	Datum		result;
	bool		isnull;
	bool		isout;

	if (withoffset)
	{
		offset = DatumGetInt32(WinGetFuncArgCurrent(winobj, 1, &isnull));
		if (isnull)
			PG_RETURN_NULL();
		const_offset = get_fn_expr_arg_stable(fcinfo->flinfo, 1);
	}
	else
	{
		offset = 1;
		const_offset = true;
	}

	result = WinGetFuncArgInPartition(winobj, 0,
									  (forward ? offset : -offset),
									  WINDOW_SEEK_CURRENT,
									  const_offset,
									  &isnull, &isout);

	if (isout)
	{
		/*
		 * target row is out of the partition; supply default value if
		 * provided.  otherwise it'll stay NULL
		 */
		if (withdefault)
			result = WinGetFuncArgCurrent(winobj, 2, &isnull);
	}

	if (isnull)
		PG_RETURN_NULL();

	PG_RETURN_DATUM(result);
}
Пример #4
0
/*
 * leadlag_common
 * common operation of lead() and lag()
 * For lead() forward is true, whereas for lag() it is false.
 * withoffset indicates we have an offset second argument.
 * withdefault indicates we have a default third argument.
 */
static datum_t
leadlag_common(struct fc_info * fcinfo, bool forward, bool withoffset, bool withdefault)
{
	winobj_s* winobj = PG_WINOBJ();
	int32 offset;
	bool const_offset;
	datum_t result;
	bool isnull;
	bool isout;

	if (withoffset) {
		offset = D_TO_INT32(winfunc_get_arg_current(winobj, 1, &isnull));
		if (isnull)
			RET_NULL();

		const_offset = get_fn_expr_arg_stable(fcinfo->flinfo, 1);
	} else {
		offset = 1;
		const_offset = true;
	}

	result = winfunc_get_arg_in_partition(
		winobj,
		0,
		(forward ? offset : -offset),
		WINDOW_SEEK_CURRENT,
		const_offset,
		&isnull,	
		&isout);
	if (isout) {
		/*
		 * target row is out of the partition; supply default value if
		 * provided.  otherwise it'll stay NULL
		 */
		if (withdefault)
			result = winfunc_get_arg_current(winobj, 2, &isnull);
	}

	if (isnull)
		RET_NULL();

	RET_DATUM(result);
}
Пример #5
0
/*
 * SQL function jsonb_build_array(variadic "any")
 */
Datum
jsonb_build_array(PG_FUNCTION_ARGS)
{
	int			nargs = PG_NARGS();
	int			i;
	Datum		arg;
	Oid			val_type;
	JsonbInState result;

	memset(&result, 0, sizeof(JsonbInState));

	result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);

	for (i = 0; i < nargs; i++)
	{
		val_type = get_fn_expr_argtype(fcinfo->flinfo, i);
		arg = PG_GETARG_DATUM(i + 1);
		/* see comments in jsonb_build_object above */
		if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i))
		{
			val_type = TEXTOID;
			if (PG_ARGISNULL(i))
				arg = (Datum) 0;
			else
				arg = CStringGetTextDatum(PG_GETARG_POINTER(i));
		}
		else
		{
			arg = PG_GETARG_DATUM(i);
		}
		if (val_type == InvalidOid || val_type == UNKNOWNOID)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("arg %d: could not determine data type", i + 1)));
		add_jsonb(arg, PG_ARGISNULL(i), &result, val_type, false);
	}

	result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
}
Пример #6
0
/*
 * SQL function jsonb_build_object(variadic "any")
 */
Datum
jsonb_build_object(PG_FUNCTION_ARGS)
{
	int			nargs = PG_NARGS();
	int			i;
	Datum		arg;
	Oid			val_type;
	JsonbInState result;

	if (nargs % 2 != 0)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("invalid number of arguments: object must be matched key value pairs")));

	memset(&result, 0, sizeof(JsonbInState));

	result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);

	for (i = 0; i < nargs; i += 2)
	{
		/* process key */

		if (PG_ARGISNULL(i))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("argument %d: key must not be null", i + 1)));
		val_type = get_fn_expr_argtype(fcinfo->flinfo, i);

		/*
		 * turn a constant (more or less literal) value that's of unknown type
		 * into text. Unknowns come in as a cstring pointer.
		 */
		if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i))
		{
			val_type = TEXTOID;
			arg = CStringGetTextDatum(PG_GETARG_POINTER(i));
		}
		else
		{
			arg = PG_GETARG_DATUM(i);
		}
		if (val_type == InvalidOid || val_type == UNKNOWNOID)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
			   errmsg("argument %d: could not determine data type", i + 1)));

		add_jsonb(arg, false, &result, val_type, true);

		/* process value */

		val_type = get_fn_expr_argtype(fcinfo->flinfo, i + 1);
		/* see comments above */
		if (val_type == UNKNOWNOID && get_fn_expr_arg_stable(fcinfo->flinfo, i + 1))
		{
			val_type = TEXTOID;
			if (PG_ARGISNULL(i + 1))
				arg = (Datum) 0;
			else
				arg = CStringGetTextDatum(PG_GETARG_POINTER(i + 1));
		}
		else
		{
			arg = PG_GETARG_DATUM(i + 1);
		}
		if (val_type == InvalidOid || val_type == UNKNOWNOID)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
			   errmsg("argument %d: could not determine data type", i + 2)));
		add_jsonb(arg, PG_ARGISNULL(i + 1), &result, val_type, false);
	}

	result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);

	PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
}
Пример #7
0
/*
 * extract_variadic_args
 *
 * Extract a set of argument values, types and NULL markers for a given
 * input function which makes use of a VARIADIC input whose argument list
 * depends on the caller context. When doing a VARIADIC call, the caller
 * has provided one argument made of an array of values, so deconstruct the
 * array data before using it for the next processing. If no VARIADIC call
 * is used, just fill in the status data based on all the arguments given
 * by the caller.
 *
 * This function returns the number of arguments generated, or -1 in the
 * case of "VARIADIC NULL".
 */
int
extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
					  bool convert_unknown, Datum **args, Oid **types,
					  bool **nulls)
{
	bool		variadic = get_fn_expr_variadic(fcinfo->flinfo);
	Datum	   *args_res;
	bool	   *nulls_res;
	Oid		   *types_res;
	int			nargs,
				i;

	*args = NULL;
	*types = NULL;
	*nulls = NULL;

	if (variadic)
	{
		ArrayType  *array_in;
		Oid			element_type;
		bool		typbyval;
		char		typalign;
		int16		typlen;

		Assert(PG_NARGS() == variadic_start + 1);

		if (PG_ARGISNULL(variadic_start))
			return -1;

		array_in = PG_GETARG_ARRAYTYPE_P(variadic_start);
		element_type = ARR_ELEMTYPE(array_in);

		get_typlenbyvalalign(element_type,
							 &typlen, &typbyval, &typalign);
		deconstruct_array(array_in, element_type, typlen, typbyval,
						  typalign, &args_res, &nulls_res,
						  &nargs);

		/* All the elements of the array have the same type */
		types_res = (Oid *) palloc0(nargs * sizeof(Oid));
		for (i = 0; i < nargs; i++)
			types_res[i] = element_type;
	}
	else
	{
		nargs = PG_NARGS() - variadic_start;
		Assert(nargs > 0);
		nulls_res = (bool *) palloc0(nargs * sizeof(bool));
		args_res = (Datum *) palloc0(nargs * sizeof(Datum));
		types_res = (Oid *) palloc0(nargs * sizeof(Oid));

		for (i = 0; i < nargs; i++)
		{
			nulls_res[i] = PG_ARGISNULL(i + variadic_start);
			types_res[i] = get_fn_expr_argtype(fcinfo->flinfo,
											   i + variadic_start);

			/*
			 * Turn a constant (more or less literal) value that's of unknown
			 * type into text if required. Unknowns come in as a cstring
			 * pointer. Note: for functions declared as taking type "any", the
			 * parser will not do any type conversion on unknown-type literals
			 * (that is, undecorated strings or NULLs).
			 */
			if (convert_unknown &&
				types_res[i] == UNKNOWNOID &&
				get_fn_expr_arg_stable(fcinfo->flinfo, i + variadic_start))
			{
				types_res[i] = TEXTOID;

				if (PG_ARGISNULL(i + variadic_start))
					args_res[i] = (Datum) 0;
				else
					args_res[i] =
						CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
			}
			else
			{
				/* no conversion needed, just take the datum as given */
				args_res[i] = PG_GETARG_DATUM(i + variadic_start);
			}

			if (!OidIsValid(types_res[i]) ||
				(convert_unknown && types_res[i] == UNKNOWNOID))
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("could not determine data type for argument %d",
								i + 1)));
		}
	}

	/* Fill in results */
	*args = args_res;
	*nulls = nulls_res;
	*types = types_res;

	return nargs;
}