10
10
* Portions Copyright (c) 1994, Regents of the University of California
11
11
*
12
12
* IDENTIFICATION
13
- * $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.8 2008/01/01 19:45:50 momjian Exp $
13
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.9 2008/01/09 20:42:27 tgl Exp $
14
14
*
15
15
*-------------------------------------------------------------------------
16
16
*/
@@ -52,10 +52,10 @@ static RestrictInfo *create_join_clause(PlannerInfo *root,
52
52
EquivalenceMember * leftem ,
53
53
EquivalenceMember * rightem ,
54
54
EquivalenceClass * parent_ec );
55
- static void reconsider_outer_join_clause (PlannerInfo * root ,
55
+ static bool reconsider_outer_join_clause (PlannerInfo * root ,
56
56
RestrictInfo * rinfo ,
57
57
bool outer_on_left );
58
- static void reconsider_full_join_clause (PlannerInfo * root ,
58
+ static bool reconsider_full_join_clause (PlannerInfo * root ,
59
59
RestrictInfo * rinfo );
60
60
61
61
@@ -1094,8 +1094,9 @@ create_join_clause(PlannerInfo *root,
1094
1094
/*
1095
1095
* reconsider_outer_join_clauses
1096
1096
* Re-examine any outer-join clauses that were set aside by
1097
- * distribute_qual_to_rels(), and either create EquivalenceClasses
1098
- * to replace them or push them out into the regular join-clause lists.
1097
+ * distribute_qual_to_rels(), and see if we can derive any
1098
+ * EquivalenceClasses from them. Then, if they were not made
1099
+ * redundant, push them out into the regular join-clause lists.
1099
1100
*
1100
1101
* When we have mergejoinable clauses A = B that are outer-join clauses,
1101
1102
* we can't blindly combine them with other clauses A = C to deduce B = C,
@@ -1112,8 +1113,8 @@ create_join_clause(PlannerInfo *root,
1112
1113
* equivalence clause.)
1113
1114
*
1114
1115
* Note that the above rule does not work for full outer joins; nor is it
1115
- * very interesting to consider cases where the equivalence clause involves
1116
- * relations entirely outside the outer join, since such clauses couldn't
1116
+ * very interesting to consider cases where the generated equivalence clause
1117
+ * would involve relations outside the outer join, since such clauses couldn't
1117
1118
* be pushed into the inner side's scan anyway. So the restriction to
1118
1119
* outervar = pseudoconstant is not really giving up anything.
1119
1120
*
@@ -1141,57 +1142,161 @@ create_join_clause(PlannerInfo *root,
1141
1142
* that could result in propagating constant restrictions from
1142
1143
* INNERVAR to OUTERVAR, which would be very wrong.
1143
1144
*
1145
+ * It's possible that the INNERVAR is also an OUTERVAR for some other
1146
+ * outer-join clause, in which case the process can be repeated. So we repeat
1147
+ * looping over the lists of clauses until no further deductions can be made.
1148
+ * Whenever we do make a deduction, we remove the generating clause from the
1149
+ * lists, since we don't want to make the same deduction twice.
1150
+ *
1144
1151
* If we don't find any match for a set-aside outer join clause, we must
1145
1152
* throw it back into the regular joinclause processing by passing it to
1146
- * distribute_restrictinfo_to_rels().
1153
+ * distribute_restrictinfo_to_rels(). If we do generate a derived clause,
1154
+ * however, the outer-join clause is redundant. We still throw it back,
1155
+ * because otherwise the join will be seen as a clauseless join and avoided
1156
+ * during join order searching; but we mark it as redundant to keep from
1157
+ * messing up the joinrel's size estimate. (This behavior means that the
1158
+ * API for this routine is uselessly complex: we could have just put all
1159
+ * the clauses into the regular processing initially. We keep it because
1160
+ * someday we might want to do something else, such as inserting "dummy"
1161
+ * joinclauses instead of real ones.)
1162
+ *
1163
+ * Outer join clauses that are marked outerjoin_delayed are special: this
1164
+ * condition means that one or both VARs might go to null due to a lower
1165
+ * outer join. We can still push a constant through the clause, but only
1166
+ * if its operator is strict; and we *have to* throw the clause back into
1167
+ * regular joinclause processing. By keeping the strict join clause,
1168
+ * we ensure that any null-extended rows that are mistakenly generated due
1169
+ * to suppressing rows not matching the constant will be rejected at the
1170
+ * upper outer join. (This doesn't work for full-join clauses.)
1147
1171
*/
1148
1172
void
1149
1173
reconsider_outer_join_clauses (PlannerInfo * root )
1150
1174
{
1151
- ListCell * lc ;
1175
+ bool found ;
1176
+ ListCell * cell ;
1177
+ ListCell * prev ;
1178
+ ListCell * next ;
1179
+
1180
+ /* Outer loop repeats until we find no more deductions */
1181
+ do
1182
+ {
1183
+ found = false;
1184
+
1185
+ /* Process the LEFT JOIN clauses */
1186
+ prev = NULL ;
1187
+ for (cell = list_head (root -> left_join_clauses ); cell ; cell = next )
1188
+ {
1189
+ RestrictInfo * rinfo = (RestrictInfo * ) lfirst (cell );
1190
+
1191
+ next = lnext (cell );
1192
+ if (reconsider_outer_join_clause (root , rinfo , true))
1193
+ {
1194
+ found = true;
1195
+ /* remove it from the list */
1196
+ root -> left_join_clauses =
1197
+ list_delete_cell (root -> left_join_clauses , cell , prev );
1198
+ /* we throw it back anyway (see notes above) */
1199
+ /* but the thrown-back clause has no extra selectivity */
1200
+ rinfo -> this_selec = 1.0 ;
1201
+ distribute_restrictinfo_to_rels (root , rinfo );
1202
+ }
1203
+ else
1204
+ prev = cell ;
1205
+ }
1206
+
1207
+ /* Process the RIGHT JOIN clauses */
1208
+ prev = NULL ;
1209
+ for (cell = list_head (root -> right_join_clauses ); cell ; cell = next )
1210
+ {
1211
+ RestrictInfo * rinfo = (RestrictInfo * ) lfirst (cell );
1212
+
1213
+ next = lnext (cell );
1214
+ if (reconsider_outer_join_clause (root , rinfo , false))
1215
+ {
1216
+ found = true;
1217
+ /* remove it from the list */
1218
+ root -> right_join_clauses =
1219
+ list_delete_cell (root -> right_join_clauses , cell , prev );
1220
+ /* we throw it back anyway (see notes above) */
1221
+ /* but the thrown-back clause has no extra selectivity */
1222
+ rinfo -> this_selec = 1.0 ;
1223
+ distribute_restrictinfo_to_rels (root , rinfo );
1224
+ }
1225
+ else
1226
+ prev = cell ;
1227
+ }
1228
+
1229
+ /* Process the FULL JOIN clauses */
1230
+ prev = NULL ;
1231
+ for (cell = list_head (root -> full_join_clauses ); cell ; cell = next )
1232
+ {
1233
+ RestrictInfo * rinfo = (RestrictInfo * ) lfirst (cell );
1234
+
1235
+ next = lnext (cell );
1236
+ if (reconsider_full_join_clause (root , rinfo ))
1237
+ {
1238
+ found = true;
1239
+ /* remove it from the list */
1240
+ root -> full_join_clauses =
1241
+ list_delete_cell (root -> full_join_clauses , cell , prev );
1242
+ /* we throw it back anyway (see notes above) */
1243
+ /* but the thrown-back clause has no extra selectivity */
1244
+ rinfo -> this_selec = 1.0 ;
1245
+ distribute_restrictinfo_to_rels (root , rinfo );
1246
+ }
1247
+ else
1248
+ prev = cell ;
1249
+ }
1250
+ } while (found );
1152
1251
1153
- /* Process the LEFT JOIN clauses */
1154
- foreach (lc , root -> left_join_clauses )
1252
+ /* Now, any remaining clauses have to be thrown back */
1253
+ foreach (cell , root -> left_join_clauses )
1155
1254
{
1156
- RestrictInfo * rinfo = (RestrictInfo * ) lfirst (lc );
1255
+ RestrictInfo * rinfo = (RestrictInfo * ) lfirst (cell );
1157
1256
1158
- reconsider_outer_join_clause (root , rinfo , true );
1257
+ distribute_restrictinfo_to_rels (root , rinfo );
1159
1258
}
1160
- /* And the RIGHT JOIN clauses */
1161
- foreach (lc , root -> right_join_clauses )
1259
+ foreach (cell , root -> right_join_clauses )
1162
1260
{
1163
- RestrictInfo * rinfo = (RestrictInfo * ) lfirst (lc );
1261
+ RestrictInfo * rinfo = (RestrictInfo * ) lfirst (cell );
1164
1262
1165
- reconsider_outer_join_clause (root , rinfo , false );
1263
+ distribute_restrictinfo_to_rels (root , rinfo );
1166
1264
}
1167
- /* And the FULL JOIN clauses */
1168
- foreach (lc , root -> full_join_clauses )
1265
+ foreach (cell , root -> full_join_clauses )
1169
1266
{
1170
- RestrictInfo * rinfo = (RestrictInfo * ) lfirst (lc );
1267
+ RestrictInfo * rinfo = (RestrictInfo * ) lfirst (cell );
1171
1268
1172
- reconsider_full_join_clause (root , rinfo );
1269
+ distribute_restrictinfo_to_rels (root , rinfo );
1173
1270
}
1174
1271
}
1175
1272
1176
1273
/*
1177
1274
* reconsider_outer_join_clauses for a single LEFT/RIGHT JOIN clause
1275
+ *
1276
+ * Returns TRUE if we were able to propagate a constant through the clause.
1178
1277
*/
1179
- static void
1278
+ static bool
1180
1279
reconsider_outer_join_clause (PlannerInfo * root , RestrictInfo * rinfo ,
1181
1280
bool outer_on_left )
1182
1281
{
1183
1282
Expr * outervar ,
1184
1283
* innervar ;
1185
- Oid left_type ,
1284
+ Oid opno ,
1285
+ left_type ,
1186
1286
right_type ,
1187
1287
inner_datatype ;
1188
1288
Relids inner_relids ;
1189
1289
ListCell * lc1 ;
1190
1290
1191
- /* Extract needed info from the clause */
1192
1291
Assert (is_opclause (rinfo -> clause ));
1193
- op_input_types (((OpExpr * ) rinfo -> clause )-> opno ,
1194
- & left_type , & right_type );
1292
+ opno = ((OpExpr * ) rinfo -> clause )-> opno ;
1293
+
1294
+ /* If clause is outerjoin_delayed, operator must be strict */
1295
+ if (rinfo -> outerjoin_delayed && !op_strict (opno ))
1296
+ return false;
1297
+
1298
+ /* Extract needed info from the clause */
1299
+ op_input_types (opno , & left_type , & right_type );
1195
1300
if (outer_on_left )
1196
1301
{
1197
1302
outervar = (Expr * ) get_leftop (rinfo -> clause );
@@ -1266,41 +1371,46 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo,
1266
1371
}
1267
1372
1268
1373
/*
1269
- * If we were able to equate INNERVAR to any constant, we're done, and
1270
- * we can throw away the outer-join clause as redundant. Otherwise,
1271
- * fall out of the search loop, since we know the OUTERVAR appears in
1272
- * at most one EC.
1374
+ * If we were able to equate INNERVAR to any constant, report success.
1375
+ * Otherwise, fall out of the search loop, since we know the OUTERVAR
1376
+ * appears in at most one EC.
1273
1377
*/
1274
1378
if (match )
1275
- return ;
1379
+ return true ;
1276
1380
else
1277
1381
break ;
1278
1382
}
1279
1383
1280
- /* We did not find a match, so throw it back into regular processing */
1281
- distribute_restrictinfo_to_rels (root , rinfo );
1384
+ return false; /* failed to make any deduction */
1282
1385
}
1283
1386
1284
1387
/*
1285
1388
* reconsider_outer_join_clauses for a single FULL JOIN clause
1389
+ *
1390
+ * Returns TRUE if we were able to propagate a constant through the clause.
1286
1391
*/
1287
- static void
1392
+ static bool
1288
1393
reconsider_full_join_clause (PlannerInfo * root , RestrictInfo * rinfo )
1289
1394
{
1290
1395
Expr * leftvar ;
1291
1396
Expr * rightvar ;
1292
- Oid left_type ,
1397
+ Oid opno ,
1398
+ left_type ,
1293
1399
right_type ;
1294
1400
Relids left_relids ,
1295
1401
right_relids ;
1296
1402
ListCell * lc1 ;
1297
1403
1404
+ /* Can't use an outerjoin_delayed clause here */
1405
+ if (rinfo -> outerjoin_delayed )
1406
+ return false;
1407
+
1298
1408
/* Extract needed info from the clause */
1299
1409
Assert (is_opclause (rinfo -> clause ));
1410
+ opno = ((OpExpr * ) rinfo -> clause )-> opno ;
1411
+ op_input_types (opno , & left_type , & right_type );
1300
1412
leftvar = (Expr * ) get_leftop (rinfo -> clause );
1301
1413
rightvar = (Expr * ) get_rightop (rinfo -> clause );
1302
- op_input_types (((OpExpr * ) rinfo -> clause )-> opno ,
1303
- & left_type , & right_type );
1304
1414
left_relids = rinfo -> left_relids ;
1305
1415
right_relids = rinfo -> right_relids ;
1306
1416
@@ -1412,7 +1522,7 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
1412
1522
if (matchleft && matchright )
1413
1523
{
1414
1524
cur_ec -> ec_members = list_delete_ptr (cur_ec -> ec_members , coal_em );
1415
- return ;
1525
+ return true ;
1416
1526
}
1417
1527
1418
1528
/*
@@ -1423,8 +1533,7 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
1423
1533
break ;
1424
1534
}
1425
1535
1426
- /* We did not find a match, so throw it back into regular processing */
1427
- distribute_restrictinfo_to_rels (root , rinfo );
1536
+ return false; /* failed to make any deduction */
1428
1537
}
1429
1538
1430
1539
@@ -1651,16 +1760,22 @@ have_relevant_eclass_joinclause(PlannerInfo *root,
1651
1760
ListCell * lc2 ;
1652
1761
1653
1762
/*
1654
- * Won't generate joinclauses if const or single-member (the latter
1655
- * test covers the volatile case too)
1763
+ * Won't generate joinclauses if single-member (this test covers the
1764
+ * volatile case too)
1656
1765
*/
1657
- if (ec -> ec_has_const || list_length (ec -> ec_members ) <= 1 )
1766
+ if (list_length (ec -> ec_members ) <= 1 )
1658
1767
continue ;
1659
1768
1660
1769
/*
1661
1770
* Note we don't test ec_broken; if we did, we'd need a separate code
1662
1771
* path to look through ec_sources. Checking the members anyway is OK
1663
1772
* as a possibly-overoptimistic heuristic.
1773
+ *
1774
+ * We don't test ec_has_const either, even though a const eclass
1775
+ * won't generate real join clauses. This is because if we had
1776
+ * "WHERE a.x = b.y and a.x = 42", it is worth considering a join
1777
+ * between a and b, since the join result is likely to be small even
1778
+ * though it'll end up being an unqualified nestloop.
1664
1779
*/
1665
1780
1666
1781
/* Needn't scan if it couldn't contain members from each rel */
@@ -1674,8 +1789,8 @@ have_relevant_eclass_joinclause(PlannerInfo *root,
1674
1789
{
1675
1790
EquivalenceMember * cur_em = (EquivalenceMember * ) lfirst (lc2 );
1676
1791
1677
- if (cur_em -> em_is_child )
1678
- continue ; /* ignore children here */
1792
+ if (cur_em -> em_is_const || cur_em -> em_is_child )
1793
+ continue ; /* ignore consts and children here */
1679
1794
if (bms_is_subset (cur_em -> em_relids , rel1 -> relids ))
1680
1795
{
1681
1796
has_rel1 = true;
@@ -1719,16 +1834,22 @@ has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
1719
1834
ListCell * lc2 ;
1720
1835
1721
1836
/*
1722
- * Won't generate joinclauses if const or single-member (the latter
1723
- * test covers the volatile case too)
1837
+ * Won't generate joinclauses if single-member (this test covers the
1838
+ * volatile case too)
1724
1839
*/
1725
- if (ec -> ec_has_const || list_length (ec -> ec_members ) <= 1 )
1840
+ if (list_length (ec -> ec_members ) <= 1 )
1726
1841
continue ;
1727
1842
1728
1843
/*
1729
1844
* Note we don't test ec_broken; if we did, we'd need a separate code
1730
1845
* path to look through ec_sources. Checking the members anyway is OK
1731
1846
* as a possibly-overoptimistic heuristic.
1847
+ *
1848
+ * We don't test ec_has_const either, even though a const eclass
1849
+ * won't generate real join clauses. This is because if we had
1850
+ * "WHERE a.x = b.y and a.x = 42", it is worth considering a join
1851
+ * between a and b, since the join result is likely to be small even
1852
+ * though it'll end up being an unqualified nestloop.
1732
1853
*/
1733
1854
1734
1855
/* Needn't scan if it couldn't contain members from each rel */
@@ -1742,8 +1863,8 @@ has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
1742
1863
{
1743
1864
EquivalenceMember * cur_em = (EquivalenceMember * ) lfirst (lc2 );
1744
1865
1745
- if (cur_em -> em_is_child )
1746
- continue ; /* ignore children here */
1866
+ if (cur_em -> em_is_const || cur_em -> em_is_child )
1867
+ continue ; /* ignore consts and children here */
1747
1868
if (bms_is_subset (cur_em -> em_relids , rel1 -> relids ))
1748
1869
{
1749
1870
has_rel1 = true;
0 commit comments