dedupe_vacuum_relations_v3.patch
application/octet-stream
Filename: dedupe_vacuum_relations_v3.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v3
| File | + | − |
|---|---|---|
| src/backend/commands/vacuum.c | 87 | 0 |
| src/test/regress/expected/vacuum.out | 1 | 0 |
| src/test/regress/sql/vacuum.sql | 1 | 0 |
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a9fe412351..fbc442f1a3 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -71,6 +71,7 @@ static BufferAccessStrategy vac_strategy;
/* non-export function prototypes */
static void get_rel_oids(List **vacrels);
static void check_columns_exist(List *relations);
+static void dedupe_relations(List **relations);
static void vac_truncate_clog(TransactionId frozenXID,
MultiXactId minMulti,
TransactionId lastSaneFrozenXid,
@@ -269,6 +270,17 @@ vacuum(int options, List *relations, VacuumParams *params,
check_columns_exist(relations);
/*
+ * Now dedupe the list to avoid any redundant work (e.g. user specifies
+ * the same relation twice). We also take care of combining any
+ * separate column lists for duplicate relations.
+ *
+ * We do this after resolving the OIDs so that we do not miss entries
+ * that have unequal RangeVars but resolve to the same OIDs. For
+ * example, "foo" and "public.foo" could be the same relation.
+ */
+ dedupe_relations(&relations);
+
+ /*
* Decide whether we need to start/commit our own transactions.
*
* For VACUUM (with or without ANALYZE): always do so, so that we can
@@ -609,6 +621,81 @@ check_columns_exist(List *relations)
}
/*
+ * De-duplicate all relations and columns specified. The OIDs for each relation
+ * must already be determined before calling this function.
+ */
+static void
+dedupe_relations(List **relations)
+{
+ int i;
+ int next_elem_index = 0;
+ List *duplicates = NIL; /* indexes of entries to remove */
+ ListCell *lc;
+ List *temp_relations = NIL;
+
+ if (*relations == NIL) /* nothing to do */
+ return;
+
+ /* mark any duplicates and combine the column lists into the first match */
+ foreach(lc, *relations)
+ {
+ VacuumRelation *relation = lfirst_node(VacuumRelation, lc);
+
+ ++next_elem_index;
+
+ /*
+ * If this one has already been marked as a duplicate, it has
+ * already been processed, and there's nothing left to do.
+ */
+ if (list_member_int(duplicates, next_elem_index - 1))
+ continue;
+
+ /* remove any duplicates in the column list */
+ relation->va_cols = list_concat_unique(NIL, relation->va_cols);
+
+ /* now look for any duplicates in the remainder of the list */
+ for (i = next_elem_index; i < list_length(*relations); ++i)
+ {
+ VacuumRelation *nth_rel = list_nth_node(VacuumRelation, *relations, i);
+
+ /* if already processed or not equal, skip */
+ if (list_member_int(duplicates, i) || relation->oid != nth_rel->oid)
+ continue;
+
+ /*
+ * For ANALYZE, if a specified relation has an empty
+ * column list, it means that all columns should be
+ * analyzed. Therefore, any time a relation is
+ * specified with an empty column list, it overrides any
+ * other column lists specified for that relation.
+ */
+ if (relation->va_cols == NIL || nth_rel->va_cols == NIL)
+ relation->va_cols = NIL;
+ else /* combine the column lists */
+ relation->va_cols = list_concat_unique(relation->va_cols, nth_rel->va_cols);
+
+ duplicates = lappend_int(duplicates, i);
+ }
+ }
+
+ /* nothing else needed if we did not find any duplicates */
+ if (duplicates == NIL)
+ return;
+
+ for (i = 0; i < list_length(*relations); ++i)
+ {
+ /* if we are a duplicate entry, skip */
+ if (list_member_int(duplicates, i))
+ continue;
+
+ /* add non-duplicate entry to the final list */
+ temp_relations = lappend(temp_relations, list_nth_node(VacuumRelation, *relations, i));
+ }
+
+ *relations = temp_relations;
+}
+
+/*
* vacuum_set_xid_limits() -- compute oldest-Xmin and freeze cutoff points
*
* The output parameters are:
diff --git a/src/test/regress/expected/vacuum.out b/src/test/regress/expected/vacuum.out
index d29dd8f3a3..113f59cfa9 100644
--- a/src/test/regress/expected/vacuum.out
+++ b/src/test/regress/expected/vacuum.out
@@ -120,6 +120,7 @@ ANALYZE VERBOSE vactst (i), vacparted (does_not_exist);
ERROR: column "does_not_exist" of relation "vacparted" does not exist
ANALYZE vactst, vactst, vactst;
ANALYZE vacparted (a), vacparted (b), vacparted;
+ANALYZE vactst (i, i), vacparted (a), vactst (i), vacparted (a, b, a);
DROP TABLE vaccluster;
DROP TABLE vactst;
DROP TABLE vacparted;
diff --git a/src/test/regress/sql/vacuum.sql b/src/test/regress/sql/vacuum.sql
index 991bea7752..1134a58be5 100644
--- a/src/test/regress/sql/vacuum.sql
+++ b/src/test/regress/sql/vacuum.sql
@@ -93,6 +93,7 @@ ANALYZE vacparted (b), vactst;
ANALYZE VERBOSE vactst (i), vacparted (does_not_exist);
ANALYZE vactst, vactst, vactst;
ANALYZE vacparted (a), vacparted (b), vacparted;
+ANALYZE vactst (i, i), vacparted (a), vactst (i), vacparted (a, b, a);
DROP TABLE vaccluster;
DROP TABLE vactst;