Re: [Proposal] vacuumdb --schema only

From: Nathan Bossart <nathandbossart(at)gmail(dot)com>
To: Gilles Darold <gilles(at)migops(dot)com>
Cc: Justin Pryzby <pryzby(at)telsasoft(dot)com>, Robert Treat <rob(at)xzilla(dot)net>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: [Proposal] vacuumdb --schema only
Date: 2022-04-18 21:56:15
Message-ID: 20220418215615.GA2300265@nathanxps13
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Thu, Apr 14, 2022 at 10:27:46PM +0200, Gilles Darold wrote:
> Attached v8 of the patch that tries to address the remarks above, fixes
> patch apply failure to master and replace calls to pg_log_error+exit
> with pg_fatal.

Thanks for the new patch.

> +enum trivalue schema_is_exclude = TRI_DEFAULT;
> +
> +/*
> + * The kind of object use in the command line filter.
> + * OBJFILTER_NONE: no filter used
> + * OBJFILTER_SCHEMA: -n | --schema or -N | --exclude-schema
> + * OBJFILTER_TABLE: -t | --table
> + */
> +enum VacObjectFilter
> +{
> + OBJFILTER_NONE,
> + OBJFILTER_TABLE,
> + OBJFILTER_SCHEMA
> +};
> +
> +enum VacObjectFilter objfilter = OBJFILTER_NONE;

I still think we ought to remove schema_is_exclude in favor of adding
OBJFILTER_SCHEMA_EXCLUDE to the enum. I think that would simplify some of
the error handling and improve readability. IMO we should add
OBJFILTER_ALL, too.

> - simple_string_list_append(&tables, optarg);
> + /* When filtering on schema name, filter by table is not allowed. */
> + if (schema_is_exclude != TRI_DEFAULT)
> + pg_fatal("cannot vacuum all tables in schema(s) and specific table(s) at the same time");
> + simple_string_list_append(&objects, optarg);
> + objfilter = OBJFILTER_TABLE;
> tbl_count++;
> break;
> }
> @@ -202,6 +224,32 @@ main(int argc, char *argv[])
> &vacopts.parallel_workers))
> exit(1);
> break;
> + case 'n': /* include schema(s) */
> + {
> + /* When filtering on schema name, filter by table is not allowed. */
> + if (tbl_count)
> + pg_fatal("cannot vacuum all tables in schema(s) and specific table(s) at the same time");
> +
> + if (schema_is_exclude == TRI_YES)
> + pg_fatal("cannot vacuum all tables in schema(s) and exclude specific schema(s) at the same time");
> + simple_string_list_append(&objects, optarg);
> + objfilter = OBJFILTER_SCHEMA;
> + schema_is_exclude = TRI_NO;
> + break;
> + }
> + case 'N': /* exclude schema(s) */
> + {
> + /* When filtering on schema name, filter by table is not allowed. */
> + if (tbl_count)
> + pg_fatal("cannot vacuum all tables in schema(s) and specific table(s) at the same time");
> + if (schema_is_exclude == TRI_NO)
> + pg_fatal("cannot vacuum all tables in schema(s) and exclude specific schema(s) at the same time");
> +
> + simple_string_list_append(&objects, optarg);
> + objfilter = OBJFILTER_SCHEMA;
> + schema_is_exclude = TRI_YES;
> + break;

I was expecting these to check objfilter. For example:

case 'N':
{
if (objfilter == OBJFILTER_TABLE)
pg_fatal("...");
else if (objfilter == OBJFILTER_SCHEMA)
pg_fatal("...");
else if (objfilter == OBJFILTER_ALL)
pg_fatal("...");

simple_string_list_append(&objects, optarg);
objfilter = OBJFILTER_SCHEMA_EXCLUDE;
break;
}

Another possible improvement could be to move the pg_fatal() calls to a
helper function that generates the message based on the current objfilter
setting and the current option. I'm envisioning something like
check_objfilter(VacObjFilter curr_objfilter, VacObjFilter curr_option).

> + /*
> + * When filtering on schema name, filter by table is not allowed.
> + * The schema name can already be set to a fqdn table name.
> + */
> + if (tbl_count && objfilter == OBJFILTER_SCHEMA && objects.head != NULL)
> + pg_fatal("cannot vacuum all tables in schema(s) and specific table(s) at the same time");

Isn't this redundant with the error in the option handling?

> - if (tables.head != NULL)
> + if (objfilter == OBJFILTER_SCHEMA && objects.head != NULL)
> + {
> + if (schema_is_exclude == TRI_YES)
> + pg_fatal("cannot exclude from vacuum specific schema(s) in all databases");
> + else if (schema_is_exclude == TRI_NO)
> + pg_fatal("cannot vacuum specific schema(s) in all databases");
> + }
> +
> + if (objfilter == OBJFILTER_TABLE && objects.head != NULL)
> pg_fatal("cannot vacuum specific table(s) in all databases");

I think we could move all these into check_objfilter(), too.

nitpick: Why do we need to check that objects.head is not NULL? Isn't the
objfilter check enough?

> /*
> - * If no tables were listed, filter for the relevant relation types. If
> - * tables were given via --table, don't bother filtering by relation type.
> - * Instead, let the server decide whether a given relation can be
> - * processed in which case the user will know about it.
> + * If no tables were listed or that a filter by schema is used, filter
> + * for the relevant relation types. If tables were given via --table,
> + * don't bother filtering by relation type. Instead, let the server
> + * decide whether a given relation can be processed in which case the
> + * user will know about it. If there is a filter by schema the use of
> + * --table is not possible so we have to filter by relation type too.
> */
> - if (!tables_listed)
> + if (!objects_listed || objfilter == OBJFILTER_SCHEMA)

Do we need to check for objects_listed here? IIUC we can just check for
objfilter != OBJFILTER_TABLE.

Unless I'm missing something, schema_is_exclude appears to only be used for
error checking and doesn't impact the generated catalog query. It looks
like the relevant logic disappeared after v4 of the patch.

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Nathan Bossart 2022-04-18 22:52:44 Re: make MaxBackends available in _PG_init
Previous Message Thomas Munro 2022-04-18 21:45:11 Re: pgsql: Add TAP test for archive_cleanup_command and recovery_end_comman