66 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
9- *$Id: analyze.c,v 1.178 2001/01/27 07:23:48 tgl Exp $
9+ *$Id: analyze.c,v 1.179 2001/02/14 21:35:01 tgl Exp $
1010 *
1111 *-------------------------------------------------------------------------
1212 */
@@ -257,11 +257,10 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
257257
258258qry -> commandType = CMD_DELETE ;
259259
260- /* set up a range table */
261- lockTargetTable (pstate ,stmt -> relname );
262- makeRangeTable (pstate ,NIL );
263- setTargetTable (pstate ,stmt -> relname ,
264- interpretInhOption (stmt -> inhOpt ), true);
260+ /* set up range table with just the result rel */
261+ qry -> resultRelation = setTargetTable (pstate ,stmt -> relname ,
262+ interpretInhOption (stmt -> inhOpt ),
263+ true);
265264
266265qry -> distinctClause = NIL ;
267266
@@ -271,7 +270,6 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
271270/* done building the range table and jointree */
272271qry -> rtable = pstate -> p_rtable ;
273272qry -> jointree = makeFromExpr (pstate -> p_joinlist ,qual );
274- qry -> resultRelation = refnameRangeTablePosn (pstate ,stmt -> relname ,NULL );
275273
276274qry -> hasSubLinks = pstate -> p_hasSubLinks ;
277275qry -> hasAggs = pstate -> p_hasAggs ;
@@ -289,6 +287,8 @@ static Query *
289287transformInsertStmt (ParseState * pstate ,InsertStmt * stmt )
290288{
291289Query * qry = makeNode (Query );
290+ List * sub_rtable ;
291+ List * sub_namespace ;
292292List * icolumns ;
293293List * attrnos ;
294294List * attnos ;
@@ -300,11 +300,35 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
300300pstate -> p_is_insert = true;
301301
302302/*
303- * Must get write lock on target table before scanning SELECT,
303+ * If a non-nil rangetable/namespace was passed in, and we are doing
304+ * INSERT/SELECT, arrange to pass the rangetable/namespace down to the
305+ * SELECT. This can only happen if we are inside a CREATE RULE,
306+ * and in that case we want the rule's OLD and NEW rtable entries to
307+ * appear as part of the SELECT's rtable, not as outer references for
308+ * it. (Kluge!) The SELECT's joinlist is not affected however.
309+ * We must do this before adding the target table to the INSERT's rtable.
310+ */
311+ if (stmt -> selectStmt )
312+ {
313+ sub_rtable = pstate -> p_rtable ;
314+ pstate -> p_rtable = NIL ;
315+ sub_namespace = pstate -> p_namespace ;
316+ pstate -> p_namespace = NIL ;
317+ }
318+ else
319+ {
320+ sub_rtable = NIL ;/* not used, but keep compiler quiet */
321+ sub_namespace = NIL ;
322+ }
323+
324+ /*
325+ * Must get write lock on INSERT target table before scanning SELECT,
304326 * else we will grab the wrong kind of initial lock if the target
305- * table is also mentioned in the SELECT part.
327+ * table is also mentioned in the SELECT part. Note that the target
328+ * table is not added to the joinlist or namespace.
306329 */
307- lockTargetTable (pstate ,stmt -> relname );
330+ qry -> resultRelation = setTargetTable (pstate ,stmt -> relname ,
331+ false, false);
308332
309333/*
310334 * Is it INSERT ... SELECT or INSERT ... VALUES?
@@ -323,15 +347,12 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
323347 * otherwise the behavior of SELECT within INSERT might be different
324348 * from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had
325349 * bugs of just that nature...)
326- *
327- * If a non-nil rangetable was passed in, pass it down to the SELECT.
328- * This can only happen if we are inside a CREATE RULE, and in that
329- * case we want the rule's OLD and NEW rtable entries to appear as
330- * part of the SELECT's rtable, not as outer references for it.
331350 */
332- sub_pstate -> p_rtable = pstate -> p_rtable ;
333- pstate -> p_rtable = NIL ;
351+ sub_pstate -> p_rtable = sub_rtable ;
352+ sub_pstate -> p_namespace = sub_namespace ;
353+
334354selectQuery = transformStmt (sub_pstate ,stmt -> selectStmt );
355+
335356release_pstate_resources (sub_pstate );
336357pfree (sub_pstate );
337358
@@ -341,7 +362,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
341362elog (ERROR ,"INSERT ... SELECT may not specify INTO" );
342363/*
343364 * Make the source be a subquery in the INSERT's rangetable,
344- * and add it to the joinlist.
365+ * and add it to theINSERT's joinlist.
345366 */
346367rte = addRangeTableEntryForSubquery (pstate ,
347368selectQuery ,
@@ -400,13 +421,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
400421/*
401422 * Now we are done with SELECT-like processing, and can get on with
402423 * transforming the target list to match the INSERT target columns.
403- *
404- * In particular, it's time to add the INSERT target to the rangetable.
405- * (We didn't want it there until now since it shouldn't be visible in
406- * the SELECT part.) Note that the INSERT target is NOT added to the
407- * joinlist, since we don't want to join over it.
408424 */
409- setTargetTable (pstate ,stmt -> relname , false, false);
410425
411426/* Prepare to assign non-conflicting resnos to resjunk attributes */
412427if (pstate -> p_last_resno <=pstate -> p_target_relation -> rd_rel -> relnatts )
@@ -495,7 +510,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
495510/* done building the range table and jointree */
496511qry -> rtable = pstate -> p_rtable ;
497512qry -> jointree = makeFromExpr (pstate -> p_joinlist ,NULL );
498- qry -> resultRelation = refnameRangeTablePosn (pstate ,stmt -> relname ,NULL );
499513
500514qry -> hasSubLinks = pstate -> p_hasSubLinks ;
501515qry -> hasAggs = pstate -> p_hasAggs ;
@@ -1565,27 +1579,27 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
15651579oldrte -> checkForRead = false;
15661580newrte -> checkForRead = false;
15671581/*
1568- * They must be in thejoinlist too for lookup purposes, but only add
1582+ * They must be in thenamespace too for lookup purposes, but only add
15691583 * the one(s) that are relevant for the current kind of rule. In an
15701584 * UPDATE rule, quals must refer to OLD.field or NEW.field to be
15711585 * unambiguous, but there's no need to be so picky for INSERT & DELETE.
15721586 * (Note we marked the RTEs "inFromCl = true" above to allow unqualified
1573- * references to their fields.)
1587+ * references to their fields.) We do not add them to the joinlist.
15741588 */
15751589switch (stmt -> event )
15761590{
15771591case CMD_SELECT :
1578- addRTEtoJoinList (pstate ,oldrte );
1592+ addRTEtoQuery (pstate ,oldrte , false, true );
15791593break ;
15801594case CMD_UPDATE :
1581- addRTEtoJoinList (pstate ,oldrte );
1582- addRTEtoJoinList (pstate ,newrte );
1595+ addRTEtoQuery (pstate ,oldrte , false, true );
1596+ addRTEtoQuery (pstate ,newrte , false, true );
15831597break ;
15841598case CMD_INSERT :
1585- addRTEtoJoinList (pstate ,newrte );
1599+ addRTEtoQuery (pstate ,newrte , false, true );
15861600break ;
15871601case CMD_DELETE :
1588- addRTEtoJoinList (pstate ,oldrte );
1602+ addRTEtoQuery (pstate ,oldrte , false, true );
15891603break ;
15901604default :
15911605elog (ERROR ,"transformRuleStmt: unexpected event type %d" ,
@@ -1638,8 +1652,9 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
16381652 * Set up OLD/NEW in the rtable for this statement. The entries
16391653 * are marked not inFromCl because we don't want them to be
16401654 * referred to by unqualified field names nor "*" in the rule
1641- * actions. We don't need to add them to the joinlist for
1642- * qualified-name lookup, either (see qualifiedNameToVar()).
1655+ * actions. We must add them to the namespace, however, or they
1656+ * won't be accessible at all. We decide later whether to put
1657+ * them in the joinlist.
16431658 */
16441659oldrte = addRangeTableEntry (sub_pstate ,stmt -> object -> relname ,
16451660makeAttr ("*OLD*" ,NULL ),
@@ -1649,6 +1664,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
16491664false, false);
16501665oldrte -> checkForRead = false;
16511666newrte -> checkForRead = false;
1667+ addRTEtoQuery (sub_pstate ,oldrte , false, true);
1668+ addRTEtoQuery (sub_pstate ,newrte , false, true);
16521669
16531670/* Transform the rule action statement */
16541671top_subqry = transformStmt (sub_pstate ,lfirst (actions ));
@@ -1712,10 +1729,10 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
17121729 */
17131730if (has_old || (has_new && stmt -> event == CMD_UPDATE ))
17141731{
1715- /* hack so we can useaddRTEtoJoinList () */
1732+ /* hack so we can useaddRTEtoQuery () */
17161733sub_pstate -> p_rtable = sub_qry -> rtable ;
17171734sub_pstate -> p_joinlist = sub_qry -> jointree -> fromlist ;
1718- addRTEtoJoinList (sub_pstate ,oldrte );
1735+ addRTEtoQuery (sub_pstate ,oldrte , true, false );
17191736sub_qry -> jointree -> fromlist = sub_pstate -> p_joinlist ;
17201737}
17211738
@@ -1779,8 +1796,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
17791796/* make FOR UPDATE clause available to addRangeTableEntry */
17801797pstate -> p_forUpdate = stmt -> forUpdate ;
17811798
1782- /*set up a range table */
1783- makeRangeTable (pstate ,stmt -> fromClause );
1799+ /*process the FROM clause */
1800+ transformFromClause (pstate ,stmt -> fromClause );
17841801
17851802/* transform targetlist and WHERE */
17861803qry -> targetList = transformTargetList (pstate ,stmt -> targetList );
@@ -2055,24 +2072,20 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
20552072if (isLeaf )
20562073{
20572074/* Process leaf SELECT */
2058- List * save_rtable ;
20592075List * selectList ;
20602076Query * selectQuery ;
20612077char selectName [32 ];
20622078RangeTblEntry * rte ;
20632079RangeTblRef * rtr ;
20642080
20652081/*
2066- * Transform SelectStmt into a Query. We do not want any previously
2067- * transformed leaf queries to be visible in the outer context of
2068- *this sub-query, so temporarily make thetop-level pstate have an
2069- *empty rtable. (We needn't do the same with thejoinlist because
2070- *we aren't entering anything in the top-level joinlist.)
2082+ * Transform SelectStmt into a Query.
2083+ *
2084+ *Note: previously transformed sub-queries don't affect theparsing
2085+ *of this sub-query, because they are not in thetoplevel pstate's
2086+ *namespace list.
20712087 */
2072- save_rtable = pstate -> p_rtable ;
2073- pstate -> p_rtable = NIL ;
20742088selectList = parse_analyze ((Node * )stmt ,pstate );
2075- pstate -> p_rtable = save_rtable ;
20762089
20772090Assert (length (selectList )== 1 );
20782091selectQuery = (Query * )lfirst (selectList );
@@ -2202,27 +2215,22 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
22022215qry -> commandType = CMD_UPDATE ;
22032216pstate -> p_is_update = true;
22042217
2218+ qry -> resultRelation = setTargetTable (pstate ,stmt -> relname ,
2219+ interpretInhOption (stmt -> inhOpt ),
2220+ true);
2221+
22052222/*
22062223 * the FROM clause is non-standard SQL syntax. We used to be able to
22072224 * do this with REPLACE in POSTQUEL so we keep the feature.
2208- *
2209- * Note: it's critical here that we process FROM before adding the
2210- * target table to the rtable --- otherwise, if the target is also
2211- * used in FROM, we'd fail to notice that it should be marked
2212- * checkForRead as well as checkForWrite. See setTargetTable().
22132225 */
2214- lockTargetTable (pstate ,stmt -> relname );
2215- makeRangeTable (pstate ,stmt -> fromClause );
2216- setTargetTable (pstate ,stmt -> relname ,
2217- interpretInhOption (stmt -> inhOpt ), true);
2226+ transformFromClause (pstate ,stmt -> fromClause );
22182227
22192228qry -> targetList = transformTargetList (pstate ,stmt -> targetList );
22202229
22212230qual = transformWhereClause (pstate ,stmt -> whereClause );
22222231
22232232qry -> rtable = pstate -> p_rtable ;
22242233qry -> jointree = makeFromExpr (pstate -> p_joinlist ,qual );
2225- qry -> resultRelation = refnameRangeTablePosn (pstate ,stmt -> relname ,NULL );
22262234
22272235qry -> hasSubLinks = pstate -> p_hasSubLinks ;
22282236qry -> hasAggs = pstate -> p_hasAggs ;