record_out and friends need to cope with dropped columns in the row
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 4 Aug 2004 19:31:15 +0000 (19:31 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 4 Aug 2004 19:31:15 +0000 (19:31 +0000)
datatype.  Per example from Gaetano Mendola, 2004-07-25.

src/backend/utils/adt/rowtypes.c

index 08189d3c143cfc2ac2e5b5cae0a5b85d0b1c8439..b5ddc05bc4a94e57aec75cb563eacd6c8c643992 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.3 2004/06/06 18:06:25 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.4 2004/08/04 19:31:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,6 +58,7 @@ record_in(PG_FUNCTION_ARGS)
    TupleDesc   tupdesc;
    HeapTuple   tuple;
    RecordIOData *my_extra;
+   bool        needComma = false;
    int         ncolumns;
    int         i;
    char       *ptr;
@@ -131,6 +132,26 @@ record_in(PG_FUNCTION_ARGS)
        ColumnIOData *column_info = &my_extra->columns[i];
        Oid         column_type = tupdesc->attrs[i]->atttypid;
 
+       /* Ignore dropped columns in datatype, but fill with nulls */
+       if (tupdesc->attrs[i]->attisdropped)
+       {
+           values[i] = (Datum) 0;
+           nulls[i] = 'n';
+           continue;
+       }
+
+       if (needComma)
+       {
+           /* Skip comma that separates prior field from this one */
+           if (*ptr == ',')
+               ptr++;
+           else                /* *ptr must be ')' */
+               ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+                        errmsg("malformed record literal: \"%s\"", string),
+                        errdetail("Too few columns.")));
+       }
+
        /* Check for null: completely empty input means null */
        if (*ptr == ',' || *ptr == ')')
        {
@@ -203,27 +224,9 @@ record_in(PG_FUNCTION_ARGS)
        /*
         * Prep for next column
         */
-       if (*ptr == ',')
-       {
-           if (i == ncolumns-1)
-               ereport(ERROR,
-                       (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-                        errmsg("malformed record literal: \"%s\"", string),
-                        errdetail("Too many columns.")));
-           ptr++;
-       }
-       else
-       {
-           /* *ptr must be ')' */
-           if (i < ncolumns-1)
-               ereport(ERROR,
-                       (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-                        errmsg("malformed record literal: \"%s\"", string),
-                        errdetail("Too few columns.")));
-       }
+       needComma = true;
    }
 
-   /* The check for ')' here is redundant except when ncolumns == 0 */
    if (*ptr++ != ')')
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
@@ -259,6 +262,7 @@ record_out(PG_FUNCTION_ARGS)
    TupleDesc   tupdesc;
    HeapTupleData tuple;
    RecordIOData *my_extra;
+   bool        needComma = false;
    int         ncolumns;
    int         i;
    Datum      *values;
@@ -333,8 +337,13 @@ record_out(PG_FUNCTION_ARGS)
        char    *tmp;
        bool    nq;
 
-       if (i > 0)
+       /* Ignore dropped columns in datatype */
+       if (tupdesc->attrs[i]->attisdropped)
+           continue;
+
+       if (needComma)
            appendStringInfoChar(&buf, ',');
+       needComma = true;
 
        if (nulls[i] == 'n')
        {
@@ -414,6 +423,8 @@ record_recv(PG_FUNCTION_ARGS)
    HeapTuple   tuple;
    RecordIOData *my_extra;
    int         ncolumns;
+   int         usercols;
+   int         validcols;
    int         i;
    Datum      *values;
    char       *nulls;
@@ -463,13 +474,21 @@ record_recv(PG_FUNCTION_ARGS)
    values = (Datum *) palloc(ncolumns * sizeof(Datum));
    nulls = (char *) palloc(ncolumns * sizeof(char));
 
-   /* Verify number of columns */
-   i = pq_getmsgint(buf, 4);
-   if (i != ncolumns)
+   /* Fetch number of columns user thinks it has */
+   usercols = pq_getmsgint(buf, 4);
+
+   /* Need to scan to count nondeleted columns */
+   validcols = 0;
+   for (i = 0; i < ncolumns; i++)
+   {
+       if (!tupdesc->attrs[i]->attisdropped)
+           validcols++;
+   }
+   if (usercols != validcols)
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("wrong number of columns: %d, expected %d",
-                       i, ncolumns)));
+                       usercols, validcols)));
 
    /* Process each column */
    for (i = 0; i < ncolumns; i++)
@@ -479,13 +498,21 @@ record_recv(PG_FUNCTION_ARGS)
        Oid         coltypoid;
        int         itemlen;
 
+       /* Ignore dropped columns in datatype, but fill with nulls */
+       if (tupdesc->attrs[i]->attisdropped)
+       {
+           values[i] = (Datum) 0;
+           nulls[i] = 'n';
+           continue;
+       }
+
        /* Verify column datatype */
        coltypoid = pq_getmsgint(buf, sizeof(Oid));
        if (coltypoid != column_type)
-       ereport(ERROR,
-               (errcode(ERRCODE_DATATYPE_MISMATCH),
-                errmsg("wrong data type: %u, expected %u",
-                       coltypoid, column_type)));
+           ereport(ERROR,
+                   (errcode(ERRCODE_DATATYPE_MISMATCH),
+                    errmsg("wrong data type: %u, expected %u",
+                           coltypoid, column_type)));
 
        /* Get and check the item length */
        itemlen = pq_getmsgint(buf, 4);
@@ -570,6 +597,7 @@ record_send(PG_FUNCTION_ARGS)
    HeapTupleData tuple;
    RecordIOData *my_extra;
    int         ncolumns;
+   int         validcols;
    int         i;
    Datum      *values;
    char       *nulls;
@@ -633,7 +661,14 @@ record_send(PG_FUNCTION_ARGS)
    /* And build the result string */
    pq_begintypsend(&buf);
 
-   pq_sendint(&buf, ncolumns, 4);
+   /* Need to scan to count nondeleted columns */
+   validcols = 0;
+   for (i = 0; i < ncolumns; i++)
+   {
+       if (!tupdesc->attrs[i]->attisdropped)
+           validcols++;
+   }
+   pq_sendint(&buf, validcols, 4);
 
    for (i = 0; i < ncolumns; i++)
    {
@@ -641,6 +676,10 @@ record_send(PG_FUNCTION_ARGS)
        Oid         column_type = tupdesc->attrs[i]->atttypid;
        bytea      *outputbytes;
 
+       /* Ignore dropped columns in datatype */
+       if (tupdesc->attrs[i]->attisdropped)
+           continue;
+
        pq_sendint(&buf, column_type, sizeof(Oid));
 
        if (nulls[i] == 'n')