diff --git a/src/backend/distributed/executor/multi_utility.c b/src/backend/distributed/executor/multi_utility.c index 1f2b7a802..839df8934 100644 --- a/src/backend/distributed/executor/multi_utility.c +++ b/src/backend/distributed/executor/multi_utility.c @@ -114,6 +114,7 @@ static void ProcessVacuumStmt(VacuumStmt *vacuumStmt, const char *vacuumCommand) static bool IsSupportedDistributedVacuumStmt(Oid relationId, VacuumStmt *vacuumStmt); static List * VacuumTaskList(Oid relationId, VacuumStmt *vacuumStmt); static StringInfo DeparseVacuumStmtPrefix(VacuumStmt *vacuumStmt); +static char * DeparseVacuumColumnNames(List *columnNameList); /* Local functions forward declarations for unsupported command checks */ @@ -988,13 +989,6 @@ IsSupportedDistributedVacuumStmt(Oid relationId, VacuumStmt *vacuumStmt) "distributed %s commands", stmtName))); } - if (vacuumStmt->va_cols != NIL) - { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("specifying a column list is currently unsupported in " - "distributed %s commands", stmtName))); - } - return true; } @@ -1012,6 +1006,7 @@ VacuumTaskList(Oid relationId, VacuumStmt *vacuumStmt) uint64 jobId = INVALID_JOB_ID; int taskId = 1; StringInfo vacuumString = DeparseVacuumStmtPrefix(vacuumStmt); + const char *columnNames = DeparseVacuumColumnNames(vacuumStmt->va_cols); const int vacuumPrefixLen = vacuumString->len; Oid schemaId = get_rel_namespace(relationId); char *schemaName = get_namespace_name(schemaId); @@ -1037,6 +1032,7 @@ VacuumTaskList(Oid relationId, VacuumStmt *vacuumStmt) vacuumString->len = vacuumPrefixLen; appendStringInfoString(vacuumString, shardName); + appendStringInfoString(vacuumString, columnNames); task = CitusMakeNode(Task); task->jobId = jobId; @@ -1086,9 +1082,8 @@ DeparseVacuumStmtPrefix(VacuumStmt *vacuumStmt) vacuumFlags &= ~VACOPT_ANALYZE; } - /* unsupported flags and options should have already been rejected */ + /* unsupported flags should have already been rejected */ Assert((vacuumFlags & unsupportedFlags) == 0); - Assert(vacuumStmt->va_cols == NIL); /* if no flags remain, exit early */ if (vacuumFlags == 0) @@ -1129,6 +1124,40 @@ DeparseVacuumStmtPrefix(VacuumStmt *vacuumStmt) } +/* + * DeparseVacuumColumnNames joins the list of strings using commas as a + * delimiter. The whole thing is placed in parenthesis and set off with a + * single space in order to facilitate appending it to the end of any VACUUM + * or ANALYZE command which uses explicit column names. If the provided list + * is empty, this function returns an empty string to keep the calling code + * simplest. + */ +static char * +DeparseVacuumColumnNames(List *columnNameList) +{ + StringInfo columnNames = makeStringInfo(); + ListCell *columnNameCell = NULL; + + if (columnNameList == NIL) + { + return columnNames->data; + } + + appendStringInfoString(columnNames, " ("); + + foreach(columnNameCell, columnNameList) + { + char *columnName = strVal(lfirst(columnNameCell)); + + appendStringInfo(columnNames, "%s,", columnName); + } + + columnNames->data[columnNames->len - 1] = ')'; + + return columnNames->data; +} + + /* * ErrorIfUnsupportedIndexStmt checks if the corresponding index statement is * supported for distributed tables and errors out if it is not. diff --git a/src/test/regress/expected/multi_utilities.out b/src/test/regress/expected/multi_utilities.out index ac68fe85b..5aed478a3 100644 --- a/src/test/regress/expected/multi_utilities.out +++ b/src/test/regress/expected/multi_utilities.out @@ -68,7 +68,7 @@ SELECT master_apply_delete_command('DELETE FROM sharded_table'); DROP TABLE sharded_table; -- VACUUM tests -- create a table with a single shard (for convenience) -CREATE TABLE dustbunnies (id integer, name text); +CREATE TABLE dustbunnies (id integer, name text, age integer); SELECT master_create_distributed_table('dustbunnies', 'id', 'hash'); master_create_distributed_table --------------------------------- @@ -82,7 +82,7 @@ SELECT master_create_worker_shards('dustbunnies', 1, 2); (1 row) -- add some data to the distributed table -\copy dustbunnies from stdin with csv +\copy dustbunnies (id, name) from stdin with csv -- following approach adapted from PostgreSQL's stats.sql file -- save relevant stat counter values in refreshable view \c - - - :worker_1_port @@ -201,6 +201,31 @@ WHERE oid='dustbunnies_990002'::regclass; t (1 row) +-- check there are no nulls in either column +SELECT attname, null_frac FROM pg_stats +WHERE tablename = 'dustbunnies_990002' ORDER BY attname; + attname | null_frac +---------+----------- + age | 1 + id | 0 + name | 0 +(3 rows) + +-- add NULL values, then perform column-specific ANALYZE +\c - - - :master_port +INSERT INTO dustbunnies VALUES (6, NULL, NULL); +ANALYZE dustbunnies (name); +-- verify that name's NULL ratio is updated but age's is not +\c - - - :worker_1_port +SELECT attname, null_frac FROM pg_stats +WHERE tablename = 'dustbunnies_990002' ORDER BY attname; + attname | null_frac +---------+----------- + age | 1 + id | 0 + name | 0.166667 +(3 rows) + \c - - - :master_port -- verify warning for unqualified VACUUM VACUUM; @@ -212,11 +237,6 @@ VACUUM dustbunnies; WARNING: not propagating VACUUM command to worker nodes HINT: Set citus.enable_ddl_propagation to true in order to send targeted VACUUM commands to worker nodes. SET citus.enable_ddl_propagation to DEFAULT; --- verify error messages for unsupported options -VACUUM (ANALYZE) dustbunnies (id); -ERROR: specifying a column list is currently unsupported in distributed VACUUM commands -ANALYZE dustbunnies (id); -ERROR: specifying a column list is currently unsupported in distributed ANALYZE commands -- TODO: support VERBOSE -- VACUUM VERBOSE dustbunnies; -- VACUUM (FULL, VERBOSE) dustbunnies; diff --git a/src/test/regress/sql/multi_utilities.sql b/src/test/regress/sql/multi_utilities.sql index 3cdfd91d7..13581353e 100644 --- a/src/test/regress/sql/multi_utilities.sql +++ b/src/test/regress/sql/multi_utilities.sql @@ -44,12 +44,12 @@ DROP TABLE sharded_table; -- VACUUM tests -- create a table with a single shard (for convenience) -CREATE TABLE dustbunnies (id integer, name text); +CREATE TABLE dustbunnies (id integer, name text, age integer); SELECT master_create_distributed_table('dustbunnies', 'id', 'hash'); SELECT master_create_worker_shards('dustbunnies', 1, 2); -- add some data to the distributed table -\copy dustbunnies from stdin with csv +\copy dustbunnies (id, name) from stdin with csv 1,bugs 2,babs 3,buster @@ -146,6 +146,20 @@ VACUUM (FREEZE) dustbunnies; SELECT relfrozenxid::text::integer > :frozenxid AS frozen_performed FROM pg_class WHERE oid='dustbunnies_990002'::regclass; +-- check there are no nulls in either column +SELECT attname, null_frac FROM pg_stats +WHERE tablename = 'dustbunnies_990002' ORDER BY attname; + +-- add NULL values, then perform column-specific ANALYZE +\c - - - :master_port +INSERT INTO dustbunnies VALUES (6, NULL, NULL); +ANALYZE dustbunnies (name); + +-- verify that name's NULL ratio is updated but age's is not +\c - - - :worker_1_port +SELECT attname, null_frac FROM pg_stats +WHERE tablename = 'dustbunnies_990002' ORDER BY attname; + \c - - - :master_port -- verify warning for unqualified VACUUM VACUUM; @@ -155,10 +169,6 @@ SET citus.enable_ddl_propagation to false; VACUUM dustbunnies; SET citus.enable_ddl_propagation to DEFAULT; --- verify error messages for unsupported options -VACUUM (ANALYZE) dustbunnies (id); -ANALYZE dustbunnies (id); - -- TODO: support VERBOSE -- VACUUM VERBOSE dustbunnies; -- VACUUM (FULL, VERBOSE) dustbunnies;