@@ -19,6 +19,7 @@ static void check_is_super_user(ClusterInfo *cluster);
19
19
static void check_for_prepared_transactions (ClusterInfo * cluster );
20
20
static void check_for_isn_and_int8_passing_mismatch (ClusterInfo * cluster );
21
21
static void check_for_reg_data_type_usage (ClusterInfo * cluster );
22
+ static void check_for_invalid_indexes (ClusterInfo * cluster );
22
23
static void get_bin_version (ClusterInfo * cluster );
23
24
24
25
@@ -99,6 +100,7 @@ check_old_cluster(bool live_check,
99
100
check_is_super_user (& old_cluster );
100
101
check_for_prepared_transactions (& old_cluster );
101
102
check_for_reg_data_type_usage (& old_cluster );
103
+ check_for_invalid_indexes (& old_cluster );
102
104
check_for_isn_and_int8_passing_mismatch (& old_cluster );
103
105
104
106
/* old = PG 8.3 checks? */
@@ -803,6 +805,95 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
803
805
}
804
806
805
807
808
+ /*
809
+ * check_for_invalid_indexes()
810
+ *
811
+ *CREATE INDEX CONCURRENTLY can create invalid indexes if the index build
812
+ *fails. These are dumped as valid indexes by pg_dump, but the
813
+ *underlying files are still invalid indexes. This checks to make sure
814
+ *no invalid indexes exist, either failed index builds or concurrent
815
+ *indexes in the process of being created.
816
+ */
817
+ static void
818
+ check_for_invalid_indexes (ClusterInfo * cluster )
819
+ {
820
+ int dbnum ;
821
+ FILE * script = NULL ;
822
+ bool found = false;
823
+ char output_path [MAXPGPATH ];
824
+
825
+ prep_status ("Checking for invalid indexes from concurrent index builds" );
826
+
827
+ snprintf (output_path ,sizeof (output_path ),"invalid_indexes.txt" );
828
+
829
+ for (dbnum = 0 ;dbnum < cluster -> dbarr .ndbs ;dbnum ++ )
830
+ {
831
+ PGresult * res ;
832
+ bool db_used = false;
833
+ int ntups ;
834
+ int rowno ;
835
+ int i_nspname ,
836
+ i_relname ;
837
+ DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
838
+ PGconn * conn = connectToServer (cluster ,active_db -> db_name );
839
+
840
+ res = executeQueryOrDie (conn ,
841
+ "SELECT n.nspname, c.relname "
842
+ "FROMpg_catalog.pg_class c, "
843
+ "pg_catalog.pg_namespace n, "
844
+ "pg_catalog.pg_index i "
845
+ "WHERE(i.indisvalid = false OR "
846
+ " i.indisready = false) AND "
847
+ "i.indexrelid = c.oid AND "
848
+ "c.relnamespace = n.oid AND "
849
+ /* we do not migrate these, so skip them */
850
+ " n.nspname != 'pg_catalog' AND "
851
+ "n.nspname != 'information_schema' AND "
852
+ /* indexes do not have toast tables */
853
+ "n.nspname != 'pg_toast'" );
854
+
855
+ ntups = PQntuples (res );
856
+ i_nspname = PQfnumber (res ,"nspname" );
857
+ i_relname = PQfnumber (res ,"relname" );
858
+ for (rowno = 0 ;rowno < ntups ;rowno ++ )
859
+ {
860
+ found = true;
861
+ if (script == NULL && (script = fopen (output_path ,"w" ))== NULL )
862
+ pg_log (PG_FATAL ,"Could not open file \"%s\": %s\n" ,
863
+ output_path ,getErrorText (errno ));
864
+ if (!db_used )
865
+ {
866
+ fprintf (script ,"Database: %s\n" ,active_db -> db_name );
867
+ db_used = true;
868
+ }
869
+ fprintf (script ," %s.%s\n" ,
870
+ PQgetvalue (res ,rowno ,i_nspname ),
871
+ PQgetvalue (res ,rowno ,i_relname ));
872
+ }
873
+
874
+ PQclear (res );
875
+
876
+ PQfinish (conn );
877
+ }
878
+
879
+ if (script )
880
+ fclose (script );
881
+
882
+ if (found )
883
+ {
884
+ pg_log (PG_REPORT ,"fatal\n" );
885
+ pg_log (PG_FATAL ,
886
+ "Your installation contains invalid indexes due to failed or\n"
887
+ "currently running CREATE INDEX CONCURRENTLY operations. You\n"
888
+ "cannot upgrade until these indexes are valid or removed. A\n"
889
+ "list of the problem indexes is in the file:\n"
890
+ " %s\n\n" ,output_path );
891
+ }
892
+ else
893
+ check_ok ();
894
+ }
895
+
896
+
806
897
static void
807
898
get_bin_version (ClusterInfo * cluster )
808
899
{