aboutsummaryrefslogtreecommitdiff
path: root/doc/src/sgml/rules.sgml
blob: 236d3fc9cc6c2bc0757224419a82ac67fb0800c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
<Chapter>
<Title>The <ProductName>Postgres</ProductName> Rule System</Title>

<Para>
     Production  rule  systems  are conceptually simple, but
     there are many subtle points involved in actually using
     them.  Consequently, we will not attempt to explain the
     actual syntax and operation of the <ProductName>Postgres</ProductName> rule system
     here.  Instead, you should read 
[<XRef LinkEnd="STON90b" EndTerm="STON90b">] to understand
     some of these points and the theoretical foundations of
     the  <ProductName>Postgres</ProductName>  rule  system before trying to use rules.
     The discussion in this section is intended  to  provide
     an  overview  of the <ProductName>Postgres</ProductName> rule system and point the
     user at helpful references and examples.

     The "query rewrite" rule  system  modifies  queries  to
     take rules into consideration, and then passes the modified 
     query to the query optimizer for  execution.   It
     is  very powerful, and can be used for many things such
     as query language procedures, views, and versions.  The
     power  of  this  rule system is discussed in 
[<XRef LinkEnd="ONG90" EndTerm="ONG90">]
 as well as
[<XRef LinkEnd="STON90b" EndTerm="STON90b">].
</Para>

<Sect1>
<Title>The Goodness of Rules</Title>

<Note>
<title>Editor's Note</title>
<Para>
This information resulted from an exchange of e-mail on 1998-02-20/22 between
<ULink url="mailto:jwieck@debis.com">Jan Wieck</ULink>,
<ULink url="mailto:Andreas.Zeugswetter@telecom.at">Andreas Zeugswetter</ULink>,
and
<ULink url="mailto:vadim@sable.krasnoyarsk.su">Vadim B. Mikheev</ULink>
on the subject.
</Para>
</Note>

<Para>
<ProgramListing>
From: Zeugswetter Andreas SARZ
To: Jan Wieck
</ProgramListing>

<Para>
Since we have so little documentation on the rules, I think we should save
every 
little word describing them, so could you simply put the following into a
rules.readme 
(undigested is still better than not adding it)

<Sect1>
<Title>Rewrite Rules versus Triggers</Title>

<Para>
> > Why I like the rewrite system is:
The benefits of the rewrite rules system include:

<VariableList>
<VarListEntry>
<Term>
Select Rewrite Possible
</Term>
<ListItem>
<Para>
A select trigger would be no good, due to optimizer concerns.
 
<Para>
Exactly that's what is done if you create  a  view.  Postgres
creates  a  regular  table  (look  at  pg_class  and into the
database directory) and then sets up a relation level instead
rewrite rule on select.
</ListItem>
</VarListEntry>

<VarListEntry>
<Term>
Dumb Client Possible
</Term>
<ListItem>
<Para>
The client can be really dumb, like MS Access or some other
standard ODBC tool
which does not know anything about funcs procs and the like
(even without using passthrough).

<Para>
The  client  must not know why and how and where the
data is left and coming from. But that's true in any case - a
trigger  for each row on insert can do anything different and
push the data wherever it wants.
</ListItem>
</VarListEntry>

<VarListEntry>
<Term>
Rewrite rules are more powerful than views
</Term>
<ListItem>
<Para>
Views are only one special rule case in Postgres.
</ListItem>
</VarListEntry>

<VarListEntry>
<Term>
Optimizer Used
</Term>
<ListItem>
<Para>
It allows the optimizer to get involved (this is where triggers
fail per definition).
</ListItem>
</VarListEntry>

<VarListEntry>
<Term>
Simple to use
</Term>
<ListItem>
<Para>
Once understood it is very easy to use;
easier than triggers with <Acronym>C</Acronym> stored procedures at least.
</Para>
</ListItem>
</VarListEntry>
</VariableList>

<Para>
Optimizing again and again. If the rules aren't instead,  the
querytree  get's  additional queries for every rule appended.
Have a table field that references an entry in another  table
and  this entry should have a refcount. So on update you must
decrease the refcount from the old ref and increase it on the
new.   You  create  two  rules so the UPDATE will result in 1
scan and 2 nestloops with scans inside - really optimized  if
the  referenced value doesn't change.  And don't think that a
rule qual of NEW != CURRENT might help - that will result  in
2 mergejoins where the scanned tuples are compared.

<Note>
<Para>
I fought that like a windmill, I guess it would be better to kill the
CURRENT keyword
with this meaning alltogether, since it only has the same meaning as the
tablename itself.
I have already crossed it out of my mind and don't miss anything.
</Para>
</Note>

I think there should instead be an OLD and NEW keyword
like in triggers:
<ProgramListing>
referencing old as <replaceable class="parameter">oldname</replaceable> new as <replaceable class="parameter">newname</replaceable>
</ProgramListing>
that only reference the tuples in memory.

<Para>
BTW,  this  sample  doesn't  work currently because the rules
queries are appended at the end of the  querytree,  thus  the
decrement  scan  having  the  same qual will not find the old
tuple    at    all    because    it's    already     outdated
(command_counter_increment  between  processing the queries).
Referencing CURRENT in a rule is not what most  people  think
it is.

<Para>
The old 4.2 postgres had a second, instance level rule system
(prs2 stubs) that fired the rules actions when  actually  the
old  tuple and the new projected tuple where handy. There you
could have made also things like 'UPDATE NEW SET a = 4'  that
really   modified  the  in  memory  tuple  in  the  executors
expression context. Who the hell removed all that? It was  so
nice :-(

<Note>
<Title>Editor's Note</Title>
<Para>
This feature was removed by Jolly et. al. prior to v1.0.x.
</Para>
</Note>

<Para>
Absolutely !    I did cry up when that was done, but nobody responded :-(
Well to be honest Vadim did respond with the trigger code, which made me
feel comfortable again.

<Para>
A  really  simple to write trigger can compare old != new and
only if send down the other two queries. This time they  wont
be  nestloops,  they  are  simple  scans. And the trigger can
arrange that the queries it uses  are  only  parsed  on  it's
first  of  all  calls and store the generated execution plans
permanently for quick execution (look at SPI_prepare).

<Para>
For the stored C procedures you're  totally  right.  I  don't
like  the  C functions because it requires postgres superuser
rights to develop them and thus I created  PL/Tcl  where  joe
user  can  hack  around without having complete access to the
whole database (look at src/pl/tcl). And  someday  after  6.3
release  I'll really start on a plain PL/pgSQL implementation
that would give a  normal  user  the  opportunity  to  create
functions and triggers on a high level. There is light at the
end of the tunnel - hope that it isn't the coming train :-)

<Para>
I guess if triggers could also trigger simple select statements, I could
do
most of what I want using triggers except of course the select stuff.
But as I said I like the rules system very much, especially after your
recent
fixes Jan :-) So please stick to supporting all 3: triggers, views and
rules. Wow :-)

<Para>
Well - a trigger cannot build a view. The relation underlying
the view doesn't contain any tuples and a select trigger will
never be fired.  As long as there is no possibility to return
tuple  sets  from  non-SQL  functions.  But  a trigger can do
things like the pg_hide_passwd stuff much more powerful.  You
could  define  the trigger so that it checks if the user is a
superuser and overwrite the passwd value  only  in  the  case
where  he/she isn't. If fired at the right place it would too
work for things like the copy command etc.

<Para>
We must stay with all 3 features. And I will take a  look  at
the  INSERT  ...  SELECT  view problem really soon as it is a
rule system problem that breaks views. But this is  only  the
SELECT  rewriting part of the rule system which I really like
(optimizable). The other areas (insert,  update,  delete)  of
the  rule  system are dangerous and I really think a powerful
PL/pgSQL language could make them obsolete.

<Sect1>
<Title>Summary from Andreas</Title>

<Para>
Ok, to sum it up:

<ItemizedList Mark="bullet">
<ListItem>
<Para>
We need and want the select part of the rewrite rules.
</Para>
</ListItem>

<ListItem>
<Para>
For the insert/update/delete rules the old instance rules system
	    was much more appropriate. TODO: dig up the old code
	    and merge it with the current trigger Implementation;
		    it must be pretty much the wanted functionality (it
supported SQL).

<Note>
<Title>Vadim's Note</Title>
<Para>
Old instance rules system was removed by Jolly & Andrew and so
it never supported SQL. I hope that Jan will give us PL/pgSQL soon
and it will be used for triggers, without changing current trigger 
implementation...
</Para>
</Note>

</Para>
</ListItem>

<ListItem>
<Para>
The CURRENT keyword in the i/u/d rewrite rules is stupid
and should be disabled
		   destroyed and burned in hell.

<Note>
<Title>Vadim's Note</Title>
<Para>
Agreed, if standard hasn't it. I know that OLD & NEW are in standard,
for triggers atleast.
</Para>
</Note>

</Para>
</ListItem>

<ListItem>
<Para>
To stick to the mainstream we should enhance the trigger
syntax,
		    and forget the rule stuff for i/u/d
		
<ProgramListing>
		create trigger passwd_utr
		..........
		referencing old as o new as n
		  for each row (statement, statement, statement, procedure,
		...... all PL/pgSQL syntax allowed );
</ProgramListing>
with a syntax to modify the new tuple in memory.

<Note>
<Title>Vadim's Note</Title>
<Para>
Yes. Statement level triggers give the same functionality as rewrite 
i/u/d rules. We could let them to return something special to skip 
user' i/u/d itself, isn't it the same as INSTEAD ?
</Para>
</Note>

</Para>
</ListItem>
</ItemizedList>

</Chapter>