1
- <!-- $Header: /cvsroot/pgsql/doc/src/sgml/rules.sgml,v 1.24 2002/09/21 18:32:53 petere Exp $ -->
1
+ <!-- $Header: /cvsroot/pgsql/doc/src/sgml/rules.sgml,v 1.25 2002/10/14 22:14:34 tgl Exp $ -->
2
2
3
3
<Chapter Id="rules">
4
4
<Title>The Rule System</Title>
189
189
In INSERT queries the target list describes the new rows that
190
190
should go into the result relation. It is the expressions in the VALUES
191
191
clause or the ones from the SELECT clause in INSERT ... SELECT.
192
- Missing columns of the result relation will be filled in by the
192
+ The first step of the rewrite process adds target list entries
193
+ for any columns that were not assigned to by the original query
194
+ and have defaults. Any remaining columns (with neither a given
195
+ value nor a default) will be filled in by the
193
196
planner with a constant NULL expression.
194
197
</Para>
195
198
196
199
<Para>
197
200
In UPDATE queries, the target list describes the new rows that should
198
201
replace the old ones. In the rule system, it contains just the
199
202
expressions from the SET attribute = expression part of the query.
200
- The planner will add missing columns by inserting expressions that
203
+ The planner will handle missing columns by inserting expressions that
201
204
copy the values from the old row into the new one. And it will add
202
205
the special <acronym>CTID</> entry just as for DELETE too.
203
206
</Para>
278
281
279
282
<Para>
280
283
Views in <ProductName>PostgreSQL</ProductName> are implemented
281
- using the rule system. In fact there is absolutely no difference
282
- between a
284
+ using the rule system. In fact there is essentially no difference
285
+ between
283
286
284
287
<ProgramListing>
285
288
CREATE VIEW myview AS SELECT * FROM mytab;
@@ -1133,7 +1136,7 @@ int4ne(NEW.sl_avail, OLD.sl_avail)
1133
1136
<ProgramListing>
1134
1137
INSERT INTO shoelace_log VALUES(
1135
1138
*NEW*.sl_name, *NEW*.sl_avail,
1136
- current_user, current_timestamp
1139
+ current_user, current_timestamp)
1137
1140
FROM shoelace_data *NEW*, shoelace_data *OLD*;
1138
1141
</ProgramListing>
1139
1142
@@ -1153,7 +1156,7 @@ INSERT INTO shoelace_log VALUES(
1153
1156
<ProgramListing>
1154
1157
INSERT INTO shoelace_log VALUES(
1155
1158
*NEW*.sl_name, *NEW*.sl_avail,
1156
- current_user, current_timestamp
1159
+ current_user, current_timestamp)
1157
1160
FROM shoelace_data *NEW*, shoelace_data *OLD*,
1158
1161
<emphasis>shoelace_data shoelace_data</emphasis>;
1159
1162
</ProgramListing>
@@ -1164,7 +1167,7 @@ INSERT INTO shoelace_log VALUES(
1164
1167
<ProgramListing>
1165
1168
INSERT INTO shoelace_log VALUES(
1166
1169
*NEW*.sl_name, *NEW*.sl_avail,
1167
- current_user, current_timestamp
1170
+ current_user, current_timestamp)
1168
1171
FROM shoelace_data *NEW*, shoelace_data *OLD*,
1169
1172
shoelace_data shoelace_data
1170
1173
<emphasis>WHERE int4ne(*NEW*.sl_avail, *OLD*.sl_avail)</emphasis>;
@@ -1174,29 +1177,31 @@ INSERT INTO shoelace_log VALUES(
1174
1177
a WHERE clause either, but the planner and executor will have no
1175
1178
difficulty with it. They need to support this same functionality
1176
1179
anyway for INSERT ... SELECT.
1180
+ </para>
1177
1181
1182
+ <para>
1178
1183
In step 3 the original parse tree's qualification is added,
1179
1184
restricting the result set further to only the rows touched
1180
1185
by the original parse tree.
1181
1186
1182
1187
<ProgramListing>
1183
1188
INSERT INTO shoelace_log VALUES(
1184
1189
*NEW*.sl_name, *NEW*.sl_avail,
1185
- current_user, current_timestamp
1190
+ current_user, current_timestamp)
1186
1191
FROM shoelace_data *NEW*, shoelace_data *OLD*,
1187
1192
shoelace_data shoelace_data
1188
1193
WHERE int4ne(*NEW*.sl_avail, *OLD*.sl_avail)
1189
1194
<emphasis>AND bpchareq(shoelace_data.sl_name, 'sl7')</emphasis>;
1190
1195
</ProgramListing>
1191
1196
1192
- Step 4 substitutes NEW references by the target list entries from the
1193
- original parse tree or with the matching variable references
1197
+ Step 4 replaces NEW references by the target list entries from the
1198
+ original parse tree or by the matching variable references
1194
1199
from the result relation.
1195
1200
1196
1201
<ProgramListing>
1197
1202
INSERT INTO shoelace_log VALUES(
1198
1203
<emphasis>shoelace_data.sl_name</emphasis>, <emphasis>6</emphasis>,
1199
- current_user, current_timestamp
1204
+ current_user, current_timestamp)
1200
1205
FROM shoelace_data *NEW*, shoelace_data *OLD*,
1201
1206
shoelace_data shoelace_data
1202
1207
WHERE int4ne(<emphasis>6</emphasis>, *OLD*.sl_avail)
@@ -1208,7 +1213,7 @@ INSERT INTO shoelace_log VALUES(
1208
1213
<ProgramListing>
1209
1214
INSERT INTO shoelace_log VALUES(
1210
1215
shoelace_data.sl_name, 6,
1211
- current_user, current_timestamp
1216
+ current_user, current_timestamp)
1212
1217
FROM shoelace_data *NEW*, shoelace_data *OLD*,
1213
1218
shoelace_data shoelace_data
1214
1219
WHERE int4ne(6, <emphasis>shoelace_data.sl_avail</emphasis>)
@@ -1222,7 +1227,7 @@ INSERT INTO shoelace_log VALUES(
1222
1227
<ProgramListing>
1223
1228
INSERT INTO shoelace_log VALUES(
1224
1229
shoelace_data.sl_name, 6,
1225
- current_user, current_timestamp
1230
+ current_user, current_timestamp)
1226
1231
FROM shoelace_data
1227
1232
WHERE 6 != shoelace_data.sl_avail
1228
1233
AND shoelace_data.sl_name = 'sl7';
@@ -1317,18 +1322,6 @@ CREATE RULE shoe_del_protect AS ON DELETE TO shoe
1317
1322
parse trees will be empty and the whole query will become
1318
1323
nothing because there is nothing left to be optimized or
1319
1324
executed after the rule system is done with it.
1320
-
1321
- <Note>
1322
- <Title>Note</Title>
1323
- <Para>
1324
- This way might irritate frontend applications because
1325
- absolutely nothing happened on the database and thus, the
1326
- backend will not return anything for the query. Not
1327
- even a <symbol>PGRES_EMPTY_QUERY</symbol> will be available in <application>libpq</>.
1328
- In <application>psql</application>, nothing happens. This might change in the future.
1329
- </Para>
1330
- </Note>
1331
-
1332
1325
</Para>
1333
1326
1334
1327
<Para>
@@ -1516,7 +1509,7 @@ UPDATE shoelace_data SET
1516
1509
1517
1510
Again an update rule has been applied and so the wheel
1518
1511
turns on and we are in rewrite round 3. This time rule
1519
- <literal>log_shoelace</literal> gets applied what produces the extra
1512
+ <literal>log_shoelace</literal> gets applied, producing the extra
1520
1513
parse tree
1521
1514
1522
1515
<ProgramListing>
@@ -1648,7 +1641,7 @@ sl9 | 0|pink | 35|inch | 88.9
1648
1641
sl10 | 1000|magenta | 40|inch | 101.6
1649
1642
</ProgramListing>
1650
1643
1651
- For the 1000 magenta shoelaces we must debt Al before we can
1644
+ For the 1000 magenta shoelaces we must debit Al before we can
1652
1645
throw 'em away, but that's another problem. The pink entry we delete.
1653
1646
To make it a little harder for <ProductName>PostgreSQL</ProductName>,
1654
1647
we don't delete it directly. Instead we create one more view
@@ -1799,6 +1792,56 @@ GRANT SELECT ON phone_number TO secretary;
1799
1792
</Para>
1800
1793
</Sect1>
1801
1794
1795
+ <Sect1 id="rules-status">
1796
+ <Title>Rules and Command Status</Title>
1797
+
1798
+ <Para>
1799
+ The <ProductName>PostgreSQL</ProductName> server returns a command
1800
+ status string, such as <literal>INSERT 149592 1</>, for each
1801
+ query it receives. This is simple enough when there are no rules
1802
+ involved, but what happens when the query is rewritten by rules?
1803
+ </Para>
1804
+
1805
+ <Para>
1806
+ As of <ProductName>PostgreSQL</ProductName> 7.3, rules affect the
1807
+ command status as follows:
1808
+
1809
+ <orderedlist>
1810
+ <listitem>
1811
+ <para>
1812
+ If there is no unconditional INSTEAD rule for the query, then
1813
+ the originally given query will be executed, and its command
1814
+ status will be returned as usual. (But note that if there were
1815
+ any conditional INSTEAD rules, the negation of their qualifications
1816
+ will have been added to the original query. This may reduce the
1817
+ number of rows it processes, and if so the reported status will
1818
+ be affected.)
1819
+ </para>
1820
+ </listitem>
1821
+
1822
+ <listitem>
1823
+ <para>
1824
+ If there is any unconditional INSTEAD rule for the query, then
1825
+ the original query will not be executed at all. In this case,
1826
+ the server will return the command status for the last query that
1827
+ was inserted by an INSTEAD rule (conditional or unconditional)
1828
+ and is of the same type (INSERT, UPDATE, or DELETE) as the original
1829
+ query. If no query meeting those requirements is added by any
1830
+ rule, then the returned command status shows the original query
1831
+ type and zeroes for the tuple-count and OID fields.
1832
+ </para>
1833
+ </listitem>
1834
+ </orderedlist>
1835
+ </Para>
1836
+
1837
+ <Para>
1838
+ The programmer can ensure that any desired INSTEAD rule is the one
1839
+ that sets the command status in the second case, by giving it the
1840
+ alphabetically last rule name among the active rules, so that it
1841
+ fires last.
1842
+ </Para>
1843
+ </Sect1>
1844
+
1802
1845
<Sect1 id="rules-triggers">
1803
1846
<Title>Rules versus Triggers</Title>
1804
1847
0 commit comments