@@ -20,6 +20,7 @@ static void check_is_super_user(ClusterInfo *cluster);
2020static void check_for_prepared_transactions (ClusterInfo * cluster );
2121static void check_for_isn_and_int8_passing_mismatch (ClusterInfo * cluster );
2222static void check_for_reg_data_type_usage (ClusterInfo * cluster );
23+ static void check_for_invalid_indexes (ClusterInfo * cluster );
2324static void get_bin_version (ClusterInfo * cluster );
2425static char * get_canonical_locale_name (int category , const char * locale );
2526
@@ -97,6 +98,7 @@ check_and_dump_old_cluster(bool live_check, char **sequence_script_file_name)
9798 check_is_super_user (& old_cluster );
9899 check_for_prepared_transactions (& old_cluster );
99100 check_for_reg_data_type_usage (& old_cluster );
101+ check_for_invalid_indexes (& old_cluster );
100102 check_for_isn_and_int8_passing_mismatch (& old_cluster );
101103
102104 /* old = PG 8.3 checks? */
@@ -924,6 +926,95 @@ check_for_reg_data_type_usage(ClusterInfo *cluster)
924926}
925927
926928
929+ /*
930+ * check_for_invalid_indexes()
931+ *
932+ * CREATE INDEX CONCURRENTLY can create invalid indexes if the index build
933+ * fails. These are dumped as valid indexes by pg_dump, but the
934+ * underlying files are still invalid indexes. This checks to make sure
935+ * no invalid indexes exist, either failed index builds or concurrent
936+ * indexes in the process of being created.
937+ */
938+ static void
939+ check_for_invalid_indexes (ClusterInfo * cluster )
940+ {
941+ int dbnum ;
942+ FILE * script = NULL ;
943+ bool found = false;
944+ char output_path [MAXPGPATH ];
945+
946+ prep_status ("Checking for invalid indexes from concurrent index builds" );
947+
948+ snprintf (output_path , sizeof (output_path ), "invalid_indexes.txt" );
949+
950+ for (dbnum = 0 ; dbnum < cluster -> dbarr .ndbs ; dbnum ++ )
951+ {
952+ PGresult * res ;
953+ bool db_used = false;
954+ int ntups ;
955+ int rowno ;
956+ int i_nspname ,
957+ i_relname ;
958+ DbInfo * active_db = & cluster -> dbarr .dbs [dbnum ];
959+ PGconn * conn = connectToServer (cluster , active_db -> db_name );
960+
961+ res = executeQueryOrDie (conn ,
962+ "SELECT n.nspname, c.relname "
963+ "FROM pg_catalog.pg_class c, "
964+ " pg_catalog.pg_namespace n, "
965+ " pg_catalog.pg_index i "
966+ "WHERE (i.indisvalid = false OR "
967+ " i.indisready = false) AND "
968+ " i.indexrelid = c.oid AND "
969+ " c.relnamespace = n.oid AND "
970+ /* we do not migrate these, so skip them */
971+ " n.nspname != 'pg_catalog' AND "
972+ " n.nspname != 'information_schema' AND "
973+ /* indexes do not have toast tables */
974+ " n.nspname != 'pg_toast'" );
975+
976+ ntups = PQntuples (res );
977+ i_nspname = PQfnumber (res , "nspname" );
978+ i_relname = PQfnumber (res , "relname" );
979+ for (rowno = 0 ; rowno < ntups ; rowno ++ )
980+ {
981+ found = true;
982+ if (script == NULL && (script = fopen_priv (output_path , "w" )) == NULL )
983+ pg_log (PG_FATAL , "Could not open file \"%s\": %s\n" ,
984+ output_path , getErrorText (errno ));
985+ if (!db_used )
986+ {
987+ fprintf (script , "Database: %s\n" , active_db -> db_name );
988+ db_used = true;
989+ }
990+ fprintf (script , " %s.%s\n" ,
991+ PQgetvalue (res , rowno , i_nspname ),
992+ PQgetvalue (res , rowno , i_relname ));
993+ }
994+
995+ PQclear (res );
996+
997+ PQfinish (conn );
998+ }
999+
1000+ if (script )
1001+ fclose (script );
1002+
1003+ if (found )
1004+ {
1005+ pg_log (PG_REPORT , "fatal\n" );
1006+ pg_log (PG_FATAL ,
1007+ "Your installation contains invalid indexes due to failed or\n"
1008+ "currently running CREATE INDEX CONCURRENTLY operations. You\n"
1009+ "cannot upgrade until these indexes are valid or removed. A\n"
1010+ "list of the problem indexes is in the file:\n"
1011+ " %s\n\n" , output_path );
1012+ }
1013+ else
1014+ check_ok ();
1015+ }
1016+
1017+
9271018static void
9281019get_bin_version (ClusterInfo * cluster )
9291020{
0 commit comments