@@ -537,9 +537,12 @@ transientrel_destroy(DestReceiver *self)
537537/*
538538 * Given a qualified temporary table name, append an underscore followed by
539539 * the given integer, to make a new table name based on the old one.
540+ * The result is a palloc'd string.
540541 *
541- * This leaks memory through palloc(), which won't be cleaned up until the
542- * current memory context is freed.
542+ * As coded, this would fail to make a valid SQL name if the given name were,
543+ * say, "FOO"."BAR". Currently, the table name portion of the input will
544+ * never be double-quoted because it's of the form "pg_temp_NNN", cf
545+ * make_new_heap(). But we might have to work harder someday.
543546 */
544547static char *
545548make_temptable_name_n (char * tempname , int n )
@@ -627,16 +630,20 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
627630 * that in a way that allows showing the first duplicated row found. Even
628631 * after we pass this test, a unique index on the materialized view may
629632 * find a duplicate key problem.
633+ *
634+ * Note: here and below, we use "tablename.*::tablerowtype" as a hack to
635+ * keep ".*" from being expanded into multiple columns in a SELECT list.
636+ * Compare ruleutils.c's get_variable().
630637 */
631638 resetStringInfo (& querybuf );
632639 appendStringInfo (& querybuf ,
633- "SELECT _$ newdata FROM %s _$ newdata "
634- "WHERE _$ newdata IS NOT NULL AND EXISTS "
635- "(SELECT 1 FROM %s _$ newdata2 WHERE _$ newdata2 IS NOT NULL "
636- "AND _$ newdata2 OPERATOR(pg_catalog.*=) _$ newdata "
637- "AND _$ newdata2.ctid OPERATOR(pg_catalog.<>) "
638- "_$ newdata.ctid)" ,
639- tempname , tempname );
640+ "SELECT newdata.*::%s FROM %s newdata "
641+ "WHERE newdata.* IS NOT NULL AND EXISTS "
642+ "(SELECT 1 FROM %s newdata2 WHERE newdata2.* IS NOT NULL "
643+ "AND newdata2.* OPERATOR(pg_catalog.*=) newdata.* "
644+ "AND newdata2.ctid OPERATOR(pg_catalog.<>) "
645+ "newdata.ctid)" ,
646+ tempname , tempname , tempname );
640647 if (SPI_execute (querybuf .data , false, 1 ) != SPI_OK_SELECT )
641648 elog (ERROR , "SPI_exec failed: %s" , querybuf .data );
642649 if (SPI_processed > 0 )
@@ -663,9 +670,9 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
663670 resetStringInfo (& querybuf );
664671 appendStringInfo (& querybuf ,
665672 "CREATE TEMP TABLE %s AS "
666- "SELECT _$ mv.ctid AS tid, _$ newdata "
667- "FROM %s _$ mv FULL JOIN %s _$ newdata ON (" ,
668- diffname , matviewname , tempname );
673+ "SELECT mv.ctid AS tid, newdata.*::%s AS newdata "
674+ "FROM %s mv FULL JOIN %s newdata ON (" ,
675+ diffname , tempname , matviewname , tempname );
669676
670677 /*
671678 * Get the list of index OIDs for the table from the relcache, and look up
@@ -757,9 +764,9 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
757764 if (foundUniqueIndex )
758765 appendStringInfoString (& querybuf , " AND " );
759766
760- leftop = quote_qualified_identifier ("_$ newdata" ,
767+ leftop = quote_qualified_identifier ("newdata" ,
761768 NameStr (attr -> attname ));
762- rightop = quote_qualified_identifier ("_$ mv" ,
769+ rightop = quote_qualified_identifier ("mv" ,
763770 NameStr (attr -> attname ));
764771
765772 generate_operator_clause (& querybuf ,
@@ -787,8 +794,8 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
787794 Assert (foundUniqueIndex );
788795
789796 appendStringInfoString (& querybuf ,
790- " AND _$ newdata OPERATOR(pg_catalog.*=) _$mv ) "
791- "WHERE _$ newdata IS NULL OR _$mv IS NULL "
797+ " AND newdata.* OPERATOR(pg_catalog.*=) mv.* ) "
798+ "WHERE newdata.* IS NULL OR mv.* IS NULL "
792799 "ORDER BY tid" );
793800
794801 /* Create the temporary "diff" table. */
@@ -814,19 +821,19 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
814821 /* Deletes must come before inserts; do them first. */
815822 resetStringInfo (& querybuf );
816823 appendStringInfo (& querybuf ,
817- "DELETE FROM %s _$ mv WHERE ctid OPERATOR(pg_catalog.=) ANY "
818- "(SELECT _$ diff.tid FROM %s _$ diff "
819- "WHERE _$ diff.tid IS NOT NULL "
820- "AND _$ diff._$ newdata IS NULL)" ,
824+ "DELETE FROM %s mv WHERE ctid OPERATOR(pg_catalog.=) ANY "
825+ "(SELECT diff.tid FROM %s diff "
826+ "WHERE diff.tid IS NOT NULL "
827+ "AND diff.newdata IS NULL)" ,
821828 matviewname , diffname );
822829 if (SPI_exec (querybuf .data , 0 ) != SPI_OK_DELETE )
823830 elog (ERROR , "SPI_exec failed: %s" , querybuf .data );
824831
825832 /* Inserts go last. */
826833 resetStringInfo (& querybuf );
827834 appendStringInfo (& querybuf ,
828- "INSERT INTO %s SELECT (_$ diff._$ newdata).* "
829- "FROM %s _$ diff WHERE tid IS NULL" ,
835+ "INSERT INTO %s SELECT (diff.newdata).* "
836+ "FROM %s diff WHERE tid IS NULL" ,
830837 matviewname , diffname );
831838 if (SPI_exec (querybuf .data , 0 ) != SPI_OK_INSERT )
832839 elog (ERROR , "SPI_exec failed: %s" , querybuf .data );
0 commit comments