Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

tupconvert.c File Reference

#include "postgres.h"
#include "access/htup_details.h"
#include "access/tupconvert.h"
#include "utils/builtins.h"
Include dependency graph for tupconvert.c:

Go to the source code of this file.

Functions

TupleConversionMapconvert_tuples_by_position (TupleDesc indesc, TupleDesc outdesc, const char *msg)
TupleConversionMapconvert_tuples_by_name (TupleDesc indesc, TupleDesc outdesc, const char *msg)
HeapTuple do_convert_tuple (HeapTuple tuple, TupleConversionMap *map)
void free_conversion_map (TupleConversionMap *map)

Function Documentation

TupleConversionMap* convert_tuples_by_name ( TupleDesc  indesc,
TupleDesc  outdesc,
const char *  msg 
)

Definition at line 203 of file tupconvert.c.

References _, TupleConversionMap::attrMap, tupleDesc::attrs, ereport, errcode(), errdetail(), errmsg_internal(), ERROR, format_type_be(), i, TupleConversionMap::indesc, TupleConversionMap::inisnull, TupleConversionMap::invalues, NameStr, tupleDesc::natts, TupleConversionMap::outdesc, TupleConversionMap::outisnull, TupleConversionMap::outvalues, palloc(), palloc0(), pfree(), and tupleDesc::tdtypeid.

Referenced by acquire_inherited_sample_rows(), and ExecEvalConvertRowtype().

{
    TupleConversionMap *map;
    AttrNumber *attrMap;
    int         n;
    int         i;
    bool        same;

    /* Verify compatibility and prepare attribute-number map */
    n = outdesc->natts;
    attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber));
    for (i = 0; i < n; i++)
    {
        Form_pg_attribute att = outdesc->attrs[i];
        char       *attname;
        Oid         atttypid;
        int32       atttypmod;
        int         j;

        if (att->attisdropped)
            continue;           /* attrMap[i] is already 0 */
        attname = NameStr(att->attname);
        atttypid = att->atttypid;
        atttypmod = att->atttypmod;
        for (j = 0; j < indesc->natts; j++)
        {
            att = indesc->attrs[j];
            if (att->attisdropped)
                continue;
            if (strcmp(attname, NameStr(att->attname)) == 0)
            {
                /* Found it, check type */
                if (atttypid != att->atttypid || atttypmod != att->atttypmod)
                    ereport(ERROR,
                            (errcode(ERRCODE_DATATYPE_MISMATCH),
                             errmsg_internal("%s", _(msg)),
                             errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.",
                                       attname,
                                       format_type_be(outdesc->tdtypeid),
                                       format_type_be(indesc->tdtypeid))));
                attrMap[i] = (AttrNumber) (j + 1);
                break;
            }
        }
        if (attrMap[i] == 0)
            ereport(ERROR,
                    (errcode(ERRCODE_DATATYPE_MISMATCH),
                     errmsg_internal("%s", _(msg)),
                     errdetail("Attribute \"%s\" of type %s does not exist in type %s.",
                               attname,
                               format_type_be(outdesc->tdtypeid),
                               format_type_be(indesc->tdtypeid))));
    }

    /*
     * Check to see if the map is one-to-one and the tuple types are the same.
     * (We check the latter because if they're not, we want to do conversion
     * to inject the right OID into the tuple datum.)
     */
    if (indesc->natts == outdesc->natts &&
        indesc->tdtypeid == outdesc->tdtypeid)
    {
        same = true;
        for (i = 0; i < n; i++)
        {
            if (attrMap[i] == (i + 1))
                continue;

            /*
             * If it's a dropped column and the corresponding input column is
             * also dropped, we needn't convert.  However, attlen and attalign
             * must agree.
             */
            if (attrMap[i] == 0 &&
                indesc->attrs[i]->attisdropped &&
                indesc->attrs[i]->attlen == outdesc->attrs[i]->attlen &&
                indesc->attrs[i]->attalign == outdesc->attrs[i]->attalign)
                continue;

            same = false;
            break;
        }
    }
    else
        same = false;

    if (same)
    {
        /* Runtime conversion is not needed */
        pfree(attrMap);
        return NULL;
    }

    /* Prepare the map structure */
    map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
    map->indesc = indesc;
    map->outdesc = outdesc;
    map->attrMap = attrMap;
    /* preallocate workspace for Datum arrays */
    map->outvalues = (Datum *) palloc(n * sizeof(Datum));
    map->outisnull = (bool *) palloc(n * sizeof(bool));
    n = indesc->natts + 1;      /* +1 for NULL */
    map->invalues = (Datum *) palloc(n * sizeof(Datum));
    map->inisnull = (bool *) palloc(n * sizeof(bool));
    map->invalues[0] = (Datum) 0;       /* set up the NULL entry */
    map->inisnull[0] = true;

    return map;
}

TupleConversionMap* convert_tuples_by_position ( TupleDesc  indesc,
TupleDesc  outdesc,
const char *  msg 
)

Definition at line 66 of file tupconvert.c.

References _, TupleConversionMap::attrMap, tupleDesc::attrs, ereport, errcode(), errdetail(), errmsg_internal(), ERROR, format_type_with_typemod(), i, TupleConversionMap::indesc, TupleConversionMap::inisnull, TupleConversionMap::invalues, tupleDesc::natts, TupleConversionMap::outdesc, TupleConversionMap::outisnull, TupleConversionMap::outvalues, palloc(), palloc0(), pfree(), and tupleDesc::tdtypeid.

Referenced by exec_stmt_return_next(), exec_stmt_return_query(), plpgsql_exec_function(), and plpgsql_exec_trigger().

{
    TupleConversionMap *map;
    AttrNumber *attrMap;
    int         nincols;
    int         noutcols;
    int         n;
    int         i;
    int         j;
    bool        same;

    /* Verify compatibility and prepare attribute-number map */
    n = outdesc->natts;
    attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber));
    j = 0;                      /* j is next physical input attribute */
    nincols = noutcols = 0;     /* these count non-dropped attributes */
    same = true;
    for (i = 0; i < n; i++)
    {
        Form_pg_attribute att = outdesc->attrs[i];
        Oid         atttypid;
        int32       atttypmod;

        if (att->attisdropped)
            continue;           /* attrMap[i] is already 0 */
        noutcols++;
        atttypid = att->atttypid;
        atttypmod = att->atttypmod;
        for (; j < indesc->natts; j++)
        {
            att = indesc->attrs[j];
            if (att->attisdropped)
                continue;
            nincols++;
            /* Found matching column, check type */
            if (atttypid != att->atttypid ||
                (atttypmod != att->atttypmod && atttypmod >= 0))
                ereport(ERROR,
                        (errcode(ERRCODE_DATATYPE_MISMATCH),
                         errmsg_internal("%s", _(msg)),
                         errdetail("Returned type %s does not match expected type %s in column %d.",
                                   format_type_with_typemod(att->atttypid,
                                                            att->atttypmod),
                                   format_type_with_typemod(atttypid,
                                                            atttypmod),
                                   noutcols)));
            attrMap[i] = (AttrNumber) (j + 1);
            j++;
            break;
        }
        if (attrMap[i] == 0)
            same = false;       /* we'll complain below */
    }

    /* Check for unused input columns */
    for (; j < indesc->natts; j++)
    {
        if (indesc->attrs[j]->attisdropped)
            continue;
        nincols++;
        same = false;           /* we'll complain below */
    }

    /* Report column count mismatch using the non-dropped-column counts */
    if (!same)
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg_internal("%s", _(msg)),
                 errdetail("Number of returned columns (%d) does not match "
                           "expected column count (%d).",
                           nincols, noutcols)));

    /*
     * Check to see if the map is one-to-one and the tuple types are the same.
     * (We check the latter because if they're not, we want to do conversion
     * to inject the right OID into the tuple datum.)
     */
    if (indesc->natts == outdesc->natts &&
        indesc->tdtypeid == outdesc->tdtypeid)
    {
        for (i = 0; i < n; i++)
        {
            if (attrMap[i] == (i + 1))
                continue;

            /*
             * If it's a dropped column and the corresponding input column is
             * also dropped, we needn't convert.  However, attlen and attalign
             * must agree.
             */
            if (attrMap[i] == 0 &&
                indesc->attrs[i]->attisdropped &&
                indesc->attrs[i]->attlen == outdesc->attrs[i]->attlen &&
                indesc->attrs[i]->attalign == outdesc->attrs[i]->attalign)
                continue;

            same = false;
            break;
        }
    }
    else
        same = false;

    if (same)
    {
        /* Runtime conversion is not needed */
        pfree(attrMap);
        return NULL;
    }

    /* Prepare the map structure */
    map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
    map->indesc = indesc;
    map->outdesc = outdesc;
    map->attrMap = attrMap;
    /* preallocate workspace for Datum arrays */
    map->outvalues = (Datum *) palloc(n * sizeof(Datum));
    map->outisnull = (bool *) palloc(n * sizeof(bool));
    n = indesc->natts + 1;      /* +1 for NULL */
    map->invalues = (Datum *) palloc(n * sizeof(Datum));
    map->inisnull = (bool *) palloc(n * sizeof(bool));
    map->invalues[0] = (Datum) 0;       /* set up the NULL entry */
    map->inisnull[0] = true;

    return map;
}

HeapTuple do_convert_tuple ( HeapTuple  tuple,
TupleConversionMap map 
)

Definition at line 319 of file tupconvert.c.

References TupleConversionMap::attrMap, heap_deform_tuple(), heap_form_tuple(), i, TupleConversionMap::indesc, TupleConversionMap::inisnull, TupleConversionMap::invalues, tupleDesc::natts, TupleConversionMap::outdesc, TupleConversionMap::outisnull, and TupleConversionMap::outvalues.

Referenced by acquire_inherited_sample_rows(), exec_stmt_return_next(), exec_stmt_return_query(), ExecEvalConvertRowtype(), plpgsql_exec_function(), and plpgsql_exec_trigger().

{
    AttrNumber *attrMap = map->attrMap;
    Datum      *invalues = map->invalues;
    bool       *inisnull = map->inisnull;
    Datum      *outvalues = map->outvalues;
    bool       *outisnull = map->outisnull;
    int         outnatts = map->outdesc->natts;
    int         i;

    /*
     * Extract all the values of the old tuple, offsetting the arrays so that
     * invalues[0] is left NULL and invalues[1] is the first source attribute;
     * this exactly matches the numbering convention in attrMap.
     */
    heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);

    /*
     * Transpose into proper fields of the new tuple.
     */
    for (i = 0; i < outnatts; i++)
    {
        int         j = attrMap[i];

        outvalues[i] = invalues[j];
        outisnull[i] = inisnull[j];
    }

    /*
     * Now form the new tuple.
     */
    return heap_form_tuple(map->outdesc, outvalues, outisnull);
}

void free_conversion_map ( TupleConversionMap map  )