/* * 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); }
/* * 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); }
/* * 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); }
/* * 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); }
/* * 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)); }
/* * 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)); }
/* * 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; }