0002-idea.patch
application/octet-stream
Filename: 0002-idea.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch 0002
| File | + | − |
|---|---|---|
| src/backend/commands/vacuum.c | 85 | 57 |
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 5736f12b8f..d7e79794cd 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -30,11 +30,13 @@
#include "access/multixact.h"
#include "access/transam.h"
#include "access/xact.h"
+#include "catalog/catalog.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
#include "commands/cluster.h"
+#include "commands/tablecmds.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
@@ -47,6 +49,7 @@
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
+#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
@@ -68,6 +71,7 @@ static BufferAccessStrategy vac_strategy;
/* non-export function prototypes */
+static bool vacuum_skip_rel(Oid relid, Form_pg_class reltuple, int elevel);
static List *expand_vacuum_rel(VacuumRelation *vrel);
static List *get_all_vacuum_rels(void);
static void vac_truncate_clog(TransactionId frozenXID,
@@ -408,6 +412,60 @@ vacuum(int options, List *relations, VacuumParams *params,
vac_context = NULL;
}
+/*
+ * Check if a given relation can be safely vacuumed or not. If the
+ * relation needs to be skipped, issue a log message and return true to
+ * let the caller know what to do with this relation.
+ */
+static bool
+vacuum_skip_rel(Oid relid, Form_pg_class reltuple, int elevel)
+{
+ /*
+ * Check permissions.
+ *
+ * We allow the user to vacuum a table if he is superuser, the table
+ * owner, or the database owner (but in the latter case, only if it's not
+ * a shared relation). pg_class_ownercheck includes the superuser case.
+ *
+ * Note we choose to treat permissions failure as a WARNING and keep
+ * trying to vacuum the rest of the DB --- is this appropriate?
+ */
+ if (!(pg_class_ownercheck(relid, GetUserId()) ||
+ (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !reltuple->relisshared)))
+ {
+ if (reltuple->relisshared)
+ ereport(elevel,
+ (errmsg("skipping \"%s\" --- only superuser can vacuum it",
+ NameStr(reltuple->relname))));
+ else if (reltuple->relnamespace == PG_CATALOG_NAMESPACE)
+ ereport(elevel,
+ (errmsg("skipping \"%s\" --- only superuser or database owner can vacuum it",
+ NameStr(reltuple->relname))));
+ else
+ ereport(elevel,
+ (errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
+ NameStr(reltuple->relname))));
+ return true;
+ }
+
+ /*
+ * Check that it's of a vacuumable relkind.
+ */
+ if (reltuple->relkind != RELKIND_RELATION &&
+ reltuple->relkind != RELKIND_MATVIEW &&
+ reltuple->relkind != RELKIND_TOASTVALUE &&
+ reltuple->relkind != RELKIND_PARTITIONED_TABLE)
+ {
+ ereport(elevel,
+ (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
+ NameStr(reltuple->relname))));
+ return true;
+ }
+
+ return false;
+}
+
+
/*
* Given a VacuumRelation, fill in the table OID if it wasn't specified,
* and optionally add VacuumRelations for partitions of the table.
@@ -456,15 +514,6 @@ expand_vacuum_rel(VacuumRelation *vrel)
*/
relid = RangeVarGetRelid(vrel->relation, AccessShareLock, false);
- /*
- * Make a returnable VacuumRelation for this rel.
- */
- oldcontext = MemoryContextSwitchTo(vac_context);
- vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
- relid,
- vrel->va_cols));
- MemoryContextSwitchTo(oldcontext);
-
/*
* To check whether the relation is a partitioned table, fetch its
* syscache entry.
@@ -473,9 +522,27 @@ expand_vacuum_rel(VacuumRelation *vrel)
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for relation %u", relid);
classForm = (Form_pg_class) GETSTRUCT(tuple);
+
+ /* check permissions of relation */
+ if (vacuum_skip_rel(relid, classForm, WARNING))
+ {
+ ReleaseSysCache(tuple);
+ UnlockRelationOid(relid, AccessShareLock);
+ return vacrels;
+ }
+
include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
ReleaseSysCache(tuple);
+ /*
+ * Make a returnable VacuumRelation for this rel.
+ */
+ oldcontext = MemoryContextSwitchTo(vac_context);
+ vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
+ relid,
+ vrel->va_cols));
+ MemoryContextSwitchTo(oldcontext);
+
/*
* If it is, make relation list entries for its partitions. Note that
* the list returned by find_all_inheritors() includes the passed-in
@@ -545,15 +612,10 @@ get_all_vacuum_rels(void)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
MemoryContext oldcontext;
+ Oid relid = HeapTupleGetOid(tuple);
- /*
- * We include partitioned tables here; depending on which operation is
- * to be performed, caller will decide whether to process or ignore
- * them.
- */
- if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW &&
- classForm->relkind != RELKIND_PARTITIONED_TABLE)
+ /* check permissions of relation */
+ if (vacuum_skip_rel(relid, classForm, DEBUG1))
continue;
/*
@@ -563,7 +625,7 @@ get_all_vacuum_rels(void)
*/
oldcontext = MemoryContextSwitchTo(vac_context);
vacrels = lappend(vacrels, makeVacuumRelation(NULL,
- HeapTupleGetOid(tuple),
+ relid,
NIL));
MemoryContextSwitchTo(oldcontext);
}
@@ -1436,47 +1498,13 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
}
/*
- * Check permissions.
- *
- * We allow the user to vacuum a table if he is superuser, the table
- * owner, or the database owner (but in the latter case, only if it's not
- * a shared relation). pg_class_ownercheck includes the superuser case.
- *
- * Note we choose to treat permissions failure as a WARNING and keep
- * trying to vacuum the rest of the DB --- is this appropriate?
- */
- if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
- (pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared)))
- {
- if (onerel->rd_rel->relisshared)
- ereport(WARNING,
- (errmsg("skipping \"%s\" --- only superuser can vacuum it",
- RelationGetRelationName(onerel))));
- else if (onerel->rd_rel->relnamespace == PG_CATALOG_NAMESPACE)
- ereport(WARNING,
- (errmsg("skipping \"%s\" --- only superuser or database owner can vacuum it",
- RelationGetRelationName(onerel))));
- else
- ereport(WARNING,
- (errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
- RelationGetRelationName(onerel))));
- relation_close(onerel, lmode);
- PopActiveSnapshot();
- CommitTransactionCommand();
- return false;
- }
-
- /*
- * Check that it's of a vacuumable relkind.
+ * Check if relation needs to be skipped. This check happens as well
+ * when building the relation list to VACUUM for a manual operation,
+ * and needs to be done here as well as this could be spawned across
+ * multiple transactions.
*/
- if (onerel->rd_rel->relkind != RELKIND_RELATION &&
- onerel->rd_rel->relkind != RELKIND_MATVIEW &&
- onerel->rd_rel->relkind != RELKIND_TOASTVALUE &&
- onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ if (vacuum_skip_rel(RelationGetRelid(onerel), onerel->rd_rel, WARNING))
{
- ereport(WARNING,
- (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
- RelationGetRelationName(onerel))));
relation_close(onerel, lmode);
PopActiveSnapshot();
CommitTransactionCommand();