On 07/30/2014 07:46 PM, Tom Lane wrote:
> Bruce Momjian <br...@momjian.us> writes:
>> On Wed, Jul 30, 2014 at 01:29:31PM -0400, Tom Lane wrote:
>>> I don't find it all that odd.  We should not be encouraging routine
>>> database-wide reindexes.
> 
>> Uh, do we encourage database-wide VACUUM FULL or CLUSTER, as we use them
>> there with no parameter.  Is there a reason REINDEX should be harder,
>> and require a dummy argument to run?
> 
> I believe that REINDEX on system catalogs carries a risk of deadlock
> failures against other processes --- there was a recent example of that
> in the mailing lists.  VACUUM FULL has such risks too, but that's been
> pretty well deprecated for many years.  (I think CLUSTER is probably
> relatively safe on this score because it's not going to think any system
> catalogs are clustered.)
> 
> If there were a variant of REINDEX that only hit user tables, I'd be fine
> with making that easy to invoke.

Here are two patches for this.

The first one, reindex_user_tables.v1.patch, implements the variant that
only hits user tables, as suggested by you.

The second one, reindex_no_dbname.v1.patch, allows the three
database-wide variants to omit the database name (voted for by Daniel
Migowski, Bruce, and myself; voted against by you).  This patch is to be
applied on top of the first one.
-- 
Vik
*** a/doc/src/sgml/ref/reindex.sgml
--- b/doc/src/sgml/ref/reindex.sgml
***************
*** 21,27 **** PostgreSQL documentation
  
   <refsynopsisdiv>
  <synopsis>
! REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">name</replaceable> [ FORCE ]
  </synopsis>
   </refsynopsisdiv>
  
--- 21,27 ----
  
   <refsynopsisdiv>
  <synopsis>
! REINDEX { INDEX | TABLE | DATABASE | SYSTEM | USER TABLES } <replaceable class="PARAMETER">name</replaceable> [ FORCE ]
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 126,139 **** REINDEX { INDEX | TABLE | DATABASE | SYSTEM } <replaceable class="PARAMETER">nam
     </varlistentry>
  
     <varlistentry>
      <term><replaceable class="PARAMETER">name</replaceable></term>
      <listitem>
       <para>
        The name of the specific index, table, or database to be
        reindexed.  Index and table names can be schema-qualified.
!       Presently, <command>REINDEX DATABASE</> and <command>REINDEX SYSTEM</>
!       can only reindex the current database, so their parameter must match
!       the current database's name.
       </para>
      </listitem>
     </varlistentry>
--- 126,151 ----
     </varlistentry>
  
     <varlistentry>
+     <term><literal>USER TABLES</literal></term>
+     <listitem>
+      <para>
+       Recreate all indexes on user tables within the current database.
+       Indexes on system catalogs are not processed.
+       This form of <command>REINDEX</command> cannot be executed inside a
+       transaction block.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
      <term><replaceable class="PARAMETER">name</replaceable></term>
      <listitem>
       <para>
        The name of the specific index, table, or database to be
        reindexed.  Index and table names can be schema-qualified.
!       Presently, <command>REINDEX DATABASE</>, <command>REINDEX SYSTEM</>,
!       and <command>REINDEX USER TABLES</> can only reindex the current
!       database, so their parameter must match the current database's name.
       </para>
      </listitem>
     </varlistentry>
*** a/doc/src/sgml/ref/reindexdb.sgml
--- b/doc/src/sgml/ref/reindexdb.sgml
***************
*** 65,70 **** PostgreSQL documentation
--- 65,80 ----
     </group>
     <arg choice="opt"><replaceable>dbname</replaceable></arg>
    </cmdsynopsis>
+ 
+   <cmdsynopsis>
+    <command>reindexdb</command>
+    <arg rep="repeat"><replaceable>connection-option</replaceable></arg>
+    <group choice="plain">
+     <arg choice="plain"><option>--usertables</option></arg>
+     <arg choice="plain"><option>-u</option></arg>
+    </group>
+    <arg choice="opt"><replaceable>dbname</replaceable></arg>
+   </cmdsynopsis>
   </refsynopsisdiv>
  
  
***************
*** 173,178 **** PostgreSQL documentation
--- 183,198 ----
        </listitem>
       </varlistentry>
  
+      <varlistentry>
+       <term><option>-u</></term>
+       <term><option>--usertables</></term>
+       <listitem>
+        <para>
+         Reindex database's user tables.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
      <varlistentry>
        <term><option>-V</></term>
        <term><option>--version</></term>
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6984,6989 **** ReindexStmt:
--- 6984,6999 ----
  					n->do_user = true;
  					$$ = (Node *)n;
  				}
+ 			| REINDEX USER TABLES name opt_force
+ 				{
+ 					ReindexStmt *n = makeNode(ReindexStmt);
+ 					n->kind = OBJECT_DATABASE;
+ 					n->name = $4;
+ 					n->relation = NULL;
+ 					n->do_system = false;
+ 					n->do_user = true;
+ 					$$ = (Node *)n;
+ 				}
  		;
  
  reindex_type:
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
***************
*** 3145,3151 **** psql_completion(const char *text, int start, int end)
  	else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
  	{
  		static const char *const list_REINDEX[] =
! 		{"TABLE", "INDEX", "SYSTEM", "DATABASE", NULL};
  
  		COMPLETE_WITH_LIST(list_REINDEX);
  	}
--- 3145,3151 ----
  	else if (pg_strcasecmp(prev_wd, "REINDEX") == 0)
  	{
  		static const char *const list_REINDEX[] =
! 		{"TABLE", "INDEX", "SYSTEM", "DATABASE", "USER TABLES", NULL};
  
  		COMPLETE_WITH_LIST(list_REINDEX);
  	}
***************
*** 3158,3163 **** psql_completion(const char *text, int start, int end)
--- 3158,3171 ----
  		else if (pg_strcasecmp(prev_wd, "SYSTEM") == 0 ||
  				 pg_strcasecmp(prev_wd, "DATABASE") == 0)
  			COMPLETE_WITH_QUERY(Query_for_list_of_databases);
+ 		else if (pg_strcasecmp(prev_wd, "USER") == 0)
+ 			COMPLETE_WITH_CONST("TABLES");
+ 	}
+ 	else if (pg_strcasecmp(prev3_wd, "REINDEX") == 0)
+ 	{
+ 		if (pg_strcasecmp(prev2_wd, "USER") == 0 &&
+ 			pg_strcasecmp(prev_wd, "TABLES") == 0)
+ 			COMPLETE_WITH_QUERY(Query_for_list_of_databases);
  	}
  
  /* SECURITY LABEL */
*** a/src/bin/scripts/reindexdb.c
--- b/src/bin/scripts/reindexdb.c
***************
*** 28,35 **** static void reindex_system_catalogs(const char *dbname,
--- 28,41 ----
  						const char *host, const char *port,
  						const char *username, enum trivalue prompt_password,
  						const char *progname, bool echo);
+ static void reindex_user_tables(const char *dbname,
+ 						const char *host, const char *port,
+ 						const char *username, enum trivalue prompt_password,
+ 						const char *progname, bool echo);
  static void help(const char *progname);
  
+ #define exit_nicely(code) exit(code)
+ 
  int
  main(int argc, char *argv[])
  {
***************
*** 44,49 **** main(int argc, char *argv[])
--- 50,56 ----
  		{"dbname", required_argument, NULL, 'd'},
  		{"all", no_argument, NULL, 'a'},
  		{"system", no_argument, NULL, 's'},
+ 		{"usertables", no_argument, NULL, 'u'},
  		{"table", required_argument, NULL, 't'},
  		{"index", required_argument, NULL, 'i'},
  		{"maintenance-db", required_argument, NULL, 2},
***************
*** 61,66 **** main(int argc, char *argv[])
--- 68,74 ----
  	const char *username = NULL;
  	enum trivalue prompt_password = TRI_DEFAULT;
  	bool		syscatalog = false;
+ 	bool		usertables = false;
  	bool		alldb = false;
  	bool		echo = false;
  	bool		quiet = false;
***************
*** 73,79 **** main(int argc, char *argv[])
  	handle_help_version_opts(argc, argv, "reindexdb", help);
  
  	/* process command-line options */
! 	while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:ast:i:", long_options, &optindex)) != -1)
  	{
  		switch (c)
  		{
--- 81,87 ----
  	handle_help_version_opts(argc, argv, "reindexdb", help);
  
  	/* process command-line options */
! 	while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:asut:i:", long_options, &optindex)) != -1)
  	{
  		switch (c)
  		{
***************
*** 107,112 **** main(int argc, char *argv[])
--- 115,123 ----
  			case 's':
  				syscatalog = true;
  				break;
+ 			case 'u':
+ 				usertables = true;
+ 				break;
  			case 't':
  				simple_string_list_append(&tables, optarg);
  				break;
***************
*** 194,199 **** main(int argc, char *argv[])
--- 205,236 ----
  		reindex_system_catalogs(dbname, host, port, username, prompt_password,
  								progname, echo);
  	}
+ 	else if (usertables)
+ 	{
+ 		if (tables.head != NULL)
+ 		{
+ 			fprintf(stderr, _("%s: cannot reindex specific table(s) and all user tables at the same time\n"), progname);
+ 			exit(1);
+ 		}
+ 		if (indexes.head != NULL)
+ 		{
+ 			fprintf(stderr, _("%s: cannot reindex specific index(es) and all user tables at the same time\n"), progname);
+ 			exit(1);
+ 		}
+ 
+ 		if (dbname == NULL)
+ 		{
+ 			if (getenv("PGDATABASE"))
+ 				dbname = getenv("PGDATABASE");
+ 			else if (getenv("PGUSER"))
+ 				dbname = getenv("PGUSER");
+ 			else
+ 				dbname = get_user_name_or_exit(progname);
+ 		}
+ 
+ 		reindex_user_tables(dbname, host, port, username, prompt_password,
+ 								progname, echo);
+ 	}
  	else
  	{
  		if (dbname == NULL)
***************
*** 336,341 **** reindex_system_catalogs(const char *dbname, const char *host, const char *port,
--- 373,413 ----
  }
  
  static void
+ reindex_user_tables(const char *dbname, const char *host, const char *port,
+ 					const char *username, enum trivalue prompt_password,
+ 					const char *progname, bool echo)
+ {
+ 	PQExpBufferData sql;
+ 
+ 	PGconn	   *conn;
+ 
+ 	initPQExpBuffer(&sql);
+ 
+ 	appendPQExpBuffer(&sql, "REINDEX USER TABLES %s;", dbname);
+ 
+ 	conn = connectDatabase(dbname, host, port, username, prompt_password,
+ 						   progname, false);
+ 
+ 	/* This feature is only available starting in 9.5 */
+ 	if (PQserverVersion(conn) < 90500)
+ 	{
+ 		fprintf(stderr, _("%s: REINDEX USER TABLES is only available in server versions 9.5 and newer\n"),
+ 				progname);
+ 		exit_nicely(1);
+ 	}
+ 
+ 	if (!executeMaintenanceCommand(conn, sql.data, echo))
+ 	{
+ 		fprintf(stderr, _("%s: reindexing of user tables failed: %s"),
+ 				progname, PQerrorMessage(conn));
+ 		PQfinish(conn);
+ 		exit(1);
+ 	}
+ 	PQfinish(conn);
+ 	termPQExpBuffer(&sql);
+ }
+ 
+ static void
  help(const char *progname)
  {
  	printf(_("%s reindexes a PostgreSQL database.\n\n"), progname);
***************
*** 348,353 **** help(const char *progname)
--- 420,426 ----
  	printf(_("  -i, --index=INDEX         recreate specific index(es) only\n"));
  	printf(_("  -q, --quiet               don't write any messages\n"));
  	printf(_("  -s, --system              reindex system catalogs\n"));
+ 	printf(_("  -u, --usertables          reindex all user tables\n"));
  	printf(_("  -t, --table=TABLE         reindex specific table(s) only\n"));
  	printf(_("  -V, --version             output version information, then exit\n"));
  	printf(_("  -?, --help                show this help, then exit\n"));
*** a/doc/src/sgml/ref/reindex.sgml
--- b/doc/src/sgml/ref/reindex.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  REINDEX { INDEX | TABLE | DATABASE | SYSTEM | USER TABLES } <replaceable class="PARAMETER">name</replaceable> [ FORCE ]
+ REINDEX { DATABASE | SYSTEM | USER TABLES }
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 145,151 **** REINDEX { INDEX | TABLE | DATABASE | SYSTEM | USER TABLES } <replaceable class="
        reindexed.  Index and table names can be schema-qualified.
        Presently, <command>REINDEX DATABASE</>, <command>REINDEX SYSTEM</>,
        and <command>REINDEX USER TABLES</> can only reindex the current
!       database, so their parameter must match the current database's name.
       </para>
      </listitem>
     </varlistentry>
--- 146,153 ----
        reindexed.  Index and table names can be schema-qualified.
        Presently, <command>REINDEX DATABASE</>, <command>REINDEX SYSTEM</>,
        and <command>REINDEX USER TABLES</> can only reindex the current
!       database, so their parameter must match the current database's name
!       if provided.
       </para>
      </listitem>
     </varlistentry>
*** a/src/backend/commands/indexcmds.c
--- b/src/backend/commands/indexcmds.c
***************
*** 1784,1799 **** ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
  	List	   *relids = NIL;
  	ListCell   *l;
  
! 	AssertArg(databaseName);
! 
! 	if (strcmp(databaseName, get_database_name(MyDatabaseId)) != 0)
  		ereport(ERROR,
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  				 errmsg("can only reindex the currently open database")));
  
  	if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
  		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
! 					   databaseName);
  
  	/*
  	 * Create a memory context that will survive forced transaction commits we
--- 1784,1797 ----
  	List	   *relids = NIL;
  	ListCell   *l;
  
! 	if (databaseName != NULL && strcmp(databaseName, get_database_name(MyDatabaseId)) != 0)
  		ereport(ERROR,
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  				 errmsg("can only reindex the currently open database")));
  
  	if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
  		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
! 					   get_database_name(MyDatabaseId));
  
  	/*
  	 * Create a memory context that will survive forced transaction commits we
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6974,6979 **** ReindexStmt:
--- 6974,6989 ----
  					n->do_user = false;
  					$$ = (Node *)n;
  				}
+ 			| REINDEX SYSTEM_P
+ 				{
+ 					ReindexStmt *n = makeNode(ReindexStmt);
+ 					n->kind = OBJECT_DATABASE;
+ 					n->name = NULL;
+ 					n->relation = NULL;
+ 					n->do_system = true;
+ 					n->do_user = false;
+ 					$$ = (Node *)n;
+ 				}
  			| REINDEX DATABASE name opt_force
  				{
  					ReindexStmt *n = makeNode(ReindexStmt);
***************
*** 6984,6989 **** ReindexStmt:
--- 6994,7009 ----
  					n->do_user = true;
  					$$ = (Node *)n;
  				}
+ 			| REINDEX DATABASE
+ 				{
+ 					ReindexStmt *n = makeNode(ReindexStmt);
+ 					n->kind = OBJECT_DATABASE;
+ 					n->name = NULL;
+ 					n->relation = NULL;
+ 					n->do_system = true;
+ 					n->do_user = true;
+ 					$$ = (Node *)n;
+ 				}
  			| REINDEX USER TABLES name opt_force
  				{
  					ReindexStmt *n = makeNode(ReindexStmt);
***************
*** 6994,6999 **** ReindexStmt:
--- 7014,7029 ----
  					n->do_user = true;
  					$$ = (Node *)n;
  				}
+ 			| REINDEX USER TABLES
+ 				{
+ 					ReindexStmt *n = makeNode(ReindexStmt);
+ 					n->kind = OBJECT_DATABASE;
+ 					n->name = NULL;
+ 					n->relation = NULL;
+ 					n->do_system = false;
+ 					n->do_user = true;
+ 					$$ = (Node *)n;
+ 				}
  		;
  
  reindex_type:
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to