@@ -119,6 +119,7 @@ static void resolve_index_tablepaces(TablespaceInfo *tbsp_info,
119119static void perform_initial_load (Relation rel_src , RangeVar * cluster_idx_rv ,
120120 Snapshot snap_hist , Relation rel_dst ,
121121 LogicalDecodingContext * ctx );
122+ static bool has_dropped_attribute (Relation rel );
122123static Oid create_transient_table (CatalogState * cat_state , TupleDesc tup_desc ,
123124 Oid tablespace , Oid relowner );
124125static Oid * build_transient_indexes (Relation rel_dst , Relation rel_src ,
@@ -896,6 +897,13 @@ check_prerequisites(Relation rel)
896897{
897898 Form_pg_class form = RelationGetForm (rel );
898899
900+ /*
901+ * The extension is not generic enough to handle AMs other than "heap".
902+ */
903+ if (form -> relam != HEAP_TABLE_AM_OID )
904+ ereport (ERROR ,
905+ (errmsg ("pg_squeeze only supports the \"heap\" access method" )));
906+
899907 /* Check the relation first. */
900908 if (form -> relkind == RELKIND_PARTITIONED_TABLE )
901909 ereport (ERROR ,
@@ -1970,6 +1978,10 @@ perform_initial_load(Relation rel_src, RangeVar *cluster_idx_rv,
19701978 old_cxt ;
19711979 XLogRecPtr end_of_wal_prev = InvalidXLogRecPtr ;
19721980 DecodingOutputState * dstate ;
1981+ bool has_dropped_attr ;
1982+ Datum values [MaxTupleAttributeNumber ];
1983+ bool isnull [MaxTupleAttributeNumber ];
1984+
19731985
19741986 /*
19751987 * Also remember that the WAL records created during the load should not
@@ -2058,6 +2070,9 @@ perform_initial_load(Relation rel_src, RangeVar *cluster_idx_rv,
20582070 /* Expect many insertions. */
20592071 bistate = GetBulkInsertState ();
20602072
2073+ /* Has the relation at least one dropped attribute? */
2074+ has_dropped_attr = has_dropped_attribute (rel_src );
2075+
20612076 /*
20622077 * The processing can take many iterations. In case any data manipulation
20632078 * below leaked, try to defend against out-of-memory conditions by using a
@@ -2078,7 +2093,7 @@ perform_initial_load(Relation rel_src, RangeVar *cluster_idx_rv,
20782093 /* Sorting cannot be split into batches. */
20792094 for (i = 0 ;; i ++ )
20802095 {
2081- bool flattened = false;
2096+ bool have_tup_copy = false;
20822097
20832098 /*
20842099 * While tuplesort is responsible for not exceeding
@@ -2150,15 +2165,43 @@ perform_initial_load(Relation rel_src, RangeVar *cluster_idx_rv,
21502165 {
21512166 tup_in = toast_flatten_tuple (tup_in ,
21522167 RelationGetDescr (rel_src ));
2153- flattened = true;
2168+ have_tup_copy = true;
2169+ }
2170+
2171+ /*
2172+ * If at least one attribute has been dropped, we need to deform /
2173+ * form the tuple to make sure that set the values of the dropped
2174+ * attribute(s) are NULL. (Unfortunately we don't know if the
2175+ * table was already squeezed since the last ALTER TABLE ... DROP
2176+ * COLUMN ... command.)
2177+ */
2178+ if (has_dropped_attr )
2179+ {
2180+ HeapTuple tup_orig = tup_in ;
2181+ TupleDesc tup_desc = RelationGetDescr (rel_src );
2182+ int i ;
2183+
2184+ heap_deform_tuple (tup_in , tup_desc , values , isnull );
2185+
2186+ for (i = 0 ; i < tup_desc -> natts ; i ++ )
2187+ {
2188+ if (TupleDescAttr (tup_desc , i )-> attisdropped )
2189+ isnull [i ] = true;
2190+ }
2191+
2192+ tup_in = heap_form_tuple (tup_desc , values , isnull );
2193+ if (have_tup_copy )
2194+ /* tup_in is a flat copy. We do not want two copies. */
2195+ heap_freetuple (tup_orig );
2196+ have_tup_copy = true;
21542197 }
21552198
21562199 if (use_sort )
21572200 {
21582201 tuplesort_putheaptuple (tuplesort , tup_in );
21592202 /* tuplesort should have copied the tuple. */
2160- if (flattened )
2161- pfree (tup_in );
2203+ if (have_tup_copy )
2204+ heap_freetuple (tup_in );
21622205 }
21632206 else
21642207 {
@@ -2204,7 +2247,7 @@ perform_initial_load(Relation rel_src, RangeVar *cluster_idx_rv,
22042247 }
22052248 }
22062249
2207- if (!flattened )
2250+ if (!have_tup_copy )
22082251 tup_in = heap_copytuple (tup_in );
22092252
22102253 /*
@@ -2366,6 +2409,24 @@ perform_initial_load(Relation rel_src, RangeVar *cluster_idx_rv,
23662409 elog (DEBUG1 , "pg_squeeze: the initial load completed" );
23672410}
23682411
2412+ /*
2413+ * Check if relation has at least one dropped attribute.
2414+ */
2415+ static bool
2416+ has_dropped_attribute (Relation rel )
2417+ {
2418+ TupleDesc tup_desc = RelationGetDescr (rel );
2419+
2420+ for (int i = 0 ; i < tup_desc -> natts ; i ++ )
2421+ {
2422+ Form_pg_attribute attr = & tup_desc -> attrs [i ];
2423+
2424+ if (attr -> attisdropped )
2425+ return true;
2426+ }
2427+
2428+ return false;
2429+ }
23692430
23702431/*
23712432 * Create a table into which we'll copy the contents of the source table, as
0 commit comments