pg_upgrade: Handle hash index upgrades more smoothly.
authorRobert Haas
Fri, 19 May 2017 20:49:38 +0000 (16:49 -0400)
committerRobert Haas
Fri, 19 May 2017 20:49:38 +0000 (16:49 -0400)
Mark any old hash indexes as invalid so that they don't get used, and
create a script to run REINDEX on all of them.  Without this, we'd
still try to use any upgraded hash indexes, but it would fail.

Amit Kapila, reviewed by me.  Per a suggestion from Tom Lane.

Discussion: http://postgr.es/m/CAA4eK1Jidtagm7Q81q-WoegOVgkotv0OxvHOjFxcvFRP4X=mSw@mail.gmail.com

src/bin/pg_upgrade/check.c
src/bin/pg_upgrade/pg_upgrade.h
src/bin/pg_upgrade/version.c

index d52c81e24955a43d18f820ebfe0cff64dd6df6fe..8b9e81eb407521be8bf02142c3d542e372f110e8 100644 (file)
@@ -98,9 +98,16 @@ check_and_dump_old_cluster(bool live_check)
    check_for_reg_data_type_usage(&old_cluster);
    check_for_isn_and_int8_passing_mismatch(&old_cluster);
 
-   /* Pre-PG 10 allowed tables with 'unknown' type columns */
+   /*
+    * Pre-PG 10 allowed tables with 'unknown' type columns and non WAL logged
+    * hash indexes
+    */
    if (GET_MAJOR_VERSION(old_cluster.major_version) <= 906)
+   {
        old_9_6_check_for_unknown_data_type_usage(&old_cluster);
+       if (user_opts.check)
+           old_9_6_invalidate_hash_indexes(&old_cluster, true);
+   }
 
    /* 9.5 and below should not have roles starting with pg_ */
    if (GET_MAJOR_VERSION(old_cluster.major_version) <= 905)
@@ -176,6 +183,14 @@ issue_warnings(void)
        new_9_0_populate_pg_largeobject_metadata(&new_cluster, false);
        stop_postmaster(false);
    }
+
+   /* Reindex hash indexes for old < 10.0 */
+   if (GET_MAJOR_VERSION(old_cluster.major_version) <= 906)
+   {
+       start_postmaster(&new_cluster, true);
+       old_9_6_invalidate_hash_indexes(&new_cluster, false);
+       stop_postmaster(false);
+   }
 }
 
 
index b78b877903d7e777049a0474924dcb8602243f1f..8fbf8acd7eb1886bab47d409fe9b1ec4622f7a88 100644 (file)
@@ -441,6 +441,8 @@ void new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster,
                                         bool check_mode);
 void       old_9_3_check_for_line_data_type_usage(ClusterInfo *cluster);
 void       old_9_6_check_for_unknown_data_type_usage(ClusterInfo *cluster);
+void old_9_6_invalidate_hash_indexes(ClusterInfo *cluster,
+                               bool check_mode);
 
 /* parallel.c */
 void parallel_exec_prog(const char *log_file, const char *opt_log_file,
index a3651aadede0763caca87c56d10bed985f005d03..814eaa522c4dbffb00b9c65a34c3ca67d458bac0 100644 (file)
@@ -287,3 +287,115 @@ old_9_6_check_for_unknown_data_type_usage(ClusterInfo *cluster)
    else
        check_ok();
 }
+
+/*
+ * old_9_6_invalidate_hash_indexes()
+ * 9.6 -> 10
+ * Hash index binary format has changed from 9.6->10.0
+ */
+void
+old_9_6_invalidate_hash_indexes(ClusterInfo *cluster, bool check_mode)
+{
+   int         dbnum;
+   FILE       *script = NULL;
+   bool        found = false;
+   char       *output_path = "reindex_hash.sql";
+
+   prep_status("Checking for hash indexes");
+
+   for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
+   {
+       PGresult   *res;
+       bool        db_used = false;
+       int         ntups;
+       int         rowno;
+       int         i_nspname,
+                   i_relname;
+       DbInfo     *active_db = &cluster->dbarr.dbs[dbnum];
+       PGconn     *conn = connectToServer(cluster, active_db->db_name);
+
+       /* find hash indexes */
+       res = executeQueryOrDie(conn,
+                               "SELECT n.nspname, c.relname "
+                               "FROM   pg_catalog.pg_class c, "
+                               "       pg_catalog.pg_index i, "
+                               "       pg_catalog.pg_am a, "
+                               "       pg_catalog.pg_namespace n "
+                               "WHERE  i.indexrelid = c.oid AND "
+                               "       c.relam = a.oid AND "
+                               "       c.relnamespace = n.oid AND "
+                               "       a.amname = 'hash'"
+           );
+
+       ntups = PQntuples(res);
+       i_nspname = PQfnumber(res, "nspname");
+       i_relname = PQfnumber(res, "relname");
+       for (rowno = 0; rowno < ntups; rowno++)
+       {
+           found = true;
+           if (!check_mode)
+           {
+               if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL)
+                   pg_fatal("could not open file \"%s\": %s\n", output_path,
+                            strerror(errno));
+               if (!db_used)
+               {
+                   PQExpBufferData connectbuf;
+
+                   initPQExpBuffer(&connectbuf);
+                   appendPsqlMetaConnect(&connectbuf, active_db->db_name);
+                   fputs(connectbuf.data, script);
+                   termPQExpBuffer(&connectbuf);
+                   db_used = true;
+               }
+               fprintf(script, "REINDEX INDEX %s.%s;\n",
+                       quote_identifier(PQgetvalue(res, rowno, i_nspname)),
+                       quote_identifier(PQgetvalue(res, rowno, i_relname)));
+           }
+       }
+
+       PQclear(res);
+
+       if (!check_mode && db_used)
+       {
+           /* mark hash indexes as invalid */
+           PQclear(executeQueryOrDie(conn,
+                                     "UPDATE pg_catalog.pg_index i "
+                                     "SET  indisvalid = false "
+                                     "FROM pg_catalog.pg_class c, "
+                                     "     pg_catalog.pg_am a, "
+                                     "     pg_catalog.pg_namespace n "
+                                     "WHERE    i.indexrelid = c.oid AND "
+                                     "     c.relam = a.oid AND "
+                                     "     c.relnamespace = n.oid AND "
+                                     "     a.amname = 'hash'"));
+       }
+
+       PQfinish(conn);
+   }
+
+   if (script)
+       fclose(script);
+
+   if (found)
+   {
+       report_status(PG_WARNING, "warning");
+       if (check_mode)
+           pg_log(PG_WARNING, "\n"
+                  "Your installation contains hash indexes.  These indexes have different\n"
+                  "internal formats between your old and new clusters, so they must be\n"
+                  "reindexed with the REINDEX command.  After upgrading, you will be given\n"
+                  "REINDEX instructions.\n\n");
+       else
+           pg_log(PG_WARNING, "\n"
+                  "Your installation contains hash indexes.  These indexes have different\n"
+                  "internal formats between your old and new clusters, so they must be\n"
+                  "reindexed with the REINDEX command.  The file:\n"
+                  "    %s\n"
+                  "when executed by psql by the database superuser will recreate all invalid\n"
+             "indexes; until then, none of these indexes will be used.\n\n",
+                  output_path);
+   }
+   else
+       check_ok();
+}