postgresql/src/backend/utils/adt/expandedrecord.c

1633 lines
48 KiB
C
Raw Normal View History

Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
/*-------------------------------------------------------------------------
*
* expandedrecord.c
* Functions for manipulating composite expanded objects.
*
* This module supports "expanded objects" (cf. expandeddatum.h) that can
* store values of named composite types, domains over named composite types,
* and record types (registered or anonymous).
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/utils/adt/expandedrecord.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/htup_details.h"
2018-05-16 20:56:52 +02:00
#include "access/tuptoaster.h"
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
#include "catalog/heap.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/expandedrecord.h"
#include "utils/memutils.h"
#include "utils/typcache.h"
/* "Methods" required for an expanded object */
static Size ER_get_flat_size(ExpandedObjectHeader *eohptr);
static void ER_flatten_into(ExpandedObjectHeader *eohptr,
void *result, Size allocated_size);
static const ExpandedObjectMethods ER_methods =
{
ER_get_flat_size,
ER_flatten_into
};
/* Other local functions */
static void ER_mc_callback(void *arg);
2018-05-16 20:56:52 +02:00
static MemoryContext get_short_term_cxt(ExpandedRecordHeader *erh);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
static void build_dummy_expanded_header(ExpandedRecordHeader *main_erh);
static pg_noinline void check_domain_for_new_field(ExpandedRecordHeader *erh,
int fnumber,
Datum newValue, bool isnull);
static pg_noinline void check_domain_for_new_tuple(ExpandedRecordHeader *erh,
HeapTuple tuple);
/*
* Build an expanded record of the specified composite type
*
* type_id can be RECORDOID, but only if a positive typmod is given.
*
* The expanded record is initially "empty", having a state logically
* equivalent to a NULL composite value (not ROW(NULL, NULL, ...)).
2018-05-16 20:56:52 +02:00
* Note that this might not be a valid state for a domain type;
* if the caller needs to check that, call
* expanded_record_set_tuple(erh, NULL, false, false).
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
*
* The expanded object will be a child of parentcontext.
*/
ExpandedRecordHeader *
make_expanded_record_from_typeid(Oid type_id, int32 typmod,
MemoryContext parentcontext)
{
ExpandedRecordHeader *erh;
int flags = 0;
TupleDesc tupdesc;
uint64 tupdesc_id;
MemoryContext objcxt;
char *chunk;
if (type_id != RECORDOID)
{
/*
* Consult the typcache to see if it's a domain over composite, and in
* any case to get the tupdesc and tupdesc identifier.
*/
TypeCacheEntry *typentry;
typentry = lookup_type_cache(type_id,
TYPECACHE_TUPDESC |
TYPECACHE_DOMAIN_BASE_INFO);
if (typentry->typtype == TYPTYPE_DOMAIN)
{
flags |= ER_FLAG_IS_DOMAIN;
typentry = lookup_type_cache(typentry->domainBaseType,
TYPECACHE_TUPDESC);
}
if (typentry->tupDesc == NULL)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("type %s is not composite",
format_type_be(type_id))));
tupdesc = typentry->tupDesc;
tupdesc_id = typentry->tupDesc_identifier;
}
else
{
/*
* For RECORD types, get the tupdesc and identifier from typcache.
*/
tupdesc = lookup_rowtype_tupdesc(type_id, typmod);
tupdesc_id = assign_record_type_identifier(type_id, typmod);
}
/*
* Allocate private context for expanded object. We use a regular-size
* context, not a small one, to improve the odds that we can fit a tupdesc
* into it without needing an extra malloc block. (This code path doesn't
* ever need to copy a tupdesc into the expanded record, but let's be
* consistent with the other ways of making an expanded record.)
*/
objcxt = AllocSetContextCreate(parentcontext,
"expanded record",
ALLOCSET_DEFAULT_SIZES);
/*
* Since we already know the number of fields in the tupdesc, we can
* allocate the dvalues/dnulls arrays along with the record header. This
* is useless if we never need those arrays, but it costs almost nothing,
* and it will save a palloc cycle if we do need them.
*/
erh = (ExpandedRecordHeader *)
MemoryContextAlloc(objcxt, MAXALIGN(sizeof(ExpandedRecordHeader))
+ tupdesc->natts * (sizeof(Datum) + sizeof(bool)));
/* Ensure all header fields are initialized to 0/null */
memset(erh, 0, sizeof(ExpandedRecordHeader));
EOH_init_header(&erh->hdr, &ER_methods, objcxt);
erh->er_magic = ER_MAGIC;
/* Set up dvalues/dnulls, with no valid contents as yet */
chunk = (char *) erh + MAXALIGN(sizeof(ExpandedRecordHeader));
erh->dvalues = (Datum *) chunk;
erh->dnulls = (bool *) (chunk + tupdesc->natts * sizeof(Datum));
erh->nfields = tupdesc->natts;
/* Fill in composite-type identification info */
erh->er_decltypeid = type_id;
erh->er_typeid = tupdesc->tdtypeid;
erh->er_typmod = tupdesc->tdtypmod;
erh->er_tupdesc_id = tupdesc_id;
erh->flags = flags;
/*
* If what we got from the typcache is a refcounted tupdesc, we need to
* acquire our own refcount on it. We manage the refcount with a memory
* context callback rather than assuming that the CurrentResourceOwner is
* longer-lived than this expanded object.
*/
if (tupdesc->tdrefcount >= 0)
{
/* Register callback to release the refcount */
erh->er_mcb.func = ER_mc_callback;
erh->er_mcb.arg = (void *) erh;
MemoryContextRegisterResetCallback(erh->hdr.eoh_context,
&erh->er_mcb);
/* And save the pointer */
erh->er_tupdesc = tupdesc;
tupdesc->tdrefcount++;
/* If we called lookup_rowtype_tupdesc, release the pin it took */
if (type_id == RECORDOID)
DecrTupleDescRefCount(tupdesc);
}
else
{
/*
* If it's not refcounted, just assume it will outlive the expanded
* object. (This can happen for shared record types, for instance.)
*/
erh->er_tupdesc = tupdesc;
}
/*
* We don't set ER_FLAG_DVALUES_VALID or ER_FLAG_FVALUE_VALID, so the
* record remains logically empty.
*/
return erh;
}
/*
* Build an expanded record of the rowtype defined by the tupdesc
*
* The tupdesc is copied if necessary (i.e., if we can't just bump its
* reference count instead).
*
* The expanded record is initially "empty", having a state logically
* equivalent to a NULL composite value (not ROW(NULL, NULL, ...)).
*
* The expanded object will be a child of parentcontext.
*/
ExpandedRecordHeader *
make_expanded_record_from_tupdesc(TupleDesc tupdesc,
MemoryContext parentcontext)
{
ExpandedRecordHeader *erh;
uint64 tupdesc_id;
MemoryContext objcxt;
MemoryContext oldcxt;
char *chunk;
if (tupdesc->tdtypeid != RECORDOID)
{
/*
* If it's a named composite type (not RECORD), we prefer to reference
* the typcache's copy of the tupdesc, which is guaranteed to be
* refcounted (the given tupdesc might not be). In any case, we need
* to consult the typcache to get the correct tupdesc identifier.
*
* Note that tdtypeid couldn't be a domain type, so we need not
* consider that case here.
*/
TypeCacheEntry *typentry;
typentry = lookup_type_cache(tupdesc->tdtypeid, TYPECACHE_TUPDESC);
if (typentry->tupDesc == NULL)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("type %s is not composite",
format_type_be(tupdesc->tdtypeid))));
tupdesc = typentry->tupDesc;
tupdesc_id = typentry->tupDesc_identifier;
}
else
{
/*
* For RECORD types, get the appropriate unique identifier (possibly
* freshly assigned).
*/
tupdesc_id = assign_record_type_identifier(tupdesc->tdtypeid,
tupdesc->tdtypmod);
}
/*
* Allocate private context for expanded object. We use a regular-size
* context, not a small one, to improve the odds that we can fit a tupdesc
* into it without needing an extra malloc block.
*/
objcxt = AllocSetContextCreate(parentcontext,
"expanded record",
ALLOCSET_DEFAULT_SIZES);
/*
* Since we already know the number of fields in the tupdesc, we can
* allocate the dvalues/dnulls arrays along with the record header. This
* is useless if we never need those arrays, but it costs almost nothing,
* and it will save a palloc cycle if we do need them.
*/
erh = (ExpandedRecordHeader *)
MemoryContextAlloc(objcxt, MAXALIGN(sizeof(ExpandedRecordHeader))
+ tupdesc->natts * (sizeof(Datum) + sizeof(bool)));
/* Ensure all header fields are initialized to 0/null */
memset(erh, 0, sizeof(ExpandedRecordHeader));
EOH_init_header(&erh->hdr, &ER_methods, objcxt);
erh->er_magic = ER_MAGIC;
/* Set up dvalues/dnulls, with no valid contents as yet */
chunk = (char *) erh + MAXALIGN(sizeof(ExpandedRecordHeader));
erh->dvalues = (Datum *) chunk;
erh->dnulls = (bool *) (chunk + tupdesc->natts * sizeof(Datum));
erh->nfields = tupdesc->natts;
/* Fill in composite-type identification info */
erh->er_decltypeid = erh->er_typeid = tupdesc->tdtypeid;
erh->er_typmod = tupdesc->tdtypmod;
erh->er_tupdesc_id = tupdesc_id;
/*
* Copy tupdesc if needed, but we prefer to bump its refcount if possible.
* We manage the refcount with a memory context callback rather than
* assuming that the CurrentResourceOwner is longer-lived than this
* expanded object.
*/
if (tupdesc->tdrefcount >= 0)
{
/* Register callback to release the refcount */
erh->er_mcb.func = ER_mc_callback;
erh->er_mcb.arg = (void *) erh;
MemoryContextRegisterResetCallback(erh->hdr.eoh_context,
&erh->er_mcb);
/* And save the pointer */
erh->er_tupdesc = tupdesc;
tupdesc->tdrefcount++;
}
else
{
/* Just copy it */
oldcxt = MemoryContextSwitchTo(objcxt);
erh->er_tupdesc = CreateTupleDescCopy(tupdesc);
erh->flags |= ER_FLAG_TUPDESC_ALLOCED;
MemoryContextSwitchTo(oldcxt);
}
/*
* We don't set ER_FLAG_DVALUES_VALID or ER_FLAG_FVALUE_VALID, so the
* record remains logically empty.
*/
return erh;
}
/*
* Build an expanded record of the same rowtype as the given expanded record
*
* This is faster than either of the above routines because we can bypass
* typcache lookup(s).
*
* The expanded record is initially "empty" --- we do not copy whatever
* tuple might be in the source expanded record.
*
* The expanded object will be a child of parentcontext.
*/
ExpandedRecordHeader *
make_expanded_record_from_exprecord(ExpandedRecordHeader *olderh,
MemoryContext parentcontext)
{
ExpandedRecordHeader *erh;
TupleDesc tupdesc = expanded_record_get_tupdesc(olderh);
MemoryContext objcxt;
MemoryContext oldcxt;
char *chunk;
/*
* Allocate private context for expanded object. We use a regular-size
* context, not a small one, to improve the odds that we can fit a tupdesc
* into it without needing an extra malloc block.
*/
objcxt = AllocSetContextCreate(parentcontext,
"expanded record",
ALLOCSET_DEFAULT_SIZES);
/*
* Since we already know the number of fields in the tupdesc, we can
* allocate the dvalues/dnulls arrays along with the record header. This
* is useless if we never need those arrays, but it costs almost nothing,
* and it will save a palloc cycle if we do need them.
*/
erh = (ExpandedRecordHeader *)
MemoryContextAlloc(objcxt, MAXALIGN(sizeof(ExpandedRecordHeader))
+ tupdesc->natts * (sizeof(Datum) + sizeof(bool)));
/* Ensure all header fields are initialized to 0/null */
memset(erh, 0, sizeof(ExpandedRecordHeader));
EOH_init_header(&erh->hdr, &ER_methods, objcxt);
erh->er_magic = ER_MAGIC;
/* Set up dvalues/dnulls, with no valid contents as yet */
chunk = (char *) erh + MAXALIGN(sizeof(ExpandedRecordHeader));
erh->dvalues = (Datum *) chunk;
erh->dnulls = (bool *) (chunk + tupdesc->natts * sizeof(Datum));
erh->nfields = tupdesc->natts;
/* Fill in composite-type identification info */
erh->er_decltypeid = olderh->er_decltypeid;
erh->er_typeid = olderh->er_typeid;
erh->er_typmod = olderh->er_typmod;
erh->er_tupdesc_id = olderh->er_tupdesc_id;
/* The only flag bit that transfers over is IS_DOMAIN */
erh->flags = olderh->flags & ER_FLAG_IS_DOMAIN;
/*
* Copy tupdesc if needed, but we prefer to bump its refcount if possible.
* We manage the refcount with a memory context callback rather than
* assuming that the CurrentResourceOwner is longer-lived than this
* expanded object.
*/
if (tupdesc->tdrefcount >= 0)
{
/* Register callback to release the refcount */
erh->er_mcb.func = ER_mc_callback;
erh->er_mcb.arg = (void *) erh;
MemoryContextRegisterResetCallback(erh->hdr.eoh_context,
&erh->er_mcb);
/* And save the pointer */
erh->er_tupdesc = tupdesc;
tupdesc->tdrefcount++;
}
else if (olderh->flags & ER_FLAG_TUPDESC_ALLOCED)
{
/* We need to make our own copy of the tupdesc */
oldcxt = MemoryContextSwitchTo(objcxt);
erh->er_tupdesc = CreateTupleDescCopy(tupdesc);
erh->flags |= ER_FLAG_TUPDESC_ALLOCED;
MemoryContextSwitchTo(oldcxt);
}
else
{
/*
* Assume the tupdesc will outlive this expanded object, just like
* we're assuming it will outlive the source object.
*/
erh->er_tupdesc = tupdesc;
}
/*
* We don't set ER_FLAG_DVALUES_VALID or ER_FLAG_FVALUE_VALID, so the
* record remains logically empty.
*/
return erh;
}
/*
* Insert given tuple as the value of the expanded record
*
* It is caller's responsibility that the tuple matches the record's
* previously-assigned rowtype. (However domain constraints, if any,
* will be checked here.)
*
* The tuple is physically copied into the expanded record's local storage
* if "copy" is true, otherwise it's caller's responsibility that the tuple
2018-05-16 20:56:52 +02:00
* will live as long as the expanded record does.
*
* Out-of-line field values in the tuple are automatically inlined if
* "expand_external" is true, otherwise not. (The combination copy = false,
* expand_external = true is not sensible and not supported.)
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
*
* Alternatively, tuple can be NULL, in which case we just set the expanded
* record to be empty.
*/
void
expanded_record_set_tuple(ExpandedRecordHeader *erh,
HeapTuple tuple,
2018-05-16 20:56:52 +02:00
bool copy,
bool expand_external)
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
{
int oldflags;
HeapTuple oldtuple;
char *oldfstartptr;
char *oldfendptr;
int newflags;
HeapTuple newtuple;
MemoryContext oldcxt;
/* Shouldn't ever be trying to assign new data to a dummy header */
Assert(!(erh->flags & ER_FLAG_IS_DUMMY));
/*
* Before performing the assignment, see if result will satisfy domain.
*/
if (erh->flags & ER_FLAG_IS_DOMAIN)
check_domain_for_new_tuple(erh, tuple);
2018-05-16 20:56:52 +02:00
/*
* If we need to get rid of out-of-line field values, do so, using the
* short-term context to avoid leaking whatever cruft the toast fetch
* might generate.
*/
if (expand_external && tuple)
{
/* Assert caller didn't ask for unsupported case */
Assert(copy);
if (HeapTupleHasExternal(tuple))
{
oldcxt = MemoryContextSwitchTo(get_short_term_cxt(erh));
tuple = toast_flatten_tuple(tuple, erh->er_tupdesc);
MemoryContextSwitchTo(oldcxt);
}
else
expand_external = false; /* need not clean up below */
}
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
/*
* Initialize new flags, keeping only non-data status bits.
*/
oldflags = erh->flags;
newflags = oldflags & ER_FLAGS_NON_DATA;
/*
* Copy tuple into local storage if needed. We must be sure this succeeds
* before we start to modify the expanded record's state.
*/
if (copy && tuple)
{
oldcxt = MemoryContextSwitchTo(erh->hdr.eoh_context);
newtuple = heap_copytuple(tuple);
newflags |= ER_FLAG_FVALUE_ALLOCED;
MemoryContextSwitchTo(oldcxt);
2018-05-16 20:56:52 +02:00
/* We can now flush anything that detoasting might have leaked. */
if (expand_external)
MemoryContextReset(erh->er_short_term_cxt);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
}
else
newtuple = tuple;
/* Make copies of fields we're about to overwrite */
oldtuple = erh->fvalue;
oldfstartptr = erh->fstartptr;
oldfendptr = erh->fendptr;
/*
* It's now safe to update the expanded record's state.
*/
if (newtuple)
{
/* Save flat representation */
erh->fvalue = newtuple;
erh->fstartptr = (char *) newtuple->t_data;
erh->fendptr = ((char *) newtuple->t_data) + newtuple->t_len;
newflags |= ER_FLAG_FVALUE_VALID;
/* Remember if we have any out-of-line field values */
if (HeapTupleHasExternal(newtuple))
newflags |= ER_FLAG_HAVE_EXTERNAL;
}
else
{
erh->fvalue = NULL;
erh->fstartptr = erh->fendptr = NULL;
}
erh->flags = newflags;
/* Reset flat-size info; we don't bother to make it valid now */
erh->flat_size = 0;
/*
* Now, release any storage belonging to old field values. It's safe to
* do this because ER_FLAG_DVALUES_VALID is no longer set in erh->flags;
* even if we fail partway through, the record is valid, and at worst
* we've failed to reclaim some space.
*/
if (oldflags & ER_FLAG_DVALUES_ALLOCED)
{
TupleDesc tupdesc = erh->er_tupdesc;
int i;
for (i = 0; i < erh->nfields; i++)
{
if (!erh->dnulls[i] &&
!(TupleDescAttr(tupdesc, i)->attbyval))
{
char *oldValue = (char *) DatumGetPointer(erh->dvalues[i]);
if (oldValue < oldfstartptr || oldValue >= oldfendptr)
pfree(oldValue);
}
}
}
/* Likewise free the old tuple, if it was locally allocated */
if (oldflags & ER_FLAG_FVALUE_ALLOCED)
heap_freetuple(oldtuple);
/* We won't make a new deconstructed representation until/unless needed */
}
/*
* make_expanded_record_from_datum: build expanded record from composite Datum
*
* This combines the functions of make_expanded_record_from_typeid and
* expanded_record_set_tuple. However, we do not force a lookup of the
* tupdesc immediately, reasoning that it might never be needed.
*
* The expanded object will be a child of parentcontext.
*
* Note: a composite datum cannot self-identify as being of a domain type,
* so we need not consider domain cases here.
*/
Datum
make_expanded_record_from_datum(Datum recorddatum, MemoryContext parentcontext)
{
ExpandedRecordHeader *erh;
HeapTupleHeader tuphdr;
HeapTupleData tmptup;
HeapTuple newtuple;
MemoryContext objcxt;
MemoryContext oldcxt;
/*
* Allocate private context for expanded object. We use a regular-size
* context, not a small one, to improve the odds that we can fit a tupdesc
* into it without needing an extra malloc block.
*/
objcxt = AllocSetContextCreate(parentcontext,
"expanded record",
ALLOCSET_DEFAULT_SIZES);
/* Set up expanded record header, initializing fields to 0/null */
erh = (ExpandedRecordHeader *)
MemoryContextAllocZero(objcxt, sizeof(ExpandedRecordHeader));
EOH_init_header(&erh->hdr, &ER_methods, objcxt);
erh->er_magic = ER_MAGIC;
/*
* Detoast and copy source record into private context, as a HeapTuple.
* (If we actually have to detoast the source, we'll leak some memory in
* the caller's context, but it doesn't seem worth worrying about.)
*/
tuphdr = DatumGetHeapTupleHeader(recorddatum);
tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr);
ItemPointerSetInvalid(&(tmptup.t_self));
tmptup.t_tableOid = InvalidOid;
tmptup.t_data = tuphdr;
oldcxt = MemoryContextSwitchTo(objcxt);
newtuple = heap_copytuple(&tmptup);
erh->flags |= ER_FLAG_FVALUE_ALLOCED;
MemoryContextSwitchTo(oldcxt);
/* Fill in composite-type identification info */
erh->er_decltypeid = erh->er_typeid = HeapTupleHeaderGetTypeId(tuphdr);
erh->er_typmod = HeapTupleHeaderGetTypMod(tuphdr);
/* remember we have a flat representation */
erh->fvalue = newtuple;
erh->fstartptr = (char *) newtuple->t_data;
erh->fendptr = ((char *) newtuple->t_data) + newtuple->t_len;
erh->flags |= ER_FLAG_FVALUE_VALID;
/* Shouldn't need to set ER_FLAG_HAVE_EXTERNAL */
Assert(!HeapTupleHeaderHasExternal(tuphdr));
/*
* We won't look up the tupdesc till we have to, nor make a deconstructed
* representation. We don't have enough info to fill flat_size and
* friends, either.
*/
/* return a R/W pointer to the expanded record */
return EOHPGetRWDatum(&erh->hdr);
}
/*
* get_flat_size method for expanded records
*
* Note: call this in a reasonably short-lived memory context, in case of
* memory leaks from activities such as detoasting.
*/
static Size
ER_get_flat_size(ExpandedObjectHeader *eohptr)
{
ExpandedRecordHeader *erh = (ExpandedRecordHeader *) eohptr;
TupleDesc tupdesc;
Size len;
Size data_len;
int hoff;
bool hasnull;
int i;
Assert(erh->er_magic == ER_MAGIC);
/*
* The flat representation has to be a valid composite datum. Make sure
* that we have a registered, not anonymous, RECORD type.
*/
if (erh->er_typeid == RECORDOID &&
erh->er_typmod < 0)
{
tupdesc = expanded_record_get_tupdesc(erh);
assign_record_type_typmod(tupdesc);
erh->er_typmod = tupdesc->tdtypmod;
}
/*
* If we have a valid flattened value without out-of-line fields, we can
* just use it as-is.
*/
if (erh->flags & ER_FLAG_FVALUE_VALID &&
!(erh->flags & ER_FLAG_HAVE_EXTERNAL))
return erh->fvalue->t_len;
/* If we have a cached size value, believe that */
if (erh->flat_size)
return erh->flat_size;
/* If we haven't yet deconstructed the tuple, do that */
if (!(erh->flags & ER_FLAG_DVALUES_VALID))
deconstruct_expanded_record(erh);
/* Tuple descriptor must be valid by now */
tupdesc = erh->er_tupdesc;
/*
* Composite datums mustn't contain any out-of-line values.
*/
if (erh->flags & ER_FLAG_HAVE_EXTERNAL)
{
for (i = 0; i < erh->nfields; i++)
{
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
if (!erh->dnulls[i] &&
!attr->attbyval && attr->attlen == -1 &&
VARATT_IS_EXTERNAL(DatumGetPointer(erh->dvalues[i])))
{
/*
2018-05-16 20:56:52 +02:00
* expanded_record_set_field_internal can do the actual work
* of detoasting. It needn't recheck domain constraints.
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
*/
expanded_record_set_field_internal(erh, i + 1,
2018-05-16 20:56:52 +02:00
erh->dvalues[i], false,
true,
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
false);
}
}
/*
* We have now removed all external field values, so we can clear the
* flag about them. This won't cause ER_flatten_into() to mistakenly
* take the fast path, since expanded_record_set_field() will have
* cleared ER_FLAG_FVALUE_VALID.
*/
erh->flags &= ~ER_FLAG_HAVE_EXTERNAL;
}
/* Test if we currently have any null values */
hasnull = false;
for (i = 0; i < erh->nfields; i++)
{
if (erh->dnulls[i])
{
hasnull = true;
break;
}
}
/* Determine total space needed */
len = offsetof(HeapTupleHeaderData, t_bits);
if (hasnull)
len += BITMAPLEN(tupdesc->natts);
hoff = len = MAXALIGN(len); /* align user data safely */
data_len = heap_compute_data_size(tupdesc, erh->dvalues, erh->dnulls);
len += data_len;
/* Cache for next time */
erh->flat_size = len;
erh->data_len = data_len;
erh->hoff = hoff;
erh->hasnull = hasnull;
return len;
}
/*
* flatten_into method for expanded records
*/
static void
ER_flatten_into(ExpandedObjectHeader *eohptr,
void *result, Size allocated_size)
{
ExpandedRecordHeader *erh = (ExpandedRecordHeader *) eohptr;
HeapTupleHeader tuphdr = (HeapTupleHeader) result;
TupleDesc tupdesc;
Assert(erh->er_magic == ER_MAGIC);
/* Easy if we have a valid flattened value without out-of-line fields */
if (erh->flags & ER_FLAG_FVALUE_VALID &&
!(erh->flags & ER_FLAG_HAVE_EXTERNAL))
{
Assert(allocated_size == erh->fvalue->t_len);
memcpy(tuphdr, erh->fvalue->t_data, allocated_size);
/* The original flattened value might not have datum header fields */
HeapTupleHeaderSetDatumLength(tuphdr, allocated_size);
HeapTupleHeaderSetTypeId(tuphdr, erh->er_typeid);
HeapTupleHeaderSetTypMod(tuphdr, erh->er_typmod);
return;
}
/* Else allocation should match previous get_flat_size result */
Assert(allocated_size == erh->flat_size);
/* We'll need the tuple descriptor */
tupdesc = expanded_record_get_tupdesc(erh);
/* We must ensure that any pad space is zero-filled */
memset(tuphdr, 0, allocated_size);
/* Set up header fields of composite Datum */
HeapTupleHeaderSetDatumLength(tuphdr, allocated_size);
HeapTupleHeaderSetTypeId(tuphdr, erh->er_typeid);
HeapTupleHeaderSetTypMod(tuphdr, erh->er_typmod);
/* We also make sure that t_ctid is invalid unless explicitly set */
ItemPointerSetInvalid(&(tuphdr->t_ctid));
HeapTupleHeaderSetNatts(tuphdr, tupdesc->natts);
tuphdr->t_hoff = erh->hoff;
/* And fill the data area from dvalues/dnulls */
heap_fill_tuple(tupdesc,
erh->dvalues,
erh->dnulls,
(char *) tuphdr + erh->hoff,
erh->data_len,
&tuphdr->t_infomask,
(erh->hasnull ? tuphdr->t_bits : NULL));
}
/*
* Look up the tupdesc for the expanded record's actual type
*
* Note: code internal to this module is allowed to just fetch
* erh->er_tupdesc if ER_FLAG_DVALUES_VALID is set; otherwise it should call
* expanded_record_get_tupdesc. This function is the out-of-line portion
* of expanded_record_get_tupdesc.
*/
TupleDesc
expanded_record_fetch_tupdesc(ExpandedRecordHeader *erh)
{
TupleDesc tupdesc;
/* Easy if we already have it (but caller should have checked already) */
if (erh->er_tupdesc)
return erh->er_tupdesc;
/* Lookup the composite type's tupdesc using the typcache */
tupdesc = lookup_rowtype_tupdesc(erh->er_typeid, erh->er_typmod);
/*
* If it's a refcounted tupdesc rather than a statically allocated one, we
* want to manage the refcount with a memory context callback rather than
* assuming that the CurrentResourceOwner is longer-lived than this
* expanded object.
*/
if (tupdesc->tdrefcount >= 0)
{
/* Register callback if we didn't already */
if (erh->er_mcb.arg == NULL)
{
erh->er_mcb.func = ER_mc_callback;
erh->er_mcb.arg = (void *) erh;
MemoryContextRegisterResetCallback(erh->hdr.eoh_context,
&erh->er_mcb);
}
/* Remember our own pointer */
erh->er_tupdesc = tupdesc;
tupdesc->tdrefcount++;
/* Release the pin lookup_rowtype_tupdesc acquired */
DecrTupleDescRefCount(tupdesc);
}
else
{
/* Just remember the pointer */
erh->er_tupdesc = tupdesc;
}
/* In either case, fetch the process-global ID for this tupdesc */
erh->er_tupdesc_id = assign_record_type_identifier(tupdesc->tdtypeid,
tupdesc->tdtypmod);
return tupdesc;
}
/*
* Get a HeapTuple representing the current value of the expanded record
*
* If valid, the originally stored tuple is returned, so caller must not
* scribble on it. Otherwise, we return a HeapTuple created in the current
* memory context. In either case, no attempt has been made to inline
* out-of-line toasted values, so the tuple isn't usable as a composite
* datum.
*
* Returns NULL if expanded record is empty.
*/
HeapTuple
expanded_record_get_tuple(ExpandedRecordHeader *erh)
{
/* Easy case if we still have original tuple */
if (erh->flags & ER_FLAG_FVALUE_VALID)
return erh->fvalue;
/* Else just build a tuple from datums */
if (erh->flags & ER_FLAG_DVALUES_VALID)
return heap_form_tuple(erh->er_tupdesc, erh->dvalues, erh->dnulls);
/* Expanded record is empty */
return NULL;
}
/*
* Memory context reset callback for cleaning up external resources
*/
static void
ER_mc_callback(void *arg)
{
ExpandedRecordHeader *erh = (ExpandedRecordHeader *) arg;
TupleDesc tupdesc = erh->er_tupdesc;
/* Release our privately-managed tupdesc refcount, if any */
if (tupdesc)
{
erh->er_tupdesc = NULL; /* just for luck */
if (tupdesc->tdrefcount > 0)
{
if (--tupdesc->tdrefcount == 0)
FreeTupleDesc(tupdesc);
}
}
}
/*
* DatumGetExpandedRecord: get a writable expanded record from an input argument
*
* Caution: if the input is a read/write pointer, this returns the input
* argument; so callers must be sure that their changes are "safe", that is
* they cannot leave the record in a corrupt state.
*/
ExpandedRecordHeader *
DatumGetExpandedRecord(Datum d)
{
/* If it's a writable expanded record already, just return it */
if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
{
ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(d);
Assert(erh->er_magic == ER_MAGIC);
return erh;
}
/* Else expand the hard way */
d = make_expanded_record_from_datum(d, CurrentMemoryContext);
return (ExpandedRecordHeader *) DatumGetEOHP(d);
}
/*
* Create the Datum/isnull representation of an expanded record object
* if we didn't do so already. After calling this, it's OK to read the
* dvalues/dnulls arrays directly, rather than going through get_field.
*
* Note that if the object is currently empty ("null"), this will change
* it to represent a row of nulls.
*/
void
deconstruct_expanded_record(ExpandedRecordHeader *erh)
{
TupleDesc tupdesc;
Datum *dvalues;
bool *dnulls;
int nfields;
if (erh->flags & ER_FLAG_DVALUES_VALID)
return; /* already valid, nothing to do */
/* We'll need the tuple descriptor */
tupdesc = expanded_record_get_tupdesc(erh);
/*
* Allocate arrays in private context, if we don't have them already. We
* don't expect to see a change in nfields here, so while we cope if it
* happens, we don't bother avoiding a leak of the old arrays (which might
* not be separately palloc'd, anyway).
*/
nfields = tupdesc->natts;
if (erh->dvalues == NULL || erh->nfields != nfields)
{
char *chunk;
/*
* To save a palloc cycle, we allocate both the Datum and isnull
* arrays in one palloc chunk.
*/
chunk = MemoryContextAlloc(erh->hdr.eoh_context,
nfields * (sizeof(Datum) + sizeof(bool)));
dvalues = (Datum *) chunk;
dnulls = (bool *) (chunk + nfields * sizeof(Datum));
erh->dvalues = dvalues;
erh->dnulls = dnulls;
erh->nfields = nfields;
}
else
{
dvalues = erh->dvalues;
dnulls = erh->dnulls;
}
if (erh->flags & ER_FLAG_FVALUE_VALID)
{
/* Deconstruct tuple */
heap_deform_tuple(erh->fvalue, tupdesc, dvalues, dnulls);
}
else
{
/* If record was empty, instantiate it as a row of nulls */
memset(dvalues, 0, nfields * sizeof(Datum));
memset(dnulls, true, nfields * sizeof(bool));
}
/* Mark the dvalues as valid */
erh->flags |= ER_FLAG_DVALUES_VALID;
}
/*
* Look up a record field by name
*
* If there is a field named "fieldname", fill in the contents of finfo
* and return "true". Else return "false" without changing *finfo.
*/
bool
expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname,
ExpandedRecordFieldInfo *finfo)
{
TupleDesc tupdesc;
int fno;
Form_pg_attribute attr;
const FormData_pg_attribute *sysattr;
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
tupdesc = expanded_record_get_tupdesc(erh);
/* First, check user-defined attributes */
for (fno = 0; fno < tupdesc->natts; fno++)
{
attr = TupleDescAttr(tupdesc, fno);
if (namestrcmp(&attr->attname, fieldname) == 0 &&
!attr->attisdropped)
{
finfo->fnumber = attr->attnum;
finfo->ftypeid = attr->atttypid;
finfo->ftypmod = attr->atttypmod;
finfo->fcollation = attr->attcollation;
return true;
}
}
/* How about system attributes? */
Remove WITH OIDS support, change oid catalog column visibility. Previously tables declared WITH OIDS, including a significant fraction of the catalog tables, stored the oid column not as a normal column, but as part of the tuple header. This special column was not shown by default, which was somewhat odd, as it's often (consider e.g. pg_class.oid) one of the more important parts of a row. Neither pg_dump nor COPY included the contents of the oid column by default. The fact that the oid column was not an ordinary column necessitated a significant amount of special case code to support oid columns. That already was painful for the existing, but upcoming work aiming to make table storage pluggable, would have required expanding and duplicating that "specialness" significantly. WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0). Remove it. Removing includes: - CREATE TABLE and ALTER TABLE syntax for declaring the table to be WITH OIDS has been removed (WITH (oids[ = true]) will error out) - pg_dump does not support dumping tables declared WITH OIDS and will issue a warning when dumping one (and ignore the oid column). - restoring an pg_dump archive with pg_restore will warn when restoring a table with oid contents (and ignore the oid column) - COPY will refuse to load binary dump that includes oids. - pg_upgrade will error out when encountering tables declared WITH OIDS, they have to be altered to remove the oid column first. - Functionality to access the oid of the last inserted row (like plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed. The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false) for CREATE TABLE) is still supported. While that requires a bit of support code, it seems unnecessary to break applications / dumps that do not use oids, and are explicit about not using them. The biggest user of WITH OID columns was postgres' catalog. This commit changes all 'magic' oid columns to be columns that are normally declared and stored. To reduce unnecessary query breakage all the newly added columns are still named 'oid', even if a table's column naming scheme would indicate 'reloid' or such. This obviously requires adapting a lot code, mostly replacing oid access via HeapTupleGetOid() with access to the underlying Form_pg_*->oid column. The bootstrap process now assigns oids for all oid columns in genbki.pl that do not have an explicit value (starting at the largest oid previously used), only oids assigned later by oids will be above FirstBootstrapObjectId. As the oid column now is a normal column the special bootstrap syntax for oids has been removed. Oids are not automatically assigned during insertion anymore, all backend code explicitly assigns oids with GetNewOidWithIndex(). For the rare case that insertions into the catalog via SQL are called for the new pg_nextoid() function can be used (which only works on catalog tables). The fact that oid columns on system tables are now normal columns means that they will be included in the set of columns expanded by * (i.e. SELECT * FROM pg_class will now include the table's oid, previously it did not). It'd not technically be hard to hide oid column by default, but that'd mean confusing behavior would either have to be carried forward forever, or it'd cause breakage down the line. While it's not unlikely that further adjustments are needed, the scope/invasiveness of the patch makes it worthwhile to get merge this now. It's painful to maintain externally, too complicated to commit after the code code freeze, and a dependency of a number of other patches. Catversion bump, for obvious reasons. Author: Andres Freund, with contributions by John Naylor Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
2018-11-21 00:36:57 +01:00
sysattr = SystemAttributeByName(fieldname);
if (sysattr != NULL)
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
{
finfo->fnumber = sysattr->attnum;
finfo->ftypeid = sysattr->atttypid;
finfo->ftypmod = sysattr->atttypmod;
finfo->fcollation = sysattr->attcollation;
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
return true;
}
return false;
}
/*
* Fetch value of record field
*
* expanded_record_get_field is the frontend for this; it handles the
* easy inline-able cases.
*/
Datum
expanded_record_fetch_field(ExpandedRecordHeader *erh, int fnumber,
bool *isnull)
{
if (fnumber > 0)
{
/* Empty record has null fields */
if (ExpandedRecordIsEmpty(erh))
{
*isnull = true;
return (Datum) 0;
}
/* Make sure we have deconstructed form */
deconstruct_expanded_record(erh);
/* Out-of-range field number reads as null */
if (unlikely(fnumber > erh->nfields))
{
*isnull = true;
return (Datum) 0;
}
*isnull = erh->dnulls[fnumber - 1];
return erh->dvalues[fnumber - 1];
}
else
{
/* System columns read as null if we haven't got flat tuple */
if (erh->fvalue == NULL)
{
*isnull = true;
return (Datum) 0;
}
/* heap_getsysattr doesn't actually use tupdesc, so just pass null */
return heap_getsysattr(erh->fvalue, fnumber, NULL, isnull);
}
}
/*
* Set value of record field
*
* If the expanded record is of domain type, the assignment will be rejected
* (without changing the record's state) if the domain's constraints would
* be violated.
*
2018-05-16 20:56:52 +02:00
* If expand_external is true and newValue is an out-of-line value, we'll
* forcibly detoast it so that the record does not depend on external storage.
*
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
* Internal callers can pass check_constraints = false to skip application
* of domain constraints. External callers should never do that.
*/
void
expanded_record_set_field_internal(ExpandedRecordHeader *erh, int fnumber,
Datum newValue, bool isnull,
2018-05-16 20:56:52 +02:00
bool expand_external,
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
bool check_constraints)
{
TupleDesc tupdesc;
Form_pg_attribute attr;
Datum *dvalues;
bool *dnulls;
char *oldValue;
/*
* Shouldn't ever be trying to assign new data to a dummy header, except
* in the case of an internal call for field inlining.
*/
Assert(!(erh->flags & ER_FLAG_IS_DUMMY) || !check_constraints);
/* Before performing the assignment, see if result will satisfy domain */
if ((erh->flags & ER_FLAG_IS_DOMAIN) && check_constraints)
check_domain_for_new_field(erh, fnumber, newValue, isnull);
/* If we haven't yet deconstructed the tuple, do that */
if (!(erh->flags & ER_FLAG_DVALUES_VALID))
deconstruct_expanded_record(erh);
/* Tuple descriptor must be valid by now */
tupdesc = erh->er_tupdesc;
Assert(erh->nfields == tupdesc->natts);
/* Caller error if fnumber is system column or nonexistent column */
if (unlikely(fnumber <= 0 || fnumber > erh->nfields))
elog(ERROR, "cannot assign to field %d of expanded record", fnumber);
/*
2018-05-16 20:56:52 +02:00
* Copy new field value into record's context, and deal with detoasting,
* if needed.
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
*/
attr = TupleDescAttr(tupdesc, fnumber - 1);
if (!isnull && !attr->attbyval)
{
MemoryContext oldcxt;
2018-05-16 20:56:52 +02:00
/* If requested, detoast any external value */
if (expand_external)
{
if (attr->attlen == -1 &&
VARATT_IS_EXTERNAL(DatumGetPointer(newValue)))
{
/* Detoasting should be done in short-lived context. */
oldcxt = MemoryContextSwitchTo(get_short_term_cxt(erh));
newValue = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *) DatumGetPointer(newValue)));
MemoryContextSwitchTo(oldcxt);
}
else
expand_external = false; /* need not clean up below */
}
/* Copy value into record's context */
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
oldcxt = MemoryContextSwitchTo(erh->hdr.eoh_context);
newValue = datumCopy(newValue, false, attr->attlen);
MemoryContextSwitchTo(oldcxt);
2018-05-16 20:56:52 +02:00
/* We can now flush anything that detoasting might have leaked */
if (expand_external)
MemoryContextReset(erh->er_short_term_cxt);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
/* Remember that we have field(s) that may need to be pfree'd */
erh->flags |= ER_FLAG_DVALUES_ALLOCED;
/*
* While we're here, note whether it's an external toasted value,
2018-05-16 20:56:52 +02:00
* because that could mean we need to inline it later. (Think not to
* merge this into the previous expand_external logic: datumCopy could
* by itself have made the value non-external.)
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
*/
if (attr->attlen == -1 &&
VARATT_IS_EXTERNAL(DatumGetPointer(newValue)))
erh->flags |= ER_FLAG_HAVE_EXTERNAL;
}
/*
* We're ready to make irreversible changes.
*/
dvalues = erh->dvalues;
dnulls = erh->dnulls;
/* Flattened value will no longer represent record accurately */
erh->flags &= ~ER_FLAG_FVALUE_VALID;
/* And we don't know the flattened size either */
erh->flat_size = 0;
/* Grab old field value for pfree'ing, if needed. */
if (!attr->attbyval && !dnulls[fnumber - 1])
oldValue = (char *) DatumGetPointer(dvalues[fnumber - 1]);
else
oldValue = NULL;
/* And finally we can insert the new field. */
dvalues[fnumber - 1] = newValue;
dnulls[fnumber - 1] = isnull;
/*
* Free old field if needed; this keeps repeated field replacements from
* bloating the record's storage. If the pfree somehow fails, it won't
* corrupt the record.
*
* If we're updating a dummy header, we can't risk pfree'ing the old
* value, because most likely the expanded record's main header still has
* a pointer to it. This won't result in any sustained memory leak, since
* whatever we just allocated here is in the short-lived domain check
* context.
*/
if (oldValue && !(erh->flags & ER_FLAG_IS_DUMMY))
{
/* Don't try to pfree a part of the original flat record */
if (oldValue < erh->fstartptr || oldValue >= erh->fendptr)
pfree(oldValue);
}
}
/*
* Set all record field(s)
*
* Caller must ensure that the provided datums are of the right types
* to match the record's previously assigned rowtype.
*
2018-05-16 20:56:52 +02:00
* If expand_external is true, we'll forcibly detoast out-of-line field values
* so that the record does not depend on external storage.
*
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
* Unlike repeated application of expanded_record_set_field(), this does not
* guarantee to leave the expanded record in a non-corrupt state in event
* of an error. Typically it would only be used for initializing a new
2018-05-16 20:56:52 +02:00
* expanded record. Also, because we expect this to be applied at most once
* in the lifespan of an expanded record, we do not worry about any cruft
* that detoasting might leak.
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
*/
void
expanded_record_set_fields(ExpandedRecordHeader *erh,
2018-05-16 20:56:52 +02:00
const Datum *newValues, const bool *isnulls,
bool expand_external)
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
{
TupleDesc tupdesc;
Datum *dvalues;
bool *dnulls;
int fnumber;
MemoryContext oldcxt;
/* Shouldn't ever be trying to assign new data to a dummy header */
Assert(!(erh->flags & ER_FLAG_IS_DUMMY));
/* If we haven't yet deconstructed the tuple, do that */
if (!(erh->flags & ER_FLAG_DVALUES_VALID))
deconstruct_expanded_record(erh);
/* Tuple descriptor must be valid by now */
tupdesc = erh->er_tupdesc;
Assert(erh->nfields == tupdesc->natts);
/* Flattened value will no longer represent record accurately */
erh->flags &= ~ER_FLAG_FVALUE_VALID;
/* And we don't know the flattened size either */
erh->flat_size = 0;
oldcxt = MemoryContextSwitchTo(erh->hdr.eoh_context);
dvalues = erh->dvalues;
dnulls = erh->dnulls;
for (fnumber = 0; fnumber < erh->nfields; fnumber++)
{
Form_pg_attribute attr = TupleDescAttr(tupdesc, fnumber);
Datum newValue;
bool isnull;
/* Ignore dropped columns */
if (attr->attisdropped)
continue;
newValue = newValues[fnumber];
isnull = isnulls[fnumber];
if (!attr->attbyval)
{
/*
2018-05-16 20:56:52 +02:00
* Copy new field value into record's context, and deal with
* detoasting, if needed.
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
*/
if (!isnull)
{
2018-05-16 20:56:52 +02:00
/* Is it an external toasted value? */
if (attr->attlen == -1 &&
VARATT_IS_EXTERNAL(DatumGetPointer(newValue)))
{
if (expand_external)
{
/* Detoast as requested while copying the value */
newValue = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *) DatumGetPointer(newValue)));
}
else
{
/* Just copy the value */
newValue = datumCopy(newValue, false, -1);
/* If it's still external, remember that */
if (VARATT_IS_EXTERNAL(DatumGetPointer(newValue)))
erh->flags |= ER_FLAG_HAVE_EXTERNAL;
}
}
else
{
/* Not an external value, just copy it */
newValue = datumCopy(newValue, false, attr->attlen);
}
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
/* Remember that we have field(s) that need to be pfree'd */
erh->flags |= ER_FLAG_DVALUES_ALLOCED;
}
/*
* Free old field value, if any (not likely, since really we ought
* to be inserting into an empty record).
*/
if (unlikely(!dnulls[fnumber]))
{
char *oldValue;
oldValue = (char *) DatumGetPointer(dvalues[fnumber]);
/* Don't try to pfree a part of the original flat record */
if (oldValue < erh->fstartptr || oldValue >= erh->fendptr)
pfree(oldValue);
}
}
/* And finally we can insert the new field. */
dvalues[fnumber] = newValue;
dnulls[fnumber] = isnull;
}
/*
* Because we don't guarantee atomicity of set_fields(), we can just leave
* checking of domain constraints to occur as the final step; if it throws
* an error, too bad.
*/
if (erh->flags & ER_FLAG_IS_DOMAIN)
{
/* We run domain_check in a short-lived context to limit cruft */
2018-05-16 20:56:52 +02:00
MemoryContextSwitchTo(get_short_term_cxt(erh));
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
domain_check(ExpandedRecordGetRODatum(erh), false,
erh->er_decltypeid,
&erh->er_domaininfo,
erh->hdr.eoh_context);
}
MemoryContextSwitchTo(oldcxt);
}
/*
2018-05-16 20:56:52 +02:00
* Construct (or reset) working memory context for short-term operations.
*
* This context is used for domain check evaluation and for detoasting.
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
*
2018-05-16 20:56:52 +02:00
* If we don't have a short-lived memory context, make one; if we have one,
* reset it to get rid of any leftover cruft. (It is a tad annoying to need a
* whole context for this, since it will often go unused --- but it's hard to
* avoid memory leaks otherwise. We can make the context small, at least.)
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
*/
static MemoryContext
2018-05-16 20:56:52 +02:00
get_short_term_cxt(ExpandedRecordHeader *erh)
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
{
2018-05-16 20:56:52 +02:00
if (erh->er_short_term_cxt == NULL)
erh->er_short_term_cxt =
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
AllocSetContextCreate(erh->hdr.eoh_context,
2018-05-16 20:56:52 +02:00
"expanded record short-term context",
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
ALLOCSET_SMALL_SIZES);
else
2018-05-16 20:56:52 +02:00
MemoryContextReset(erh->er_short_term_cxt);
return erh->er_short_term_cxt;
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
}
/*
* Construct "dummy header" for checking domain constraints.
*
* Since we don't want to modify the state of the expanded record until
* we've validated the constraints, our approach is to set up a dummy
* record header containing the new field value(s) and then pass that to
* domain_check. We retain the dummy header as part of the expanded
* record's state to save palloc cycles, but reinitialize (most of)
* its contents on each use.
*/
static void
build_dummy_expanded_header(ExpandedRecordHeader *main_erh)
{
ExpandedRecordHeader *erh;
TupleDesc tupdesc = expanded_record_get_tupdesc(main_erh);
2018-05-16 20:56:52 +02:00
/* Ensure we have a short-lived context */
(void) get_short_term_cxt(main_erh);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
/*
* Allocate dummy header on first time through, or in the unlikely event
* that the number of fields changes (in which case we just leak the old
* one). Include space for its field values in the request.
*/
erh = main_erh->er_dummy_header;
if (erh == NULL || erh->nfields != tupdesc->natts)
{
char *chunk;
erh = (ExpandedRecordHeader *)
MemoryContextAlloc(main_erh->hdr.eoh_context,
MAXALIGN(sizeof(ExpandedRecordHeader))
+ tupdesc->natts * (sizeof(Datum) + sizeof(bool)));
/* Ensure all header fields are initialized to 0/null */
memset(erh, 0, sizeof(ExpandedRecordHeader));
/*
* We set up the dummy header with an indication that its memory
* context is the short-lived context. This is so that, if any
* detoasting of out-of-line values happens due to an attempt to
* extract a composite datum from the dummy header, the detoasted
* stuff will end up in the short-lived context and not cause a leak.
* This is cheating a bit on the expanded-object protocol; but since
* we never pass a R/W pointer to the dummy object to any other code,
* nothing else is authorized to delete or transfer ownership of the
* object's context, so it should be safe enough.
*/
2018-05-16 20:56:52 +02:00
EOH_init_header(&erh->hdr, &ER_methods, main_erh->er_short_term_cxt);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
erh->er_magic = ER_MAGIC;
/* Set up dvalues/dnulls, with no valid contents as yet */
chunk = (char *) erh + MAXALIGN(sizeof(ExpandedRecordHeader));
erh->dvalues = (Datum *) chunk;
erh->dnulls = (bool *) (chunk + tupdesc->natts * sizeof(Datum));
erh->nfields = tupdesc->natts;
/*
* The fields we just set are assumed to remain constant through
* multiple uses of the dummy header to check domain constraints. All
* other dummy header fields should be explicitly reset below, to
* ensure there's not accidental effects of one check on the next one.
*/
main_erh->er_dummy_header = erh;
}
/*
* If anything inquires about the dummy header's declared type, it should
* report the composite base type, not the domain type (since the VALUE in
* a domain check constraint is of the base type not the domain). Hence
* we do not transfer over the IS_DOMAIN flag, nor indeed any of the main
* header's flags, since the dummy header is empty of data at this point.
* But don't forget to mark header as dummy.
*/
erh->flags = ER_FLAG_IS_DUMMY;
/* Copy composite-type identification info */
erh->er_decltypeid = erh->er_typeid = main_erh->er_typeid;
erh->er_typmod = main_erh->er_typmod;
/* Dummy header does not need its own tupdesc refcount */
erh->er_tupdesc = tupdesc;
erh->er_tupdesc_id = main_erh->er_tupdesc_id;
/*
* It's tempting to copy over whatever we know about the flat size, but
* there's no point since we're surely about to modify the dummy record's
* field(s). Instead just clear anything left over from a previous usage
* cycle.
*/
erh->flat_size = 0;
/* Copy over fvalue if we have it, so that system columns are available */
erh->fvalue = main_erh->fvalue;
erh->fstartptr = main_erh->fstartptr;
erh->fendptr = main_erh->fendptr;
}
/*
* Precheck domain constraints for a set_field operation
*/
static pg_noinline void
check_domain_for_new_field(ExpandedRecordHeader *erh, int fnumber,
Datum newValue, bool isnull)
{
ExpandedRecordHeader *dummy_erh;
MemoryContext oldcxt;
/* Construct dummy header to contain proposed new field set */
build_dummy_expanded_header(erh);
dummy_erh = erh->er_dummy_header;
/*
* If record isn't empty, just deconstruct it (if needed) and copy over
* the existing field values. If it is empty, just fill fields with nulls
* manually --- don't call deconstruct_expanded_record prematurely.
*/
if (!ExpandedRecordIsEmpty(erh))
{
deconstruct_expanded_record(erh);
memcpy(dummy_erh->dvalues, erh->dvalues,
dummy_erh->nfields * sizeof(Datum));
memcpy(dummy_erh->dnulls, erh->dnulls,
dummy_erh->nfields * sizeof(bool));
/* There might be some external values in there... */
dummy_erh->flags |= erh->flags & ER_FLAG_HAVE_EXTERNAL;
}
else
{
memset(dummy_erh->dvalues, 0, dummy_erh->nfields * sizeof(Datum));
memset(dummy_erh->dnulls, true, dummy_erh->nfields * sizeof(bool));
}
/* Either way, we now have valid dvalues */
dummy_erh->flags |= ER_FLAG_DVALUES_VALID;
/* Caller error if fnumber is system column or nonexistent column */
if (unlikely(fnumber <= 0 || fnumber > dummy_erh->nfields))
elog(ERROR, "cannot assign to field %d of expanded record", fnumber);
/* Insert proposed new value into dummy field array */
dummy_erh->dvalues[fnumber - 1] = newValue;
dummy_erh->dnulls[fnumber - 1] = isnull;
/*
* The proposed new value might be external, in which case we'd better set
* the flag for that in dummy_erh. (This matters in case something in the
* domain check expressions tries to extract a flat value from the dummy
* header.)
*/
if (!isnull)
{
Form_pg_attribute attr = TupleDescAttr(erh->er_tupdesc, fnumber - 1);
if (!attr->attbyval && attr->attlen == -1 &&
VARATT_IS_EXTERNAL(DatumGetPointer(newValue)))
dummy_erh->flags |= ER_FLAG_HAVE_EXTERNAL;
}
/*
* We call domain_check in the short-lived context, so that any cruft
* leaked by expression evaluation can be reclaimed.
*/
2018-05-16 20:56:52 +02:00
oldcxt = MemoryContextSwitchTo(erh->er_short_term_cxt);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
/*
* And now we can apply the check. Note we use main header's domain cache
* space, so that caching carries across repeated uses.
*/
domain_check(ExpandedRecordGetRODatum(dummy_erh), false,
erh->er_decltypeid,
&erh->er_domaininfo,
erh->hdr.eoh_context);
MemoryContextSwitchTo(oldcxt);
/* We might as well clean up cruft immediately. */
2018-05-16 20:56:52 +02:00
MemoryContextReset(erh->er_short_term_cxt);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
}
/*
* Precheck domain constraints for a set_tuple operation
*/
static pg_noinline void
check_domain_for_new_tuple(ExpandedRecordHeader *erh, HeapTuple tuple)
{
ExpandedRecordHeader *dummy_erh;
MemoryContext oldcxt;
/* If we're being told to set record to empty, just see if NULL is OK */
if (tuple == NULL)
{
/* We run domain_check in a short-lived context to limit cruft */
2018-05-16 20:56:52 +02:00
oldcxt = MemoryContextSwitchTo(get_short_term_cxt(erh));
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
domain_check((Datum) 0, true,
erh->er_decltypeid,
&erh->er_domaininfo,
erh->hdr.eoh_context);
MemoryContextSwitchTo(oldcxt);
/* We might as well clean up cruft immediately. */
2018-05-16 20:56:52 +02:00
MemoryContextReset(erh->er_short_term_cxt);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
return;
}
/* Construct dummy header to contain replacement tuple */
build_dummy_expanded_header(erh);
dummy_erh = erh->er_dummy_header;
/* Insert tuple, but don't bother to deconstruct its fields for now */
dummy_erh->fvalue = tuple;
dummy_erh->fstartptr = (char *) tuple->t_data;
dummy_erh->fendptr = ((char *) tuple->t_data) + tuple->t_len;
dummy_erh->flags |= ER_FLAG_FVALUE_VALID;
/* Remember if we have any out-of-line field values */
if (HeapTupleHasExternal(tuple))
dummy_erh->flags |= ER_FLAG_HAVE_EXTERNAL;
/*
* We call domain_check in the short-lived context, so that any cruft
* leaked by expression evaluation can be reclaimed.
*/
2018-05-16 20:56:52 +02:00
oldcxt = MemoryContextSwitchTo(erh->er_short_term_cxt);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
/*
* And now we can apply the check. Note we use main header's domain cache
* space, so that caching carries across repeated uses.
*/
domain_check(ExpandedRecordGetRODatum(dummy_erh), false,
erh->er_decltypeid,
&erh->er_domaininfo,
erh->hdr.eoh_context);
MemoryContextSwitchTo(oldcxt);
/* We might as well clean up cruft immediately. */
2018-05-16 20:56:52 +02:00
MemoryContextReset(erh->er_short_term_cxt);
Make plpgsql use its DTYPE_REC code paths for composite-type variables. Formerly, DTYPE_REC was used only for variables declared as "record"; variables of named composite types used DTYPE_ROW, which is faster for some purposes but much less flexible. In particular, the ROW code paths are entirely incapable of dealing with DDL-caused changes to the number or data types of the columns of a row variable, once a particular plpgsql function has been parsed for the first time in a session. And, since the stored representation of a ROW isn't a tuple, there wasn't any easy way to deal with variables of domain-over-composite types, since the domain constraint checking code would expect the value to be checked to be a tuple. A lesser, but still real, annoyance is that ROW format cannot represent a true NULL composite value, only a row of per-field NULL values, which is not exactly the same thing. Hence, switch to using DTYPE_REC for all composite-typed variables, whether "record", named composite type, or domain over named composite type. DTYPE_ROW remains but is used only for its native purpose, to represent a fixed-at-compile-time list of variables, for instance the targets of an INTO clause. To accomplish this without taking significant performance losses, introduce infrastructure that allows storing composite-type variables as "expanded objects", similar to the "expanded array" infrastructure introduced in commit 1dc5ebc90. A composite variable's value is thereby kept (most of the time) in the form of separate Datums, so that field accesses and updates are not much more expensive than they were in the ROW format. This holds the line, more or less, on performance of variables of named composite types in field-access-intensive microbenchmarks, and makes variables declared "record" perform much better than before in similar tests. In addition, the logic involved with enforcing composite-domain constraints against updates of individual fields is in the expanded record infrastructure not plpgsql proper, so that it might be reusable for other purposes. In further support of this, introduce a typcache feature for assigning a unique-within-process identifier to each distinct tuple descriptor of interest; in particular, DDL alterations on composite types result in a new identifier for that type. This allows very cheap detection of the need to refresh tupdesc-dependent data. This improves on the "tupDescSeqNo" idea I had in commit 687f096ea: that assigned identifying sequence numbers to successive versions of individual composite types, but the numbers were not unique across different types, nor was there support for assigning numbers to registered record types. In passing, allow plpgsql functions to accept as well as return type "record". There was no good reason for the old restriction, and it was out of step with most of the other PLs. Tom Lane, reviewed by Pavel Stehule Discussion: https://postgr.es/m/8962.1514399547@sss.pgh.pa.us
2018-02-14 00:52:21 +01:00
}