in src/backend/utils/adt/agtype_ops.c [412:572]
Datum agtype_sub(PG_FUNCTION_ARGS)
{
agtype *lhs = AG_GET_ARG_AGTYPE_P(0);
agtype *rhs = AG_GET_ARG_AGTYPE_P(1);
agtype_value *agtv_lhs;
agtype_value *agtv_rhs;
agtype_value agtv_result;
/*
* Logic to handle when the rhs is a non scalar array. In this
* case;
* 1. if the lhs is an object, the values in the rhs array
* are string keys to be removed from the object.
* 2. if the lhs is an array, the values in the rhs array
* are integer indexes at which values should be removed from array.
* otherwise throw an error
*/
if (AGT_ROOT_IS_ARRAY(rhs) && !AGT_ROOT_IS_SCALAR(rhs))
{
agtype_iterator *it = NULL;
agtype_value elem;
if (AGT_ROOT_IS_OBJECT(lhs))
{
/*
* if rhs array contains any non-string element, error out
* else delete the given keys in the rhs array from lhs object
*/
while ((it = get_next_list_element(it, &rhs->root, &elem)))
{
if (elem.type == AGTV_STRING)
{
lhs = delete_from_object(lhs, elem.val.string.val,
elem.val.string.len);
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("expected agtype string, not agtype %s",
agtype_value_type_to_string(elem.type))));
}
}
}
else if (AGT_ROOT_IS_ARRAY(lhs) && !(AGT_ROOT_IS_SCALAR(lhs)))
{
/*
* if rhs array contains any non-integer element, error out
* else delete the values at the given indexes in rhs array
* from the lhs array
*/
while ((it = get_next_list_element(it, &rhs->root, &elem)))
{
if (elem.type != AGTV_INTEGER)
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("expected agtype integer, not agtype %s",
agtype_value_type_to_string(elem.type))));
}
}
lhs = delete_from_array(lhs, rhs);
}
else
{
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("must be object or array, not a scalar value")));
}
AG_RETURN_AGTYPE_P(lhs);
}
/*
* When the lhs is an object and rhs is a string, remove the key from
* the object.
* When the lhs is an array and the rhs is an integer then
* remove the value at that index from the array,
* otherwise give an error
*/
if(!AGT_ROOT_IS_SCALAR(lhs))
{
agtype_value *key;
key = get_ith_agtype_value_from_container(&rhs->root, 0);
if (AGT_ROOT_IS_OBJECT(lhs) && key->type == AGTV_STRING)
{
AG_RETURN_AGTYPE_P(delete_from_object(lhs, key->val.string.val,
key->val.string.len));
}
else if (AGT_ROOT_IS_ARRAY(lhs) && key->type == AGTV_INTEGER)
{
AG_RETURN_AGTYPE_P(delete_from_array(lhs, rhs));
}
else
{
if (AGT_ROOT_IS_OBJECT(lhs))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("expected agtype string, not agtype %s",
agtype_value_type_to_string(key->type))));
}
else if (AGT_ROOT_IS_ARRAY(lhs))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("expected agtype integer, not agtype %s",
agtype_value_type_to_string(key->type))));
}
}
}
agtv_lhs = get_ith_agtype_value_from_container(&lhs->root, 0);
agtv_rhs = get_ith_agtype_value_from_container(&rhs->root, 0);
if (agtv_lhs->type == AGTV_INTEGER && agtv_rhs->type == AGTV_INTEGER)
{
agtv_result.type = AGTV_INTEGER;
agtv_result.val.int_value = agtv_lhs->val.int_value -
agtv_rhs->val.int_value;
}
else if (agtv_lhs->type == AGTV_FLOAT && agtv_rhs->type == AGTV_FLOAT)
{
agtv_result.type = AGTV_FLOAT;
agtv_result.val.float_value = agtv_lhs->val.float_value -
agtv_rhs->val.float_value;
}
else if (agtv_lhs->type == AGTV_FLOAT && agtv_rhs->type == AGTV_INTEGER)
{
agtv_result.type = AGTV_FLOAT;
agtv_result.val.float_value = agtv_lhs->val.float_value -
agtv_rhs->val.int_value;
}
else if (agtv_lhs->type == AGTV_INTEGER && agtv_rhs->type == AGTV_FLOAT)
{
agtv_result.type = AGTV_FLOAT;
agtv_result.val.float_value = agtv_lhs->val.int_value -
agtv_rhs->val.float_value;
}
/* Is this a numeric result */
else if (is_numeric_result(agtv_lhs, agtv_rhs))
{
Datum numd, lhsd, rhsd;
lhsd = get_numeric_datum_from_agtype_value(agtv_lhs);
rhsd = get_numeric_datum_from_agtype_value(agtv_rhs);
numd = DirectFunctionCall2(numeric_sub, lhsd, rhsd);
agtv_result.type = AGTV_NUMERIC;
agtv_result.val.numeric = DatumGetNumeric(numd);
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Invalid input parameter types for agtype_sub")));
}
AG_RETURN_AGTYPE_P(agtype_value_to_agtype(&agtv_result));
}