static void convert_agtype_object()

in src/backend/utils/adt/agtype_util.c [2124:2253]


static void convert_agtype_object(StringInfo buffer, agtentry *pheader,
                                  agtype_value *val, int level)
{
    int base_offset;
    int agtentry_offset;
    int i;
    int totallen;
    uint32 header;
    int num_pairs = val->val.object.num_pairs;

    /* Remember where in the buffer this object starts. */
    base_offset = buffer->len;

    /* Align to 4-byte boundary (any padding counts as part of my data) */
    pad_buffer_to_int(buffer);

    /*
     * Construct the header agtentry and store it in the beginning of the
     * variable-length payload.
     */
    header = num_pairs | AGT_FOBJECT;
    append_to_buffer(buffer, (char *)&header, sizeof(uint32));

    /* Reserve space for the agtentrys of the keys and values. */
    agtentry_offset = reserve_from_buffer(buffer,
                                          sizeof(agtentry) * num_pairs * 2);

    /*
     * Iterate over the keys, then over the values, since that is the ordering
     * we want in the on-disk representation.
     */
    totallen = 0;
    for (i = 0; i < num_pairs; i++)
    {
        agtype_pair *pair = &val->val.object.pairs[i];
        int len;
        agtentry meta;

        /*
         * Convert key, producing an agtentry and appending its variable-length
         * data to buffer
         */
        convert_agtype_scalar(buffer, &meta, &pair->key);

        len = AGTE_OFFLENFLD(meta);
        totallen += len;

        /*
         * Bail out if total variable-length data exceeds what will fit in a
         * agtentry length field.  We check this in each iteration, not just
         * once at the end, to forestall possible integer overflow.
         */
        if (totallen > AGTENTRY_OFFLENMASK)
        {
            ereport(
                ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg(
                     "total size of agtype object elements exceeds the maximum of %u bytes",
                     AGTENTRY_OFFLENMASK)));
        }

        /*
         * Convert each AGT_OFFSET_STRIDE'th length to an offset.
         */
        if ((i % AGT_OFFSET_STRIDE) == 0)
            meta = (meta & AGTENTRY_TYPEMASK) | totallen | AGTENTRY_HAS_OFF;

        copy_to_buffer(buffer, agtentry_offset, (char *)&meta,
                       sizeof(agtentry));
        agtentry_offset += sizeof(agtentry);
    }
    for (i = 0; i < num_pairs; i++)
    {
        agtype_pair *pair = &val->val.object.pairs[i];
        int len;
        agtentry meta;

        /*
         * Convert value, producing an agtentry and appending its
         * variable-length data to buffer
         */
        convert_agtype_value(buffer, &meta, &pair->value, level + 1);

        len = AGTE_OFFLENFLD(meta);
        totallen += len;

        /*
         * Bail out if total variable-length data exceeds what will fit in a
         * agtentry length field.  We check this in each iteration, not just
         * once at the end, to forestall possible integer overflow.
         */
        if (totallen > AGTENTRY_OFFLENMASK)
        {
            ereport(
                ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg(
                     "total size of agtype object elements exceeds the maximum of %u bytes",
                     AGTENTRY_OFFLENMASK)));
        }

        /*
         * Convert each AGT_OFFSET_STRIDE'th length to an offset.
         */
        if (((i + num_pairs) % AGT_OFFSET_STRIDE) == 0)
            meta = (meta & AGTENTRY_TYPEMASK) | totallen | AGTENTRY_HAS_OFF;

        copy_to_buffer(buffer, agtentry_offset, (char *)&meta,
                       sizeof(agtentry));
        agtentry_offset += sizeof(agtentry);
    }

    /* Total data size is everything we've appended to buffer */
    totallen = buffer->len - base_offset;

    /* Check length again, since we didn't include the metadata above */
    if (totallen > AGTENTRY_OFFLENMASK)
    {
        ereport(
            ERROR,
            (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
             errmsg(
                 "total size of agtype object elements exceeds the maximum of %u bytes",
                 AGTENTRY_OFFLENMASK)));
    }

    /* Initialize the header of this node in the container's agtentry array */
    *pheader = AGTENTRY_IS_CONTAINER | totallen;
}