@@ -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
+ "FROMpg_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
+ }