66 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
9- *$Id: analyze.c,v 1.168 2000/11/24 20:16:39 petere Exp $
9+ *$Id: analyze.c,v 1.169 2000/12/05 19:15:10 tgl Exp $
1010 *
1111 *-------------------------------------------------------------------------
1212 */
@@ -312,7 +312,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
312312 */
313313if (stmt -> selectStmt )
314314{
315- List * selectList ;
315+ ParseState * sub_pstate = make_parsestate ( pstate -> parentParseState ) ;
316316Query * selectQuery ;
317317RangeTblEntry * rte ;
318318RangeTblRef * rtr ;
@@ -324,11 +324,18 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
324324 * otherwise the behavior of SELECT within INSERT might be different
325325 * from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had
326326 * bugs of just that nature...)
327+ *
328+ * If a non-nil rangetable was passed in, pass it down to the SELECT.
329+ * This can only happen if we are inside a CREATE RULE, and in that
330+ * case we want the rule's OLD and NEW rtable entries to appear as
331+ * part of the SELECT's rtable, not as outer references for it.
327332 */
328- selectList = parse_analyze (stmt -> selectStmt ,pstate );
329- Assert (length (selectList )== 1 );
333+ sub_pstate -> p_rtable = pstate -> p_rtable ;
334+ pstate -> p_rtable = NIL ;
335+ selectQuery = transformStmt (sub_pstate ,stmt -> selectStmt );
336+ release_pstate_resources (sub_pstate );
337+ pfree (sub_pstate );
330338
331- selectQuery = (Query * )lfirst (selectList );
332339Assert (IsA (selectQuery ,Query ));
333340Assert (selectQuery -> commandType == CMD_SELECT );
334341if (selectQuery -> into || selectQuery -> isPortal )
@@ -1587,7 +1594,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
15871594foreach (actions ,stmt -> actions )
15881595{
15891596ParseState * sub_pstate = make_parsestate (pstate -> parentParseState );
1590- Query * sub_qry ;
1597+ Query * sub_qry ,
1598+ * top_subqry ;
15911599bool has_old ,
15921600has_new ;
15931601
@@ -1608,7 +1616,14 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
16081616newrte -> checkForRead = false;
16091617
16101618/* Transform the rule action statement */
1611- sub_qry = transformStmt (sub_pstate ,lfirst (actions ));
1619+ top_subqry = transformStmt (sub_pstate ,lfirst (actions ));
1620+
1621+ /*
1622+ * If the action is INSERT...SELECT, OLD/NEW have been pushed
1623+ * down into the SELECT, and that's what we need to look at.
1624+ * (Ugly kluge ... try to fix this when we redesign querytrees.)
1625+ */
1626+ sub_qry = getInsertSelectQuery (top_subqry ,NULL );
16121627
16131628/*
16141629 * Validate action's use of OLD/NEW, qual too
@@ -1648,15 +1663,28 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
16481663/*
16491664 * For efficiency's sake, add OLD to the rule action's jointree
16501665 * only if it was actually referenced in the statement or qual.
1651- * NEW is not really a relation and should never be added.
1666+ *
1667+ * For INSERT, NEW is not really a relation (only a reference to
1668+ * the to-be-inserted tuple) and should never be added to the
1669+ * jointree.
1670+ *
1671+ * For UPDATE, we treat NEW as being another kind of reference to
1672+ * OLD, because it represents references to *transformed* tuples
1673+ * of the existing relation. It would be wrong to enter NEW
1674+ * separately in the jointree, since that would cause a double
1675+ * join of the updated relation. It's also wrong to fail to make
1676+ * a jointree entry if only NEW and not OLD is mentioned.
16521677 */
1653- if (has_old )
1678+ if (has_old || ( has_new && stmt -> event == CMD_UPDATE ) )
16541679{
1680+ /* hack so we can use addRTEtoJoinList() */
1681+ sub_pstate -> p_rtable = sub_qry -> rtable ;
1682+ sub_pstate -> p_joinlist = sub_qry -> jointree -> fromlist ;
16551683addRTEtoJoinList (sub_pstate ,oldrte );
16561684sub_qry -> jointree -> fromlist = sub_pstate -> p_joinlist ;
16571685}
16581686
1659- lfirst (actions )= sub_qry ;
1687+ lfirst (actions )= top_subqry ;
16601688
16611689release_pstate_resources (sub_pstate );
16621690pfree (sub_pstate );