2006-07-31 03:16:38 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* toasting.c
|
|
|
|
* This file contains routines to support creation of toast tables
|
|
|
|
*
|
|
|
|
*
|
2019-01-02 18:44:25 +01:00
|
|
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
|
2006-07-31 03:16:38 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/catalog/toasting.c
|
2006-07-31 03:16:38 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
Don't include heapam.h from others headers.
heapam.h previously was included in a number of widely used
headers (e.g. execnodes.h, indirectly in executor.h, ...). That's
problematic on its own, as heapam.h contains a lot of low-level
details that don't need to be exposed that widely, but becomes more
problematic with the upcoming introduction of pluggable table storage
- it seems inappropriate for heapam.h to be included that widely
afterwards.
heapam.h was largely only included in other headers to get the
HeapScanDesc typedef (which was defined in heapam.h, even though
HeapScanDescData is defined in relscan.h). The better solution here
seems to be to just use the underlying struct (forward declared where
necessary). Similar for BulkInsertState.
Another problem was that LockTupleMode was used in executor.h - parts
of the file tried to cope without heapam.h, but due to the fact that
it indirectly included it, several subsequent violations of that goal
were not not noticed. We could just reuse the approach of declaring
parameters as int, but it seems nicer to move LockTupleMode to
lockoptions.h - that's not a perfect location, but also doesn't seem
bad.
As a number of files relied on implicitly included heapam.h, a
significant number of files grew an explicit include. It's quite
probably that a few external projects will need to do the same.
Author: Andres Freund
Reviewed-By: Alvaro Herrera
Discussion: https://postgr.es/m/20190114000701.y4ttcb74jpskkcfb@alap3.anarazel.de
2019-01-15 00:54:18 +01:00
|
|
|
#include "access/heapam.h"
|
2006-07-31 03:16:38 +02:00
|
|
|
#include "access/tuptoaster.h"
|
|
|
|
#include "access/xact.h"
|
2013-12-19 22:10:01 +01:00
|
|
|
#include "catalog/binary_upgrade.h"
|
Ignore attempts to add TOAST table to shared or catalog tables
Running ALTER TABLE on any table will check if a TOAST table needs to be
added. On shared tables, this would previously fail, thus effectively
disabling ALTER TABLE for those tables. On (non-shared) system
catalogs, on the other hand, it would add a TOAST table, even though we
don't really want TOAST tables on some system catalogs. In some cases,
it would also fail with an error "AccessExclusiveLock required to add
toast table.", depending on what locks the ALTER TABLE actions had
already taken.
So instead, just ignore attempts to add TOAST tables to such tables,
outside of bootstrap mode, pretending they don't need one.
This allows running ALTER TABLE on such tables without messing up the
TOAST situation. Legitimate uses for ALTER TABLE on system catalogs
include setting reloptions (say, fillfactor or autovacuum settings).
(All this still requires allow_system_table_mods, which is independent
of this.)
Discussion: https://www.postgresql.org/message-id/flat/e49f825b-fb25-0bc8-8afc-d5ad895c7975@2ndquadrant.com
2019-03-19 10:48:03 +01:00
|
|
|
#include "catalog/catalog.h"
|
2006-07-31 03:16:38 +02:00
|
|
|
#include "catalog/dependency.h"
|
|
|
|
#include "catalog/heap.h"
|
|
|
|
#include "catalog/index.h"
|
2007-07-26 00:16:18 +02:00
|
|
|
#include "catalog/namespace.h"
|
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler
function. All the data formerly obtained from pg_am is now provided
in a C struct returned by the handler function. This is similar to
the designs we've adopted for FDWs and tablesample methods. There
are multiple advantages. For one, the index AM's support functions
are now simple C functions, making them faster to call and much less
error-prone, since the C compiler can now check function signatures.
For another, this will make it far more practical to define index access
methods in installable extensions.
A disadvantage is that SQL-level code can no longer see attributes
of index AMs; in particular, some of the crosschecks in the opr_sanity
regression test are no longer possible from SQL. We've addressed that
by adding a facility for the index AM to perform such checks instead.
(Much more could be done in that line, but for now we're content if the
amvalidate functions more or less replace what opr_sanity used to do.)
We might also want to expose some sort of reporting functionality, but
this patch doesn't do that.
Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily
editorialized on by me.
2016-01-18 01:36:59 +01:00
|
|
|
#include "catalog/pg_am.h"
|
2006-07-31 03:16:38 +02:00
|
|
|
#include "catalog/pg_namespace.h"
|
|
|
|
#include "catalog/pg_opclass.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "catalog/toasting.h"
|
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "nodes/makefuncs.h"
|
2014-04-06 17:13:43 +02:00
|
|
|
#include "storage/lock.h"
|
2006-07-31 03:16:38 +02:00
|
|
|
#include "utils/builtins.h"
|
2011-02-23 18:18:09 +01:00
|
|
|
#include "utils/rel.h"
|
2006-07-31 03:16:38 +02:00
|
|
|
#include "utils/syscache.h"
|
|
|
|
|
2015-03-11 03:33:25 +01:00
|
|
|
/* Potentially set by pg_upgrade_support functions */
|
2011-01-08 03:25:34 +01:00
|
|
|
Oid binary_upgrade_next_toast_pg_type_oid = InvalidOid;
|
2010-02-03 02:14:17 +01:00
|
|
|
|
2014-04-06 17:13:43 +02:00
|
|
|
static void CheckAndCreateToastTable(Oid relOid, Datum reloptions,
|
2014-05-06 18:12:18 +02:00
|
|
|
LOCKMODE lockmode, bool check);
|
2009-02-02 20:31:40 +01:00
|
|
|
static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
|
2014-05-06 18:12:18 +02:00
|
|
|
Datum reloptions, LOCKMODE lockmode, bool check);
|
2006-07-31 03:16:38 +02:00
|
|
|
static bool needs_toast_table(Relation rel);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2014-04-06 17:13:43 +02:00
|
|
|
* CreateToastTable variants
|
2006-07-31 03:16:38 +02:00
|
|
|
* If the table needs a toast table, and doesn't already have one,
|
2010-01-06 04:04:03 +01:00
|
|
|
* then create a toast table for it.
|
2009-06-11 22:46:11 +02:00
|
|
|
*
|
2009-05-08 00:58:28 +02:00
|
|
|
* reloptions for the toast table can be passed, too. Pass (Datum) 0
|
|
|
|
* for default reloptions.
|
2006-07-31 03:16:38 +02:00
|
|
|
*
|
|
|
|
* We expect the caller to have verified that the relation is a table and have
|
|
|
|
* already done any necessary permission checks. Callers expect this function
|
|
|
|
* to end with CommandCounterIncrement if it makes any changes.
|
|
|
|
*/
|
|
|
|
void
|
2014-04-06 17:13:43 +02:00
|
|
|
AlterTableCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode)
|
|
|
|
{
|
|
|
|
CheckAndCreateToastTable(relOid, reloptions, lockmode, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
NewHeapCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode)
|
|
|
|
{
|
|
|
|
CheckAndCreateToastTable(relOid, reloptions, lockmode, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
NewRelationCreateToastTable(Oid relOid, Datum reloptions)
|
|
|
|
{
|
|
|
|
CheckAndCreateToastTable(relOid, reloptions, AccessExclusiveLock, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
CheckAndCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode, bool check)
|
2006-07-31 03:16:38 +02:00
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_open(relOid, lockmode);
|
2006-07-31 03:16:38 +02:00
|
|
|
|
|
|
|
/* create_toast_table does all the work */
|
2014-04-06 17:13:43 +02:00
|
|
|
(void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions, lockmode, check);
|
2006-07-31 03:16:38 +02:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(rel, NoLock);
|
2006-07-31 03:16:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a toast table during bootstrap
|
|
|
|
*
|
|
|
|
* Here we need to prespecify the OIDs of the toast table and its index
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
|
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
Relation rel;
|
2006-07-31 03:16:38 +02:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
rel = table_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock);
|
2006-07-31 03:16:38 +02:00
|
|
|
|
2013-03-04 01:23:31 +01:00
|
|
|
if (rel->rd_rel->relkind != RELKIND_RELATION &&
|
|
|
|
rel->rd_rel->relkind != RELKIND_MATVIEW)
|
2006-07-31 03:16:38 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2013-03-04 01:23:31 +01:00
|
|
|
errmsg("\"%s\" is not a table or materialized view",
|
2006-07-31 03:16:38 +02:00
|
|
|
relName)));
|
|
|
|
|
|
|
|
/* create_toast_table does all the work */
|
2014-04-06 17:13:43 +02:00
|
|
|
if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0,
|
2014-05-06 18:12:18 +02:00
|
|
|
AccessExclusiveLock, false))
|
2006-07-31 03:16:38 +02:00
|
|
|
elog(ERROR, "\"%s\" does not require a toast table",
|
|
|
|
relName);
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(rel, NoLock);
|
2006-07-31 03:16:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* create_toast_table --- internal workhorse
|
|
|
|
*
|
2011-04-14 03:07:14 +02:00
|
|
|
* rel is already opened and locked
|
2010-01-06 04:04:03 +01:00
|
|
|
* toastOid and toastIndexOid are normally InvalidOid, but during
|
|
|
|
* bootstrap they can be nonzero to specify hand-assigned OIDs
|
2006-07-31 03:16:38 +02:00
|
|
|
*/
|
|
|
|
static bool
|
2014-04-06 17:13:43 +02:00
|
|
|
create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
|
|
|
|
Datum reloptions, LOCKMODE lockmode, bool check)
|
2006-07-31 03:16:38 +02:00
|
|
|
{
|
|
|
|
Oid relOid = RelationGetRelid(rel);
|
|
|
|
HeapTuple reltup;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
bool shared_relation;
|
2010-02-07 21:48:13 +01:00
|
|
|
bool mapped_relation;
|
2011-01-25 21:42:03 +01:00
|
|
|
Relation toast_rel;
|
2006-07-31 03:16:38 +02:00
|
|
|
Relation class_rel;
|
|
|
|
Oid toast_relid;
|
2009-12-24 23:09:24 +01:00
|
|
|
Oid toast_typid = InvalidOid;
|
2007-07-26 00:16:18 +02:00
|
|
|
Oid namespaceid;
|
2006-07-31 03:16:38 +02:00
|
|
|
char toast_relname[NAMEDATALEN];
|
|
|
|
char toast_idxname[NAMEDATALEN];
|
|
|
|
IndexInfo *indexInfo;
|
2011-02-08 22:04:18 +01:00
|
|
|
Oid collationObjectId[2];
|
2006-07-31 03:16:38 +02:00
|
|
|
Oid classObjectId[2];
|
2007-01-09 03:14:16 +01:00
|
|
|
int16 coloptions[2];
|
2006-07-31 03:16:38 +02:00
|
|
|
ObjectAddress baseobject,
|
|
|
|
toastobject;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Is it already toasted?
|
|
|
|
*/
|
|
|
|
if (rel->rd_rel->reltoastrelid != InvalidOid)
|
|
|
|
return false;
|
|
|
|
|
Fix pg_upgrade to not fail when new-cluster TOAST rules differ from old.
This patch essentially reverts commit 4c6780fd17aa43ed, in favor of a much
simpler solution for the case where the new cluster would choose to create
a TOAST table but the old cluster doesn't have one: just don't create a
TOAST table.
The existing code failed in at least two different ways if the situation
arose: (1) ALTER TABLE RESET didn't grab an exclusive lock, so that the
lock sanity check in create_toast_table failed; (2) pg_upgrade did not
provide a pg_type OID for the new toast table, so that the crosscheck in
TypeCreate failed. While both these problems were introduced by later
patches, they show that the hack being used to cause TOAST table creation
is overwhelmingly fragile (and untested). I also note that before the
TypeCreate crosscheck was added, the code would have resulted in assigning
an indeterminate pg_type OID to the toast table, possibly causing a later
OID conflict in that catalog; so that it didn't really work even when
committed.
If we simply don't create a TOAST table, there will only be a problem if
the code tries to store a tuple that's wider than a page, and field
compression isn't sufficient to get it under a page. Given that the TOAST
creation threshold is intended to be about a quarter of a page, it's very
hard to believe that cross-version differences in the do-we-need-a-toast-
table heuristic could result in an observable problem. So let's just
follow the old version's conclusion about whether a TOAST table is needed.
(If we ever do change needs_toast_table() so much that this conclusion
doesn't apply, we can devise a solution at that time, and hopefully do
it in a less klugy way than 4c6780fd17aa43ed did.)
Back-patch to 9.3, like the previous patch.
Discussion: <8110.1462291671@sss.pgh.pa.us>
2016-05-07 04:05:51 +02:00
|
|
|
/*
|
|
|
|
* Check to see whether the table actually needs a TOAST table.
|
|
|
|
*/
|
2014-08-07 20:56:13 +02:00
|
|
|
if (!IsBinaryUpgrade)
|
|
|
|
{
|
Fix pg_upgrade to not fail when new-cluster TOAST rules differ from old.
This patch essentially reverts commit 4c6780fd17aa43ed, in favor of a much
simpler solution for the case where the new cluster would choose to create
a TOAST table but the old cluster doesn't have one: just don't create a
TOAST table.
The existing code failed in at least two different ways if the situation
arose: (1) ALTER TABLE RESET didn't grab an exclusive lock, so that the
lock sanity check in create_toast_table failed; (2) pg_upgrade did not
provide a pg_type OID for the new toast table, so that the crosscheck in
TypeCreate failed. While both these problems were introduced by later
patches, they show that the hack being used to cause TOAST table creation
is overwhelmingly fragile (and untested). I also note that before the
TypeCreate crosscheck was added, the code would have resulted in assigning
an indeterminate pg_type OID to the toast table, possibly causing a later
OID conflict in that catalog; so that it didn't really work even when
committed.
If we simply don't create a TOAST table, there will only be a problem if
the code tries to store a tuple that's wider than a page, and field
compression isn't sufficient to get it under a page. Given that the TOAST
creation threshold is intended to be about a quarter of a page, it's very
hard to believe that cross-version differences in the do-we-need-a-toast-
table heuristic could result in an observable problem. So let's just
follow the old version's conclusion about whether a TOAST table is needed.
(If we ever do change needs_toast_table() so much that this conclusion
doesn't apply, we can devise a solution at that time, and hopefully do
it in a less klugy way than 4c6780fd17aa43ed did.)
Back-patch to 9.3, like the previous patch.
Discussion: <8110.1462291671@sss.pgh.pa.us>
2016-05-07 04:05:51 +02:00
|
|
|
/* Normal mode, normal check */
|
2014-08-07 20:56:13 +02:00
|
|
|
if (!needs_toast_table(rel))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
Fix pg_upgrade to not fail when new-cluster TOAST rules differ from old.
This patch essentially reverts commit 4c6780fd17aa43ed, in favor of a much
simpler solution for the case where the new cluster would choose to create
a TOAST table but the old cluster doesn't have one: just don't create a
TOAST table.
The existing code failed in at least two different ways if the situation
arose: (1) ALTER TABLE RESET didn't grab an exclusive lock, so that the
lock sanity check in create_toast_table failed; (2) pg_upgrade did not
provide a pg_type OID for the new toast table, so that the crosscheck in
TypeCreate failed. While both these problems were introduced by later
patches, they show that the hack being used to cause TOAST table creation
is overwhelmingly fragile (and untested). I also note that before the
TypeCreate crosscheck was added, the code would have resulted in assigning
an indeterminate pg_type OID to the toast table, possibly causing a later
OID conflict in that catalog; so that it didn't really work even when
committed.
If we simply don't create a TOAST table, there will only be a problem if
the code tries to store a tuple that's wider than a page, and field
compression isn't sufficient to get it under a page. Given that the TOAST
creation threshold is intended to be about a quarter of a page, it's very
hard to believe that cross-version differences in the do-we-need-a-toast-
table heuristic could result in an observable problem. So let's just
follow the old version's conclusion about whether a TOAST table is needed.
(If we ever do change needs_toast_table() so much that this conclusion
doesn't apply, we can devise a solution at that time, and hopefully do
it in a less klugy way than 4c6780fd17aa43ed did.)
Back-patch to 9.3, like the previous patch.
Discussion: <8110.1462291671@sss.pgh.pa.us>
2016-05-07 04:05:51 +02:00
|
|
|
* In binary-upgrade mode, create a TOAST table if and only if
|
|
|
|
* pg_upgrade told us to (ie, a TOAST table OID has been provided).
|
2014-08-07 20:56:13 +02:00
|
|
|
*
|
Fix pg_upgrade to not fail when new-cluster TOAST rules differ from old.
This patch essentially reverts commit 4c6780fd17aa43ed, in favor of a much
simpler solution for the case where the new cluster would choose to create
a TOAST table but the old cluster doesn't have one: just don't create a
TOAST table.
The existing code failed in at least two different ways if the situation
arose: (1) ALTER TABLE RESET didn't grab an exclusive lock, so that the
lock sanity check in create_toast_table failed; (2) pg_upgrade did not
provide a pg_type OID for the new toast table, so that the crosscheck in
TypeCreate failed. While both these problems were introduced by later
patches, they show that the hack being used to cause TOAST table creation
is overwhelmingly fragile (and untested). I also note that before the
TypeCreate crosscheck was added, the code would have resulted in assigning
an indeterminate pg_type OID to the toast table, possibly causing a later
OID conflict in that catalog; so that it didn't really work even when
committed.
If we simply don't create a TOAST table, there will only be a problem if
the code tries to store a tuple that's wider than a page, and field
compression isn't sufficient to get it under a page. Given that the TOAST
creation threshold is intended to be about a quarter of a page, it's very
hard to believe that cross-version differences in the do-we-need-a-toast-
table heuristic could result in an observable problem. So let's just
follow the old version's conclusion about whether a TOAST table is needed.
(If we ever do change needs_toast_table() so much that this conclusion
doesn't apply, we can devise a solution at that time, and hopefully do
it in a less klugy way than 4c6780fd17aa43ed did.)
Back-patch to 9.3, like the previous patch.
Discussion: <8110.1462291671@sss.pgh.pa.us>
2016-05-07 04:05:51 +02:00
|
|
|
* This indicates that the old cluster had a TOAST table for the
|
|
|
|
* current table. We must create a TOAST table to receive the old
|
|
|
|
* TOAST file, even if the table seems not to need one.
|
|
|
|
*
|
|
|
|
* Contrariwise, if the old cluster did not have a TOAST table, we
|
|
|
|
* should be able to get along without one even if the new version's
|
|
|
|
* needs_toast_table rules suggest we should have one. There is a lot
|
|
|
|
* of daylight between where we will create a TOAST table and where
|
|
|
|
* one is really necessary to avoid failures, so small cross-version
|
|
|
|
* differences in the when-to-create heuristic shouldn't be a problem.
|
|
|
|
* If we tried to create a TOAST table anyway, we would have the
|
|
|
|
* problem that it might take up an OID that will conflict with some
|
|
|
|
* old-cluster table we haven't seen yet.
|
2014-08-07 20:56:13 +02:00
|
|
|
*/
|
Fix pg_upgrade to not fail when new-cluster TOAST rules differ from old.
This patch essentially reverts commit 4c6780fd17aa43ed, in favor of a much
simpler solution for the case where the new cluster would choose to create
a TOAST table but the old cluster doesn't have one: just don't create a
TOAST table.
The existing code failed in at least two different ways if the situation
arose: (1) ALTER TABLE RESET didn't grab an exclusive lock, so that the
lock sanity check in create_toast_table failed; (2) pg_upgrade did not
provide a pg_type OID for the new toast table, so that the crosscheck in
TypeCreate failed. While both these problems were introduced by later
patches, they show that the hack being used to cause TOAST table creation
is overwhelmingly fragile (and untested). I also note that before the
TypeCreate crosscheck was added, the code would have resulted in assigning
an indeterminate pg_type OID to the toast table, possibly causing a later
OID conflict in that catalog; so that it didn't really work even when
committed.
If we simply don't create a TOAST table, there will only be a problem if
the code tries to store a tuple that's wider than a page, and field
compression isn't sufficient to get it under a page. Given that the TOAST
creation threshold is intended to be about a quarter of a page, it's very
hard to believe that cross-version differences in the do-we-need-a-toast-
table heuristic could result in an observable problem. So let's just
follow the old version's conclusion about whether a TOAST table is needed.
(If we ever do change needs_toast_table() so much that this conclusion
doesn't apply, we can devise a solution at that time, and hopefully do
it in a less klugy way than 4c6780fd17aa43ed did.)
Back-patch to 9.3, like the previous patch.
Discussion: <8110.1462291671@sss.pgh.pa.us>
2016-05-07 04:05:51 +02:00
|
|
|
if (!OidIsValid(binary_upgrade_next_toast_pg_class_oid) ||
|
|
|
|
!OidIsValid(binary_upgrade_next_toast_pg_type_oid))
|
2014-08-07 20:56:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
2006-07-31 03:16:38 +02:00
|
|
|
|
2014-04-06 17:13:43 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* If requested check lockmode is sufficient. This is a cross check in
|
|
|
|
* case of errors or conflicting decisions in earlier code.
|
2014-04-06 17:13:43 +02:00
|
|
|
*/
|
|
|
|
if (check && lockmode != AccessExclusiveLock)
|
|
|
|
elog(ERROR, "AccessExclusiveLock required to add toast table.");
|
|
|
|
|
2006-07-31 03:16:38 +02:00
|
|
|
/*
|
|
|
|
* Create the toast table and its index
|
|
|
|
*/
|
|
|
|
snprintf(toast_relname, sizeof(toast_relname),
|
|
|
|
"pg_toast_%u", relOid);
|
|
|
|
snprintf(toast_idxname, sizeof(toast_idxname),
|
|
|
|
"pg_toast_%u_index", relOid);
|
|
|
|
|
|
|
|
/* this is pretty painful... need a 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
|
|
|
tupdesc = CreateTemplateTupleDesc(3);
|
2006-07-31 03:16:38 +02:00
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 1,
|
|
|
|
"chunk_id",
|
|
|
|
OIDOID,
|
|
|
|
-1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 2,
|
|
|
|
"chunk_seq",
|
|
|
|
INT4OID,
|
|
|
|
-1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 3,
|
|
|
|
"chunk_data",
|
|
|
|
BYTEAOID,
|
|
|
|
-1, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure that the toast table doesn't itself get toasted, or we'll be
|
|
|
|
* toast :-(. This is essential for chunk_data because type bytea is
|
|
|
|
* toastable; hit the other two just to be sure.
|
|
|
|
*/
|
2017-08-20 20:19:07 +02:00
|
|
|
TupleDescAttr(tupdesc, 0)->attstorage = 'p';
|
|
|
|
TupleDescAttr(tupdesc, 1)->attstorage = 'p';
|
|
|
|
TupleDescAttr(tupdesc, 2)->attstorage = 'p';
|
2006-07-31 03:16:38 +02:00
|
|
|
|
|
|
|
/*
|
2007-07-26 00:16:18 +02:00
|
|
|
* Toast tables for regular relations go in pg_toast; those for temp
|
|
|
|
* relations go into the per-backend temp-toast-table namespace.
|
|
|
|
*/
|
2014-08-26 03:28:19 +02:00
|
|
|
if (isTempOrTempToastNamespace(rel->rd_rel->relnamespace))
|
2007-07-26 00:16:18 +02:00
|
|
|
namespaceid = GetTempToastNamespace();
|
|
|
|
else
|
|
|
|
namespaceid = PG_TOAST_NAMESPACE;
|
|
|
|
|
2014-08-26 04:19:05 +02:00
|
|
|
/*
|
2015-05-24 03:35:49 +02:00
|
|
|
* Use binary-upgrade override for pg_type.oid, if supplied. We might be
|
|
|
|
* in the post-schema-restore phase where we are doing ALTER TABLE to
|
|
|
|
* create TOAST tables that didn't exist in the old cluster.
|
2014-08-26 04:19:05 +02:00
|
|
|
*/
|
2011-04-25 18:00:21 +02:00
|
|
|
if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_toast_pg_type_oid))
|
2009-12-24 23:09:24 +01:00
|
|
|
{
|
2011-01-08 03:25:34 +01:00
|
|
|
toast_typid = binary_upgrade_next_toast_pg_type_oid;
|
|
|
|
binary_upgrade_next_toast_pg_type_oid = InvalidOid;
|
2009-12-24 23:09:24 +01:00
|
|
|
}
|
|
|
|
|
Ignore attempts to add TOAST table to shared or catalog tables
Running ALTER TABLE on any table will check if a TOAST table needs to be
added. On shared tables, this would previously fail, thus effectively
disabling ALTER TABLE for those tables. On (non-shared) system
catalogs, on the other hand, it would add a TOAST table, even though we
don't really want TOAST tables on some system catalogs. In some cases,
it would also fail with an error "AccessExclusiveLock required to add
toast table.", depending on what locks the ALTER TABLE actions had
already taken.
So instead, just ignore attempts to add TOAST tables to such tables,
outside of bootstrap mode, pretending they don't need one.
This allows running ALTER TABLE on such tables without messing up the
TOAST situation. Legitimate uses for ALTER TABLE on system catalogs
include setting reloptions (say, fillfactor or autovacuum settings).
(All this still requires allow_system_table_mods, which is independent
of this.)
Discussion: https://www.postgresql.org/message-id/flat/e49f825b-fb25-0bc8-8afc-d5ad895c7975@2ndquadrant.com
2019-03-19 10:48:03 +01:00
|
|
|
/* Toast table is shared if and only if its parent is. */
|
|
|
|
shared_relation = rel->rd_rel->relisshared;
|
|
|
|
|
|
|
|
/* It's mapped if and only if its parent is, too */
|
|
|
|
mapped_relation = RelationIsMapped(rel);
|
|
|
|
|
2006-07-31 03:16:38 +02:00
|
|
|
toast_relid = heap_create_with_catalog(toast_relname,
|
2007-07-26 00:16:18 +02:00
|
|
|
namespaceid,
|
2006-07-31 03:16:38 +02:00
|
|
|
rel->rd_rel->reltablespace,
|
|
|
|
toastOid,
|
2009-12-24 23:09:24 +01:00
|
|
|
toast_typid,
|
2010-01-29 00:21:13 +01:00
|
|
|
InvalidOid,
|
2006-07-31 03:16:38 +02:00
|
|
|
rel->rd_rel->relowner,
|
tableam: introduce table AM infrastructure.
This introduces the concept of table access methods, i.e. CREATE
ACCESS METHOD ... TYPE TABLE and
CREATE TABLE ... USING (storage-engine).
No table access functionality is delegated to table AMs as of this
commit, that'll be done in following commits.
Subsequent commits will incrementally abstract table access
functionality to be routed through table access methods. That change
is too large to be reviewed & committed at once, so it'll be done
incrementally.
Docs will be updated at the end, as adding them incrementally would
likely make them less coherent, and definitely is a lot more work,
without a lot of benefit.
Table access methods are specified similar to index access methods,
i.e. pg_am.amhandler returns, as INTERNAL, a pointer to a struct with
callbacks. In contrast to index AMs that struct needs to live as long
as a backend, typically that's achieved by just returning a pointer to
a constant struct.
Psql's \d+ now displays a table's access method. That can be disabled
with HIDE_TABLEAM=true, which is mainly useful so regression tests can
be run against different AMs. It's quite possible that this behaviour
still needs to be fine tuned.
For now it's not allowed to set a table AM for a partitioned table, as
we've not resolved how partitions would inherit that. Disallowing
allows us to introduce, if we decide that's the way forward, such a
behaviour without a compatibility break.
Catversion bumped, to add the heap table AM and references to it.
Author: Haribabu Kommi, Andres Freund, Alvaro Herrera, Dimitri Golgov and others
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
https://postgr.es/m/20190107235616.6lur25ph22u5u5av@alap3.anarazel.de
https://postgr.es/m/20190304234700.w5tmhducs5wxgzls@alap3.anarazel.de
2019-03-06 18:54:38 +01:00
|
|
|
rel->rd_rel->relam,
|
2006-07-31 03:16:38 +02:00
|
|
|
tupdesc,
|
2008-05-10 01:32:05 +02:00
|
|
|
NIL,
|
2006-07-31 03:16:38 +02:00
|
|
|
RELKIND_TOASTVALUE,
|
2010-12-13 18:34:26 +01:00
|
|
|
rel->rd_rel->relpersistence,
|
2006-07-31 03:16:38 +02:00
|
|
|
shared_relation,
|
2010-02-07 21:48:13 +01:00
|
|
|
mapped_relation,
|
2006-07-31 03:16:38 +02:00
|
|
|
ONCOMMIT_NOOP,
|
2009-02-02 20:31:40 +01:00
|
|
|
reloptions,
|
2009-10-05 21:24:49 +02:00
|
|
|
false,
|
2012-10-23 23:07:26 +02:00
|
|
|
true,
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
true,
|
2018-03-21 14:13:24 +01:00
|
|
|
InvalidOid,
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
NULL);
|
2010-07-26 01:21:22 +02:00
|
|
|
Assert(toast_relid != InvalidOid);
|
2006-07-31 03:16:38 +02:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
/* make the toast relation visible, else table_open will fail */
|
2006-07-31 03:16:38 +02:00
|
|
|
CommandCounterIncrement();
|
|
|
|
|
2011-01-25 21:42:03 +01:00
|
|
|
/* ShareLock is not really needed here, but take it anyway */
|
2019-01-21 19:32:19 +01:00
|
|
|
toast_rel = table_open(toast_relid, ShareLock);
|
2011-01-25 21:42:03 +01:00
|
|
|
|
2006-07-31 03:16:38 +02:00
|
|
|
/*
|
|
|
|
* Create unique index on chunk_id, chunk_seq.
|
|
|
|
*
|
|
|
|
* NOTE: the normal TOAST access routines could actually function with a
|
|
|
|
* single-column index on chunk_id only. However, the slice access
|
|
|
|
* routines use both columns for faster access to an individual chunk. In
|
|
|
|
* addition, we want it to be unique as a check against the possibility of
|
|
|
|
* duplicate TOAST chunk OIDs. The index might also be a little more
|
|
|
|
* efficient this way, since btree isn't all that happy with large numbers
|
|
|
|
* of equal keys.
|
|
|
|
*/
|
|
|
|
|
|
|
|
indexInfo = makeNode(IndexInfo);
|
|
|
|
indexInfo->ii_NumIndexAttrs = 2;
|
2018-04-07 22:00:39 +02:00
|
|
|
indexInfo->ii_NumIndexKeyAttrs = 2;
|
2018-04-12 12:02:45 +02:00
|
|
|
indexInfo->ii_IndexAttrNumbers[0] = 1;
|
|
|
|
indexInfo->ii_IndexAttrNumbers[1] = 2;
|
2006-07-31 03:16:38 +02:00
|
|
|
indexInfo->ii_Expressions = NIL;
|
|
|
|
indexInfo->ii_ExpressionsState = NIL;
|
|
|
|
indexInfo->ii_Predicate = NIL;
|
Faster expression evaluation and targetlist projection.
This replaces the old, recursive tree-walk based evaluation, with
non-recursive, opcode dispatch based, expression evaluation.
Projection is now implemented as part of expression evaluation.
This both leads to significant performance improvements, and makes
future just-in-time compilation of expressions easier.
The speed gains primarily come from:
- non-recursive implementation reduces stack usage / overhead
- simple sub-expressions are implemented with a single jump, without
function calls
- sharing some state between different sub-expressions
- reduced amount of indirect/hard to predict memory accesses by laying
out operation metadata sequentially; including the avoidance of
nearly all of the previously used linked lists
- more code has been moved to expression initialization, avoiding
constant re-checks at evaluation time
Future just-in-time compilation (JIT) has become easier, as
demonstrated by released patches intended to be merged in a later
release, for primarily two reasons: Firstly, due to a stricter split
between expression initialization and evaluation, less code has to be
handled by the JIT. Secondly, due to the non-recursive nature of the
generated "instructions", less performance-critical code-paths can
easily be shared between interpreted and compiled evaluation.
The new framework allows for significant future optimizations. E.g.:
- basic infrastructure for to later reduce the per executor-startup
overhead of expression evaluation, by caching state in prepared
statements. That'd be helpful in OLTPish scenarios where
initialization overhead is measurable.
- optimizing the generated "code". A number of proposals for potential
work has already been made.
- optimizing the interpreter. Similarly a number of proposals have
been made here too.
The move of logic into the expression initialization step leads to some
backward-incompatible changes:
- Function permission checks are now done during expression
initialization, whereas previously they were done during
execution. In edge cases this can lead to errors being raised that
previously wouldn't have been, e.g. a NULL array being coerced to a
different array type previously didn't perform checks.
- The set of domain constraints to be checked, is now evaluated once
during expression initialization, previously it was re-built
every time a domain check was evaluated. For normal queries this
doesn't change much, but e.g. for plpgsql functions, which caches
ExprStates, the old set could stick around longer. The behavior
around might still change.
Author: Andres Freund, with significant changes by Tom Lane,
changes by Heikki Linnakangas
Reviewed-By: Tom Lane, Heikki Linnakangas
Discussion: https://postgr.es/m/20161206034955.bh33paeralxbtluv@alap3.anarazel.de
2017-03-14 23:45:36 +01:00
|
|
|
indexInfo->ii_PredicateState = NULL;
|
2009-12-07 06:22:23 +01:00
|
|
|
indexInfo->ii_ExclusionOps = NULL;
|
|
|
|
indexInfo->ii_ExclusionProcs = NULL;
|
|
|
|
indexInfo->ii_ExclusionStrats = NULL;
|
2006-07-31 03:16:38 +02:00
|
|
|
indexInfo->ii_Unique = true;
|
2007-09-20 19:56:33 +02:00
|
|
|
indexInfo->ii_ReadyForInserts = true;
|
2006-08-25 06:06:58 +02:00
|
|
|
indexInfo->ii_Concurrent = false;
|
2007-09-20 19:56:33 +02:00
|
|
|
indexInfo->ii_BrokenHotChain = false;
|
Support parallel btree index builds.
To make this work, tuplesort.c and logtape.c must also support
parallelism, so this patch adds that infrastructure and then applies
it to the particular case of parallel btree index builds. Testing
to date shows that this can often be 2-3x faster than a serial
index build.
The model for deciding how many workers to use is fairly primitive
at present, but it's better than not having the feature. We can
refine it as we get more experience.
Peter Geoghegan with some help from Rushabh Lathia. While Heikki
Linnakangas is not an author of this patch, he wrote other patches
without which this feature would not have been possible, and
therefore the release notes should possibly credit him as an author
of this feature. Reviewed by Claudio Freire, Heikki Linnakangas,
Thomas Munro, Tels, Amit Kapila, me.
Discussion: http://postgr.es/m/CAM3SWZQKM=Pzc=CAHzRixKjp2eO5Q0Jg1SoFQqeXFQ647JiwqQ@mail.gmail.com
Discussion: http://postgr.es/m/CAH2-Wz=AxWqDoVvGU7dq856S4r6sJAj6DBn7VMtigkB33N5eyg@mail.gmail.com
2018-02-02 19:25:55 +01:00
|
|
|
indexInfo->ii_ParallelWorkers = 0;
|
Local partitioned indexes
When CREATE INDEX is run on a partitioned table, create catalog entries
for an index on the partitioned table (which is just a placeholder since
the table proper has no data of its own), and recurse to create actual
indexes on the existing partitions; create them in future partitions
also.
As a convenience gadget, if the new index definition matches some
existing index in partitions, these are picked up and used instead of
creating new ones. Whichever way these indexes come about, they become
attached to the index on the parent table and are dropped alongside it,
and cannot be dropped on isolation unless they are detached first.
To support pg_dump'ing these indexes, add commands
CREATE INDEX ON ONLY <table>
(which creates the index on the parent partitioned table, without
recursing) and
ALTER INDEX ATTACH PARTITION
(which is used after the indexes have been created individually on each
partition, to attach them to the parent index). These reconstruct prior
database state exactly.
Reviewed-by: (in alphabetical order) Peter Eisentraut, Robert Haas, Amit
Langote, Jesper Pedersen, Simon Riggs, David Rowley
Discussion: https://postgr.es/m/20171113170646.gzweigyrgg6pwsg4@alvherre.pgsql
2018-01-19 15:49:22 +01:00
|
|
|
indexInfo->ii_Am = BTREE_AM_OID;
|
Allow index AMs to cache data across aminsert calls within a SQL command.
It's always been possible for index AMs to cache data across successive
amgettuple calls within a single SQL command: the IndexScanDesc.opaque
field is meant for precisely that. However, no comparable facility
exists for amortizing setup work across successive aminsert calls.
This patch adds such a feature and teaches GIN, GIST, and BRIN to use it
to amortize catalog lookups they'd previously been doing on every call.
(The other standard index AMs keep everything they need in the relcache,
so there's little to improve there.)
For GIN, the overall improvement in a statement that inserts many rows
can be as much as 10%, though it seems a bit less for the other two.
In addition, this makes a really significant difference in runtime
for CLOBBER_CACHE_ALWAYS tests, since in those builds the repeated
catalog lookups are vastly more expensive.
The reason this has been hard up to now is that the aminsert function is
not passed any useful place to cache per-statement data. What I chose to
do is to add suitable fields to struct IndexInfo and pass that to aminsert.
That's not widening the index AM API very much because IndexInfo is already
within the ken of ambuild; in fact, by passing the same info to aminsert
as to ambuild, this is really removing an inconsistency in the AM API.
Discussion: https://postgr.es/m/27568.1486508680@sss.pgh.pa.us
2017-02-09 17:52:12 +01:00
|
|
|
indexInfo->ii_AmCache = NULL;
|
|
|
|
indexInfo->ii_Context = CurrentMemoryContext;
|
2006-07-31 03:16:38 +02:00
|
|
|
|
2011-02-08 22:04:18 +01:00
|
|
|
collationObjectId[0] = InvalidOid;
|
|
|
|
collationObjectId[1] = InvalidOid;
|
|
|
|
|
2006-07-31 03:16:38 +02:00
|
|
|
classObjectId[0] = OID_BTREE_OPS_OID;
|
|
|
|
classObjectId[1] = INT4_BTREE_OPS_OID;
|
|
|
|
|
2007-01-09 03:14:16 +01:00
|
|
|
coloptions[0] = 0;
|
|
|
|
coloptions[1] = 0;
|
|
|
|
|
2011-07-18 17:02:48 +02:00
|
|
|
index_create(toast_rel, toast_idxname, toastIndexOid, InvalidOid,
|
2018-02-19 20:59:37 +01:00
|
|
|
InvalidOid, InvalidOid,
|
2011-06-09 20:32:50 +02:00
|
|
|
indexInfo,
|
|
|
|
list_make2("chunk_id", "chunk_seq"),
|
|
|
|
BTREE_AM_OID,
|
|
|
|
rel->rd_rel->reltablespace,
|
|
|
|
collationObjectId, classObjectId, coloptions, (Datum) 0,
|
2018-02-19 20:59:37 +01:00
|
|
|
INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL);
|
2006-07-31 03:16:38 +02:00
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(toast_rel, NoLock);
|
2011-01-25 21:42:03 +01:00
|
|
|
|
2006-07-31 03:16:38 +02:00
|
|
|
/*
|
|
|
|
* Store the toast table's OID in the parent relation's pg_class row
|
|
|
|
*/
|
2019-01-21 19:32:19 +01:00
|
|
|
class_rel = table_open(RelationRelationId, RowExclusiveLock);
|
2006-07-31 03:16:38 +02:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid));
|
2006-07-31 03:16:38 +02:00
|
|
|
if (!HeapTupleIsValid(reltup))
|
|
|
|
elog(ERROR, "cache lookup failed for relation %u", relOid);
|
|
|
|
|
|
|
|
((Form_pg_class) GETSTRUCT(reltup))->reltoastrelid = toast_relid;
|
|
|
|
|
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
/* normal case, use a transactional update */
|
2017-01-31 22:42:24 +01:00
|
|
|
CatalogTupleUpdate(class_rel, &reltup->t_self, reltup);
|
2006-07-31 03:16:38 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* While bootstrapping, we cannot UPDATE, so overwrite in-place */
|
|
|
|
heap_inplace_update(class_rel, reltup);
|
|
|
|
}
|
|
|
|
|
|
|
|
heap_freetuple(reltup);
|
|
|
|
|
2019-01-21 19:32:19 +01:00
|
|
|
table_close(class_rel, RowExclusiveLock);
|
2006-07-31 03:16:38 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Register dependency from the toast table to the master, so that the
|
|
|
|
* toast table will be deleted if the master is. Skip this in bootstrap
|
|
|
|
* mode.
|
|
|
|
*/
|
|
|
|
if (!IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
baseobject.classId = RelationRelationId;
|
|
|
|
baseobject.objectId = relOid;
|
|
|
|
baseobject.objectSubId = 0;
|
|
|
|
toastobject.classId = RelationRelationId;
|
|
|
|
toastobject.objectId = toast_relid;
|
|
|
|
toastobject.objectSubId = 0;
|
|
|
|
|
|
|
|
recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make changes visible
|
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Check to see whether the table needs a TOAST table. It does only if
|
2006-07-31 03:16:38 +02:00
|
|
|
* (1) there are any toastable attributes, and (2) the maximum length
|
|
|
|
* of a tuple could exceed TOAST_TUPLE_THRESHOLD. (We don't want to
|
|
|
|
* create a toast table for something like "f1 varchar(20)".)
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
needs_toast_table(Relation rel)
|
|
|
|
{
|
|
|
|
int32 data_length = 0;
|
|
|
|
bool maxlength_unknown = false;
|
|
|
|
bool has_toastable_attrs = false;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
int32 tuple_length;
|
|
|
|
int i;
|
|
|
|
|
Ignore attempts to add TOAST table to shared or catalog tables
Running ALTER TABLE on any table will check if a TOAST table needs to be
added. On shared tables, this would previously fail, thus effectively
disabling ALTER TABLE for those tables. On (non-shared) system
catalogs, on the other hand, it would add a TOAST table, even though we
don't really want TOAST tables on some system catalogs. In some cases,
it would also fail with an error "AccessExclusiveLock required to add
toast table.", depending on what locks the ALTER TABLE actions had
already taken.
So instead, just ignore attempts to add TOAST tables to such tables,
outside of bootstrap mode, pretending they don't need one.
This allows running ALTER TABLE on such tables without messing up the
TOAST situation. Legitimate uses for ALTER TABLE on system catalogs
include setting reloptions (say, fillfactor or autovacuum settings).
(All this still requires allow_system_table_mods, which is independent
of this.)
Discussion: https://www.postgresql.org/message-id/flat/e49f825b-fb25-0bc8-8afc-d5ad895c7975@2ndquadrant.com
2019-03-19 10:48:03 +01:00
|
|
|
/*
|
|
|
|
* No need to create a TOAST table for partitioned tables.
|
|
|
|
*/
|
2018-03-22 18:49:38 +01:00
|
|
|
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
|
|
|
|
return false;
|
|
|
|
|
Ignore attempts to add TOAST table to shared or catalog tables
Running ALTER TABLE on any table will check if a TOAST table needs to be
added. On shared tables, this would previously fail, thus effectively
disabling ALTER TABLE for those tables. On (non-shared) system
catalogs, on the other hand, it would add a TOAST table, even though we
don't really want TOAST tables on some system catalogs. In some cases,
it would also fail with an error "AccessExclusiveLock required to add
toast table.", depending on what locks the ALTER TABLE actions had
already taken.
So instead, just ignore attempts to add TOAST tables to such tables,
outside of bootstrap mode, pretending they don't need one.
This allows running ALTER TABLE on such tables without messing up the
TOAST situation. Legitimate uses for ALTER TABLE on system catalogs
include setting reloptions (say, fillfactor or autovacuum settings).
(All this still requires allow_system_table_mods, which is independent
of this.)
Discussion: https://www.postgresql.org/message-id/flat/e49f825b-fb25-0bc8-8afc-d5ad895c7975@2ndquadrant.com
2019-03-19 10:48:03 +01:00
|
|
|
/*
|
|
|
|
* We cannot allow toasting a shared relation after initdb (because
|
|
|
|
* there's no way to mark it toasted in other databases' pg_class).
|
|
|
|
*/
|
|
|
|
if (rel->rd_rel->relisshared && !IsBootstrapProcessingMode())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ignore attempts to create toast tables on catalog tables after initdb.
|
|
|
|
* Which catalogs get toast tables is explicitly chosen in
|
|
|
|
* catalog/toasting.h. (We could get here via some ALTER TABLE command if
|
|
|
|
* the catalog doesn't have a toast table.)
|
|
|
|
*/
|
|
|
|
if (IsCatalogRelation(rel) && !IsBootstrapProcessingMode())
|
|
|
|
return false;
|
|
|
|
|
2006-07-31 03:16:38 +02:00
|
|
|
tupdesc = rel->rd_att;
|
|
|
|
|
|
|
|
for (i = 0; i < tupdesc->natts; i++)
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute att = TupleDescAttr(tupdesc, i);
|
|
|
|
|
|
|
|
if (att->attisdropped)
|
2006-07-31 03:16:38 +02:00
|
|
|
continue;
|
2017-08-20 20:19:07 +02:00
|
|
|
data_length = att_align_nominal(data_length, att->attalign);
|
|
|
|
if (att->attlen > 0)
|
2006-07-31 03:16:38 +02:00
|
|
|
{
|
|
|
|
/* Fixed-length types are never toastable */
|
2017-08-20 20:19:07 +02:00
|
|
|
data_length += att->attlen;
|
2006-07-31 03:16:38 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
int32 maxlen = type_maximum_size(att->atttypid,
|
|
|
|
att->atttypmod);
|
2006-07-31 03:16:38 +02:00
|
|
|
|
|
|
|
if (maxlen < 0)
|
|
|
|
maxlength_unknown = true;
|
|
|
|
else
|
|
|
|
data_length += maxlen;
|
2017-08-20 20:19:07 +02:00
|
|
|
if (att->attstorage != 'p')
|
2006-07-31 03:16:38 +02:00
|
|
|
has_toastable_attrs = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!has_toastable_attrs)
|
|
|
|
return false; /* nothing to toast? */
|
|
|
|
if (maxlength_unknown)
|
|
|
|
return true; /* any unlimited-length attrs? */
|
2015-02-21 21:13:06 +01:00
|
|
|
tuple_length = MAXALIGN(SizeofHeapTupleHeader +
|
2006-07-31 03:16:38 +02:00
|
|
|
BITMAPLEN(tupdesc->natts)) +
|
|
|
|
MAXALIGN(data_length);
|
|
|
|
return (tuple_length > TOAST_TUPLE_THRESHOLD);
|
|
|
|
}
|