|
7 | 7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | 8 | * |
9 | 9 | * IDENTIFICATION |
10 | | - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.131 2003/11/29 19:51:55 pgsql Exp $ |
| 10 | + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.132 2004/01/14 03:39:22 tgl Exp $ |
11 | 11 | * |
12 | 12 | *------------------------------------------------------------------------- |
13 | 13 | */ |
@@ -70,11 +70,9 @@ rewriteRuleAction(Query *parsetree, |
70 | 70 | { |
71 | 71 | intcurrent_varno, |
72 | 72 | new_varno; |
73 | | -List*main_rtable; |
74 | 73 | intrt_length; |
75 | 74 | Query*sub_action; |
76 | 75 | Query**sub_action_ptr; |
77 | | -List*rt; |
78 | 76 |
|
79 | 77 | /* |
80 | 78 | * Make modifiable copies of rule action and qual (what we're passed |
@@ -109,32 +107,32 @@ rewriteRuleAction(Query *parsetree, |
109 | 107 | * Generate expanded rtable consisting of main parsetree's rtable plus |
110 | 108 | * rule action's rtable; this becomes the complete rtable for the rule |
111 | 109 | * action.Some of the entries may be unused after we finish |
112 | | - * rewriting, but if we tried to remove them we'd have a much harder |
113 | | - * job to adjust RT indexes in the query's Vars. It's OK to have |
114 | | - * unused RT entries, since planner will ignore them. |
| 110 | + * rewriting, but we leave them all in place for two reasons: |
| 111 | + * |
| 112 | + ** We'd have a much harder job to adjust the query's varnos |
| 113 | + * if we selectively removed RT entries. |
| 114 | + * |
| 115 | + ** If the rule is INSTEAD, then the original query won't be |
| 116 | + * executed at all, and so its rtable must be preserved so that |
| 117 | + * the executor will do the correct permissions checks on it. |
| 118 | + * |
| 119 | + * RT entries that are not referenced in the completed jointree will be |
| 120 | + * ignored by the planner, so they do not affect query semantics. But |
| 121 | + * any permissions checks specified in them will be applied during |
| 122 | + * executor startup (see ExecCheckRTEPerms()). This allows us to check |
| 123 | + * that the caller has, say, insert-permission on a view, when the view |
| 124 | + * is not semantically referenced at all in the resulting query. |
| 125 | + * |
| 126 | + * When a rule is not INSTEAD, the permissions checks done on its copied |
| 127 | + * RT entries will be redundant with those done during execution of the |
| 128 | + * original query, but we don't bother to treat that case differently. |
115 | 129 | * |
116 | 130 | * NOTE: because planner will destructively alter rtable, we must ensure |
117 | 131 | * that rule action's rtable is separate and shares no substructure |
118 | 132 | * with the main rtable. Hence do a deep copy here. |
119 | | - * |
120 | | - * Also, we must disable write-access checking in all the RT entries |
121 | | - * copied from the main query.This is safe since in fact the rule |
122 | | - * action won't write on them, and it's necessary because the rule |
123 | | - * action may have a different commandType than the main query, |
124 | | - * causing ExecCheckRTEPerms() to make an inappropriate check.The |
125 | | - * read-access checks can be left enabled, although they're probably |
126 | | - * redundant. |
127 | 133 | */ |
128 | | -main_rtable= (List*)copyObject(parsetree->rtable); |
129 | | - |
130 | | -foreach(rt,main_rtable) |
131 | | -{ |
132 | | -RangeTblEntry*rte= (RangeTblEntry*)lfirst(rt); |
133 | | - |
134 | | -rte->checkForWrite= false; |
135 | | -} |
136 | | - |
137 | | -sub_action->rtable=nconc(main_rtable,sub_action->rtable); |
| 134 | +sub_action->rtable=nconc((List*)copyObject(parsetree->rtable), |
| 135 | +sub_action->rtable); |
138 | 136 |
|
139 | 137 | /* |
140 | 138 | * Each rule action's jointree should be the main parsetree's jointree |
|