|
20 | 20 | #include "postgres.h" |
21 | 21 |
|
22 | 22 | #include "access/htup_details.h" |
| 23 | +#include "catalog/pg_class.h" |
23 | 24 | #include "catalog/pg_language.h" |
24 | 25 | #include "catalog/pg_operator.h" |
25 | 26 | #include "catalog/pg_proc.h" |
|
36 | 37 | #include "optimizer/clauses.h" |
37 | 38 | #include "optimizer/cost.h" |
38 | 39 | #include "optimizer/optimizer.h" |
| 40 | +#include "optimizer/pathnode.h" |
39 | 41 | #include "optimizer/plancat.h" |
40 | 42 | #include "optimizer/planmain.h" |
41 | 43 | #include "parser/analyze.h" |
42 | 44 | #include "parser/parse_coerce.h" |
43 | 45 | #include "parser/parse_collate.h" |
44 | 46 | #include "parser/parse_func.h" |
45 | 47 | #include "parser/parse_oper.h" |
| 48 | +#include "parser/parsetree.h" |
46 | 49 | #include "rewrite/rewriteHandler.h" |
47 | 50 | #include "rewrite/rewriteManip.h" |
48 | 51 | #include "tcop/tcopprot.h" |
@@ -2242,7 +2245,8 @@ rowtype_field_matches(Oid rowtypeid, int fieldnum, |
2242 | 2245 | * only operators and functions that are reasonable to try to execute. |
2243 | 2246 | * |
2244 | 2247 | * NOTE: "root" can be passed as NULL if the caller never wants to do any |
2245 | | - * Param substitutions nor receive info about inlined functions. |
| 2248 | + * Param substitutions nor receive info about inlined functions nor reduce |
| 2249 | + * NullTest for Vars to constant true or constant false. |
2246 | 2250 | * |
2247 | 2251 | * NOTE: the planner assumes that this will always flatten nested AND and |
2248 | 2252 | * OR clauses into N-argument form. See comments in prepqual.c. |
@@ -3544,6 +3548,31 @@ eval_const_expressions_mutator(Node *node, |
3544 | 3548 |
|
3545 | 3549 | return makeBoolConst(result, false); |
3546 | 3550 | } |
| 3551 | + if (!ntest->argisrow && arg && IsA(arg, Var) && context->root) |
| 3552 | + { |
| 3553 | + Var *varg = (Var *) arg; |
| 3554 | + bool result; |
| 3555 | + |
| 3556 | + if (var_is_nonnullable(context->root, varg, false)) |
| 3557 | + { |
| 3558 | + switch (ntest->nulltesttype) |
| 3559 | + { |
| 3560 | + case IS_NULL: |
| 3561 | + result = false; |
| 3562 | + break; |
| 3563 | + case IS_NOT_NULL: |
| 3564 | + result = true; |
| 3565 | + break; |
| 3566 | + default: |
| 3567 | + elog(ERROR, "unrecognized nulltesttype: %d", |
| 3568 | + (int) ntest->nulltesttype); |
| 3569 | + result = false; /* keep compiler quiet */ |
| 3570 | + break; |
| 3571 | + } |
| 3572 | + |
| 3573 | + return makeBoolConst(result, false); |
| 3574 | + } |
| 3575 | + } |
3547 | 3576 |
|
3548 | 3577 | newntest = makeNode(NullTest); |
3549 | 3578 | newntest->arg = (Expr *) arg; |
@@ -4162,6 +4191,67 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, |
4162 | 4191 | return newexpr; |
4163 | 4192 | } |
4164 | 4193 |
|
| 4194 | +/* |
| 4195 | + * var_is_nonnullable: check to see if the Var cannot be NULL |
| 4196 | + * |
| 4197 | + * If the Var is defined NOT NULL and meanwhile is not nulled by any outer |
| 4198 | + * joins or grouping sets, then we can know that it cannot be NULL. |
| 4199 | + * |
| 4200 | + * use_rel_info indicates whether the corresponding RelOptInfo is available for |
| 4201 | + * use. |
| 4202 | + */ |
| 4203 | +bool |
| 4204 | +var_is_nonnullable(PlannerInfo *root, Var *var, bool use_rel_info) |
| 4205 | +{ |
| 4206 | + Relids notnullattnums = NULL; |
| 4207 | + |
| 4208 | + Assert(IsA(var, Var)); |
| 4209 | + |
| 4210 | + /* skip upper-level Vars */ |
| 4211 | + if (var->varlevelsup != 0) |
| 4212 | + return false; |
| 4213 | + |
| 4214 | + /* could the Var be nulled by any outer joins or grouping sets? */ |
| 4215 | + if (!bms_is_empty(var->varnullingrels)) |
| 4216 | + return false; |
| 4217 | + |
| 4218 | + /* system columns cannot be NULL */ |
| 4219 | + if (var->varattno < 0) |
| 4220 | + return true; |
| 4221 | + |
| 4222 | + /* |
| 4223 | + * Check if the Var is defined as NOT NULL. We retrieve the column NOT |
| 4224 | + * NULL constraint information from the corresponding RelOptInfo if it is |
| 4225 | + * available; otherwise, we search the hash table for this information. |
| 4226 | + */ |
| 4227 | + if (use_rel_info) |
| 4228 | + { |
| 4229 | + RelOptInfo *rel = find_base_rel(root, var->varno); |
| 4230 | + |
| 4231 | + notnullattnums = rel->notnullattnums; |
| 4232 | + } |
| 4233 | + else |
| 4234 | + { |
| 4235 | + RangeTblEntry *rte = planner_rt_fetch(var->varno, root); |
| 4236 | + |
| 4237 | + /* |
| 4238 | + * We must skip inheritance parent tables, as some child tables may |
| 4239 | + * have a NOT NULL constraint for a column while others may not. This |
| 4240 | + * cannot happen with partitioned tables, though. |
| 4241 | + */ |
| 4242 | + if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE) |
| 4243 | + return false; |
| 4244 | + |
| 4245 | + notnullattnums = find_relation_notnullatts(root, rte->relid); |
| 4246 | + } |
| 4247 | + |
| 4248 | + if (var->varattno > 0 && |
| 4249 | + bms_is_member(var->varattno, notnullattnums)) |
| 4250 | + return true; |
| 4251 | + |
| 4252 | + return false; |
| 4253 | +} |
| 4254 | + |
4165 | 4255 | /* |
4166 | 4256 | * expand_function_arguments: convert named-notation args to positional args |
4167 | 4257 | * and/or insert default args, as needed |
|
0 commit comments