diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 348f620..d479276 100644
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
*************** get_target_list(List *targetList, depars
*** 4610,4615 ****
--- 4610,4652 ----
  		appendStringInfoString(buf, targetbuf.data);
  	}
  
+ 	/*
+ 	 * An empty targetlist (or RETURNING list) is syntactically impossible,
+ 	 * but we might nonetheless find no elements in the list, as a result of
+ 	 * constructs such as "SELECT * FROM zero_column_table".  You might think
+ 	 * we could just print a star and be done, but that fails in cases like
+ 	 * "SELECT z.* FROM zero_column_table z, normal_table".  So, dig through
+ 	 * the namespace lists looking for a zero-column RTE and use its alias;
+ 	 * this is valid even if the original syntax was just "*".
+ 	 */
+ 	if (colno == 0)
+ 	{
+ 		foreach(l, context->namespaces)
+ 		{
+ 			deparse_namespace *dpns = (deparse_namespace *) lfirst(l);
+ 			ListCell   *ln,
+ 					   *lc;
+ 
+ 			forboth(ln, dpns->rtable_names, lc, dpns->rtable_columns)
+ 			{
+ 				char	   *refname = (char *) lfirst(ln);
+ 				deparse_columns *colinfo = (deparse_columns *) lfirst(lc);
+ 
+ 				if (refname && colinfo->num_cols == 0)
+ 				{
+ 					appendStringInfo(buf, " %s.*", quote_identifier(refname));
+ 					colno++;
+ 					break;
+ 				}
+ 			}
+ 			if (colno)
+ 				break;
+ 		}
+ 		/* If we didn't find a suitable RTE, just print a star. */
+ 		if (colno == 0)
+ 			appendStringInfoString(buf, " *");
+ 	}
+ 
  	/* clean up */
  	pfree(targetbuf.data);
  }
