@@ -17,6 +17,7 @@ static void check_locale_and_encoding(migratorContext *ctx, ControlData *oldctrl
17
17
static void check_for_isn_and_int8_passing_mismatch (migratorContext * ctx ,
18
18
Cluster whichCluster );
19
19
static void check_for_reg_data_type_usage (migratorContext * ctx , Cluster whichCluster );
20
+ static void check_for_invalid_indexes (migratorContext * ctx , Cluster whichCluster );
20
21
21
22
22
23
/*
@@ -96,6 +97,7 @@ check_old_cluster(migratorContext *ctx, bool live_check,
96
97
97
98
check_for_reg_data_type_usage (ctx , CLUSTER_OLD );
98
99
check_for_isn_and_int8_passing_mismatch (ctx , CLUSTER_OLD );
100
+ check_for_invalid_indexes (ctx , CLUSTER_OLD );
99
101
100
102
/* old = PG 8.3 checks? */
101
103
if (GET_MAJOR_VERSION (ctx -> old .major_version ) <= 803 )
@@ -676,3 +678,93 @@ check_for_reg_data_type_usage(migratorContext *ctx, Cluster whichCluster)
676
678
else
677
679
check_ok (ctx );
678
680
}
681
+
682
+
683
+ /*
684
+ * check_for_invalid_indexes()
685
+ *
686
+ * CREATE INDEX CONCURRENTLY can create invalid indexes if the index build
687
+ * fails. These are dumped as valid indexes by pg_dump, but the
688
+ * underlying files are still invalid indexes. This checks to make sure
689
+ * no invalid indexes exist, either failed index builds or concurrent
690
+ * indexes in the process of being created.
691
+ */
692
+ static void
693
+ check_for_invalid_indexes (migratorContext * ctx , Cluster whichCluster )
694
+ {
695
+ ClusterInfo * cluster = (whichCluster == CLUSTER_OLD ) ?
696
+ & ctx -> old : & ctx -> new ;
697
+ int dbnum ;
698
+ FILE * script = NULL ;
699
+ bool found = false;
700
+ char output_path [MAXPGPATH ];
701
+
702
+ prep_status (ctx , "Checking for invalid indexes from concurrent index builds" );
703
+
704
+ snprintf (output_path , sizeof (output_path ), "invalid_indexes.txt" );
705
+
706
+ for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
707
+ {
708
+ PGresult * res ;
709
+ bool db_used = false;
710
+ int ntups ;
711
+ int rowno ;
712
+ int i_nspname ,
713
+ i_relname ;
714
+ DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
715
+ PGconn * conn = connectToServer (ctx , active_db -> db_name , whichCluster );
716
+
717
+ res = executeQueryOrDie (ctx , conn ,
718
+ "SELECT n.nspname, c.relname "
719
+ "FROM pg_catalog.pg_class c, "
720
+ " pg_catalog.pg_namespace n, "
721
+ " pg_catalog.pg_index i "
722
+ "WHERE (i.indisvalid = false OR "
723
+ " i.indisready = false) AND "
724
+ " i.indexrelid = c.oid AND "
725
+ " c.relnamespace = n.oid AND "
726
+ /* we do not migrate these, so skip them */
727
+ " n.nspname != 'pg_catalog' AND "
728
+ " n.nspname != 'information_schema' AND "
729
+ /* indexes do not have toast tables */
730
+ " n.nspname != 'pg_toast'" );
731
+
732
+ ntups = PQntuples (res );
733
+ i_nspname = PQfnumber (res , "nspname" );
734
+ i_relname = PQfnumber (res , "relname" );
735
+ for (rowno = 0 ; rowno < ntups ; rowno ++ )
736
+ {
737
+ found = true;
738
+ if (script == NULL && (script = fopen (output_path , "w" )) == NULL )
739
+ pg_log (ctx , PG_FATAL , "Could not create necessary file: %s\n" , output_path );
740
+ if (!db_used )
741
+ {
742
+ fprintf (script , "Database: %s\n" , active_db -> db_name );
743
+ db_used = true;
744
+ }
745
+ fprintf (script , " %s.%s\n" ,
746
+ PQgetvalue (res , rowno , i_nspname ),
747
+ PQgetvalue (res , rowno , i_relname ));
748
+ }
749
+
750
+ PQclear (res );
751
+
752
+ PQfinish (conn );
753
+ }
754
+
755
+ if (script )
756
+ fclose (script );
757
+
758
+ if (found )
759
+ {
760
+ pg_log (ctx , PG_REPORT , "fatal\n" );
761
+ pg_log (ctx , PG_FATAL ,
762
+ "Your installation contains invalid indexes due to failed or\n"
763
+ "currently running CREATE INDEX CONCURRENTLY operations. You\n"
764
+ "cannot upgrade until these indexes are valid or removed. A\n"
765
+ "list of the problem indexes is in the file:\n"
766
+ " %s\n\n" , output_path );
767
+ }
768
+ else
769
+ check_ok (ctx );
770
+ }
0 commit comments