1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* tupdesc.c
|
1996-07-09 08:22:35 +02:00
|
|
|
* POSTGRES tuple descriptor support code
|
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/access/common/tupdesc.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* some of the executor utility code such as "ExecTypeFromTL" should be
|
|
|
|
* moved here.
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "postgres.h"
|
1996-11-01 10:41:41 +01:00
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
Allow configurable LZ4 TOAST compression.
There is now a per-column COMPRESSION option which can be set to pglz
(the default, and the only option in up until now) or lz4. Or, if you
like, you can set the new default_toast_compression GUC to lz4, and
then that will be the default for new table columns for which no value
is specified. We don't have lz4 support in the PostgreSQL code, so
to use lz4 compression, PostgreSQL must be built --with-lz4.
In general, TOAST compression means compression of individual column
values, not the whole tuple, and those values can either be compressed
inline within the tuple or compressed and then stored externally in
the TOAST table, so those properties also apply to this feature.
Prior to this commit, a TOAST pointer has two unused bits as part of
the va_extsize field, and a compessed datum has two unused bits as
part of the va_rawsize field. These bits are unused because the length
of a varlena is limited to 1GB; we now use them to indicate the
compression type that was used. This means we only have bit space for
2 more built-in compresison types, but we could work around that
problem, if necessary, by introducing a new vartag_external value for
any further types we end up wanting to add. Hopefully, it won't be
too important to offer a wide selection of algorithms here, since
each one we add not only takes more coding but also adds a build
dependency for every packager. Nevertheless, it seems worth doing
at least this much, because LZ4 gets better compression than PGLZ
with less CPU usage.
It's possible for LZ4-compressed datums to leak into composite type
values stored on disk, just as it is for PGLZ. It's also possible for
LZ4-compressed attributes to be copied into a different table via SQL
commands such as CREATE TABLE AS or INSERT .. SELECT. It would be
expensive to force such values to be decompressed, so PostgreSQL has
never done so. For the same reasons, we also don't force recompression
of already-compressed values even if the target table prefers a
different compression method than was used for the source data. These
architectural decisions are perhaps arguable but revisiting them is
well beyond the scope of what seemed possible to do as part of this
project. However, it's relatively cheap to recompress as part of
VACUUM FULL or CLUSTER, so this commit adjusts those commands to do
so, if the configured compression method of the table happens not to
match what was used for some column value stored therein.
Dilip Kumar. The original patches on which this work was based were
written by Ildus Kurbangaliev, and those were patches were based on
even earlier work by Nikita Glukhov, but the design has since changed
very substantially, since allow a potentially large number of
compression methods that could be added and dropped on a running
system proved too problematic given some of the architectural issues
mentioned above; the choice of which specific compression method to
add first is now different; and a lot of the code has been heavily
refactored. More recently, Justin Przyby helped quite a bit with
testing and reviewing and this version also includes some code
contributions from him. Other design input and review from Tomas
Vondra, Álvaro Herrera, Andres Freund, Oleg Bartunov, Alexander
Korotkov, and me.
Discussion: http://postgr.es/m/20170907194236.4cefce96%40wp.localdomain
Discussion: http://postgr.es/m/CAFiTN-uUpX3ck%3DK0mLEk-G_kUQY%3DSNOTeqdaNRR9FMdQrHKebw%40mail.gmail.com
2021-03-19 20:10:38 +01:00
|
|
|
#include "access/toast_compression.h"
|
2018-03-28 02:13:52 +02:00
|
|
|
#include "access/tupdesc_details.h"
|
2017-01-24 22:59:18 +01:00
|
|
|
#include "catalog/pg_collation.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2020-02-27 04:55:41 +01:00
|
|
|
#include "common/hashfn.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "utils/builtins.h"
|
2018-03-28 02:13:52 +02:00
|
|
|
#include "utils/datum.h"
|
Make ResourceOwners more easily extensible.
Instead of having a separate array/hash for each resource kind, use a
single array and hash to hold all kinds of resources. This makes it
possible to introduce new resource "kinds" without having to modify
the ResourceOwnerData struct. In particular, this makes it possible
for extensions to register custom resource kinds.
The old approach was to have a small array of resources of each kind,
and if it fills up, switch to a hash table. The new approach also uses
an array and a hash, but now the array and the hash are used at the
same time. The array is used to hold the recently added resources, and
when it fills up, they are moved to the hash. This keeps the access to
recent entries fast, even when there are a lot of long-held resources.
All the resource-specific ResourceOwnerEnlarge*(),
ResourceOwnerRemember*(), and ResourceOwnerForget*() functions have
been replaced with three generic functions that take resource kind as
argument. For convenience, we still define resource-specific wrapper
macros around the generic functions with the old names, but they are
now defined in the source files that use those resource kinds.
The release callback no longer needs to call ResourceOwnerForget on
the resource being released. ResourceOwnerRelease unregisters the
resource from the owner before calling the callback. That needed some
changes in bufmgr.c and some other files, where releasing the
resources previously always called ResourceOwnerForget.
Each resource kind specifies a release priority, and
ResourceOwnerReleaseAll releases the resources in priority order. To
make that possible, we have to restrict what you can do between
phases. After calling ResourceOwnerRelease(), you are no longer
allowed to remember any more resources in it or to forget any
previously remembered resources by calling ResourceOwnerForget. There
was one case where that was done previously. At subtransaction commit,
AtEOSubXact_Inval() would handle the invalidation messages and call
RelationFlushRelation(), which temporarily increased the reference
count on the relation being flushed. We now switch to the parent
subtransaction's resource owner before calling AtEOSubXact_Inval(), so
that there is a valid ResourceOwner to temporarily hold that relcache
reference.
Other end-of-xact routines make similar calls to AtEOXact_Inval()
between release phases, but I didn't see any regression test failures
from those, so I'm not sure if they could reach a codepath that needs
remembering extra resources.
There were two exceptions to how the resource leak WARNINGs on commit
were printed previously: llvmjit silently released the context without
printing the warning, and a leaked buffer io triggered a PANIC. Now
everything prints a WARNING, including those cases.
Add tests in src/test/modules/test_resowner.
Reviewed-by: Aleksander Alekseev, Michael Paquier, Julien Rouhaud
Reviewed-by: Kyotaro Horiguchi, Hayato Kuroda, Álvaro Herrera, Zhihong Yu
Reviewed-by: Peter Eisentraut, Andres Freund
Discussion: https://www.postgresql.org/message-id/cbfabeb0-cd3c-e951-a572-19b365ed314d%40iki.fi
2023-11-08 12:30:50 +01:00
|
|
|
#include "utils/resowner.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "utils/syscache.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
Make ResourceOwners more easily extensible.
Instead of having a separate array/hash for each resource kind, use a
single array and hash to hold all kinds of resources. This makes it
possible to introduce new resource "kinds" without having to modify
the ResourceOwnerData struct. In particular, this makes it possible
for extensions to register custom resource kinds.
The old approach was to have a small array of resources of each kind,
and if it fills up, switch to a hash table. The new approach also uses
an array and a hash, but now the array and the hash are used at the
same time. The array is used to hold the recently added resources, and
when it fills up, they are moved to the hash. This keeps the access to
recent entries fast, even when there are a lot of long-held resources.
All the resource-specific ResourceOwnerEnlarge*(),
ResourceOwnerRemember*(), and ResourceOwnerForget*() functions have
been replaced with three generic functions that take resource kind as
argument. For convenience, we still define resource-specific wrapper
macros around the generic functions with the old names, but they are
now defined in the source files that use those resource kinds.
The release callback no longer needs to call ResourceOwnerForget on
the resource being released. ResourceOwnerRelease unregisters the
resource from the owner before calling the callback. That needed some
changes in bufmgr.c and some other files, where releasing the
resources previously always called ResourceOwnerForget.
Each resource kind specifies a release priority, and
ResourceOwnerReleaseAll releases the resources in priority order. To
make that possible, we have to restrict what you can do between
phases. After calling ResourceOwnerRelease(), you are no longer
allowed to remember any more resources in it or to forget any
previously remembered resources by calling ResourceOwnerForget. There
was one case where that was done previously. At subtransaction commit,
AtEOSubXact_Inval() would handle the invalidation messages and call
RelationFlushRelation(), which temporarily increased the reference
count on the relation being flushed. We now switch to the parent
subtransaction's resource owner before calling AtEOSubXact_Inval(), so
that there is a valid ResourceOwner to temporarily hold that relcache
reference.
Other end-of-xact routines make similar calls to AtEOXact_Inval()
between release phases, but I didn't see any regression test failures
from those, so I'm not sure if they could reach a codepath that needs
remembering extra resources.
There were two exceptions to how the resource leak WARNINGs on commit
were printed previously: llvmjit silently released the context without
printing the warning, and a leaked buffer io triggered a PANIC. Now
everything prints a WARNING, including those cases.
Add tests in src/test/modules/test_resowner.
Reviewed-by: Aleksander Alekseev, Michael Paquier, Julien Rouhaud
Reviewed-by: Kyotaro Horiguchi, Hayato Kuroda, Álvaro Herrera, Zhihong Yu
Reviewed-by: Peter Eisentraut, Andres Freund
Discussion: https://www.postgresql.org/message-id/cbfabeb0-cd3c-e951-a572-19b365ed314d%40iki.fi
2023-11-08 12:30:50 +01:00
|
|
|
/* ResourceOwner callbacks to hold tupledesc references */
|
|
|
|
static void ResOwnerReleaseTupleDesc(Datum res);
|
|
|
|
static char *ResOwnerPrintTupleDesc(Datum res);
|
|
|
|
|
|
|
|
static const ResourceOwnerDesc tupdesc_resowner_desc =
|
|
|
|
{
|
|
|
|
.name = "tupdesc reference",
|
|
|
|
.release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
|
|
|
|
.release_priority = RELEASE_PRIO_TUPDESC_REFS,
|
|
|
|
.ReleaseResource = ResOwnerReleaseTupleDesc,
|
|
|
|
.DebugPrint = ResOwnerPrintTupleDesc
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Convenience wrappers over ResourceOwnerRemember/Forget */
|
|
|
|
static inline void
|
|
|
|
ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
|
|
|
|
{
|
|
|
|
ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
|
|
|
|
{
|
|
|
|
ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
|
|
|
|
}
|
1996-10-21 00:04:49 +02:00
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* CreateTemplateTupleDesc
|
|
|
|
* This function allocates an empty tuple descriptor structure.
|
2004-04-01 23:28:47 +02:00
|
|
|
*
|
|
|
|
* Tuple type ID information is initially set for an anonymous record type;
|
|
|
|
* caller can overwrite this if needed.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
TupleDesc
|
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
|
|
|
CreateTemplateTupleDesc(int natts)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
|
|
|
TupleDesc desc;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* sanity checks
|
|
|
|
*/
|
2022-10-28 09:19:06 +02:00
|
|
|
Assert(natts >= 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
2005-03-07 05:42:17 +01:00
|
|
|
* Allocate enough memory for the tuple descriptor, including the
|
2017-08-20 20:19:12 +02:00
|
|
|
* attribute rows.
|
2018-01-03 23:53:06 +01:00
|
|
|
*
|
|
|
|
* Note: the attribute array stride is sizeof(FormData_pg_attribute),
|
|
|
|
* since we declare the array elements as FormData_pg_attribute for
|
|
|
|
* notational convenience. However, we only guarantee that the first
|
|
|
|
* ATTRIBUTE_FIXED_PART_SIZE bytes of each entry are valid; most code that
|
|
|
|
* copies tupdesc entries around copies just that much. In principle that
|
|
|
|
* could be less due to trailing padding, although with the current
|
|
|
|
* definition of pg_attribute there probably isn't any padding.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2019-01-15 01:15:20 +01:00
|
|
|
desc = (TupleDesc) palloc(offsetof(struct TupleDescData, attrs) +
|
2017-08-20 20:19:12 +02:00
|
|
|
natts * sizeof(FormData_pg_attribute));
|
2004-04-01 23:28:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize other fields of the tupdesc.
|
|
|
|
*/
|
|
|
|
desc->natts = natts;
|
2002-09-28 22:00:19 +02:00
|
|
|
desc->constr = NULL;
|
2004-04-01 23:28:47 +02:00
|
|
|
desc->tdtypeid = RECORDOID;
|
|
|
|
desc->tdtypmod = -1;
|
2006-06-16 20:42:24 +02:00
|
|
|
desc->tdrefcount = -1; /* assume not reference-counted */
|
2002-09-28 22:00:19 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* CreateTupleDesc
|
2017-08-20 20:19:12 +02:00
|
|
|
* This function allocates a new TupleDesc by copying a given
|
2005-03-07 05:42:17 +01:00
|
|
|
* Form_pg_attribute array.
|
|
|
|
*
|
2004-04-01 23:28:47 +02:00
|
|
|
* Tuple type ID information is initially set for an anonymous record type;
|
|
|
|
* caller can overwrite this if needed.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
TupleDesc
|
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
|
|
|
CreateTupleDesc(int natts, Form_pg_attribute *attrs)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
|
|
|
TupleDesc desc;
|
2017-08-20 20:19:12 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
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
|
|
|
desc = CreateTemplateTupleDesc(natts);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2017-08-20 20:19:12 +02:00
|
|
|
for (i = 0; i < natts; ++i)
|
|
|
|
memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* CreateTupleDescCopy
|
1996-07-09 08:22:35 +02:00
|
|
|
* This function creates a new TupleDesc by copying from an existing
|
2005-03-07 05:42:17 +01:00
|
|
|
* TupleDesc.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2005-03-07 05:42:17 +01:00
|
|
|
* !!! Constraints and defaults are not copied !!!
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
TupleDesc
|
|
|
|
CreateTupleDescCopy(TupleDesc tupdesc)
|
|
|
|
{
|
|
|
|
TupleDesc desc;
|
2004-04-01 23:28:47 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
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
|
|
|
desc = CreateTemplateTupleDesc(tupdesc->natts);
|
2005-03-07 05:42:17 +01:00
|
|
|
|
2018-01-03 23:53:06 +01:00
|
|
|
/* Flat-copy the attribute array */
|
|
|
|
memcpy(TupleDescAttr(desc, 0),
|
|
|
|
TupleDescAttr(tupdesc, 0),
|
|
|
|
desc->natts * sizeof(FormData_pg_attribute));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since we're not copying constraints and defaults, clear fields
|
|
|
|
* associated with them.
|
|
|
|
*/
|
2005-03-07 05:42:17 +01:00
|
|
|
for (i = 0; i < desc->natts; i++)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2017-08-20 20:19:12 +02:00
|
|
|
Form_pg_attribute att = TupleDescAttr(desc, i);
|
|
|
|
|
|
|
|
att->attnotnull = false;
|
|
|
|
att->atthasdef = false;
|
2018-03-28 02:13:52 +02:00
|
|
|
att->atthasmissing = false;
|
2017-08-20 20:19:12 +02:00
|
|
|
att->attidentity = '\0';
|
2019-03-30 08:13:09 +01:00
|
|
|
att->attgenerated = '\0';
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2004-04-01 23:28:47 +02:00
|
|
|
|
2018-01-03 23:53:06 +01:00
|
|
|
/* We can copy the tuple type identification, too */
|
2004-04-01 23:28:47 +02:00
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* CreateTupleDescCopyConstr
|
1997-08-22 04:55:39 +02:00
|
|
|
* This function creates a new TupleDesc by copying from an existing
|
2005-03-07 05:42:17 +01:00
|
|
|
* TupleDesc (including its constraints and defaults).
|
1997-08-22 04:55:39 +02:00
|
|
|
*/
|
|
|
|
TupleDesc
|
|
|
|
CreateTupleDescCopyConstr(TupleDesc tupdesc)
|
|
|
|
{
|
|
|
|
TupleDesc desc;
|
|
|
|
TupleConstr *constr = tupdesc->constr;
|
2004-04-01 23:28:47 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
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
|
|
|
desc = CreateTemplateTupleDesc(tupdesc->natts);
|
2005-03-07 05:42:17 +01:00
|
|
|
|
2018-01-03 23:53:06 +01:00
|
|
|
/* Flat-copy the attribute array */
|
|
|
|
memcpy(TupleDescAttr(desc, 0),
|
|
|
|
TupleDescAttr(tupdesc, 0),
|
|
|
|
desc->natts * sizeof(FormData_pg_attribute));
|
2004-04-01 23:28:47 +02:00
|
|
|
|
2018-01-03 23:53:06 +01:00
|
|
|
/* Copy the TupleConstr data structure, if any */
|
1997-08-22 04:55:39 +02:00
|
|
|
if (constr)
|
|
|
|
{
|
2004-04-01 23:28:47 +02:00
|
|
|
TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-08-22 04:55:39 +02:00
|
|
|
cpy->has_not_null = constr->has_not_null;
|
2019-03-30 08:13:09 +01:00
|
|
|
cpy->has_generated_stored = constr->has_generated_stored;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-08-22 04:55:39 +02:00
|
|
|
if ((cpy->num_defval = constr->num_defval) > 0)
|
|
|
|
{
|
|
|
|
cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
|
|
|
|
memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
|
|
|
|
for (i = cpy->num_defval - 1; i >= 0; i--)
|
Clean up treatment of missing default and CHECK-constraint records.
Andrew Gierth reported that it's possible to crash the backend if no
pg_attrdef record is found to match an attribute that has atthasdef set.
AttrDefaultFetch warns about this situation, but then leaves behind
a relation tupdesc that has null "adbin" pointer(s), which most places
don't guard against.
We considered promoting the warning to an error, but throwing errors
during relcache load is pretty drastic: it effectively locks one out
of using the relation at all. What seems better is to leave the
load-time behavior as a warning, but then throw an error in any code
path that wants to use a default and can't find it. This confines
the error to a subset of INSERT/UPDATE operations on the table, and
in particular will at least allow a pg_dump to succeed.
Also, we should fix AttrDefaultFetch to not leave any null pointers
in the tupdesc, because that just creates an untested bug hazard.
While at it, apply the same philosophy of "warn at load, throw error
only upon use of the known-missing info" to CHECK constraints.
CheckConstraintFetch is very nearly the same logic as AttrDefaultFetch,
but for reasons lost in the mists of time, it was throwing ERROR for
the same cases that AttrDefaultFetch treats as WARNING. Make the two
functions more nearly alike.
In passing, get rid of potentially-O(N^2) loops in equalTupleDesc
by making AttrDefaultFetch sort the entries after fetching them,
so that equalTupleDesc can assume that entries in two equal tupdescs
must be in matching order. (CheckConstraintFetch already was sorting
CHECK constraints, but equalTupleDesc hadn't been told about it.)
There's some argument for back-patching this, but with such a small
number of field reports, I'm content to fix it in HEAD.
Discussion: https://postgr.es/m/87pmzaq4gx.fsf@news-spur.riddles.org.uk
2021-04-06 16:34:37 +02:00
|
|
|
cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2018-03-28 02:13:52 +02:00
|
|
|
if (constr->missing)
|
|
|
|
{
|
|
|
|
cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
|
|
|
|
memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
|
|
|
|
for (i = tupdesc->natts - 1; i >= 0; i--)
|
|
|
|
{
|
2018-06-27 04:46:13 +02:00
|
|
|
if (constr->missing[i].am_present)
|
2018-03-28 02:13:52 +02:00
|
|
|
{
|
|
|
|
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
|
|
|
|
|
2018-06-27 04:46:13 +02:00
|
|
|
cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
|
|
|
|
attr->attbyval,
|
|
|
|
attr->attlen);
|
2018-03-28 02:13:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-08-22 04:55:39 +02:00
|
|
|
if ((cpy->num_check = constr->num_check) > 0)
|
|
|
|
{
|
|
|
|
cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
|
|
|
|
memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
|
|
|
|
for (i = cpy->num_check - 1; i >= 0; i--)
|
|
|
|
{
|
Clean up treatment of missing default and CHECK-constraint records.
Andrew Gierth reported that it's possible to crash the backend if no
pg_attrdef record is found to match an attribute that has atthasdef set.
AttrDefaultFetch warns about this situation, but then leaves behind
a relation tupdesc that has null "adbin" pointer(s), which most places
don't guard against.
We considered promoting the warning to an error, but throwing errors
during relcache load is pretty drastic: it effectively locks one out
of using the relation at all. What seems better is to leave the
load-time behavior as a warning, but then throw an error in any code
path that wants to use a default and can't find it. This confines
the error to a subset of INSERT/UPDATE operations on the table, and
in particular will at least allow a pg_dump to succeed.
Also, we should fix AttrDefaultFetch to not leave any null pointers
in the tupdesc, because that just creates an untested bug hazard.
While at it, apply the same philosophy of "warn at load, throw error
only upon use of the known-missing info" to CHECK constraints.
CheckConstraintFetch is very nearly the same logic as AttrDefaultFetch,
but for reasons lost in the mists of time, it was throwing ERROR for
the same cases that AttrDefaultFetch treats as WARNING. Make the two
functions more nearly alike.
In passing, get rid of potentially-O(N^2) loops in equalTupleDesc
by making AttrDefaultFetch sort the entries after fetching them,
so that equalTupleDesc can assume that entries in two equal tupdescs
must be in matching order. (CheckConstraintFetch already was sorting
CHECK constraints, but equalTupleDesc hadn't been told about it.)
There's some argument for back-patching this, but with such a small
number of field reports, I'm content to fix it in HEAD.
Discussion: https://postgr.es/m/87pmzaq4gx.fsf@news-spur.riddles.org.uk
2021-04-06 16:34:37 +02:00
|
|
|
cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
|
|
|
|
cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
|
2011-06-02 00:43:50 +02:00
|
|
|
cpy->check[i].ccvalid = constr->check[i].ccvalid;
|
2014-03-23 07:13:43 +01:00
|
|
|
cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
|
1997-08-22 04:55:39 +02:00
|
|
|
}
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-08-22 04:55:39 +02:00
|
|
|
desc->constr = cpy;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-01-03 23:53:06 +01:00
|
|
|
/* We can copy the tuple type identification, too */
|
2004-04-01 23:28:47 +02:00
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
|
|
|
|
1997-08-22 04:55:39 +02:00
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
2017-09-15 04:59:21 +02:00
|
|
|
/*
|
|
|
|
* TupleDescCopy
|
|
|
|
* Copy a tuple descriptor into caller-supplied memory.
|
|
|
|
* The memory may be shared memory mapped at any address, and must
|
|
|
|
* be sufficient to hold TupleDescSize(src) bytes.
|
|
|
|
*
|
|
|
|
* !!! Constraints and defaults are not copied !!!
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
TupleDescCopy(TupleDesc dst, TupleDesc src)
|
|
|
|
{
|
2018-01-03 23:53:06 +01:00
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Flat-copy the header and attribute array */
|
2017-09-15 04:59:21 +02:00
|
|
|
memcpy(dst, src, TupleDescSize(src));
|
2018-01-03 23:53:06 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since we're not copying constraints and defaults, clear fields
|
|
|
|
* associated with them.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < dst->natts; i++)
|
|
|
|
{
|
|
|
|
Form_pg_attribute att = TupleDescAttr(dst, i);
|
|
|
|
|
|
|
|
att->attnotnull = false;
|
|
|
|
att->atthasdef = false;
|
2018-03-28 02:13:52 +02:00
|
|
|
att->atthasmissing = false;
|
2018-01-03 23:53:06 +01:00
|
|
|
att->attidentity = '\0';
|
2019-03-30 08:13:09 +01:00
|
|
|
att->attgenerated = '\0';
|
2018-01-03 23:53:06 +01:00
|
|
|
}
|
2017-09-15 04:59:21 +02:00
|
|
|
dst->constr = NULL;
|
2018-01-03 23:53:06 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Also, assume the destination is not to be ref-counted. (Copying the
|
|
|
|
* source's refcount would be wrong in any case.)
|
|
|
|
*/
|
2017-09-15 04:59:21 +02:00
|
|
|
dst->tdrefcount = -1;
|
|
|
|
}
|
|
|
|
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
/*
|
|
|
|
* TupleDescCopyEntry
|
|
|
|
* This function copies a single attribute structure from one tuple
|
|
|
|
* descriptor to another.
|
|
|
|
*
|
|
|
|
* !!! Constraints and defaults are not copied !!!
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
|
|
|
|
TupleDesc src, AttrNumber srcAttno)
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
|
|
|
|
Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
|
|
|
|
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
/*
|
|
|
|
* sanity checks
|
|
|
|
*/
|
2022-10-28 09:19:06 +02:00
|
|
|
Assert(PointerIsValid(src));
|
|
|
|
Assert(PointerIsValid(dst));
|
|
|
|
Assert(srcAttno >= 1);
|
|
|
|
Assert(srcAttno <= src->natts);
|
|
|
|
Assert(dstAttno >= 1);
|
|
|
|
Assert(dstAttno <= dst->natts);
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
|
2017-08-20 20:19:07 +02:00
|
|
|
memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Aside from updating the attno, we'd better reset attcacheoff.
|
|
|
|
*
|
|
|
|
* XXX Actually, to be entirely safe we'd need to reset the attcacheoff of
|
|
|
|
* all following columns in dst as well. Current usage scenarios don't
|
|
|
|
* require that though, because all following columns will get initialized
|
|
|
|
* by other uses of this function or TupleDescInitEntry. So we cheat a
|
|
|
|
* bit to avoid a useless O(N^2) penalty.
|
|
|
|
*/
|
2017-08-20 20:19:07 +02:00
|
|
|
dstAtt->attnum = dstAttno;
|
|
|
|
dstAtt->attcacheoff = -1;
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
|
|
|
|
/* since we're not copying constraints or defaults, clear these */
|
2017-08-20 20:19:07 +02:00
|
|
|
dstAtt->attnotnull = false;
|
|
|
|
dstAtt->atthasdef = false;
|
2018-03-28 02:13:52 +02:00
|
|
|
dstAtt->atthasmissing = false;
|
2017-08-20 20:19:07 +02:00
|
|
|
dstAtt->attidentity = '\0';
|
2019-03-30 08:13:09 +01:00
|
|
|
dstAtt->attgenerated = '\0';
|
Support multi-argument UNNEST(), and TABLE() syntax for multiple functions.
This patch adds the ability to write TABLE( function1(), function2(), ...)
as a single FROM-clause entry. The result is the concatenation of the
first row from each function, followed by the second row from each
function, etc; with NULLs inserted if any function produces fewer rows than
others. This is believed to be a much more useful behavior than what
Postgres currently does with multiple SRFs in a SELECT list.
This syntax also provides a reasonable way to combine use of column
definition lists with WITH ORDINALITY: put the column definition list
inside TABLE(), where it's clear that it doesn't control the ordinality
column as well.
Also implement SQL-compliant multiple-argument UNNEST(), by turning
UNNEST(a,b,c) into TABLE(unnest(a), unnest(b), unnest(c)).
The SQL standard specifies TABLE() with only a single function, not
multiple functions, and it seems to require an implicit UNNEST() which is
not what this patch does. There may be something wrong with that reading
of the spec, though, because if it's right then the spec's TABLE() is just
a pointless alternative spelling of UNNEST(). After further review of
that, we might choose to adopt a different syntax for what this patch does,
but in any case this functionality seems clearly worthwhile.
Andrew Gierth, reviewed by Zoltán Böszörményi and Heikki Linnakangas, and
significantly revised by me
2013-11-22 01:37:02 +01:00
|
|
|
}
|
|
|
|
|
2004-04-01 23:28:47 +02:00
|
|
|
/*
|
|
|
|
* Free a TupleDesc including all substructure
|
|
|
|
*/
|
1997-08-22 04:55:39 +02:00
|
|
|
void
|
|
|
|
FreeTupleDesc(TupleDesc tupdesc)
|
|
|
|
{
|
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2006-06-16 20:42:24 +02:00
|
|
|
/*
|
|
|
|
* Possibly this should assert tdrefcount == 0, to disallow explicit
|
|
|
|
* freeing of un-refcounted tupdescs?
|
|
|
|
*/
|
|
|
|
Assert(tupdesc->tdrefcount <= 0);
|
|
|
|
|
1997-08-22 04:55:39 +02:00
|
|
|
if (tupdesc->constr)
|
|
|
|
{
|
|
|
|
if (tupdesc->constr->num_defval > 0)
|
|
|
|
{
|
|
|
|
AttrDefault *attrdef = tupdesc->constr->defval;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-08-22 04:55:39 +02:00
|
|
|
for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
|
Clean up treatment of missing default and CHECK-constraint records.
Andrew Gierth reported that it's possible to crash the backend if no
pg_attrdef record is found to match an attribute that has atthasdef set.
AttrDefaultFetch warns about this situation, but then leaves behind
a relation tupdesc that has null "adbin" pointer(s), which most places
don't guard against.
We considered promoting the warning to an error, but throwing errors
during relcache load is pretty drastic: it effectively locks one out
of using the relation at all. What seems better is to leave the
load-time behavior as a warning, but then throw an error in any code
path that wants to use a default and can't find it. This confines
the error to a subset of INSERT/UPDATE operations on the table, and
in particular will at least allow a pg_dump to succeed.
Also, we should fix AttrDefaultFetch to not leave any null pointers
in the tupdesc, because that just creates an untested bug hazard.
While at it, apply the same philosophy of "warn at load, throw error
only upon use of the known-missing info" to CHECK constraints.
CheckConstraintFetch is very nearly the same logic as AttrDefaultFetch,
but for reasons lost in the mists of time, it was throwing ERROR for
the same cases that AttrDefaultFetch treats as WARNING. Make the two
functions more nearly alike.
In passing, get rid of potentially-O(N^2) loops in equalTupleDesc
by making AttrDefaultFetch sort the entries after fetching them,
so that equalTupleDesc can assume that entries in two equal tupdescs
must be in matching order. (CheckConstraintFetch already was sorting
CHECK constraints, but equalTupleDesc hadn't been told about it.)
There's some argument for back-patching this, but with such a small
number of field reports, I'm content to fix it in HEAD.
Discussion: https://postgr.es/m/87pmzaq4gx.fsf@news-spur.riddles.org.uk
2021-04-06 16:34:37 +02:00
|
|
|
pfree(attrdef[i].adbin);
|
1997-08-22 04:55:39 +02:00
|
|
|
pfree(attrdef);
|
|
|
|
}
|
2018-03-28 02:13:52 +02:00
|
|
|
if (tupdesc->constr->missing)
|
|
|
|
{
|
|
|
|
AttrMissing *attrmiss = tupdesc->constr->missing;
|
|
|
|
|
|
|
|
for (i = tupdesc->natts - 1; i >= 0; i--)
|
|
|
|
{
|
2018-06-27 04:46:13 +02:00
|
|
|
if (attrmiss[i].am_present
|
2018-03-28 02:13:52 +02:00
|
|
|
&& !TupleDescAttr(tupdesc, i)->attbyval)
|
2018-06-27 04:46:13 +02:00
|
|
|
pfree(DatumGetPointer(attrmiss[i].am_value));
|
2018-03-28 02:13:52 +02:00
|
|
|
}
|
|
|
|
pfree(attrmiss);
|
|
|
|
}
|
1997-08-22 04:55:39 +02:00
|
|
|
if (tupdesc->constr->num_check > 0)
|
|
|
|
{
|
|
|
|
ConstrCheck *check = tupdesc->constr->check;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-08-22 04:55:39 +02:00
|
|
|
for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
|
|
|
|
{
|
Clean up treatment of missing default and CHECK-constraint records.
Andrew Gierth reported that it's possible to crash the backend if no
pg_attrdef record is found to match an attribute that has atthasdef set.
AttrDefaultFetch warns about this situation, but then leaves behind
a relation tupdesc that has null "adbin" pointer(s), which most places
don't guard against.
We considered promoting the warning to an error, but throwing errors
during relcache load is pretty drastic: it effectively locks one out
of using the relation at all. What seems better is to leave the
load-time behavior as a warning, but then throw an error in any code
path that wants to use a default and can't find it. This confines
the error to a subset of INSERT/UPDATE operations on the table, and
in particular will at least allow a pg_dump to succeed.
Also, we should fix AttrDefaultFetch to not leave any null pointers
in the tupdesc, because that just creates an untested bug hazard.
While at it, apply the same philosophy of "warn at load, throw error
only upon use of the known-missing info" to CHECK constraints.
CheckConstraintFetch is very nearly the same logic as AttrDefaultFetch,
but for reasons lost in the mists of time, it was throwing ERROR for
the same cases that AttrDefaultFetch treats as WARNING. Make the two
functions more nearly alike.
In passing, get rid of potentially-O(N^2) loops in equalTupleDesc
by making AttrDefaultFetch sort the entries after fetching them,
so that equalTupleDesc can assume that entries in two equal tupdescs
must be in matching order. (CheckConstraintFetch already was sorting
CHECK constraints, but equalTupleDesc hadn't been told about it.)
There's some argument for back-patching this, but with such a small
number of field reports, I'm content to fix it in HEAD.
Discussion: https://postgr.es/m/87pmzaq4gx.fsf@news-spur.riddles.org.uk
2021-04-06 16:34:37 +02:00
|
|
|
pfree(check[i].ccname);
|
|
|
|
pfree(check[i].ccbin);
|
1997-08-22 04:55:39 +02:00
|
|
|
}
|
|
|
|
pfree(check);
|
|
|
|
}
|
|
|
|
pfree(tupdesc->constr);
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-08-22 04:55:39 +02:00
|
|
|
pfree(tupdesc);
|
|
|
|
}
|
|
|
|
|
2006-06-16 20:42:24 +02:00
|
|
|
/*
|
|
|
|
* Increment the reference count of a tupdesc, and log the reference in
|
|
|
|
* CurrentResourceOwner.
|
|
|
|
*
|
|
|
|
* Do not apply this to tupdescs that are not being refcounted. (Use the
|
|
|
|
* macro PinTupleDesc for tupdescs of uncertain status.)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
IncrTupleDescRefCount(TupleDesc tupdesc)
|
|
|
|
{
|
|
|
|
Assert(tupdesc->tdrefcount >= 0);
|
|
|
|
|
Make ResourceOwners more easily extensible.
Instead of having a separate array/hash for each resource kind, use a
single array and hash to hold all kinds of resources. This makes it
possible to introduce new resource "kinds" without having to modify
the ResourceOwnerData struct. In particular, this makes it possible
for extensions to register custom resource kinds.
The old approach was to have a small array of resources of each kind,
and if it fills up, switch to a hash table. The new approach also uses
an array and a hash, but now the array and the hash are used at the
same time. The array is used to hold the recently added resources, and
when it fills up, they are moved to the hash. This keeps the access to
recent entries fast, even when there are a lot of long-held resources.
All the resource-specific ResourceOwnerEnlarge*(),
ResourceOwnerRemember*(), and ResourceOwnerForget*() functions have
been replaced with three generic functions that take resource kind as
argument. For convenience, we still define resource-specific wrapper
macros around the generic functions with the old names, but they are
now defined in the source files that use those resource kinds.
The release callback no longer needs to call ResourceOwnerForget on
the resource being released. ResourceOwnerRelease unregisters the
resource from the owner before calling the callback. That needed some
changes in bufmgr.c and some other files, where releasing the
resources previously always called ResourceOwnerForget.
Each resource kind specifies a release priority, and
ResourceOwnerReleaseAll releases the resources in priority order. To
make that possible, we have to restrict what you can do between
phases. After calling ResourceOwnerRelease(), you are no longer
allowed to remember any more resources in it or to forget any
previously remembered resources by calling ResourceOwnerForget. There
was one case where that was done previously. At subtransaction commit,
AtEOSubXact_Inval() would handle the invalidation messages and call
RelationFlushRelation(), which temporarily increased the reference
count on the relation being flushed. We now switch to the parent
subtransaction's resource owner before calling AtEOSubXact_Inval(), so
that there is a valid ResourceOwner to temporarily hold that relcache
reference.
Other end-of-xact routines make similar calls to AtEOXact_Inval()
between release phases, but I didn't see any regression test failures
from those, so I'm not sure if they could reach a codepath that needs
remembering extra resources.
There were two exceptions to how the resource leak WARNINGs on commit
were printed previously: llvmjit silently released the context without
printing the warning, and a leaked buffer io triggered a PANIC. Now
everything prints a WARNING, including those cases.
Add tests in src/test/modules/test_resowner.
Reviewed-by: Aleksander Alekseev, Michael Paquier, Julien Rouhaud
Reviewed-by: Kyotaro Horiguchi, Hayato Kuroda, Álvaro Herrera, Zhihong Yu
Reviewed-by: Peter Eisentraut, Andres Freund
Discussion: https://www.postgresql.org/message-id/cbfabeb0-cd3c-e951-a572-19b365ed314d%40iki.fi
2023-11-08 12:30:50 +01:00
|
|
|
ResourceOwnerEnlarge(CurrentResourceOwner);
|
2006-06-16 20:42:24 +02:00
|
|
|
tupdesc->tdrefcount++;
|
|
|
|
ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Decrement the reference count of a tupdesc, remove the corresponding
|
|
|
|
* reference from CurrentResourceOwner, and free the tupdesc if no more
|
|
|
|
* references remain.
|
|
|
|
*
|
|
|
|
* Do not apply this to tupdescs that are not being refcounted. (Use the
|
|
|
|
* macro ReleaseTupleDesc for tupdescs of uncertain status.)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
DecrTupleDescRefCount(TupleDesc tupdesc)
|
|
|
|
{
|
|
|
|
Assert(tupdesc->tdrefcount > 0);
|
|
|
|
|
|
|
|
ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
|
|
|
|
if (--tupdesc->tdrefcount == 0)
|
|
|
|
FreeTupleDesc(tupdesc);
|
|
|
|
}
|
|
|
|
|
2002-08-30 21:23:20 +02:00
|
|
|
/*
|
|
|
|
* Compare two TupleDesc structures for logical equality
|
2004-04-01 23:28:47 +02:00
|
|
|
*
|
|
|
|
* Note: we deliberately do not check the attrelid and tdtypmod fields.
|
|
|
|
* This allows typcache.c to use this routine to see if a cached record type
|
|
|
|
* matches a requested type, and is harmless for relcache.c's uses.
|
2006-06-16 20:42:24 +02:00
|
|
|
* We don't compare tdrefcount, either.
|
2002-08-30 21:23:20 +02:00
|
|
|
*/
|
2000-01-31 05:35:57 +01:00
|
|
|
bool
|
|
|
|
equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
|
|
|
{
|
2000-11-08 23:10:03 +01:00
|
|
|
int i,
|
|
|
|
n;
|
2000-01-31 05:35:57 +01:00
|
|
|
|
|
|
|
if (tupdesc1->natts != tupdesc2->natts)
|
|
|
|
return false;
|
2004-04-01 23:28:47 +02:00
|
|
|
if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
|
|
|
|
return false;
|
|
|
|
|
2000-01-31 05:35:57 +01:00
|
|
|
for (i = 0; i < tupdesc1->natts; i++)
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
|
|
|
|
Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
|
2000-01-31 05:35:57 +01:00
|
|
|
|
|
|
|
/*
|
2001-05-07 02:43:27 +02:00
|
|
|
* We do not need to check every single field here: we can disregard
|
2005-04-15 00:34:48 +02:00
|
|
|
* attrelid and attnum (which were used to place the row in the attrs
|
|
|
|
* array in the first place). It might look like we could dispense
|
|
|
|
* with checking attlen/attbyval/attalign, since these are derived
|
|
|
|
* from atttypid; but in the case of dropped columns we must check
|
|
|
|
* them (since atttypid will be zero for all dropped columns) and in
|
|
|
|
* general it seems safer to check them always.
|
|
|
|
*
|
|
|
|
* attcacheoff must NOT be checked since it's possibly not set in both
|
2021-05-23 18:12:09 +02:00
|
|
|
* copies. We also intentionally ignore atthasmissing, since that's
|
|
|
|
* not very relevant in tupdescs, which lack the attmissingval field.
|
2000-01-31 05:35:57 +01:00
|
|
|
*/
|
|
|
|
if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
|
|
|
|
return false;
|
|
|
|
if (attr1->atttypid != attr2->atttypid)
|
|
|
|
return false;
|
2001-05-07 02:43:27 +02:00
|
|
|
if (attr1->attstattarget != attr2->attstattarget)
|
|
|
|
return false;
|
2005-04-15 00:34:48 +02:00
|
|
|
if (attr1->attlen != attr2->attlen)
|
|
|
|
return false;
|
2004-04-01 23:28:47 +02:00
|
|
|
if (attr1->attndims != attr2->attndims)
|
|
|
|
return false;
|
2000-01-31 05:35:57 +01:00
|
|
|
if (attr1->atttypmod != attr2->atttypmod)
|
|
|
|
return false;
|
2005-04-15 00:34:48 +02:00
|
|
|
if (attr1->attbyval != attr2->attbyval)
|
|
|
|
return false;
|
2021-05-23 18:12:09 +02:00
|
|
|
if (attr1->attalign != attr2->attalign)
|
|
|
|
return false;
|
2000-01-31 05:35:57 +01:00
|
|
|
if (attr1->attstorage != attr2->attstorage)
|
|
|
|
return false;
|
2021-05-23 18:12:09 +02:00
|
|
|
if (attr1->attcompression != attr2->attcompression)
|
2005-04-15 00:34:48 +02:00
|
|
|
return false;
|
2000-01-31 05:35:57 +01:00
|
|
|
if (attr1->attnotnull != attr2->attnotnull)
|
|
|
|
return false;
|
2002-08-30 21:23:20 +02:00
|
|
|
if (attr1->atthasdef != attr2->atthasdef)
|
|
|
|
return false;
|
2017-04-06 14:33:16 +02:00
|
|
|
if (attr1->attidentity != attr2->attidentity)
|
|
|
|
return false;
|
2019-03-30 08:13:09 +01:00
|
|
|
if (attr1->attgenerated != attr2->attgenerated)
|
|
|
|
return false;
|
2002-08-02 20:15:10 +02:00
|
|
|
if (attr1->attisdropped != attr2->attisdropped)
|
|
|
|
return false;
|
2002-09-22 21:42:52 +02:00
|
|
|
if (attr1->attislocal != attr2->attislocal)
|
|
|
|
return false;
|
|
|
|
if (attr1->attinhcount != attr2->attinhcount)
|
2002-08-30 21:23:20 +02:00
|
|
|
return false;
|
2011-04-22 23:43:18 +02:00
|
|
|
if (attr1->attcollation != attr2->attcollation)
|
|
|
|
return false;
|
2021-05-23 18:12:09 +02:00
|
|
|
/* variable-length fields are not even present... */
|
2000-01-31 05:35:57 +01:00
|
|
|
}
|
2004-04-01 23:28:47 +02:00
|
|
|
|
2000-01-31 05:35:57 +01:00
|
|
|
if (tupdesc1->constr != NULL)
|
|
|
|
{
|
|
|
|
TupleConstr *constr1 = tupdesc1->constr;
|
|
|
|
TupleConstr *constr2 = tupdesc2->constr;
|
|
|
|
|
|
|
|
if (constr2 == NULL)
|
|
|
|
return false;
|
2000-11-08 23:10:03 +01:00
|
|
|
if (constr1->has_not_null != constr2->has_not_null)
|
|
|
|
return false;
|
2019-03-30 08:13:09 +01:00
|
|
|
if (constr1->has_generated_stored != constr2->has_generated_stored)
|
|
|
|
return false;
|
2000-11-08 23:10:03 +01:00
|
|
|
n = constr1->num_defval;
|
|
|
|
if (n != (int) constr2->num_defval)
|
2000-01-31 05:35:57 +01:00
|
|
|
return false;
|
Clean up treatment of missing default and CHECK-constraint records.
Andrew Gierth reported that it's possible to crash the backend if no
pg_attrdef record is found to match an attribute that has atthasdef set.
AttrDefaultFetch warns about this situation, but then leaves behind
a relation tupdesc that has null "adbin" pointer(s), which most places
don't guard against.
We considered promoting the warning to an error, but throwing errors
during relcache load is pretty drastic: it effectively locks one out
of using the relation at all. What seems better is to leave the
load-time behavior as a warning, but then throw an error in any code
path that wants to use a default and can't find it. This confines
the error to a subset of INSERT/UPDATE operations on the table, and
in particular will at least allow a pg_dump to succeed.
Also, we should fix AttrDefaultFetch to not leave any null pointers
in the tupdesc, because that just creates an untested bug hazard.
While at it, apply the same philosophy of "warn at load, throw error
only upon use of the known-missing info" to CHECK constraints.
CheckConstraintFetch is very nearly the same logic as AttrDefaultFetch,
but for reasons lost in the mists of time, it was throwing ERROR for
the same cases that AttrDefaultFetch treats as WARNING. Make the two
functions more nearly alike.
In passing, get rid of potentially-O(N^2) loops in equalTupleDesc
by making AttrDefaultFetch sort the entries after fetching them,
so that equalTupleDesc can assume that entries in two equal tupdescs
must be in matching order. (CheckConstraintFetch already was sorting
CHECK constraints, but equalTupleDesc hadn't been told about it.)
There's some argument for back-patching this, but with such a small
number of field reports, I'm content to fix it in HEAD.
Discussion: https://postgr.es/m/87pmzaq4gx.fsf@news-spur.riddles.org.uk
2021-04-06 16:34:37 +02:00
|
|
|
/* We assume here that both AttrDefault arrays are in adnum order */
|
2000-11-08 23:10:03 +01:00
|
|
|
for (i = 0; i < n; i++)
|
2000-01-31 05:35:57 +01:00
|
|
|
{
|
|
|
|
AttrDefault *defval1 = constr1->defval + i;
|
Clean up treatment of missing default and CHECK-constraint records.
Andrew Gierth reported that it's possible to crash the backend if no
pg_attrdef record is found to match an attribute that has atthasdef set.
AttrDefaultFetch warns about this situation, but then leaves behind
a relation tupdesc that has null "adbin" pointer(s), which most places
don't guard against.
We considered promoting the warning to an error, but throwing errors
during relcache load is pretty drastic: it effectively locks one out
of using the relation at all. What seems better is to leave the
load-time behavior as a warning, but then throw an error in any code
path that wants to use a default and can't find it. This confines
the error to a subset of INSERT/UPDATE operations on the table, and
in particular will at least allow a pg_dump to succeed.
Also, we should fix AttrDefaultFetch to not leave any null pointers
in the tupdesc, because that just creates an untested bug hazard.
While at it, apply the same philosophy of "warn at load, throw error
only upon use of the known-missing info" to CHECK constraints.
CheckConstraintFetch is very nearly the same logic as AttrDefaultFetch,
but for reasons lost in the mists of time, it was throwing ERROR for
the same cases that AttrDefaultFetch treats as WARNING. Make the two
functions more nearly alike.
In passing, get rid of potentially-O(N^2) loops in equalTupleDesc
by making AttrDefaultFetch sort the entries after fetching them,
so that equalTupleDesc can assume that entries in two equal tupdescs
must be in matching order. (CheckConstraintFetch already was sorting
CHECK constraints, but equalTupleDesc hadn't been told about it.)
There's some argument for back-patching this, but with such a small
number of field reports, I'm content to fix it in HEAD.
Discussion: https://postgr.es/m/87pmzaq4gx.fsf@news-spur.riddles.org.uk
2021-04-06 16:34:37 +02:00
|
|
|
AttrDefault *defval2 = constr2->defval + i;
|
|
|
|
|
|
|
|
if (defval1->adnum != defval2->adnum)
|
2000-01-31 05:35:57 +01:00
|
|
|
return false;
|
|
|
|
if (strcmp(defval1->adbin, defval2->adbin) != 0)
|
|
|
|
return false;
|
|
|
|
}
|
2018-03-28 02:13:52 +02:00
|
|
|
if (constr1->missing)
|
|
|
|
{
|
|
|
|
if (!constr2->missing)
|
|
|
|
return false;
|
|
|
|
for (i = 0; i < tupdesc1->natts; i++)
|
|
|
|
{
|
|
|
|
AttrMissing *missval1 = constr1->missing + i;
|
|
|
|
AttrMissing *missval2 = constr2->missing + i;
|
|
|
|
|
2018-06-27 04:46:13 +02:00
|
|
|
if (missval1->am_present != missval2->am_present)
|
2018-03-28 02:13:52 +02:00
|
|
|
return false;
|
2018-06-27 04:46:13 +02:00
|
|
|
if (missval1->am_present)
|
2018-03-28 02:13:52 +02:00
|
|
|
{
|
|
|
|
Form_pg_attribute missatt1 = TupleDescAttr(tupdesc1, i);
|
|
|
|
|
2018-06-27 04:46:13 +02:00
|
|
|
if (!datumIsEqual(missval1->am_value, missval2->am_value,
|
2018-03-28 02:13:52 +02:00
|
|
|
missatt1->attbyval, missatt1->attlen))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (constr2->missing)
|
|
|
|
return false;
|
2000-11-08 23:10:03 +01:00
|
|
|
n = constr1->num_check;
|
|
|
|
if (n != (int) constr2->num_check)
|
2000-01-31 05:35:57 +01:00
|
|
|
return false;
|
Clean up treatment of missing default and CHECK-constraint records.
Andrew Gierth reported that it's possible to crash the backend if no
pg_attrdef record is found to match an attribute that has atthasdef set.
AttrDefaultFetch warns about this situation, but then leaves behind
a relation tupdesc that has null "adbin" pointer(s), which most places
don't guard against.
We considered promoting the warning to an error, but throwing errors
during relcache load is pretty drastic: it effectively locks one out
of using the relation at all. What seems better is to leave the
load-time behavior as a warning, but then throw an error in any code
path that wants to use a default and can't find it. This confines
the error to a subset of INSERT/UPDATE operations on the table, and
in particular will at least allow a pg_dump to succeed.
Also, we should fix AttrDefaultFetch to not leave any null pointers
in the tupdesc, because that just creates an untested bug hazard.
While at it, apply the same philosophy of "warn at load, throw error
only upon use of the known-missing info" to CHECK constraints.
CheckConstraintFetch is very nearly the same logic as AttrDefaultFetch,
but for reasons lost in the mists of time, it was throwing ERROR for
the same cases that AttrDefaultFetch treats as WARNING. Make the two
functions more nearly alike.
In passing, get rid of potentially-O(N^2) loops in equalTupleDesc
by making AttrDefaultFetch sort the entries after fetching them,
so that equalTupleDesc can assume that entries in two equal tupdescs
must be in matching order. (CheckConstraintFetch already was sorting
CHECK constraints, but equalTupleDesc hadn't been told about it.)
There's some argument for back-patching this, but with such a small
number of field reports, I'm content to fix it in HEAD.
Discussion: https://postgr.es/m/87pmzaq4gx.fsf@news-spur.riddles.org.uk
2021-04-06 16:34:37 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Similarly, we rely here on the ConstrCheck entries being sorted by
|
|
|
|
* name. If there are duplicate names, the outcome of the comparison
|
|
|
|
* is uncertain, but that should not happen.
|
|
|
|
*/
|
2000-11-08 23:10:03 +01:00
|
|
|
for (i = 0; i < n; i++)
|
2000-01-31 05:35:57 +01:00
|
|
|
{
|
|
|
|
ConstrCheck *check1 = constr1->check + i;
|
Clean up treatment of missing default and CHECK-constraint records.
Andrew Gierth reported that it's possible to crash the backend if no
pg_attrdef record is found to match an attribute that has atthasdef set.
AttrDefaultFetch warns about this situation, but then leaves behind
a relation tupdesc that has null "adbin" pointer(s), which most places
don't guard against.
We considered promoting the warning to an error, but throwing errors
during relcache load is pretty drastic: it effectively locks one out
of using the relation at all. What seems better is to leave the
load-time behavior as a warning, but then throw an error in any code
path that wants to use a default and can't find it. This confines
the error to a subset of INSERT/UPDATE operations on the table, and
in particular will at least allow a pg_dump to succeed.
Also, we should fix AttrDefaultFetch to not leave any null pointers
in the tupdesc, because that just creates an untested bug hazard.
While at it, apply the same philosophy of "warn at load, throw error
only upon use of the known-missing info" to CHECK constraints.
CheckConstraintFetch is very nearly the same logic as AttrDefaultFetch,
but for reasons lost in the mists of time, it was throwing ERROR for
the same cases that AttrDefaultFetch treats as WARNING. Make the two
functions more nearly alike.
In passing, get rid of potentially-O(N^2) loops in equalTupleDesc
by making AttrDefaultFetch sort the entries after fetching them,
so that equalTupleDesc can assume that entries in two equal tupdescs
must be in matching order. (CheckConstraintFetch already was sorting
CHECK constraints, but equalTupleDesc hadn't been told about it.)
There's some argument for back-patching this, but with such a small
number of field reports, I'm content to fix it in HEAD.
Discussion: https://postgr.es/m/87pmzaq4gx.fsf@news-spur.riddles.org.uk
2021-04-06 16:34:37 +02:00
|
|
|
ConstrCheck *check2 = constr2->check + i;
|
|
|
|
|
|
|
|
if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
|
|
|
|
strcmp(check1->ccbin, check2->ccbin) == 0 &&
|
|
|
|
check1->ccvalid == check2->ccvalid &&
|
|
|
|
check1->ccnoinherit == check2->ccnoinherit))
|
2000-01-31 05:35:57 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tupdesc2->constr != NULL)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-08-23 01:05:48 +02:00
|
|
|
/*
|
|
|
|
* hashTupleDesc
|
|
|
|
* Compute a hash value for a tuple descriptor.
|
|
|
|
*
|
|
|
|
* If two tuple descriptors would be considered equal by equalTupleDescs()
|
|
|
|
* then their hash value will be equal according to this function.
|
|
|
|
*
|
|
|
|
* Note that currently contents of constraint are not hashed - it'd be a bit
|
|
|
|
* painful to do so, and conflicts just due to constraints are unlikely.
|
|
|
|
*/
|
|
|
|
uint32
|
|
|
|
hashTupleDesc(TupleDesc desc)
|
|
|
|
{
|
|
|
|
uint32 s;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
s = hash_combine(0, hash_uint32(desc->natts));
|
|
|
|
s = hash_combine(s, hash_uint32(desc->tdtypeid));
|
|
|
|
for (i = 0; i < desc->natts; ++i)
|
|
|
|
s = hash_combine(s, hash_uint32(TupleDescAttr(desc, i)->atttypid));
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* TupleDescInitEntry
|
1996-07-09 08:22:35 +02:00
|
|
|
* This function initializes a single attribute structure in
|
2005-03-07 05:42:17 +01:00
|
|
|
* a previously allocated tuple descriptor.
|
2011-03-26 23:28:40 +01:00
|
|
|
*
|
2013-10-29 01:49:24 +01:00
|
|
|
* If attributeName is NULL, the attname field is set to an empty string
|
|
|
|
* (this is for cases where we don't know or need a name for the field).
|
|
|
|
* Also, some callers use this function to change the datatype-related fields
|
|
|
|
* in an existing tupdesc; they pass attributeName = NameStr(att->attname)
|
|
|
|
* to indicate that the attname field shouldn't be modified.
|
|
|
|
*
|
2011-03-26 23:28:40 +01:00
|
|
|
* Note that attcollation is set to the default for the specified datatype.
|
|
|
|
* If a nondefault collation is needed, insert it afterwards using
|
|
|
|
* TupleDescInitEntryCollation.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2002-03-29 20:06:29 +01:00
|
|
|
void
|
1996-07-09 08:22:35 +02:00
|
|
|
TupleDescInitEntry(TupleDesc desc,
|
|
|
|
AttrNumber attributeNumber,
|
2003-08-12 01:04:50 +02:00
|
|
|
const char *attributeName,
|
2000-05-22 04:34:23 +02:00
|
|
|
Oid oidtypeid,
|
1998-07-12 23:29:40 +02:00
|
|
|
int32 typmod,
|
2004-04-01 23:28:47 +02:00
|
|
|
int attdim)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
|
|
|
HeapTuple tuple;
|
|
|
|
Form_pg_type typeForm;
|
|
|
|
Form_pg_attribute att;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
|
|
|
* sanity checks
|
|
|
|
*/
|
2022-10-28 09:19:06 +02:00
|
|
|
Assert(PointerIsValid(desc));
|
|
|
|
Assert(attributeNumber >= 1);
|
|
|
|
Assert(attributeNumber <= desc->natts);
|
2023-03-28 09:58:14 +02:00
|
|
|
Assert(attdim >= 0);
|
|
|
|
Assert(attdim <= PG_INT16_MAX);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
2000-12-28 00:59:14 +01:00
|
|
|
* initialize the attribute fields
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2017-08-20 20:19:07 +02:00
|
|
|
att = TupleDescAttr(desc, attributeNumber - 1);
|
2005-03-07 05:42:17 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
att->attrelid = 0; /* dummy value */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2003-08-12 01:04:50 +02:00
|
|
|
/*
|
|
|
|
* Note: attributeName can be NULL, because the planner doesn't always
|
|
|
|
* fill in valid resname values in targetlists, particularly for resjunk
|
2013-10-29 01:49:24 +01:00
|
|
|
* attributes. Also, do nothing if caller wants to re-use the old attname.
|
2003-08-12 01:04:50 +02:00
|
|
|
*/
|
2013-10-29 01:49:24 +01:00
|
|
|
if (attributeName == NULL)
|
1999-11-08 00:08:36 +01:00
|
|
|
MemSet(NameStr(att->attname), 0, NAMEDATALEN);
|
2013-10-29 01:49:24 +01:00
|
|
|
else if (attributeName != NameStr(att->attname))
|
|
|
|
namestrcpy(&(att->attname), attributeName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-07-31 19:19:54 +02:00
|
|
|
att->attstattarget = -1;
|
1996-07-09 08:22:35 +02:00
|
|
|
att->attcacheoff = -1;
|
1998-02-10 05:02:59 +01:00
|
|
|
att->atttypmod = typmod;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
att->attnum = attributeNumber;
|
2001-05-07 02:43:27 +02:00
|
|
|
att->attndims = attdim;
|
1998-02-26 05:46:47 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
att->attnotnull = false;
|
1997-08-21 03:32:19 +02:00
|
|
|
att->atthasdef = false;
|
2018-03-28 02:13:52 +02:00
|
|
|
att->atthasmissing = false;
|
2017-04-06 14:33:16 +02:00
|
|
|
att->attidentity = '\0';
|
2019-03-30 08:13:09 +01:00
|
|
|
att->attgenerated = '\0';
|
2002-08-02 20:15:10 +02:00
|
|
|
att->attisdropped = false;
|
2002-09-22 21:42:52 +02:00
|
|
|
att->attislocal = true;
|
|
|
|
att->attinhcount = 0;
|
2021-11-26 09:57:23 +01:00
|
|
|
/* variable-length fields are not present in tupledescs */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
|
1996-07-09 08:22:35 +02:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
2003-07-21 22:29:40 +02:00
|
|
|
elog(ERROR, "cache lookup failed for type %u", oidtypeid);
|
1996-07-09 08:22:35 +02:00
|
|
|
typeForm = (Form_pg_type) GETSTRUCT(tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-04-01 23:28:47 +02:00
|
|
|
att->atttypid = oidtypeid;
|
|
|
|
att->attlen = typeForm->typlen;
|
|
|
|
att->attbyval = typeForm->typbyval;
|
|
|
|
att->attalign = typeForm->typalign;
|
|
|
|
att->attstorage = typeForm->typstorage;
|
2021-05-27 19:24:24 +02:00
|
|
|
att->attcompression = InvalidCompressionMethod;
|
2021-05-23 18:12:09 +02:00
|
|
|
att->attcollation = typeForm->typcollation;
|
Allow configurable LZ4 TOAST compression.
There is now a per-column COMPRESSION option which can be set to pglz
(the default, and the only option in up until now) or lz4. Or, if you
like, you can set the new default_toast_compression GUC to lz4, and
then that will be the default for new table columns for which no value
is specified. We don't have lz4 support in the PostgreSQL code, so
to use lz4 compression, PostgreSQL must be built --with-lz4.
In general, TOAST compression means compression of individual column
values, not the whole tuple, and those values can either be compressed
inline within the tuple or compressed and then stored externally in
the TOAST table, so those properties also apply to this feature.
Prior to this commit, a TOAST pointer has two unused bits as part of
the va_extsize field, and a compessed datum has two unused bits as
part of the va_rawsize field. These bits are unused because the length
of a varlena is limited to 1GB; we now use them to indicate the
compression type that was used. This means we only have bit space for
2 more built-in compresison types, but we could work around that
problem, if necessary, by introducing a new vartag_external value for
any further types we end up wanting to add. Hopefully, it won't be
too important to offer a wide selection of algorithms here, since
each one we add not only takes more coding but also adds a build
dependency for every packager. Nevertheless, it seems worth doing
at least this much, because LZ4 gets better compression than PGLZ
with less CPU usage.
It's possible for LZ4-compressed datums to leak into composite type
values stored on disk, just as it is for PGLZ. It's also possible for
LZ4-compressed attributes to be copied into a different table via SQL
commands such as CREATE TABLE AS or INSERT .. SELECT. It would be
expensive to force such values to be decompressed, so PostgreSQL has
never done so. For the same reasons, we also don't force recompression
of already-compressed values even if the target table prefers a
different compression method than was used for the source data. These
architectural decisions are perhaps arguable but revisiting them is
well beyond the scope of what seemed possible to do as part of this
project. However, it's relatively cheap to recompress as part of
VACUUM FULL or CLUSTER, so this commit adjusts those commands to do
so, if the configured compression method of the table happens not to
match what was used for some column value stored therein.
Dilip Kumar. The original patches on which this work was based were
written by Ildus Kurbangaliev, and those were patches were based on
even earlier work by Nikita Glukhov, but the design has since changed
very substantially, since allow a potentially large number of
compression methods that could be added and dropped on a running
system proved too problematic given some of the architectural issues
mentioned above; the choice of which specific compression method to
add first is now different; and a lot of the code has been heavily
refactored. More recently, Justin Przyby helped quite a bit with
testing and reviewing and this version also includes some code
contributions from him. Other design input and review from Tomas
Vondra, Álvaro Herrera, Andres Freund, Oleg Bartunov, Alexander
Korotkov, and me.
Discussion: http://postgr.es/m/20170907194236.4cefce96%40wp.localdomain
Discussion: http://postgr.es/m/CAFiTN-uUpX3ck%3DK0mLEk-G_kUQY%3DSNOTeqdaNRR9FMdQrHKebw%40mail.gmail.com
2021-03-19 20:10:38 +01:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
ReleaseSysCache(tuple);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2017-01-24 22:59:18 +01:00
|
|
|
/*
|
|
|
|
* TupleDescInitBuiltinEntry
|
|
|
|
* Initialize a tuple descriptor without catalog access. Only
|
|
|
|
* a limited range of builtin types are supported.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
TupleDescInitBuiltinEntry(TupleDesc desc,
|
|
|
|
AttrNumber attributeNumber,
|
|
|
|
const char *attributeName,
|
|
|
|
Oid oidtypeid,
|
|
|
|
int32 typmod,
|
|
|
|
int attdim)
|
|
|
|
{
|
|
|
|
Form_pg_attribute att;
|
|
|
|
|
|
|
|
/* sanity checks */
|
2022-10-28 09:19:06 +02:00
|
|
|
Assert(PointerIsValid(desc));
|
|
|
|
Assert(attributeNumber >= 1);
|
|
|
|
Assert(attributeNumber <= desc->natts);
|
2023-03-28 09:58:14 +02:00
|
|
|
Assert(attdim >= 0);
|
|
|
|
Assert(attdim <= PG_INT16_MAX);
|
2017-01-24 22:59:18 +01:00
|
|
|
|
|
|
|
/* initialize the attribute fields */
|
2017-08-20 20:19:07 +02:00
|
|
|
att = TupleDescAttr(desc, attributeNumber - 1);
|
2017-01-24 22:59:18 +01:00
|
|
|
att->attrelid = 0; /* dummy value */
|
|
|
|
|
|
|
|
/* unlike TupleDescInitEntry, we require an attribute name */
|
|
|
|
Assert(attributeName != NULL);
|
|
|
|
namestrcpy(&(att->attname), attributeName);
|
|
|
|
|
|
|
|
att->attstattarget = -1;
|
|
|
|
att->attcacheoff = -1;
|
|
|
|
att->atttypmod = typmod;
|
|
|
|
|
|
|
|
att->attnum = attributeNumber;
|
|
|
|
att->attndims = attdim;
|
|
|
|
|
|
|
|
att->attnotnull = false;
|
|
|
|
att->atthasdef = false;
|
2018-03-28 02:13:52 +02:00
|
|
|
att->atthasmissing = false;
|
2017-04-06 14:33:16 +02:00
|
|
|
att->attidentity = '\0';
|
2019-03-30 08:13:09 +01:00
|
|
|
att->attgenerated = '\0';
|
2017-01-24 22:59:18 +01:00
|
|
|
att->attisdropped = false;
|
|
|
|
att->attislocal = true;
|
|
|
|
att->attinhcount = 0;
|
2021-11-26 09:57:23 +01:00
|
|
|
/* variable-length fields are not present in tupledescs */
|
2017-01-24 22:59:18 +01:00
|
|
|
|
|
|
|
att->atttypid = oidtypeid;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Our goal here is to support just enough types to let basic builtin
|
|
|
|
* commands work without catalog access - e.g. so that we can do certain
|
|
|
|
* things even in processes that are not connected to a database.
|
|
|
|
*/
|
|
|
|
switch (oidtypeid)
|
|
|
|
{
|
|
|
|
case TEXTOID:
|
|
|
|
case TEXTARRAYOID:
|
|
|
|
att->attlen = -1;
|
|
|
|
att->attbyval = false;
|
2020-03-04 16:34:25 +01:00
|
|
|
att->attalign = TYPALIGN_INT;
|
|
|
|
att->attstorage = TYPSTORAGE_EXTENDED;
|
2021-05-27 19:24:24 +02:00
|
|
|
att->attcompression = InvalidCompressionMethod;
|
2017-01-24 22:59:18 +01:00
|
|
|
att->attcollation = DEFAULT_COLLATION_OID;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BOOLOID:
|
|
|
|
att->attlen = 1;
|
|
|
|
att->attbyval = true;
|
2020-03-04 16:34:25 +01:00
|
|
|
att->attalign = TYPALIGN_CHAR;
|
|
|
|
att->attstorage = TYPSTORAGE_PLAIN;
|
2021-05-23 18:12:09 +02:00
|
|
|
att->attcompression = InvalidCompressionMethod;
|
2017-01-24 22:59:18 +01:00
|
|
|
att->attcollation = InvalidOid;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INT4OID:
|
|
|
|
att->attlen = 4;
|
|
|
|
att->attbyval = true;
|
2020-03-04 16:34:25 +01:00
|
|
|
att->attalign = TYPALIGN_INT;
|
|
|
|
att->attstorage = TYPSTORAGE_PLAIN;
|
2021-05-23 18:12:09 +02:00
|
|
|
att->attcompression = InvalidCompressionMethod;
|
2017-01-24 22:59:18 +01:00
|
|
|
att->attcollation = InvalidOid;
|
2017-02-01 19:42:41 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case INT8OID:
|
|
|
|
att->attlen = 8;
|
|
|
|
att->attbyval = FLOAT8PASSBYVAL;
|
2020-03-04 16:34:25 +01:00
|
|
|
att->attalign = TYPALIGN_DOUBLE;
|
|
|
|
att->attstorage = TYPSTORAGE_PLAIN;
|
2021-05-23 18:12:09 +02:00
|
|
|
att->attcompression = InvalidCompressionMethod;
|
2017-02-01 19:42:41 +01:00
|
|
|
att->attcollation = InvalidOid;
|
2017-01-24 22:59:18 +01:00
|
|
|
break;
|
2018-12-10 16:38:48 +01:00
|
|
|
|
2022-07-04 07:25:26 +02:00
|
|
|
case OIDOID:
|
|
|
|
att->attlen = 4;
|
|
|
|
att->attbyval = true;
|
|
|
|
att->attalign = TYPALIGN_INT;
|
|
|
|
att->attstorage = TYPSTORAGE_PLAIN;
|
|
|
|
att->attcompression = InvalidCompressionMethod;
|
|
|
|
att->attcollation = InvalidOid;
|
|
|
|
break;
|
|
|
|
|
2018-12-10 16:38:48 +01:00
|
|
|
default:
|
|
|
|
elog(ERROR, "unsupported type %u", oidtypeid);
|
2017-01-24 22:59:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-08 22:04:18 +01:00
|
|
|
/*
|
|
|
|
* TupleDescInitEntryCollation
|
|
|
|
*
|
2011-03-26 23:28:40 +01:00
|
|
|
* Assign a nondefault collation to a previously initialized tuple descriptor
|
|
|
|
* entry.
|
2011-02-08 22:04:18 +01:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
TupleDescInitEntryCollation(TupleDesc desc,
|
|
|
|
AttrNumber attributeNumber,
|
|
|
|
Oid collationid)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* sanity checks
|
|
|
|
*/
|
2022-10-28 09:19:06 +02:00
|
|
|
Assert(PointerIsValid(desc));
|
|
|
|
Assert(attributeNumber >= 1);
|
|
|
|
Assert(attributeNumber <= desc->natts);
|
2011-02-08 22:04:18 +01:00
|
|
|
|
2017-08-20 20:19:07 +02:00
|
|
|
TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
|
2011-02-08 22:04:18 +01:00
|
|
|
}
|
|
|
|
|
2006-03-16 01:31:55 +01:00
|
|
|
/*
|
|
|
|
* BuildDescFromLists
|
|
|
|
*
|
|
|
|
* Build a TupleDesc given lists of column names (as String nodes),
|
2011-04-22 23:43:18 +02:00
|
|
|
* column type OIDs, typmods, and collation OIDs.
|
|
|
|
*
|
|
|
|
* No constraints are generated.
|
2006-03-16 01:31:55 +01:00
|
|
|
*
|
2023-10-05 16:17:16 +02:00
|
|
|
* This is for use with functions returning RECORD.
|
2006-03-16 01:31:55 +01:00
|
|
|
*/
|
|
|
|
TupleDesc
|
2023-09-26 17:08:35 +02:00
|
|
|
BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
|
2006-03-16 01:31:55 +01:00
|
|
|
{
|
|
|
|
int natts;
|
|
|
|
AttrNumber attnum;
|
|
|
|
ListCell *l1;
|
|
|
|
ListCell *l2;
|
|
|
|
ListCell *l3;
|
2011-02-08 22:04:18 +01:00
|
|
|
ListCell *l4;
|
2006-03-16 01:31:55 +01:00
|
|
|
TupleDesc desc;
|
|
|
|
|
|
|
|
natts = list_length(names);
|
|
|
|
Assert(natts == list_length(types));
|
|
|
|
Assert(natts == list_length(typmods));
|
2011-02-08 22:04:18 +01:00
|
|
|
Assert(natts == list_length(collations));
|
2006-03-16 01:31:55 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* allocate a new tuple descriptor
|
|
|
|
*/
|
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
|
|
|
desc = CreateTemplateTupleDesc(natts);
|
2006-03-16 01:31:55 +01:00
|
|
|
|
|
|
|
attnum = 0;
|
2019-02-28 20:25:01 +01:00
|
|
|
forfour(l1, names, l2, types, l3, typmods, l4, collations)
|
2006-03-16 01:31:55 +01:00
|
|
|
{
|
|
|
|
char *attname = strVal(lfirst(l1));
|
2019-02-28 20:25:01 +01:00
|
|
|
Oid atttypid = lfirst_oid(l2);
|
|
|
|
int32 atttypmod = lfirst_int(l3);
|
|
|
|
Oid attcollation = lfirst_oid(l4);
|
2006-03-16 01:31:55 +01:00
|
|
|
|
|
|
|
attnum++;
|
|
|
|
|
|
|
|
TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
|
2011-02-08 22:04:18 +01:00
|
|
|
TupleDescInitEntryCollation(desc, attnum, attcollation);
|
2006-03-16 01:31:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return desc;
|
|
|
|
}
|
2023-09-27 19:52:40 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get default expression (or NULL if none) for the given attribute number.
|
|
|
|
*/
|
|
|
|
Node *
|
|
|
|
TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
|
|
|
|
{
|
|
|
|
Node *result = NULL;
|
|
|
|
|
|
|
|
if (tupdesc->constr)
|
|
|
|
{
|
|
|
|
AttrDefault *attrdef = tupdesc->constr->defval;
|
|
|
|
|
|
|
|
for (int i = 0; i < tupdesc->constr->num_defval; i++)
|
|
|
|
{
|
|
|
|
if (attrdef[i].adnum == attnum)
|
|
|
|
{
|
|
|
|
result = stringToNode(attrdef[i].adbin);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
Make ResourceOwners more easily extensible.
Instead of having a separate array/hash for each resource kind, use a
single array and hash to hold all kinds of resources. This makes it
possible to introduce new resource "kinds" without having to modify
the ResourceOwnerData struct. In particular, this makes it possible
for extensions to register custom resource kinds.
The old approach was to have a small array of resources of each kind,
and if it fills up, switch to a hash table. The new approach also uses
an array and a hash, but now the array and the hash are used at the
same time. The array is used to hold the recently added resources, and
when it fills up, they are moved to the hash. This keeps the access to
recent entries fast, even when there are a lot of long-held resources.
All the resource-specific ResourceOwnerEnlarge*(),
ResourceOwnerRemember*(), and ResourceOwnerForget*() functions have
been replaced with three generic functions that take resource kind as
argument. For convenience, we still define resource-specific wrapper
macros around the generic functions with the old names, but they are
now defined in the source files that use those resource kinds.
The release callback no longer needs to call ResourceOwnerForget on
the resource being released. ResourceOwnerRelease unregisters the
resource from the owner before calling the callback. That needed some
changes in bufmgr.c and some other files, where releasing the
resources previously always called ResourceOwnerForget.
Each resource kind specifies a release priority, and
ResourceOwnerReleaseAll releases the resources in priority order. To
make that possible, we have to restrict what you can do between
phases. After calling ResourceOwnerRelease(), you are no longer
allowed to remember any more resources in it or to forget any
previously remembered resources by calling ResourceOwnerForget. There
was one case where that was done previously. At subtransaction commit,
AtEOSubXact_Inval() would handle the invalidation messages and call
RelationFlushRelation(), which temporarily increased the reference
count on the relation being flushed. We now switch to the parent
subtransaction's resource owner before calling AtEOSubXact_Inval(), so
that there is a valid ResourceOwner to temporarily hold that relcache
reference.
Other end-of-xact routines make similar calls to AtEOXact_Inval()
between release phases, but I didn't see any regression test failures
from those, so I'm not sure if they could reach a codepath that needs
remembering extra resources.
There were two exceptions to how the resource leak WARNINGs on commit
were printed previously: llvmjit silently released the context without
printing the warning, and a leaked buffer io triggered a PANIC. Now
everything prints a WARNING, including those cases.
Add tests in src/test/modules/test_resowner.
Reviewed-by: Aleksander Alekseev, Michael Paquier, Julien Rouhaud
Reviewed-by: Kyotaro Horiguchi, Hayato Kuroda, Álvaro Herrera, Zhihong Yu
Reviewed-by: Peter Eisentraut, Andres Freund
Discussion: https://www.postgresql.org/message-id/cbfabeb0-cd3c-e951-a572-19b365ed314d%40iki.fi
2023-11-08 12:30:50 +01:00
|
|
|
|
|
|
|
/* ResourceOwner callbacks */
|
|
|
|
|
|
|
|
static void
|
|
|
|
ResOwnerReleaseTupleDesc(Datum res)
|
|
|
|
{
|
|
|
|
TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
|
|
|
|
|
|
|
|
/* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
|
|
|
|
Assert(tupdesc->tdrefcount > 0);
|
|
|
|
if (--tupdesc->tdrefcount == 0)
|
|
|
|
FreeTupleDesc(tupdesc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
ResOwnerPrintTupleDesc(Datum res)
|
|
|
|
{
|
|
|
|
TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
|
|
|
|
|
|
|
|
return psprintf("TupleDesc %p (%u,%d)",
|
|
|
|
tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
|
|
|
|
}
|