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')