Re: TupleDescCopy doesn't clear atthasdef, attnotnull, attidentity - Mailing list pgsql-hackers

From Tom Lane
Subject Re: TupleDescCopy doesn't clear atthasdef, attnotnull, attidentity
Date
Msg-id 31310.1515020488@sss.pgh.pa.us
Whole thread Raw
In response to TupleDescCopy doesn't clear atthasdef, attnotnull, attidentity  (Thomas Munro <thomas.munro@enterprisedb.com>)
Responses Re: TupleDescCopy doesn't clear atthasdef, attnotnull, attidentity
Re: TupleDescCopy doesn't clear atthasdef, attnotnull, attidentity
List pgsql-hackers
Thomas Munro <thomas.munro@enterprisedb.com> writes:
> Andrew Gierth complained off-list that TupleDescCopy() doesn't clear
> atthasdef.  Yeah, that's an oversight.  The function is new in commit
> cc5f81366c36 and was written by me to support "flat" (pointer-free)
> tuple descriptors for use in DSM.  Following the example of
> CreateTupleDescCopy() I think it should also clear attnotnull and
> attidentity.  Please see attached.

I've pushed this with some editorialization.  I added some comments, and
noting that you have TupleDescCopy() copying the entire attribute array
in one memcpy, I propagated that same approach into CreateTupleDescCopy
and CreateTupleDescCopyConstr.  This should make things a bit faster
since memcpy can spend more time in its maximum-stride loop.

The reason I note this explicitly is that I don't find it to be
entirely safe.  If ATTRIBUTE_FIXED_PART_SIZE were less than
sizeof(FormData_pg_attribute) due to alignment padding at the end of
the struct, I think we would get some valgrind complaints about copying
uninitialized data, since there are code paths in which only the first
ATTRIBUTE_FIXED_PART_SIZE bytes of each array entry get filled in.
Now, currently I don't think there's any padding there anyway on any
platform we support.  But if we're going to do things like this, I think
that we ought to explicitly make ATTRIBUTE_FIXED_PART_SIZE the same as
sizeof(FormData_pg_attribute).  Hence, I propose the attached follow-on
patch.

            regards, tom lane

diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index f1f4423..67d3d3d 100644
*** a/src/backend/access/common/tupdesc.c
--- b/src/backend/access/common/tupdesc.c
*************** CreateTemplateTupleDesc(int natts, bool
*** 57,65 ****
       * since we declare the array elements as FormData_pg_attribute for
       * notational convenience.  However, we only guarantee that the first
       * ATTRIBUTE_FIXED_PART_SIZE bytes of each entry are valid; most code that
!      * copies tupdesc entries around copies just that much.  In principle that
!      * could be less due to trailing padding, although with the current
!      * definition of pg_attribute there probably isn't any padding.
       */
      desc = (TupleDesc) palloc(offsetof(struct tupleDesc, attrs) +
                                natts * sizeof(FormData_pg_attribute));
--- 57,69 ----
       * since we declare the array elements as FormData_pg_attribute for
       * notational convenience.  However, we only guarantee that the first
       * ATTRIBUTE_FIXED_PART_SIZE bytes of each entry are valid; most code that
!      * copies tupdesc entries around copies just that much.  Currently, that
!      * symbol is just defined as sizeof(FormData_pg_attribute) anyway, so this
!      * distinction is somewhat academic.  If there were any trailing padding
!      * space in FormData_pg_attribute, it'd be possible to define
!      * ATTRIBUTE_FIXED_PART_SIZE to omit it, but that might cause complaints
!      * from valgrind about copying uninitialized padding bytes, so it seems
!      * best to keep them the same.
       */
      desc = (TupleDesc) palloc(offsetof(struct tupleDesc, attrs) +
                                natts * sizeof(FormData_pg_attribute));
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index 6104254..739e784 100644
*** a/src/include/catalog/pg_attribute.h
--- b/src/include/catalog/pg_attribute.h
*************** CATALOG(pg_attribute,1249) BKI_BOOTSTRAP
*** 175,183 ****
   * guaranteed-not-null part of a pg_attribute row.  This is in fact as much
   * of the row as gets copied into tuple descriptors, so don't expect you
   * can access fields beyond attcollation except in a real tuple!
   */
  #define ATTRIBUTE_FIXED_PART_SIZE \
!     (offsetof(FormData_pg_attribute,attcollation) + sizeof(Oid))

  /* ----------------
   *        Form_pg_attribute corresponds to a pointer to a tuple with
--- 175,188 ----
   * guaranteed-not-null part of a pg_attribute row.  This is in fact as much
   * of the row as gets copied into tuple descriptors, so don't expect you
   * can access fields beyond attcollation except in a real tuple!
+  *
+  * Since the introduction of CATALOG_VARLEN, this can just be defined as
+  * sizeof(FormData_pg_attribute).  It's possible that that would include
+  * some trailing alignment padding, but that's harmless (and anyway there
+  * is no such padding given the current contents of pg_attribute).
   */
  #define ATTRIBUTE_FIXED_PART_SIZE \
!     sizeof(FormData_pg_attribute)

  /* ----------------
   *        Form_pg_attribute corresponds to a pointer to a tuple with

pgsql-hackers by date:

Previous
From: Alexander Korotkov
Date:
Subject: Re: [HACKERS] Pluggable storage
Next
From: Tom Lane
Date:
Subject: Re: LIKE foo% optimization easily defeated by OR?