Datum agtype_sub()

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