]> granicus.if.org Git - postgresql/blob - src/backend/partitioning/partprune.c
901433c68c771309d8ce949134c914f58fc1230d
[postgresql] / src / backend / partitioning / partprune.c
1 /*-------------------------------------------------------------------------
2  *
3  * partprune.c
4  *              Support for partition pruning during query planning and execution
5  *
6  * This module implements partition pruning using the information contained in
7  * a table's partition descriptor, query clauses, and run-time parameters.
8  *
9  * During planning, clauses that can be matched to the table's partition key
10  * are turned into a set of "pruning steps", which are then executed to
11  * identify a set of partitions (as indexes in the RelOptInfo->part_rels
12  * array) that satisfy the constraints in the step.  Partitions not in the set
13  * are said to have been pruned.
14  *
15  * A base pruning step may involve expressions whose values are only known
16  * during execution, such as Params, in which case pruning cannot occur
17  * entirely during planning.  In that case, such steps are included alongside
18  * the plan, so that they can be used by the executor for further pruning.
19  *
20  * There are two kinds of pruning steps.  A "base" pruning step represents
21  * tests on partition key column(s), typically comparisons to expressions.
22  * A "combine" pruning step represents a Boolean connector (AND/OR), and
23  * combines the outputs of some previous steps using the appropriate
24  * combination method.
25  *
26  * See gen_partprune_steps_internal() for more details on step generation.
27  *
28  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
29  * Portions Copyright (c) 1994, Regents of the University of California
30  *
31  * IDENTIFICATION
32  *                src/backend/partitioning/partprune.c
33  *
34  *-------------------------------------------------------------------------
35 */
36 #include "postgres.h"
37
38 #include "access/hash.h"
39 #include "access/nbtree.h"
40 #include "catalog/pg_operator.h"
41 #include "catalog/pg_opfamily.h"
42 #include "catalog/pg_type.h"
43 #include "executor/executor.h"
44 #include "miscadmin.h"
45 #include "nodes/makefuncs.h"
46 #include "nodes/nodeFuncs.h"
47 #include "optimizer/appendinfo.h"
48 #include "optimizer/clauses.h"
49 #include "optimizer/pathnode.h"
50 #include "optimizer/planner.h"
51 #include "optimizer/predtest.h"
52 #include "optimizer/prep.h"
53 #include "optimizer/var.h"
54 #include "partitioning/partprune.h"
55 #include "partitioning/partbounds.h"
56 #include "rewrite/rewriteManip.h"
57 #include "utils/lsyscache.h"
58
59
60 /*
61  * Information about a clause matched with a partition key.
62  */
63 typedef struct PartClauseInfo
64 {
65         int                     keyno;                  /* Partition key number (0 to partnatts - 1) */
66         Oid                     opno;                   /* operator used to compare partkey to expr */
67         bool            op_is_ne;               /* is clause's original operator <> ? */
68         Expr       *expr;                       /* expr the partition key is compared to */
69         Oid                     cmpfn;                  /* Oid of function to compare 'expr' to the
70                                                                  * partition key */
71         int                     op_strategy;    /* btree strategy identifying the operator */
72 } PartClauseInfo;
73
74 /*
75  * PartClauseMatchStatus
76  *              Describes the result of match_clause_to_partition_key()
77  */
78 typedef enum PartClauseMatchStatus
79 {
80         PARTCLAUSE_NOMATCH,
81         PARTCLAUSE_MATCH_CLAUSE,
82         PARTCLAUSE_MATCH_NULLNESS,
83         PARTCLAUSE_MATCH_STEPS,
84         PARTCLAUSE_MATCH_CONTRADICT,
85         PARTCLAUSE_UNSUPPORTED
86 } PartClauseMatchStatus;
87
88 /*
89  * GeneratePruningStepsContext
90  *              Information about the current state of generation of "pruning steps"
91  *              for a given set of clauses
92  *
93  * gen_partprune_steps() initializes an instance of this struct, which is used
94  * throughout the step generation process.
95  */
96 typedef struct GeneratePruningStepsContext
97 {
98         int                     next_step_id;
99         List       *steps;
100 } GeneratePruningStepsContext;
101
102 /* The result of performing one PartitionPruneStep */
103 typedef struct PruneStepResult
104 {
105         /*
106          * The offsets of bounds (in a table's boundinfo) whose partition is
107          * selected by the pruning step.
108          */
109         Bitmapset  *bound_offsets;
110
111         bool            scan_default;   /* Scan the default partition? */
112         bool            scan_null;              /* Scan the partition for NULL values? */
113 } PruneStepResult;
114
115
116 static List *make_partitionedrel_pruneinfo(PlannerInfo *root,
117                                                           RelOptInfo *parentrel,
118                                                           int *relid_subplan_map,
119                                                           List *partitioned_rels, List *prunequal,
120                                                           Bitmapset **matchedsubplans);
121 static List *gen_partprune_steps(RelOptInfo *rel, List *clauses,
122                                         bool *contradictory);
123 static List *gen_partprune_steps_internal(GeneratePruningStepsContext *context,
124                                                          RelOptInfo *rel, List *clauses,
125                                                          bool *contradictory);
126 static PartitionPruneStep *gen_prune_step_op(GeneratePruningStepsContext *context,
127                                   StrategyNumber opstrategy, bool op_is_ne,
128                                   List *exprs, List *cmpfns, Bitmapset *nullkeys);
129 static PartitionPruneStep *gen_prune_step_combine(GeneratePruningStepsContext *context,
130                                            List *source_stepids,
131                                            PartitionPruneCombineOp combineOp);
132 static PartitionPruneStep *gen_prune_steps_from_opexps(PartitionScheme part_scheme,
133                                                         GeneratePruningStepsContext *context,
134                                                         List **keyclauses, Bitmapset *nullkeys);
135 static PartClauseMatchStatus match_clause_to_partition_key(RelOptInfo *rel,
136                                                           GeneratePruningStepsContext *context,
137                                                           Expr *clause, Expr *partkey, int partkeyidx,
138                                                           bool *clause_is_not_null,
139                                                           PartClauseInfo **pc, List **clause_steps);
140 static List *get_steps_using_prefix(GeneratePruningStepsContext *context,
141                                            StrategyNumber step_opstrategy,
142                                            bool step_op_is_ne,
143                                            Expr *step_lastexpr,
144                                            Oid step_lastcmpfn,
145                                            int step_lastkeyno,
146                                            Bitmapset *step_nullkeys,
147                                            List *prefix);
148 static List *get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
149                                                            StrategyNumber step_opstrategy,
150                                                            bool step_op_is_ne,
151                                                            Expr *step_lastexpr,
152                                                            Oid step_lastcmpfn,
153                                                            int step_lastkeyno,
154                                                            Bitmapset *step_nullkeys,
155                                                            ListCell *start,
156                                                            List *step_exprs,
157                                                            List *step_cmpfns);
158 static PruneStepResult *get_matching_hash_bounds(PartitionPruneContext *context,
159                                                  StrategyNumber opstrategy, Datum *values, int nvalues,
160                                                  FmgrInfo *partsupfunc, Bitmapset *nullkeys);
161 static PruneStepResult *get_matching_list_bounds(PartitionPruneContext *context,
162                                                  StrategyNumber opstrategy, Datum value, int nvalues,
163                                                  FmgrInfo *partsupfunc, Bitmapset *nullkeys);
164 static PruneStepResult *get_matching_range_bounds(PartitionPruneContext *context,
165                                                   StrategyNumber opstrategy, Datum *values, int nvalues,
166                                                   FmgrInfo *partsupfunc, Bitmapset *nullkeys);
167 static Bitmapset *pull_exec_paramids(Expr *expr);
168 static bool pull_exec_paramids_walker(Node *node, Bitmapset **context);
169 static bool analyze_partkey_exprs(PartitionedRelPruneInfo *pinfo, List *steps,
170                                           int partnatts);
171 static PruneStepResult *perform_pruning_base_step(PartitionPruneContext *context,
172                                                   PartitionPruneStepOp *opstep);
173 static PruneStepResult *perform_pruning_combine_step(PartitionPruneContext *context,
174                                                          PartitionPruneStepCombine *cstep,
175                                                          PruneStepResult **step_results);
176 static bool match_boolean_partition_clause(Oid partopfamily, Expr *clause,
177                                                            Expr *partkey, Expr **outconst);
178 static bool partkey_datum_from_expr(PartitionPruneContext *context,
179                                                 Expr *expr, int stateidx,
180                                                 Datum *value, bool *isnull);
181
182
183 /*
184  * make_partition_pruneinfo
185  *              Builds a PartitionPruneInfo which can be used in the executor to allow
186  *              additional partition pruning to take place.  Returns NULL when
187  *              partition pruning would be useless.
188  *
189  * 'parentrel' is the RelOptInfo for an appendrel, and 'subpaths' is the list
190  * of scan paths for its child rels.
191  *
192  * 'partitioned_rels' is a List containing Lists of relids of partitioned
193  * tables (a/k/a non-leaf partitions) that are parents of some of the child
194  * rels.  Here we attempt to populate the PartitionPruneInfo by adding a
195  * 'prune_infos' item for each sublist in the 'partitioned_rels' list.
196  * However, some of the sets of partitioned relations may not require any
197  * run-time pruning.  In these cases we'll simply not include a 'prune_infos'
198  * item for that set and instead we'll add all the subplans which belong to
199  * that set into the PartitionPruneInfo's 'other_subplans' field.  Callers
200  * will likely never want to prune subplans which are mentioned in this field.
201  *
202  * 'prunequal' is a list of potential pruning quals.
203  */
204 PartitionPruneInfo *
205 make_partition_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
206                                                  List *subpaths, List *partitioned_rels,
207                                                  List *prunequal)
208 {
209         PartitionPruneInfo *pruneinfo;
210         Bitmapset  *allmatchedsubplans = NULL;
211         int                *relid_subplan_map;
212         ListCell   *lc;
213         List       *prunerelinfos;
214         int                     i;
215
216         /*
217          * Construct a temporary array to map from planner relids to subplan
218          * indexes.  For convenience, we use 1-based indexes here, so that zero
219          * can represent an un-filled array entry.
220          */
221         relid_subplan_map = palloc0(sizeof(int) * root->simple_rel_array_size);
222
223         /*
224          * relid_subplan_map maps relid of a leaf partition to the index in
225          * 'subpaths' of the scan plan for that partition.
226          */
227         i = 1;
228         foreach(lc, subpaths)
229         {
230                 Path       *path = (Path *) lfirst(lc);
231                 RelOptInfo *pathrel = path->parent;
232
233                 Assert(IS_SIMPLE_REL(pathrel));
234                 Assert(pathrel->relid < root->simple_rel_array_size);
235                 /* No duplicates please */
236                 Assert(relid_subplan_map[pathrel->relid] == 0);
237
238                 relid_subplan_map[pathrel->relid] = i++;
239         }
240
241         /* We now build a PartitionedRelPruneInfo for each partitioned rel. */
242         prunerelinfos = NIL;
243         foreach(lc, partitioned_rels)
244         {
245                 List       *rels = (List *) lfirst(lc);
246                 List       *pinfolist;
247                 Bitmapset  *matchedsubplans = NULL;
248
249                 pinfolist = make_partitionedrel_pruneinfo(root, parentrel,
250                                                                                                   relid_subplan_map,
251                                                                                                   rels, prunequal,
252                                                                                                   &matchedsubplans);
253
254                 /* When pruning is possible, record the matched subplans */
255                 if (pinfolist != NIL)
256                 {
257                         prunerelinfos = lappend(prunerelinfos, pinfolist);
258                         allmatchedsubplans = bms_join(matchedsubplans,
259                                                                                   allmatchedsubplans);
260                 }
261         }
262
263         pfree(relid_subplan_map);
264
265         /*
266          * If none of the partition hierarchies had any useful run-time pruning
267          * quals, then we can just not bother with run-time pruning.
268          */
269         if (prunerelinfos == NIL)
270                 return NULL;
271
272         /* Else build the result data structure */
273         pruneinfo = makeNode(PartitionPruneInfo);
274         pruneinfo->prune_infos = prunerelinfos;
275
276         /*
277          * Some subplans may not belong to any of the listed partitioned rels.
278          * This can happen for UNION ALL queries which include a non-partitioned
279          * table, or when some of the hierarchies aren't run-time prunable.  Build
280          * a bitmapset of the indexes of all such subplans, so that the executor
281          * can identify which subplans should never be pruned.
282          */
283         if (bms_num_members(allmatchedsubplans) < list_length(subpaths))
284         {
285                 Bitmapset  *other_subplans;
286
287                 /* Create the complement of allmatchedsubplans */
288                 other_subplans = bms_add_range(NULL, 0, list_length(subpaths) - 1);
289                 other_subplans = bms_del_members(other_subplans, allmatchedsubplans);
290
291                 pruneinfo->other_subplans = other_subplans;
292         }
293         else
294                 pruneinfo->other_subplans = NULL;
295
296         return pruneinfo;
297 }
298
299 /*
300  * make_partitionedrel_pruneinfo
301  *              Build a List of PartitionedRelPruneInfos, one for each partitioned
302  *              rel.  These can be used in the executor to allow additional partition
303  *              pruning to take place.
304  *
305  * Here we generate partition pruning steps for 'prunequal' and also build a
306  * data structure which allows mapping of partition indexes into 'subpaths'
307  * indexes.
308  *
309  * If no non-Const expressions are being compared to the partition key in any
310  * of the 'partitioned_rels', then we return NIL to indicate no run-time
311  * pruning should be performed.  Run-time pruning would be useless since the
312  * pruning done during planning will have pruned everything that can be.
313  *
314  * On non-NIL return, 'matchedsubplans' is set to the subplan indexes which
315  * were matched to this partition hierarchy.
316  */
317 static List *
318 make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
319                                                           int *relid_subplan_map,
320                                                           List *partitioned_rels, List *prunequal,
321                                                           Bitmapset **matchedsubplans)
322 {
323         RelOptInfo *targetpart = NULL;
324         List       *pinfolist = NIL;
325         bool            doruntimeprune = false;
326         int                *relid_subpart_map;
327         Bitmapset  *subplansfound = NULL;
328         ListCell   *lc;
329         int                     i;
330
331         /*
332          * Construct a temporary array to map from planner relids to index of the
333          * partitioned_rel.  For convenience, we use 1-based indexes here, so that
334          * zero can represent an un-filled array entry.
335          */
336         relid_subpart_map = palloc0(sizeof(int) * root->simple_rel_array_size);
337
338         /*
339          * relid_subpart_map maps relid of a non-leaf partition to the index in
340          * 'partitioned_rels' of that rel (which will also be the index in the
341          * returned PartitionedRelPruneInfo list of the info for that partition).
342          */
343         i = 1;
344         foreach(lc, partitioned_rels)
345         {
346                 Index           rti = lfirst_int(lc);
347
348                 Assert(rti < root->simple_rel_array_size);
349                 /* No duplicates please */
350                 Assert(relid_subpart_map[rti] == 0);
351
352                 relid_subpart_map[rti] = i++;
353         }
354
355         /* We now build a PartitionedRelPruneInfo for each partitioned rel */
356         foreach(lc, partitioned_rels)
357         {
358                 Index           rti = lfirst_int(lc);
359                 RelOptInfo *subpart = find_base_rel(root, rti);
360                 PartitionedRelPruneInfo *pinfo;
361                 Bitmapset  *present_parts;
362                 int                     nparts = subpart->nparts;
363                 int                     partnatts = subpart->part_scheme->partnatts;
364                 int                *subplan_map;
365                 int                *subpart_map;
366                 List       *partprunequal;
367                 List       *pruning_steps;
368                 bool            contradictory;
369
370                 /*
371                  * The first item in the list is the target partitioned relation.
372                  */
373                 if (!targetpart)
374                 {
375                         targetpart = subpart;
376
377                         /*
378                          * The prunequal is presented to us as a qual for 'parentrel'.
379                          * Frequently this rel is the same as targetpart, so we can skip
380                          * an adjust_appendrel_attrs step.  But it might not be, and then
381                          * we have to translate.  We update the prunequal parameter here,
382                          * because in later iterations of the loop for child partitions,
383                          * we want to translate from parent to child variables.
384                          */
385                         if (!bms_equal(parentrel->relids, subpart->relids))
386                         {
387                                 int                     nappinfos;
388                                 AppendRelInfo **appinfos = find_appinfos_by_relids(root,
389                                                                                                                                    subpart->relids,
390                                                                                                                                    &nappinfos);
391
392                                 prunequal = (List *) adjust_appendrel_attrs(root, (Node *)
393                                                                                                                         prunequal,
394                                                                                                                         nappinfos,
395                                                                                                                         appinfos);
396
397                                 pfree(appinfos);
398                         }
399
400                         partprunequal = prunequal;
401                 }
402                 else
403                 {
404                         /*
405                          * For sub-partitioned tables the columns may not be in the same
406                          * order as the parent, so we must translate the prunequal to make
407                          * it compatible with this relation.
408                          */
409                         partprunequal = (List *)
410                                 adjust_appendrel_attrs_multilevel(root,
411                                                                                                   (Node *) prunequal,
412                                                                                                   subpart->relids,
413                                                                                                   targetpart->relids);
414                 }
415
416                 pruning_steps = gen_partprune_steps(subpart, partprunequal,
417                                                                                         &contradictory);
418
419                 if (contradictory)
420                 {
421                         /*
422                          * This shouldn't happen as the planner should have detected this
423                          * earlier. However, we do use additional quals from parameterized
424                          * paths here. These do only compare Params to the partition key,
425                          * so this shouldn't cause the discovery of any new qual
426                          * contradictions that were not previously discovered as the Param
427                          * values are unknown during planning.  Anyway, we'd better do
428                          * something sane here, so let's just disable run-time pruning.
429                          */
430                         return NIL;
431                 }
432
433                 /*
434                  * Construct the subplan and subpart maps for this partitioning level.
435                  * Here we convert to zero-based indexes, with -1 for empty entries.
436                  * Also construct a Bitmapset of all partitions that are present (that
437                  * is, not pruned already).
438                  */
439                 subplan_map = (int *) palloc(nparts * sizeof(int));
440                 subpart_map = (int *) palloc(nparts * sizeof(int));
441                 present_parts = NULL;
442
443                 for (i = 0; i < nparts; i++)
444                 {
445                         RelOptInfo *partrel = subpart->part_rels[i];
446                         int                     subplanidx = relid_subplan_map[partrel->relid] - 1;
447                         int                     subpartidx = relid_subpart_map[partrel->relid] - 1;
448
449                         subplan_map[i] = subplanidx;
450                         subpart_map[i] = subpartidx;
451                         if (subplanidx >= 0)
452                         {
453                                 present_parts = bms_add_member(present_parts, i);
454
455                                 /* Record finding this subplan  */
456                                 subplansfound = bms_add_member(subplansfound, subplanidx);
457                         }
458                         else if (subpartidx >= 0)
459                                 present_parts = bms_add_member(present_parts, i);
460                 }
461
462                 pinfo = makeNode(PartitionedRelPruneInfo);
463                 pinfo->rtindex = rti;
464                 pinfo->pruning_steps = pruning_steps;
465                 pinfo->present_parts = present_parts;
466                 pinfo->nparts = nparts;
467                 pinfo->subplan_map = subplan_map;
468                 pinfo->subpart_map = subpart_map;
469
470                 /* Determine which pruning types should be enabled at this level */
471                 doruntimeprune |= analyze_partkey_exprs(pinfo, pruning_steps,
472                                                                                                 partnatts);
473
474                 pinfolist = lappend(pinfolist, pinfo);
475         }
476
477         pfree(relid_subpart_map);
478
479         if (!doruntimeprune)
480         {
481                 /* No run-time pruning required. */
482                 return NIL;
483         }
484
485         *matchedsubplans = subplansfound;
486
487         return pinfolist;
488 }
489
490 /*
491  * gen_partprune_steps
492  *              Process 'clauses' (a rel's baserestrictinfo list of clauses) and return
493  *              a list of "partition pruning steps"
494  *
495  * If the clauses in the input list are contradictory or there is a
496  * pseudo-constant "false", *contradictory is set to true upon return.
497  */
498 static List *
499 gen_partprune_steps(RelOptInfo *rel, List *clauses, bool *contradictory)
500 {
501         GeneratePruningStepsContext context;
502
503         context.next_step_id = 0;
504         context.steps = NIL;
505
506         /* The clauses list may be modified below, so better make a copy. */
507         clauses = list_copy(clauses);
508
509         /*
510          * For sub-partitioned tables there's a corner case where if the
511          * sub-partitioned table shares any partition keys with its parent, then
512          * it's possible that the partitioning hierarchy allows the parent
513          * partition to only contain a narrower range of values than the
514          * sub-partitioned table does.  In this case it is possible that we'd
515          * include partitions that could not possibly have any tuples matching
516          * 'clauses'.  The possibility of such a partition arrangement is perhaps
517          * unlikely for non-default partitions, but it may be more likely in the
518          * case of default partitions, so we'll add the parent partition table's
519          * partition qual to the clause list in this case only.  This may result
520          * in the default partition being eliminated.
521          */
522         if (partition_bound_has_default(rel->boundinfo) &&
523                 rel->partition_qual != NIL)
524         {
525                 List       *partqual = rel->partition_qual;
526
527                 partqual = (List *) expression_planner((Expr *) partqual);
528
529                 /* Fix Vars to have the desired varno */
530                 if (rel->relid != 1)
531                         ChangeVarNodes((Node *) partqual, 1, rel->relid, 0);
532
533                 clauses = list_concat(clauses, partqual);
534         }
535
536         /* Down into the rabbit-hole. */
537         gen_partprune_steps_internal(&context, rel, clauses, contradictory);
538
539         return context.steps;
540 }
541
542 /*
543  * prune_append_rel_partitions
544  *              Returns RT indexes of the minimum set of child partitions which must
545  *              be scanned to satisfy rel's baserestrictinfo quals.
546  *
547  * Callers must ensure that 'rel' is a partitioned table.
548  */
549 Relids
550 prune_append_rel_partitions(RelOptInfo *rel)
551 {
552         Relids          result;
553         List       *clauses = rel->baserestrictinfo;
554         List       *pruning_steps;
555         bool            contradictory;
556         PartitionPruneContext context;
557         Bitmapset  *partindexes;
558         int                     i;
559
560         Assert(clauses != NIL);
561         Assert(rel->part_scheme != NULL);
562
563         /* If there are no partitions, return the empty set */
564         if (rel->nparts == 0)
565                 return NULL;
566
567         /*
568          * Process clauses.  If the clauses are found to be contradictory, we can
569          * return the empty set.
570          */
571         pruning_steps = gen_partprune_steps(rel, clauses, &contradictory);
572         if (contradictory)
573                 return NULL;
574
575         /* Set up PartitionPruneContext */
576         context.strategy = rel->part_scheme->strategy;
577         context.partnatts = rel->part_scheme->partnatts;
578         context.nparts = rel->nparts;
579         context.boundinfo = rel->boundinfo;
580         context.partcollation = rel->part_scheme->partcollation;
581         context.partsupfunc = rel->part_scheme->partsupfunc;
582         context.stepcmpfuncs = (FmgrInfo *) palloc0(sizeof(FmgrInfo) *
583                                                                                                 context.partnatts *
584                                                                                                 list_length(pruning_steps));
585         context.ppccontext = CurrentMemoryContext;
586
587         /* These are not valid when being called from the planner */
588         context.planstate = NULL;
589         context.exprstates = NULL;
590         context.exprhasexecparam = NULL;
591         context.evalexecparams = false;
592
593         /* Actual pruning happens here. */
594         partindexes = get_matching_partitions(&context, pruning_steps);
595
596         /* Add selected partitions' RT indexes to result. */
597         i = -1;
598         result = NULL;
599         while ((i = bms_next_member(partindexes, i)) >= 0)
600                 result = bms_add_member(result, rel->part_rels[i]->relid);
601
602         return result;
603 }
604
605 /*
606  * get_matching_partitions
607  *              Determine partitions that survive partition pruning
608  *
609  * Returns a Bitmapset of the RelOptInfo->part_rels indexes of the surviving
610  * partitions.
611  */
612 Bitmapset *
613 get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
614 {
615         Bitmapset  *result;
616         int                     num_steps = list_length(pruning_steps),
617                                 i;
618         PruneStepResult **results,
619                            *final_result;
620         ListCell   *lc;
621
622         /* If there are no pruning steps then all partitions match. */
623         if (num_steps == 0)
624         {
625                 Assert(context->nparts > 0);
626                 return bms_add_range(NULL, 0, context->nparts - 1);
627         }
628
629         /*
630          * Allocate space for individual pruning steps to store its result.  Each
631          * slot will hold a PruneStepResult after performing a given pruning step.
632          * Later steps may use the result of one or more earlier steps.  The
633          * result of applying all pruning steps is the value contained in the slot
634          * of the last pruning step.
635          */
636         results = (PruneStepResult **)
637                 palloc0(num_steps * sizeof(PruneStepResult *));
638         foreach(lc, pruning_steps)
639         {
640                 PartitionPruneStep *step = lfirst(lc);
641
642                 switch (nodeTag(step))
643                 {
644                         case T_PartitionPruneStepOp:
645                                 results[step->step_id] =
646                                         perform_pruning_base_step(context,
647                                                                                           (PartitionPruneStepOp *) step);
648                                 break;
649
650                         case T_PartitionPruneStepCombine:
651                                 results[step->step_id] =
652                                         perform_pruning_combine_step(context,
653                                                                                                  (PartitionPruneStepCombine *) step,
654                                                                                                  results);
655                                 break;
656
657                         default:
658                                 elog(ERROR, "invalid pruning step type: %d",
659                                          (int) nodeTag(step));
660                 }
661         }
662
663         /*
664          * At this point we know the offsets of all the datums whose corresponding
665          * partitions need to be in the result, including special null-accepting
666          * and default partitions.  Collect the actual partition indexes now.
667          */
668         final_result = results[num_steps - 1];
669         Assert(final_result != NULL);
670         i = -1;
671         result = NULL;
672         while ((i = bms_next_member(final_result->bound_offsets, i)) >= 0)
673         {
674                 int                     partindex = context->boundinfo->indexes[i];
675
676                 /*
677                  * In range and hash partitioning cases, some slots may contain -1,
678                  * indicating that no partition has been defined to accept a given
679                  * range of data or for a given remainder, respectively. The default
680                  * partition, if any, in case of range partitioning, will be added to
681                  * the result, because the specified range still satisfies the query's
682                  * conditions.
683                  */
684                 if (partindex >= 0)
685                         result = bms_add_member(result, partindex);
686         }
687
688         /* Add the null and/or default partition if needed and if present. */
689         if (final_result->scan_null)
690         {
691                 Assert(context->strategy == PARTITION_STRATEGY_LIST);
692                 Assert(partition_bound_accepts_nulls(context->boundinfo));
693                 result = bms_add_member(result, context->boundinfo->null_index);
694         }
695         if (final_result->scan_default)
696         {
697                 Assert(context->strategy == PARTITION_STRATEGY_LIST ||
698                            context->strategy == PARTITION_STRATEGY_RANGE);
699                 Assert(partition_bound_has_default(context->boundinfo));
700                 result = bms_add_member(result, context->boundinfo->default_index);
701         }
702
703         return result;
704 }
705
706 /*
707  * gen_partprune_steps_internal
708  *              Processes 'clauses' to generate partition pruning steps.
709  *
710  * From OpExpr clauses that are mutually AND'd, we find combinations of those
711  * that match to the partition key columns and for every such combination,
712  * we emit a PartitionPruneStepOp containing a vector of expressions whose
713  * values are used as a look up key to search partitions by comparing the
714  * values with partition bounds.  Relevant details of the operator and a
715  * vector of (possibly cross-type) comparison functions is also included with
716  * each step.
717  *
718  * For BoolExpr clauses, we recursively generate steps for each argument, and
719  * return a PartitionPruneStepCombine of their results.
720  *
721  * The return value is a list of the steps generated, which are also added to
722  * the context's steps list.  Each step is assigned a step identifier, unique
723  * even across recursive calls.
724  *
725  * If we find clauses that are mutually contradictory, or a pseudoconstant
726  * clause that contains false, we set *contradictory to true and return NIL
727  * (that is, no pruning steps).  Caller should consider all partitions as
728  * pruned in that case.  Otherwise, *contradictory is set to false.
729  *
730  * Note: the 'clauses' List may be modified inside this function. Callers may
731  * like to make a copy of it before passing them to this function.
732  */
733 static List *
734 gen_partprune_steps_internal(GeneratePruningStepsContext *context,
735                                                          RelOptInfo *rel, List *clauses,
736                                                          bool *contradictory)
737 {
738         PartitionScheme part_scheme = rel->part_scheme;
739         List       *keyclauses[PARTITION_MAX_KEYS];
740         Bitmapset  *nullkeys = NULL,
741                            *notnullkeys = NULL;
742         bool            generate_opsteps = false;
743         List       *result = NIL;
744         ListCell   *lc;
745
746         *contradictory = false;
747
748         memset(keyclauses, 0, sizeof(keyclauses));
749         foreach(lc, clauses)
750         {
751                 Expr       *clause = (Expr *) lfirst(lc);
752                 int                     i;
753
754                 /* Look through RestrictInfo, if any */
755                 if (IsA(clause, RestrictInfo))
756                         clause = ((RestrictInfo *) clause)->clause;
757
758                 /* Constant-false-or-null is contradictory */
759                 if (IsA(clause, Const) &&
760                         (((Const *) clause)->constisnull ||
761                          !DatumGetBool(((Const *) clause)->constvalue)))
762                 {
763                         *contradictory = true;
764                         return NIL;
765                 }
766
767                 /* Get the BoolExpr's out of the way. */
768                 if (IsA(clause, BoolExpr))
769                 {
770                         /*
771                          * Generate steps for arguments.
772                          *
773                          * While steps generated for the arguments themselves will be
774                          * added to context->steps during recursion and will be evaluated
775                          * independently, collect their step IDs to be stored in the
776                          * combine step we'll be creating.
777                          */
778                         if (or_clause((Node *) clause))
779                         {
780                                 List       *arg_stepids = NIL;
781                                 bool            all_args_contradictory = true;
782                                 ListCell   *lc1;
783
784                                 /*
785                                  * Get pruning step for each arg.  If we get contradictory for
786                                  * all args, it means the OR expression is false as a whole.
787                                  */
788                                 foreach(lc1, ((BoolExpr *) clause)->args)
789                                 {
790                                         Expr       *arg = lfirst(lc1);
791                                         bool            arg_contradictory;
792                                         List       *argsteps;
793
794                                         argsteps =
795                                                 gen_partprune_steps_internal(context, rel,
796                                                                                                          list_make1(arg),
797                                                                                                          &arg_contradictory);
798                                         if (!arg_contradictory)
799                                                 all_args_contradictory = false;
800
801                                         if (argsteps != NIL)
802                                         {
803                                                 PartitionPruneStep *step;
804
805                                                 Assert(list_length(argsteps) == 1);
806                                                 step = (PartitionPruneStep *) linitial(argsteps);
807                                                 arg_stepids = lappend_int(arg_stepids, step->step_id);
808                                         }
809                                         else
810                                         {
811                                                 /*
812                                                  * No steps either means that arg_contradictory is
813                                                  * true or the arg didn't contain a clause matching
814                                                  * this partition key.
815                                                  *
816                                                  * In case of the latter, we cannot prune using such
817                                                  * an arg.  To indicate that to the pruning code, we
818                                                  * must construct a dummy PartitionPruneStepCombine
819                                                  * whose source_stepids is set to an empty List.
820                                                  * However, if we can prove using constraint exclusion
821                                                  * that the clause refutes the table's partition
822                                                  * constraint (if it's sub-partitioned), we need not
823                                                  * bother with that.  That is, we effectively ignore
824                                                  * this OR arm.
825                                                  */
826                                                 List       *partconstr = rel->partition_qual;
827                                                 PartitionPruneStep *orstep;
828
829                                                 /* Just ignore this argument. */
830                                                 if (arg_contradictory)
831                                                         continue;
832
833                                                 if (partconstr)
834                                                 {
835                                                         partconstr = (List *)
836                                                                 expression_planner((Expr *) partconstr);
837                                                         if (rel->relid != 1)
838                                                                 ChangeVarNodes((Node *) partconstr, 1,
839                                                                                            rel->relid, 0);
840                                                         if (predicate_refuted_by(partconstr,
841                                                                                                          list_make1(arg),
842                                                                                                          false))
843                                                                 continue;
844                                                 }
845
846                                                 orstep = gen_prune_step_combine(context, NIL,
847                                                                                                                 PARTPRUNE_COMBINE_UNION);
848                                                 arg_stepids = lappend_int(arg_stepids, orstep->step_id);
849                                         }
850                                 }
851
852                                 *contradictory = all_args_contradictory;
853
854                                 /* Check if any contradicting clauses were found */
855                                 if (*contradictory)
856                                         return NIL;
857
858                                 if (arg_stepids != NIL)
859                                 {
860                                         PartitionPruneStep *step;
861
862                                         step = gen_prune_step_combine(context, arg_stepids,
863                                                                                                   PARTPRUNE_COMBINE_UNION);
864                                         result = lappend(result, step);
865                                 }
866                                 continue;
867                         }
868                         else if (and_clause((Node *) clause))
869                         {
870                                 List       *args = ((BoolExpr *) clause)->args;
871                                 List       *argsteps,
872                                                    *arg_stepids = NIL;
873                                 ListCell   *lc1;
874
875                                 /*
876                                  * args may itself contain clauses of arbitrary type, so just
877                                  * recurse and later combine the component partitions sets
878                                  * using a combine step.
879                                  */
880                                 argsteps = gen_partprune_steps_internal(context, rel, args,
881                                                                                                                 contradictory);
882                                 if (*contradictory)
883                                         return NIL;
884
885                                 foreach(lc1, argsteps)
886                                 {
887                                         PartitionPruneStep *step = lfirst(lc1);
888
889                                         arg_stepids = lappend_int(arg_stepids, step->step_id);
890                                 }
891
892                                 if (arg_stepids != NIL)
893                                 {
894                                         PartitionPruneStep *step;
895
896                                         step = gen_prune_step_combine(context, arg_stepids,
897                                                                                                   PARTPRUNE_COMBINE_INTERSECT);
898                                         result = lappend(result, step);
899                                 }
900                                 continue;
901                         }
902
903                         /*
904                          * Fall-through for a NOT clause, which if it's a Boolean clause,
905                          * will be handled in match_clause_to_partition_key(). We
906                          * currently don't perform any pruning for more complex NOT
907                          * clauses.
908                          */
909                 }
910
911                 /*
912                  * Must be a clause for which we can check if one of its args matches
913                  * the partition key.
914                  */
915                 for (i = 0; i < part_scheme->partnatts; i++)
916                 {
917                         Expr       *partkey = linitial(rel->partexprs[i]);
918                         bool            clause_is_not_null = false;
919                         PartClauseInfo *pc = NULL;
920                         List       *clause_steps = NIL;
921
922                         switch (match_clause_to_partition_key(rel, context,
923                                                                                                   clause, partkey, i,
924                                                                                                   &clause_is_not_null,
925                                                                                                   &pc, &clause_steps))
926                         {
927                                 case PARTCLAUSE_MATCH_CLAUSE:
928                                         Assert(pc != NULL);
929
930                                         /*
931                                          * Since we only allow strict operators, check for any
932                                          * contradicting IS NULL.
933                                          */
934                                         if (bms_is_member(i, nullkeys))
935                                         {
936                                                 *contradictory = true;
937                                                 return NIL;
938                                         }
939                                         generate_opsteps = true;
940                                         keyclauses[i] = lappend(keyclauses[i], pc);
941                                         break;
942
943                                 case PARTCLAUSE_MATCH_NULLNESS:
944                                         if (!clause_is_not_null)
945                                         {
946                                                 /* check for conflicting IS NOT NULL */
947                                                 if (bms_is_member(i, notnullkeys))
948                                                 {
949                                                         *contradictory = true;
950                                                         return NIL;
951                                                 }
952                                                 nullkeys = bms_add_member(nullkeys, i);
953                                         }
954                                         else
955                                         {
956                                                 /* check for conflicting IS NULL */
957                                                 if (bms_is_member(i, nullkeys))
958                                                 {
959                                                         *contradictory = true;
960                                                         return NIL;
961                                                 }
962                                                 notnullkeys = bms_add_member(notnullkeys, i);
963                                         }
964                                         break;
965
966                                 case PARTCLAUSE_MATCH_STEPS:
967                                         Assert(clause_steps != NIL);
968                                         result = list_concat(result, clause_steps);
969                                         break;
970
971                                 case PARTCLAUSE_MATCH_CONTRADICT:
972                                         /* We've nothing more to do if a contradiction was found. */
973                                         *contradictory = true;
974                                         return NIL;
975
976                                 case PARTCLAUSE_NOMATCH:
977
978                                         /*
979                                          * Clause didn't match this key, but it might match the
980                                          * next one.
981                                          */
982                                         continue;
983
984                                 case PARTCLAUSE_UNSUPPORTED:
985                                         /* This clause cannot be used for pruning. */
986                                         break;
987                         }
988
989                         /* done; go check the next clause. */
990                         break;
991                 }
992         }
993
994         /*-----------
995          * Now generate some (more) pruning steps.  We have three strategies:
996          *
997          * 1) Generate pruning steps based on IS NULL clauses:
998          *   a) For list partitioning, null partition keys can only be found in
999          *      the designated null-accepting partition, so if there are IS NULL
1000          *      clauses containing partition keys we should generate a pruning
1001          *      step that gets rid of all partitions but that one.  We can
1002          *      disregard any OpExpr we may have found.
1003          *   b) For range partitioning, only the default partition can contain
1004          *      NULL values, so the same rationale applies.
1005          *   c) For hash partitioning, we only apply this strategy if we have
1006          *      IS NULL clauses for all the keys.  Strategy 2 below will take
1007          *      care of the case where some keys have OpExprs and others have
1008          *      IS NULL clauses.
1009          *
1010          * 2) If not, generate steps based on OpExprs we have (if any).
1011          *
1012          * 3) If this doesn't work either, we may be able to generate steps to
1013          *    prune just the null-accepting partition (if one exists), if we have
1014          *    IS NOT NULL clauses for all partition keys.
1015          */
1016         if (!bms_is_empty(nullkeys) &&
1017                 (part_scheme->strategy == PARTITION_STRATEGY_LIST ||
1018                  part_scheme->strategy == PARTITION_STRATEGY_RANGE ||
1019                  (part_scheme->strategy == PARTITION_STRATEGY_HASH &&
1020                   bms_num_members(nullkeys) == part_scheme->partnatts)))
1021         {
1022                 PartitionPruneStep *step;
1023
1024                 /* Strategy 1 */
1025                 step = gen_prune_step_op(context, InvalidStrategy,
1026                                                                  false, NIL, NIL, nullkeys);
1027                 result = lappend(result, step);
1028         }
1029         else if (generate_opsteps)
1030         {
1031                 PartitionPruneStep *step;
1032
1033                 /* Strategy 2 */
1034                 step = gen_prune_steps_from_opexps(part_scheme, context,
1035                                                                                    keyclauses, nullkeys);
1036                 if (step != NULL)
1037                         result = lappend(result, step);
1038         }
1039         else if (bms_num_members(notnullkeys) == part_scheme->partnatts)
1040         {
1041                 PartitionPruneStep *step;
1042
1043                 /* Strategy 3 */
1044                 step = gen_prune_step_op(context, InvalidStrategy,
1045                                                                  false, NIL, NIL, NULL);
1046                 result = lappend(result, step);
1047         }
1048
1049         /*
1050          * Finally, results from all entries appearing in result should be
1051          * combined using an INTERSECT combine step, if more than one.
1052          */
1053         if (list_length(result) > 1)
1054         {
1055                 List       *step_ids = NIL;
1056
1057                 foreach(lc, result)
1058                 {
1059                         PartitionPruneStep *step = lfirst(lc);
1060
1061                         step_ids = lappend_int(step_ids, step->step_id);
1062                 }
1063
1064                 if (step_ids != NIL)
1065                 {
1066                         PartitionPruneStep *step;
1067
1068                         step = gen_prune_step_combine(context, step_ids,
1069                                                                                   PARTPRUNE_COMBINE_INTERSECT);
1070                         result = lappend(result, step);
1071                 }
1072         }
1073
1074         return result;
1075 }
1076
1077 /*
1078  * gen_prune_step_op
1079  *              Generate a pruning step for a specific operator
1080  *
1081  * The step is assigned a unique step identifier and added to context's 'steps'
1082  * list.
1083  */
1084 static PartitionPruneStep *
1085 gen_prune_step_op(GeneratePruningStepsContext *context,
1086                                   StrategyNumber opstrategy, bool op_is_ne,
1087                                   List *exprs, List *cmpfns,
1088                                   Bitmapset *nullkeys)
1089 {
1090         PartitionPruneStepOp *opstep = makeNode(PartitionPruneStepOp);
1091
1092         opstep->step.step_id = context->next_step_id++;
1093
1094         /*
1095          * For clauses that contain an <> operator, set opstrategy to
1096          * InvalidStrategy to signal get_matching_list_bounds to do the right
1097          * thing.
1098          */
1099         opstep->opstrategy = op_is_ne ? InvalidStrategy : opstrategy;
1100         Assert(list_length(exprs) == list_length(cmpfns));
1101         opstep->exprs = exprs;
1102         opstep->cmpfns = cmpfns;
1103         opstep->nullkeys = nullkeys;
1104
1105         context->steps = lappend(context->steps, opstep);
1106
1107         return (PartitionPruneStep *) opstep;
1108 }
1109
1110 /*
1111  * gen_prune_step_combine
1112  *              Generate a pruning step for a combination of several other steps
1113  *
1114  * The step is assigned a unique step identifier and added to context's
1115  * 'steps' list.
1116  */
1117 static PartitionPruneStep *
1118 gen_prune_step_combine(GeneratePruningStepsContext *context,
1119                                            List *source_stepids,
1120                                            PartitionPruneCombineOp combineOp)
1121 {
1122         PartitionPruneStepCombine *cstep = makeNode(PartitionPruneStepCombine);
1123
1124         cstep->step.step_id = context->next_step_id++;
1125         cstep->combineOp = combineOp;
1126         cstep->source_stepids = source_stepids;
1127
1128         context->steps = lappend(context->steps, cstep);
1129
1130         return (PartitionPruneStep *) cstep;
1131 }
1132
1133 /*
1134  * gen_prune_steps_from_opexps
1135  *              Generate pruning steps based on clauses for partition keys
1136  *
1137  * 'keyclauses' contains one list of clauses per partition key.  We check here
1138  * if we have found clauses for a valid subset of the partition key. In some
1139  * cases, (depending on the type of partitioning being used) if we didn't
1140  * find clauses for a given key, we discard clauses that may have been
1141  * found for any subsequent keys; see specific notes below.
1142  */
1143 static PartitionPruneStep *
1144 gen_prune_steps_from_opexps(PartitionScheme part_scheme,
1145                                                         GeneratePruningStepsContext *context,
1146                                                         List **keyclauses, Bitmapset *nullkeys)
1147 {
1148         ListCell   *lc;
1149         List       *opsteps = NIL;
1150         List       *btree_clauses[BTMaxStrategyNumber + 1],
1151                            *hash_clauses[HTMaxStrategyNumber + 1];
1152         bool            need_next_less,
1153                                 need_next_eq,
1154                                 need_next_greater;
1155         int                     i;
1156
1157         memset(btree_clauses, 0, sizeof(btree_clauses));
1158         memset(hash_clauses, 0, sizeof(hash_clauses));
1159         for (i = 0; i < part_scheme->partnatts; i++)
1160         {
1161                 List       *clauselist = keyclauses[i];
1162                 bool            consider_next_key = true;
1163
1164                 /*
1165                  * To be useful for pruning, we must have clauses for a prefix of
1166                  * partition keys in the case of range partitioning.  So, ignore
1167                  * clauses for keys after this one.
1168                  */
1169                 if (part_scheme->strategy == PARTITION_STRATEGY_RANGE &&
1170                         clauselist == NIL)
1171                         break;
1172
1173                 /*
1174                  * For hash partitioning, if a column doesn't have the necessary
1175                  * equality clause, there should be an IS NULL clause, otherwise
1176                  * pruning is not possible.
1177                  */
1178                 if (part_scheme->strategy == PARTITION_STRATEGY_HASH &&
1179                         clauselist == NIL && !bms_is_member(i, nullkeys))
1180                         return NULL;
1181
1182                 need_next_eq = need_next_less = need_next_greater = true;
1183                 foreach(lc, clauselist)
1184                 {
1185                         PartClauseInfo *pc = (PartClauseInfo *) lfirst(lc);
1186                         Oid                     lefttype,
1187                                                 righttype;
1188
1189                         /* Look up the operator's btree/hash strategy number. */
1190                         if (pc->op_strategy == InvalidStrategy)
1191                                 get_op_opfamily_properties(pc->opno,
1192                                                                                    part_scheme->partopfamily[i],
1193                                                                                    false,
1194                                                                                    &pc->op_strategy,
1195                                                                                    &lefttype,
1196                                                                                    &righttype);
1197
1198                         switch (part_scheme->strategy)
1199                         {
1200                                 case PARTITION_STRATEGY_LIST:
1201                                 case PARTITION_STRATEGY_RANGE:
1202                                         {
1203                                                 PartClauseInfo *last = NULL;
1204                                                 bool            inclusive = false;
1205
1206                                                 /*
1207                                                  * Add this clause to the list of clauses to be used
1208                                                  * for pruning if this is the first such key for this
1209                                                  * operator strategy or if it is consecutively next to
1210                                                  * the last column for which a clause with this
1211                                                  * operator strategy was matched.
1212                                                  */
1213                                                 if (btree_clauses[pc->op_strategy] != NIL)
1214                                                         last = llast(btree_clauses[pc->op_strategy]);
1215
1216                                                 if (last == NULL ||
1217                                                         i == last->keyno || i == last->keyno + 1)
1218                                                         btree_clauses[pc->op_strategy] =
1219                                                                 lappend(btree_clauses[pc->op_strategy], pc);
1220
1221                                                 /*
1222                                                  * We may not need the next clause if they're of
1223                                                  * certain strategy.
1224                                                  */
1225                                                 switch (pc->op_strategy)
1226                                                 {
1227                                                         case BTLessEqualStrategyNumber:
1228                                                                 inclusive = true;
1229                                                                 /* fall through */
1230                                                         case BTLessStrategyNumber:
1231                                                                 if (!inclusive)
1232                                                                         need_next_eq = need_next_less = false;
1233                                                                 break;
1234                                                         case BTEqualStrategyNumber:
1235                                                                 /* always accept clauses for the next key. */
1236                                                                 break;
1237                                                         case BTGreaterEqualStrategyNumber:
1238                                                                 inclusive = true;
1239                                                                 /* fall through */
1240                                                         case BTGreaterStrategyNumber:
1241                                                                 if (!inclusive)
1242                                                                         need_next_eq = need_next_greater = false;
1243                                                                 break;
1244                                                 }
1245
1246                                                 /* We may want to change our mind. */
1247                                                 if (consider_next_key)
1248                                                         consider_next_key = (need_next_eq ||
1249                                                                                                  need_next_less ||
1250                                                                                                  need_next_greater);
1251                                                 break;
1252                                         }
1253
1254                                 case PARTITION_STRATEGY_HASH:
1255                                         if (pc->op_strategy != HTEqualStrategyNumber)
1256                                                 elog(ERROR, "invalid clause for hash partitioning");
1257                                         hash_clauses[pc->op_strategy] =
1258                                                 lappend(hash_clauses[pc->op_strategy], pc);
1259                                         break;
1260
1261                                 default:
1262                                         elog(ERROR, "invalid partition strategy: %c",
1263                                                  part_scheme->strategy);
1264                                         break;
1265                         }
1266                 }
1267
1268                 /*
1269                  * If we've decided that clauses for subsequent partition keys
1270                  * wouldn't be useful for pruning, don't search any further.
1271                  */
1272                 if (!consider_next_key)
1273                         break;
1274         }
1275
1276         /*
1277          * Now, we have divided clauses according to their operator strategies.
1278          * Check for each strategy if we can generate pruning step(s) by
1279          * collecting a list of expressions whose values will constitute a vector
1280          * that can be used as a lookup key by a partition bound searching
1281          * function.
1282          */
1283         switch (part_scheme->strategy)
1284         {
1285                 case PARTITION_STRATEGY_LIST:
1286                 case PARTITION_STRATEGY_RANGE:
1287                         {
1288                                 List       *eq_clauses = btree_clauses[BTEqualStrategyNumber];
1289                                 List       *le_clauses = btree_clauses[BTLessEqualStrategyNumber];
1290                                 List       *ge_clauses = btree_clauses[BTGreaterEqualStrategyNumber];
1291                                 int                     strat;
1292
1293                                 /*
1294                                  * For each clause under consideration for a given strategy,
1295                                  * we collect expressions from clauses for earlier keys, whose
1296                                  * operator strategy is inclusive, into a list called
1297                                  * 'prefix'. By appending the clause's own expression to the
1298                                  * 'prefix', we'll generate one step using the so generated
1299                                  * vector and assign the current strategy to it.  Actually,
1300                                  * 'prefix' might contain multiple clauses for the same key,
1301                                  * in which case, we must generate steps for various
1302                                  * combinations of expressions of different keys, which
1303                                  * get_steps_using_prefix takes care of for us.
1304                                  */
1305                                 for (strat = 1; strat <= BTMaxStrategyNumber; strat++)
1306                                 {
1307                                         foreach(lc, btree_clauses[strat])
1308                                         {
1309                                                 PartClauseInfo *pc = lfirst(lc);
1310                                                 ListCell   *lc1;
1311                                                 List       *prefix = NIL;
1312                                                 List       *pc_steps;
1313
1314                                                 /*
1315                                                  * Expressions from = clauses can always be in the
1316                                                  * prefix, provided they're from an earlier key.
1317                                                  */
1318                                                 foreach(lc1, eq_clauses)
1319                                                 {
1320                                                         PartClauseInfo *eqpc = lfirst(lc1);
1321
1322                                                         if (eqpc->keyno == pc->keyno)
1323                                                                 break;
1324                                                         if (eqpc->keyno < pc->keyno)
1325                                                                 prefix = lappend(prefix, eqpc);
1326                                                 }
1327
1328                                                 /*
1329                                                  * If we're generating steps for </<= strategy, we can
1330                                                  * add other <= clauses to the prefix, provided
1331                                                  * they're from an earlier key.
1332                                                  */
1333                                                 if (strat == BTLessStrategyNumber ||
1334                                                         strat == BTLessEqualStrategyNumber)
1335                                                 {
1336                                                         foreach(lc1, le_clauses)
1337                                                         {
1338                                                                 PartClauseInfo *lepc = lfirst(lc1);
1339
1340                                                                 if (lepc->keyno == pc->keyno)
1341                                                                         break;
1342                                                                 if (lepc->keyno < pc->keyno)
1343                                                                         prefix = lappend(prefix, lepc);
1344                                                         }
1345                                                 }
1346
1347                                                 /*
1348                                                  * If we're generating steps for >/>= strategy, we can
1349                                                  * add other >= clauses to the prefix, provided
1350                                                  * they're from an earlier key.
1351                                                  */
1352                                                 if (strat == BTGreaterStrategyNumber ||
1353                                                         strat == BTGreaterEqualStrategyNumber)
1354                                                 {
1355                                                         foreach(lc1, ge_clauses)
1356                                                         {
1357                                                                 PartClauseInfo *gepc = lfirst(lc1);
1358
1359                                                                 if (gepc->keyno == pc->keyno)
1360                                                                         break;
1361                                                                 if (gepc->keyno < pc->keyno)
1362                                                                         prefix = lappend(prefix, gepc);
1363                                                         }
1364                                                 }
1365
1366                                                 /*
1367                                                  * As mentioned above, if 'prefix' contains multiple
1368                                                  * expressions for the same key, the following will
1369                                                  * generate multiple steps, one for each combination
1370                                                  * of the expressions for different keys.
1371                                                  *
1372                                                  * Note that we pass NULL for step_nullkeys, because
1373                                                  * we don't search list/range partition bounds where
1374                                                  * some keys are NULL.
1375                                                  */
1376                                                 Assert(pc->op_strategy == strat);
1377                                                 pc_steps = get_steps_using_prefix(context, strat,
1378                                                                                                                   pc->op_is_ne,
1379                                                                                                                   pc->expr,
1380                                                                                                                   pc->cmpfn,
1381                                                                                                                   pc->keyno,
1382                                                                                                                   NULL,
1383                                                                                                                   prefix);
1384                                                 opsteps = list_concat(opsteps, list_copy(pc_steps));
1385                                         }
1386                                 }
1387                                 break;
1388                         }
1389
1390                 case PARTITION_STRATEGY_HASH:
1391                         {
1392                                 List       *eq_clauses = hash_clauses[HTEqualStrategyNumber];
1393
1394                                 /* For hash partitioning, we have just the = strategy. */
1395                                 if (eq_clauses != NIL)
1396                                 {
1397                                         PartClauseInfo *pc;
1398                                         List       *pc_steps;
1399                                         List       *prefix = NIL;
1400                                         int                     last_keyno;
1401                                         ListCell   *lc1;
1402
1403                                         /*
1404                                          * Locate the clause for the greatest column.  This may
1405                                          * not belong to the last partition key, but it is the
1406                                          * clause belonging to the last partition key we found a
1407                                          * clause for above.
1408                                          */
1409                                         pc = llast(eq_clauses);
1410
1411                                         /*
1412                                          * There might be multiple clauses which matched to that
1413                                          * partition key; find the first such clause.  While at
1414                                          * it, add all the clauses before that one to 'prefix'.
1415                                          */
1416                                         last_keyno = pc->keyno;
1417                                         foreach(lc, eq_clauses)
1418                                         {
1419                                                 pc = lfirst(lc);
1420                                                 if (pc->keyno == last_keyno)
1421                                                         break;
1422                                                 prefix = lappend(prefix, pc);
1423                                         }
1424
1425                                         /*
1426                                          * For each clause for the "last" column, after appending
1427                                          * the clause's own expression to the 'prefix', we'll
1428                                          * generate one step using the so generated vector and
1429                                          * assign = as its strategy.  Actually, 'prefix' might
1430                                          * contain multiple clauses for the same key, in which
1431                                          * case, we must generate steps for various combinations
1432                                          * of expressions of different keys, which
1433                                          * get_steps_using_prefix will take care of for us.
1434                                          */
1435                                         for_each_cell(lc1, lc)
1436                                         {
1437                                                 pc = lfirst(lc1);
1438
1439                                                 /*
1440                                                  * Note that we pass nullkeys for step_nullkeys,
1441                                                  * because we need to tell hash partition bound search
1442                                                  * function which of the keys we found IS NULL clauses
1443                                                  * for.
1444                                                  */
1445                                                 Assert(pc->op_strategy == HTEqualStrategyNumber);
1446                                                 pc_steps =
1447                                                         get_steps_using_prefix(context,
1448                                                                                                    HTEqualStrategyNumber,
1449                                                                                                    false,
1450                                                                                                    pc->expr,
1451                                                                                                    pc->cmpfn,
1452                                                                                                    pc->keyno,
1453                                                                                                    nullkeys,
1454                                                                                                    prefix);
1455                                                 opsteps = list_concat(opsteps, list_copy(pc_steps));
1456                                         }
1457                                 }
1458                                 break;
1459                         }
1460
1461                 default:
1462                         elog(ERROR, "invalid partition strategy: %c",
1463                                  part_scheme->strategy);
1464                         break;
1465         }
1466
1467         /* Lastly, add a combine step to mutually AND these op steps, if needed */
1468         if (list_length(opsteps) > 1)
1469         {
1470                 List       *opstep_ids = NIL;
1471
1472                 foreach(lc, opsteps)
1473                 {
1474                         PartitionPruneStep *step = lfirst(lc);
1475
1476                         opstep_ids = lappend_int(opstep_ids, step->step_id);
1477                 }
1478
1479                 if (opstep_ids != NIL)
1480                         return gen_prune_step_combine(context, opstep_ids,
1481                                                                                   PARTPRUNE_COMBINE_INTERSECT);
1482                 return NULL;
1483         }
1484         else if (opsteps != NIL)
1485                 return linitial(opsteps);
1486
1487         return NULL;
1488 }
1489
1490 /*
1491  * If the partition key has a collation, then the clause must have the same
1492  * input collation.  If the partition key is non-collatable, we assume the
1493  * collation doesn't matter, because while collation wasn't considered when
1494  * performing partitioning, the clause still may have a collation assigned
1495  * due to the other input being of a collatable type.
1496  *
1497  * See also IndexCollMatchesExprColl.
1498  */
1499 #define PartCollMatchesExprColl(partcoll, exprcoll) \
1500         ((partcoll) == InvalidOid || (partcoll) == (exprcoll))
1501
1502 /*
1503  * match_clause_to_partition_key
1504  *              Attempt to match the given 'clause' with the specified partition key.
1505  *
1506  * Return value is:
1507  * * PARTCLAUSE_NOMATCH if the clause doesn't match this partition key (but
1508  *   caller should keep trying, because it might match a subsequent key).
1509  *   Output arguments: none set.
1510  *
1511  * * PARTCLAUSE_MATCH_CLAUSE if there is a match.
1512  *   Output arguments: *pc is set to a PartClauseInfo constructed for the
1513  *   matched clause.
1514  *
1515  * * PARTCLAUSE_MATCH_NULLNESS if there is a match, and the matched clause was
1516  *   either a "a IS NULL" or "a IS NOT NULL" clause.
1517  *   Output arguments: *clause_is_not_null is set to false in the former case
1518  *   true otherwise.
1519  *
1520  * * PARTCLAUSE_MATCH_STEPS if there is a match.
1521  *   Output arguments: *clause_steps is set to a list of PartitionPruneStep
1522  *   generated for the clause.
1523  *
1524  * * PARTCLAUSE_MATCH_CONTRADICT if the clause is self-contradictory, ie
1525  *   it provably returns FALSE or NULL.
1526  *   Output arguments: none set.
1527  *
1528  * * PARTCLAUSE_UNSUPPORTED if the clause doesn't match this partition key
1529  *   and couldn't possibly match any other one either, due to its form or
1530  *   properties (such as containing a volatile function).
1531  *   Output arguments: none set.
1532  */
1533 static PartClauseMatchStatus
1534 match_clause_to_partition_key(RelOptInfo *rel,
1535                                                           GeneratePruningStepsContext *context,
1536                                                           Expr *clause, Expr *partkey, int partkeyidx,
1537                                                           bool *clause_is_not_null, PartClauseInfo **pc,
1538                                                           List **clause_steps)
1539 {
1540         PartitionScheme part_scheme = rel->part_scheme;
1541         Oid                     partopfamily = part_scheme->partopfamily[partkeyidx],
1542                                 partcoll = part_scheme->partcollation[partkeyidx];
1543         Expr       *expr;
1544
1545         /*
1546          * Recognize specially shaped clauses that match with the Boolean
1547          * partition key.
1548          */
1549         if (match_boolean_partition_clause(partopfamily, clause, partkey, &expr))
1550         {
1551                 PartClauseInfo *partclause;
1552
1553                 partclause = (PartClauseInfo *) palloc(sizeof(PartClauseInfo));
1554                 partclause->keyno = partkeyidx;
1555                 /* Do pruning with the Boolean equality operator. */
1556                 partclause->opno = BooleanEqualOperator;
1557                 partclause->op_is_ne = false;
1558                 partclause->expr = expr;
1559                 /* We know that expr is of Boolean type. */
1560                 partclause->cmpfn = rel->part_scheme->partsupfunc[partkeyidx].fn_oid;
1561                 partclause->op_strategy = InvalidStrategy;
1562
1563                 *pc = partclause;
1564
1565                 return PARTCLAUSE_MATCH_CLAUSE;
1566         }
1567         else if (IsA(clause, OpExpr) &&
1568                          list_length(((OpExpr *) clause)->args) == 2)
1569         {
1570                 OpExpr     *opclause = (OpExpr *) clause;
1571                 Expr       *leftop,
1572                                    *rightop;
1573                 Oid                     opno,
1574                                         op_lefttype,
1575                                         op_righttype,
1576                                         negator = InvalidOid;
1577                 Oid                     cmpfn;
1578                 int                     op_strategy;
1579                 bool            is_opne_listp = false;
1580                 PartClauseInfo *partclause;
1581
1582                 leftop = (Expr *) get_leftop(clause);
1583                 if (IsA(leftop, RelabelType))
1584                         leftop = ((RelabelType *) leftop)->arg;
1585                 rightop = (Expr *) get_rightop(clause);
1586                 if (IsA(rightop, RelabelType))
1587                         rightop = ((RelabelType *) rightop)->arg;
1588                 opno = opclause->opno;
1589
1590                 /* check if the clause matches this partition key */
1591                 if (equal(leftop, partkey))
1592                         expr = rightop;
1593                 else if (equal(rightop, partkey))
1594                 {
1595                         /*
1596                          * It's only useful if we can commute the operator to put the
1597                          * partkey on the left.  If we can't, the clause can be deemed
1598                          * UNSUPPORTED.  Even if its leftop matches some later partkey, we
1599                          * now know it has Vars on the right, so it's no use.
1600                          */
1601                         opno = get_commutator(opno);
1602                         if (!OidIsValid(opno))
1603                                 return PARTCLAUSE_UNSUPPORTED;
1604                         expr = leftop;
1605                 }
1606                 else
1607                         /* clause does not match this partition key, but perhaps next. */
1608                         return PARTCLAUSE_NOMATCH;
1609
1610                 /*
1611                  * Partition key match also requires collation match.  There may be
1612                  * multiple partkeys with the same expression but different
1613                  * collations, so failure is NOMATCH.
1614                  */
1615                 if (!PartCollMatchesExprColl(partcoll, opclause->inputcollid))
1616                         return PARTCLAUSE_NOMATCH;
1617
1618                 /*
1619                  * Matched with this key.  Now check various properties of the clause
1620                  * to see if it's sane to use it for pruning.  In most of these cases,
1621                  * we can return UNSUPPORTED because the same failure would occur no
1622                  * matter which partkey it's matched to.
1623                  */
1624
1625                 /*
1626                  * We can't prune using an expression with Vars.  (Report failure as
1627                  * UNSUPPORTED, not NOMATCH: as in the no-commutator case above, we
1628                  * now know there are Vars on both sides, so it's no good.)
1629                  */
1630                 if (contain_var_clause((Node *) expr))
1631                         return PARTCLAUSE_UNSUPPORTED;
1632
1633                 /*
1634                  * Only allow strict operators.  This will guarantee nulls are
1635                  * filtered.
1636                  */
1637                 if (!op_strict(opno))
1638                         return PARTCLAUSE_UNSUPPORTED;
1639
1640                 /* We can't use any volatile expressions to prune partitions. */
1641                 if (contain_volatile_functions((Node *) expr))
1642                         return PARTCLAUSE_UNSUPPORTED;
1643
1644                 /*
1645                  * See if the operator is relevant to the partitioning opfamily.
1646                  *
1647                  * Normally we only care about operators that are listed as being part
1648                  * of the partitioning operator family.  But there is one exception:
1649                  * the not-equals operators are not listed in any operator family
1650                  * whatsoever, but their negators (equality) are.  We can use one of
1651                  * those if we find it, but only for list partitioning.
1652                  *
1653                  * Note: we report NOMATCH on failure, in case a later partkey has the
1654                  * same expression but different opfamily.  That's unlikely, but not
1655                  * much more so than duplicate expressions with different collations.
1656                  */
1657                 if (op_in_opfamily(opno, partopfamily))
1658                 {
1659                         get_op_opfamily_properties(opno, partopfamily, false,
1660                                                                            &op_strategy, &op_lefttype,
1661                                                                            &op_righttype);
1662                 }
1663                 else
1664                 {
1665                         if (part_scheme->strategy != PARTITION_STRATEGY_LIST)
1666                                 return PARTCLAUSE_NOMATCH;
1667
1668                         /* See if the negator is equality */
1669                         negator = get_negator(opno);
1670                         if (OidIsValid(negator) && op_in_opfamily(negator, partopfamily))
1671                         {
1672                                 get_op_opfamily_properties(negator, partopfamily, false,
1673                                                                                    &op_strategy, &op_lefttype,
1674                                                                                    &op_righttype);
1675                                 if (op_strategy == BTEqualStrategyNumber)
1676                                         is_opne_listp = true;   /* bingo */
1677                         }
1678
1679                         /* Nope, it's not <> either. */
1680                         if (!is_opne_listp)
1681                                 return PARTCLAUSE_NOMATCH;
1682                 }
1683
1684                 /*
1685                  * Now find the procedure to use, based on the types.  If the clause's
1686                  * other argument is of the same type as the partitioning opclass's
1687                  * declared input type, we can use the procedure cached in
1688                  * PartitionKey.  If not, search for a cross-type one in the same
1689                  * opfamily; if one doesn't exist, report no match.
1690                  */
1691                 if (op_righttype == part_scheme->partopcintype[partkeyidx])
1692                         cmpfn = part_scheme->partsupfunc[partkeyidx].fn_oid;
1693                 else
1694                 {
1695                         switch (part_scheme->strategy)
1696                         {
1697                                         /*
1698                                          * For range and list partitioning, we need the ordering
1699                                          * procedure with lefttype being the partition key's type,
1700                                          * and righttype the clause's operator's right type.
1701                                          */
1702                                 case PARTITION_STRATEGY_LIST:
1703                                 case PARTITION_STRATEGY_RANGE:
1704                                         cmpfn =
1705                                                 get_opfamily_proc(part_scheme->partopfamily[partkeyidx],
1706                                                                                   part_scheme->partopcintype[partkeyidx],
1707                                                                                   op_righttype, BTORDER_PROC);
1708                                         break;
1709
1710                                         /*
1711                                          * For hash partitioning, we need the hashing procedure
1712                                          * for the clause's type.
1713                                          */
1714                                 case PARTITION_STRATEGY_HASH:
1715                                         cmpfn =
1716                                                 get_opfamily_proc(part_scheme->partopfamily[partkeyidx],
1717                                                                                   op_righttype, op_righttype,
1718                                                                                   HASHEXTENDED_PROC);
1719                                         break;
1720
1721                                 default:
1722                                         elog(ERROR, "invalid partition strategy: %c",
1723                                                  part_scheme->strategy);
1724                                         cmpfn = InvalidOid; /* keep compiler quiet */
1725                                         break;
1726                         }
1727
1728                         if (!OidIsValid(cmpfn))
1729                                 return PARTCLAUSE_NOMATCH;
1730                 }
1731
1732                 /*
1733                  * Build the clause, passing the negator if applicable.
1734                  */
1735                 partclause = (PartClauseInfo *) palloc(sizeof(PartClauseInfo));
1736                 partclause->keyno = partkeyidx;
1737                 if (is_opne_listp)
1738                 {
1739                         Assert(OidIsValid(negator));
1740                         partclause->opno = negator;
1741                         partclause->op_is_ne = true;
1742                         partclause->op_strategy = InvalidStrategy;
1743                 }
1744                 else
1745                 {
1746                         partclause->opno = opno;
1747                         partclause->op_is_ne = false;
1748                         partclause->op_strategy = op_strategy;
1749                 }
1750                 partclause->expr = expr;
1751                 partclause->cmpfn = cmpfn;
1752
1753                 *pc = partclause;
1754
1755                 return PARTCLAUSE_MATCH_CLAUSE;
1756         }
1757         else if (IsA(clause, ScalarArrayOpExpr))
1758         {
1759                 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
1760                 Oid                     saop_op = saop->opno;
1761                 Oid                     saop_coll = saop->inputcollid;
1762                 Expr       *leftop = (Expr *) linitial(saop->args),
1763                                    *rightop = (Expr *) lsecond(saop->args);
1764                 List       *elem_exprs,
1765                                    *elem_clauses;
1766                 ListCell   *lc1;
1767                 bool            contradictory;
1768
1769                 if (IsA(leftop, RelabelType))
1770                         leftop = ((RelabelType *) leftop)->arg;
1771
1772                 /* Check it matches this partition key */
1773                 if (!equal(leftop, partkey) ||
1774                         !PartCollMatchesExprColl(partcoll, saop->inputcollid))
1775                         return PARTCLAUSE_NOMATCH;
1776
1777                 /*
1778                  * Matched with this key.  Check various properties of the clause to
1779                  * see if it can sanely be used for partition pruning (this is mostly
1780                  * the same as for a plain OpExpr).
1781                  */
1782
1783                 /* We can't prune using an expression with Vars. */
1784                 if (contain_var_clause((Node *) rightop))
1785                         return PARTCLAUSE_UNSUPPORTED;
1786
1787                 /*
1788                  * Only allow strict operators.  This will guarantee nulls are
1789                  * filtered.
1790                  */
1791                 if (!op_strict(saop_op))
1792                         return PARTCLAUSE_UNSUPPORTED;
1793
1794                 /* We can't use any volatile expressions to prune partitions. */
1795                 if (contain_volatile_functions((Node *) rightop))
1796                         return PARTCLAUSE_UNSUPPORTED;
1797
1798                 /*
1799                  * In case of NOT IN (..), we get a '<>', which we handle if list
1800                  * partitioning is in use and we're able to confirm that it's negator
1801                  * is a btree equality operator belonging to the partitioning operator
1802                  * family.  As above, report NOMATCH for non-matching operator.
1803                  */
1804                 if (!op_in_opfamily(saop_op, partopfamily))
1805                 {
1806                         Oid                     negator;
1807
1808                         if (part_scheme->strategy != PARTITION_STRATEGY_LIST)
1809                                 return PARTCLAUSE_NOMATCH;
1810
1811                         negator = get_negator(saop_op);
1812                         if (OidIsValid(negator) && op_in_opfamily(negator, partopfamily))
1813                         {
1814                                 int                     strategy;
1815                                 Oid                     lefttype,
1816                                                         righttype;
1817
1818                                 get_op_opfamily_properties(negator, partopfamily,
1819                                                                                    false, &strategy,
1820                                                                                    &lefttype, &righttype);
1821                                 if (strategy != BTEqualStrategyNumber)
1822                                         return PARTCLAUSE_NOMATCH;
1823                         }
1824                         else
1825                                 return PARTCLAUSE_NOMATCH;      /* no useful negator */
1826                 }
1827
1828                 /*
1829                  * First generate a list of Const nodes, one for each array element
1830                  * (excepting nulls).
1831                  */
1832                 elem_exprs = NIL;
1833                 if (IsA(rightop, Const))
1834                 {
1835                         Const      *arr = (Const *) rightop;
1836                         ArrayType  *arrval = DatumGetArrayTypeP(arr->constvalue);
1837                         int16           elemlen;
1838                         bool            elembyval;
1839                         char            elemalign;
1840                         Datum      *elem_values;
1841                         bool       *elem_nulls;
1842                         int                     num_elems,
1843                                                 i;
1844
1845                         get_typlenbyvalalign(ARR_ELEMTYPE(arrval),
1846                                                                  &elemlen, &elembyval, &elemalign);
1847                         deconstruct_array(arrval,
1848                                                           ARR_ELEMTYPE(arrval),
1849                                                           elemlen, elembyval, elemalign,
1850                                                           &elem_values, &elem_nulls,
1851                                                           &num_elems);
1852                         for (i = 0; i < num_elems; i++)
1853                         {
1854                                 Const      *elem_expr;
1855
1856                                 /*
1857                                  * A null array element must lead to a null comparison result,
1858                                  * since saop_op is known strict.  We can ignore it in the
1859                                  * useOr case, but otherwise it implies self-contradiction.
1860                                  */
1861                                 if (elem_nulls[i])
1862                                 {
1863                                         if (saop->useOr)
1864                                                 continue;
1865                                         return PARTCLAUSE_MATCH_CONTRADICT;
1866                                 }
1867
1868                                 elem_expr = makeConst(ARR_ELEMTYPE(arrval), -1,
1869                                                                           arr->constcollid, elemlen,
1870                                                                           elem_values[i], false, elembyval);
1871                                 elem_exprs = lappend(elem_exprs, elem_expr);
1872                         }
1873                 }
1874                 else if (IsA(rightop, ArrayExpr))
1875                 {
1876                         ArrayExpr  *arrexpr = castNode(ArrayExpr, rightop);
1877
1878                         /*
1879                          * For a nested ArrayExpr, we don't know how to get the actual
1880                          * scalar values out into a flat list, so we give up doing
1881                          * anything with this ScalarArrayOpExpr.
1882                          */
1883                         if (arrexpr->multidims)
1884                                 return PARTCLAUSE_UNSUPPORTED;
1885
1886                         elem_exprs = arrexpr->elements;
1887                 }
1888                 else
1889                 {
1890                         /* Give up on any other clause types. */
1891                         return PARTCLAUSE_UNSUPPORTED;
1892                 }
1893
1894                 /*
1895                  * Now generate a list of clauses, one for each array element, of the
1896                  * form saop_leftop saop_op elem_expr
1897                  */
1898                 elem_clauses = NIL;
1899                 foreach(lc1, elem_exprs)
1900                 {
1901                         Expr       *rightop = (Expr *) lfirst(lc1),
1902                                            *elem_clause;
1903
1904                         elem_clause = make_opclause(saop_op, BOOLOID, false,
1905                                                                                 leftop, rightop,
1906                                                                                 InvalidOid, saop_coll);
1907                         elem_clauses = lappend(elem_clauses, elem_clause);
1908                 }
1909
1910                 /*
1911                  * If we have an ANY clause and multiple elements, now turn the list
1912                  * of clauses into an OR expression.
1913                  */
1914                 if (saop->useOr && list_length(elem_clauses) > 1)
1915                         elem_clauses = list_make1(makeBoolExpr(OR_EXPR, elem_clauses, -1));
1916
1917                 /* Finally, generate steps */
1918                 *clause_steps =
1919                         gen_partprune_steps_internal(context, rel, elem_clauses,
1920                                                                                  &contradictory);
1921                 if (contradictory)
1922                         return PARTCLAUSE_MATCH_CONTRADICT;
1923                 else if (*clause_steps == NIL)
1924                         return PARTCLAUSE_UNSUPPORTED;  /* step generation failed */
1925                 return PARTCLAUSE_MATCH_STEPS;
1926         }
1927         else if (IsA(clause, NullTest))
1928         {
1929                 NullTest   *nulltest = (NullTest *) clause;
1930                 Expr       *arg = nulltest->arg;
1931
1932                 if (IsA(arg, RelabelType))
1933                         arg = ((RelabelType *) arg)->arg;
1934
1935                 /* Does arg match with this partition key column? */
1936                 if (!equal(arg, partkey))
1937                         return PARTCLAUSE_NOMATCH;
1938
1939                 *clause_is_not_null = (nulltest->nulltesttype == IS_NOT_NULL);
1940
1941                 return PARTCLAUSE_MATCH_NULLNESS;
1942         }
1943
1944         return PARTCLAUSE_UNSUPPORTED;
1945 }
1946
1947 /*
1948  * get_steps_using_prefix
1949  *              Generate list of PartitionPruneStepOp steps each consisting of given
1950  *              opstrategy
1951  *
1952  * To generate steps, step_lastexpr and step_lastcmpfn are appended to
1953  * expressions and cmpfns, respectively, extracted from the clauses in
1954  * 'prefix'.  Actually, since 'prefix' may contain multiple clauses for the
1955  * same partition key column, we must generate steps for various combinations
1956  * of the clauses of different keys.
1957  */
1958 static List *
1959 get_steps_using_prefix(GeneratePruningStepsContext *context,
1960                                            StrategyNumber step_opstrategy,
1961                                            bool step_op_is_ne,
1962                                            Expr *step_lastexpr,
1963                                            Oid step_lastcmpfn,
1964                                            int step_lastkeyno,
1965                                            Bitmapset *step_nullkeys,
1966                                            List *prefix)
1967 {
1968         /* Quick exit if there are no values to prefix with. */
1969         if (list_length(prefix) == 0)
1970         {
1971                 PartitionPruneStep *step;
1972
1973                 step = gen_prune_step_op(context,
1974                                                                  step_opstrategy,
1975                                                                  step_op_is_ne,
1976                                                                  list_make1(step_lastexpr),
1977                                                                  list_make1_oid(step_lastcmpfn),
1978                                                                  step_nullkeys);
1979                 return list_make1(step);
1980         }
1981
1982         /* Recurse to generate steps for various combinations. */
1983         return get_steps_using_prefix_recurse(context,
1984                                                                                   step_opstrategy,
1985                                                                                   step_op_is_ne,
1986                                                                                   step_lastexpr,
1987                                                                                   step_lastcmpfn,
1988                                                                                   step_lastkeyno,
1989                                                                                   step_nullkeys,
1990                                                                                   list_head(prefix),
1991                                                                                   NIL, NIL);
1992 }
1993
1994 /*
1995  * get_steps_using_prefix_recurse
1996  *              Recursively generate combinations of clauses for different partition
1997  *              keys and start generating steps upon reaching clauses for the greatest
1998  *              column that is less than the one for which we're currently generating
1999  *              steps (that is, step_lastkeyno)
2000  *
2001  * 'start' is where we should start iterating for the current invocation.
2002  * 'step_exprs' and 'step_cmpfns' each contains the expressions and cmpfns
2003  * we've generated so far from the clauses for the previous part keys.
2004  */
2005 static List *
2006 get_steps_using_prefix_recurse(GeneratePruningStepsContext *context,
2007                                                            StrategyNumber step_opstrategy,
2008                                                            bool step_op_is_ne,
2009                                                            Expr *step_lastexpr,
2010                                                            Oid step_lastcmpfn,
2011                                                            int step_lastkeyno,
2012                                                            Bitmapset *step_nullkeys,
2013                                                            ListCell *start,
2014                                                            List *step_exprs,
2015                                                            List *step_cmpfns)
2016 {
2017         List       *result = NIL;
2018         ListCell   *lc;
2019         int                     cur_keyno;
2020
2021         /* Actually, recursion would be limited by PARTITION_MAX_KEYS. */
2022         check_stack_depth();
2023
2024         /* Check if we need to recurse. */
2025         Assert(start != NULL);
2026         cur_keyno = ((PartClauseInfo *) lfirst(start))->keyno;
2027         if (cur_keyno < step_lastkeyno - 1)
2028         {
2029                 PartClauseInfo *pc;
2030                 ListCell   *next_start;
2031
2032                 /*
2033                  * For each clause with cur_keyno, adds its expr and cmpfn to
2034                  * step_exprs and step_cmpfns, respectively, and recurse after setting
2035                  * next_start to the ListCell of the first clause for the next
2036                  * partition key.
2037                  */
2038                 for_each_cell(lc, start)
2039                 {
2040                         pc = lfirst(lc);
2041
2042                         if (pc->keyno > cur_keyno)
2043                                 break;
2044                 }
2045                 next_start = lc;
2046
2047                 for_each_cell(lc, start)
2048                 {
2049                         List       *moresteps;
2050
2051                         pc = lfirst(lc);
2052                         if (pc->keyno == cur_keyno)
2053                         {
2054                                 /* clean up before starting a new recursion cycle. */
2055                                 if (cur_keyno == 0)
2056                                 {
2057                                         list_free(step_exprs);
2058                                         list_free(step_cmpfns);
2059                                         step_exprs = list_make1(pc->expr);
2060                                         step_cmpfns = list_make1_oid(pc->cmpfn);
2061                                 }
2062                                 else
2063                                 {
2064                                         step_exprs = lappend(step_exprs, pc->expr);
2065                                         step_cmpfns = lappend_oid(step_cmpfns, pc->cmpfn);
2066                                 }
2067                         }
2068                         else
2069                         {
2070                                 Assert(pc->keyno > cur_keyno);
2071                                 break;
2072                         }
2073
2074                         moresteps = get_steps_using_prefix_recurse(context,
2075                                                                                                            step_opstrategy,
2076                                                                                                            step_op_is_ne,
2077                                                                                                            step_lastexpr,
2078                                                                                                            step_lastcmpfn,
2079                                                                                                            step_lastkeyno,
2080                                                                                                            step_nullkeys,
2081                                                                                                            next_start,
2082                                                                                                            step_exprs,
2083                                                                                                            step_cmpfns);
2084                         result = list_concat(result, moresteps);
2085                 }
2086         }
2087         else
2088         {
2089                 /*
2090                  * End the current recursion cycle and start generating steps, one for
2091                  * each clause with cur_keyno, which is all clauses from here onward
2092                  * till the end of the list.
2093                  */
2094                 Assert(list_length(step_exprs) == cur_keyno);
2095                 for_each_cell(lc, start)
2096                 {
2097                         PartClauseInfo *pc = lfirst(lc);
2098                         PartitionPruneStep *step;
2099                         List       *step_exprs1,
2100                                            *step_cmpfns1;
2101
2102                         Assert(pc->keyno == cur_keyno);
2103
2104                         /* Leave the original step_exprs unmodified. */
2105                         step_exprs1 = list_copy(step_exprs);
2106                         step_exprs1 = lappend(step_exprs1, pc->expr);
2107                         step_exprs1 = lappend(step_exprs1, step_lastexpr);
2108
2109                         /* Leave the original step_cmpfns unmodified. */
2110                         step_cmpfns1 = list_copy(step_cmpfns);
2111                         step_cmpfns1 = lappend_oid(step_cmpfns1, pc->cmpfn);
2112                         step_cmpfns1 = lappend_oid(step_cmpfns1, step_lastcmpfn);
2113
2114                         step = gen_prune_step_op(context,
2115                                                                          step_opstrategy, step_op_is_ne,
2116                                                                          step_exprs1, step_cmpfns1,
2117                                                                          step_nullkeys);
2118                         result = lappend(result, step);
2119                 }
2120         }
2121
2122         return result;
2123 }
2124
2125 /*
2126  * get_matching_hash_bounds
2127  *              Determine offset of the hash bound matching the specified values,
2128  *              considering that all the non-null values come from clauses containing
2129  *              a compatible hash equality operator and any keys that are null come
2130  *              from an IS NULL clause.
2131  *
2132  * Generally this function will return a single matching bound offset,
2133  * although if a partition has not been setup for a given modulus then we may
2134  * return no matches.  If the number of clauses found don't cover the entire
2135  * partition key, then we'll need to return all offsets.
2136  *
2137  * 'opstrategy' if non-zero must be HTEqualStrategyNumber.
2138  *
2139  * 'values' contains Datums indexed by the partition key to use for pruning.
2140  *
2141  * 'nvalues', the number of Datums in the 'values' array.
2142  *
2143  * 'partsupfunc' contains partition hashing functions that can produce correct
2144  * hash for the type of the values contained in 'values'.
2145  *
2146  * 'nullkeys' is the set of partition keys that are null.
2147  */
2148 static PruneStepResult *
2149 get_matching_hash_bounds(PartitionPruneContext *context,
2150                                                  StrategyNumber opstrategy, Datum *values, int nvalues,
2151                                                  FmgrInfo *partsupfunc, Bitmapset *nullkeys)
2152 {
2153         PruneStepResult *result = (PruneStepResult *) palloc0(sizeof(PruneStepResult));
2154         PartitionBoundInfo boundinfo = context->boundinfo;
2155         int                *partindices = boundinfo->indexes;
2156         int                     partnatts = context->partnatts;
2157         bool            isnull[PARTITION_MAX_KEYS];
2158         int                     i;
2159         uint64          rowHash;
2160         int                     greatest_modulus;
2161
2162         Assert(context->strategy == PARTITION_STRATEGY_HASH);
2163
2164         /*
2165          * For hash partitioning we can only perform pruning based on equality
2166          * clauses to the partition key or IS NULL clauses.  We also can only
2167          * prune if we got values for all keys.
2168          */
2169         if (nvalues + bms_num_members(nullkeys) == partnatts)
2170         {
2171                 /*
2172                  * If there are any values, they must have come from clauses
2173                  * containing an equality operator compatible with hash partitioning.
2174                  */
2175                 Assert(opstrategy == HTEqualStrategyNumber || nvalues == 0);
2176
2177                 for (i = 0; i < partnatts; i++)
2178                         isnull[i] = bms_is_member(i, nullkeys);
2179
2180                 greatest_modulus = get_hash_partition_greatest_modulus(boundinfo);
2181                 rowHash = compute_partition_hash_value(partnatts, partsupfunc,
2182                                                                                            values, isnull);
2183
2184                 if (partindices[rowHash % greatest_modulus] >= 0)
2185                         result->bound_offsets =
2186                                 bms_make_singleton(rowHash % greatest_modulus);
2187         }
2188         else
2189         {
2190                 /* Getting here means at least one hash partition exists. */
2191                 Assert(boundinfo->ndatums > 0);
2192                 result->bound_offsets = bms_add_range(NULL, 0,
2193                                                                                           boundinfo->ndatums - 1);
2194         }
2195
2196         /*
2197          * There is neither a special hash null partition or the default hash
2198          * partition.
2199          */
2200         result->scan_null = result->scan_default = false;
2201
2202         return result;
2203 }
2204
2205 /*
2206  * get_matching_list_bounds
2207  *              Determine the offsets of list bounds matching the specified value,
2208  *              according to the semantics of the given operator strategy
2209  * 'opstrategy' if non-zero must be a btree strategy number.
2210  *
2211  * 'value' contains the value to use for pruning.
2212  *
2213  * 'nvalues', if non-zero, should be exactly 1, because of list partitioning.
2214  *
2215  * 'partsupfunc' contains the list partitioning comparison function to be used
2216  * to perform partition_list_bsearch
2217  *
2218  * 'nullkeys' is the set of partition keys that are null.
2219  */
2220 static PruneStepResult *
2221 get_matching_list_bounds(PartitionPruneContext *context,
2222                                                  StrategyNumber opstrategy, Datum value, int nvalues,
2223                                                  FmgrInfo *partsupfunc, Bitmapset *nullkeys)
2224 {
2225         PruneStepResult *result = (PruneStepResult *) palloc0(sizeof(PruneStepResult));
2226         PartitionBoundInfo boundinfo = context->boundinfo;
2227         int                     off,
2228                                 minoff,
2229                                 maxoff;
2230         bool            is_equal;
2231         bool            inclusive = false;
2232         Oid                *partcollation = context->partcollation;
2233
2234         Assert(context->strategy == PARTITION_STRATEGY_LIST);
2235         Assert(context->partnatts == 1);
2236
2237         result->scan_null = result->scan_default = false;
2238
2239         if (!bms_is_empty(nullkeys))
2240         {
2241                 /*
2242                  * Nulls may exist in only one partition - the partition whose
2243                  * accepted set of values includes null or the default partition if
2244                  * the former doesn't exist.
2245                  */
2246                 if (partition_bound_accepts_nulls(boundinfo))
2247                         result->scan_null = true;
2248                 else
2249                         result->scan_default = partition_bound_has_default(boundinfo);
2250                 return result;
2251         }
2252
2253         /*
2254          * If there are no datums to compare keys with, but there are partitions,
2255          * just return the default partition if one exists.
2256          */
2257         if (boundinfo->ndatums == 0)
2258         {
2259                 result->scan_default = partition_bound_has_default(boundinfo);
2260                 return result;
2261         }
2262
2263         minoff = 0;
2264         maxoff = boundinfo->ndatums - 1;
2265
2266         /*
2267          * If there are no values to compare with the datums in boundinfo, it
2268          * means the caller asked for partitions for all non-null datums.  Add
2269          * indexes of *all* partitions, including the default if any.
2270          */
2271         if (nvalues == 0)
2272         {
2273                 Assert(boundinfo->ndatums > 0);
2274                 result->bound_offsets = bms_add_range(NULL, 0,
2275                                                                                           boundinfo->ndatums - 1);
2276                 result->scan_default = partition_bound_has_default(boundinfo);
2277                 return result;
2278         }
2279
2280         /* Special case handling of values coming from a <> operator clause. */
2281         if (opstrategy == InvalidStrategy)
2282         {
2283                 /*
2284                  * First match to all bounds.  We'll remove any matching datums below.
2285                  */
2286                 Assert(boundinfo->ndatums > 0);
2287                 result->bound_offsets = bms_add_range(NULL, 0,
2288                                                                                           boundinfo->ndatums - 1);
2289
2290                 off = partition_list_bsearch(partsupfunc, partcollation, boundinfo,
2291                                                                          value, &is_equal);
2292                 if (off >= 0 && is_equal)
2293                 {
2294
2295                         /* We have a match. Remove from the result. */
2296                         Assert(boundinfo->indexes[off] >= 0);
2297                         result->bound_offsets = bms_del_member(result->bound_offsets,
2298                                                                                                    off);
2299                 }
2300
2301                 /* Always include the default partition if any. */
2302                 result->scan_default = partition_bound_has_default(boundinfo);
2303
2304                 return result;
2305         }
2306
2307         /*
2308          * With range queries, always include the default list partition, because
2309          * list partitions divide the key space in a discontinuous manner, not all
2310          * values in the given range will have a partition assigned.  This may not
2311          * technically be true for some data types (e.g. integer types), however,
2312          * we currently lack any sort of infrastructure to provide us with proofs
2313          * that would allow us to do anything smarter here.
2314          */
2315         if (opstrategy != BTEqualStrategyNumber)
2316                 result->scan_default = partition_bound_has_default(boundinfo);
2317
2318         switch (opstrategy)
2319         {
2320                 case BTEqualStrategyNumber:
2321                         off = partition_list_bsearch(partsupfunc,
2322                                                                                  partcollation,
2323                                                                                  boundinfo, value,
2324                                                                                  &is_equal);
2325                         if (off >= 0 && is_equal)
2326                         {
2327                                 Assert(boundinfo->indexes[off] >= 0);
2328                                 result->bound_offsets = bms_make_singleton(off);
2329                         }
2330                         else
2331                                 result->scan_default = partition_bound_has_default(boundinfo);
2332                         return result;
2333
2334                 case BTGreaterEqualStrategyNumber:
2335                         inclusive = true;
2336                         /* fall through */
2337                 case BTGreaterStrategyNumber:
2338                         off = partition_list_bsearch(partsupfunc,
2339                                                                                  partcollation,
2340                                                                                  boundinfo, value,
2341                                                                                  &is_equal);
2342                         if (off >= 0)
2343                         {
2344                                 /* We don't want the matched datum to be in the result. */
2345                                 if (!is_equal || !inclusive)
2346                                         off++;
2347                         }
2348                         else
2349                         {
2350                                 /*
2351                                  * This case means all partition bounds are greater, which in
2352                                  * turn means that all partitions satisfy this key.
2353                                  */
2354                                 off = 0;
2355                         }
2356
2357                         /*
2358                          * off is greater than the numbers of datums we have partitions
2359                          * for.  The only possible partition that could contain a match is
2360                          * the default partition, but we must've set context->scan_default
2361                          * above anyway if one exists.
2362                          */
2363                         if (off > boundinfo->ndatums - 1)
2364                                 return result;
2365
2366                         minoff = off;
2367                         break;
2368
2369                 case BTLessEqualStrategyNumber:
2370                         inclusive = true;
2371                         /* fall through */
2372                 case BTLessStrategyNumber:
2373                         off = partition_list_bsearch(partsupfunc,
2374                                                                                  partcollation,
2375                                                                                  boundinfo, value,
2376                                                                                  &is_equal);
2377                         if (off >= 0 && is_equal && !inclusive)
2378                                 off--;
2379
2380                         /*
2381                          * off is smaller than the datums of all non-default partitions.
2382                          * The only possible partition that could contain a match is the
2383                          * default partition, but we must've set context->scan_default
2384                          * above anyway if one exists.
2385                          */
2386                         if (off < 0)
2387                                 return result;
2388
2389                         maxoff = off;
2390                         break;
2391
2392                 default:
2393                         elog(ERROR, "invalid strategy number %d", opstrategy);
2394                         break;
2395         }
2396
2397         Assert(minoff >= 0 && maxoff >= 0);
2398         result->bound_offsets = bms_add_range(NULL, minoff, maxoff);
2399         return result;
2400 }
2401
2402
2403 /*
2404  * get_matching_range_bounds
2405  *              Determine the offsets of range bounds matching the specified values,
2406  *              according to the semantics of the given operator strategy
2407  *
2408  * Each datum whose offset is in result is to be treated as the upper bound of
2409  * the partition that will contain the desired values.
2410  *
2411  * If default partition needs to be scanned for given values, set scan_default
2412  * in result if present.
2413  *
2414  * 'opstrategy' if non-zero must be a btree strategy number.
2415  *
2416  * 'values' contains Datums indexed by the partition key to use for pruning.
2417  *
2418  * 'nvalues', number of Datums in 'values' array. Must be <= context->partnatts.
2419  *
2420  * 'partsupfunc' contains the range partitioning comparison functions to be
2421  * used to perform partition_range_datum_bsearch or partition_rbound_datum_cmp
2422  * using.
2423  *
2424  * 'nullkeys' is the set of partition keys that are null.
2425  */
2426 static PruneStepResult *
2427 get_matching_range_bounds(PartitionPruneContext *context,
2428                                                   StrategyNumber opstrategy, Datum *values, int nvalues,
2429                                                   FmgrInfo *partsupfunc, Bitmapset *nullkeys)
2430 {
2431         PruneStepResult *result = (PruneStepResult *) palloc0(sizeof(PruneStepResult));
2432         PartitionBoundInfo boundinfo = context->boundinfo;
2433         Oid                *partcollation = context->partcollation;
2434         int                     partnatts = context->partnatts;
2435         int                *partindices = boundinfo->indexes;
2436         int                     off,
2437                                 minoff,
2438                                 maxoff,
2439                                 i;
2440         bool            is_equal;
2441         bool            inclusive = false;
2442
2443         Assert(context->strategy == PARTITION_STRATEGY_RANGE);
2444         Assert(nvalues <= partnatts);
2445
2446         result->scan_null = result->scan_default = false;
2447
2448         /*
2449          * If there are no datums to compare keys with, or if we got an IS NULL
2450          * clause just return the default partition, if it exists.
2451          */
2452         if (boundinfo->ndatums == 0 || !bms_is_empty(nullkeys))
2453         {
2454                 result->scan_default = partition_bound_has_default(boundinfo);
2455                 return result;
2456         }
2457
2458         minoff = 0;
2459         maxoff = boundinfo->ndatums;
2460
2461         /*
2462          * If there are no values to compare with the datums in boundinfo, it
2463          * means the caller asked for partitions for all non-null datums.  Add
2464          * indexes of *all* partitions, including the default partition if one
2465          * exists.
2466          */
2467         if (nvalues == 0)
2468         {
2469                 if (partindices[minoff] < 0)
2470                         minoff++;
2471                 if (partindices[maxoff] < 0)
2472                         maxoff--;
2473
2474                 result->scan_default = partition_bound_has_default(boundinfo);
2475                 Assert(minoff >= 0 && maxoff >= 0);
2476                 result->bound_offsets = bms_add_range(NULL, minoff, maxoff);
2477
2478                 return result;
2479         }
2480
2481         /*
2482          * If the query does not constrain all key columns, we'll need to scan the
2483          * default partition, if any.
2484          */
2485         if (nvalues < partnatts)
2486                 result->scan_default = partition_bound_has_default(boundinfo);
2487
2488         switch (opstrategy)
2489         {
2490                 case BTEqualStrategyNumber:
2491                         /* Look for the smallest bound that is = lookup value. */
2492                         off = partition_range_datum_bsearch(partsupfunc,
2493                                                                                                 partcollation,
2494                                                                                                 boundinfo,
2495                                                                                                 nvalues, values,
2496                                                                                                 &is_equal);
2497
2498                         if (off >= 0 && is_equal)
2499                         {
2500                                 if (nvalues == partnatts)
2501                                 {
2502                                         /* There can only be zero or one matching partition. */
2503                                         if (partindices[off + 1] >= 0)
2504                                                 result->bound_offsets = bms_make_singleton(off + 1);
2505                                         else
2506                                                 result->scan_default =
2507                                                         partition_bound_has_default(boundinfo);
2508                                         return result;
2509                                 }
2510                                 else
2511                                 {
2512                                         int                     saved_off = off;
2513
2514                                         /*
2515                                          * Since the lookup value contains only a prefix of keys,
2516                                          * we must find other bounds that may also match the
2517                                          * prefix.  partition_range_datum_bsearch() returns the
2518                                          * offset of one of them, find others by checking adjacent
2519                                          * bounds.
2520                                          */
2521
2522                                         /*
2523                                          * First find greatest bound that's smaller than the
2524                                          * lookup value.
2525                                          */
2526                                         while (off >= 1)
2527                                         {
2528                                                 int32           cmpval;
2529
2530                                                 cmpval =
2531                                                         partition_rbound_datum_cmp(partsupfunc,
2532                                                                                                            partcollation,
2533                                                                                                            boundinfo->datums[off - 1],
2534                                                                                                            boundinfo->kind[off - 1],
2535                                                                                                            values, nvalues);
2536                                                 if (cmpval != 0)
2537                                                         break;
2538                                                 off--;
2539                                         }
2540
2541                                         Assert(0 ==
2542                                                    partition_rbound_datum_cmp(partsupfunc,
2543                                                                                                           partcollation,
2544                                                                                                           boundinfo->datums[off],
2545                                                                                                           boundinfo->kind[off],
2546                                                                                                           values, nvalues));
2547
2548                                         /*
2549                                          * We can treat 'off' as the offset of the smallest bound
2550                                          * to be included in the result, if we know it is the
2551                                          * upper bound of the partition in which the lookup value
2552                                          * could possibly exist.  One case it couldn't is if the
2553                                          * bound, or precisely the matched portion of its prefix,
2554                                          * is not inclusive.
2555                                          */
2556                                         if (boundinfo->kind[off][nvalues] ==
2557                                                 PARTITION_RANGE_DATUM_MINVALUE)
2558                                                 off++;
2559
2560                                         minoff = off;
2561
2562                                         /*
2563                                          * Now find smallest bound that's greater than the lookup
2564                                          * value.
2565                                          */
2566                                         off = saved_off;
2567                                         while (off < boundinfo->ndatums - 1)
2568                                         {
2569                                                 int32           cmpval;
2570
2571                                                 cmpval = partition_rbound_datum_cmp(partsupfunc,
2572                                                                                                                         partcollation,
2573                                                                                                                         boundinfo->datums[off + 1],
2574                                                                                                                         boundinfo->kind[off + 1],
2575                                                                                                                         values, nvalues);
2576                                                 if (cmpval != 0)
2577                                                         break;
2578                                                 off++;
2579                                         }
2580
2581                                         Assert(0 ==
2582                                                    partition_rbound_datum_cmp(partsupfunc,
2583                                                                                                           partcollation,
2584                                                                                                           boundinfo->datums[off],
2585                                                                                                           boundinfo->kind[off],
2586                                                                                                           values, nvalues));
2587
2588                                         /*
2589                                          * off + 1, then would be the offset of the greatest bound
2590                                          * to be included in the result.
2591                                          */
2592                                         maxoff = off + 1;
2593                                 }
2594
2595                                 /*
2596                                  * Skip if minoff/maxoff are actually the upper bound of a
2597                                  * un-assigned portion of values.
2598                                  */
2599                                 if (partindices[minoff] < 0 && minoff < boundinfo->ndatums)
2600                                         minoff++;
2601                                 if (partindices[maxoff] < 0 && maxoff >= 1)
2602                                         maxoff--;
2603
2604                                 /*
2605                                  * There may exist a range of values unassigned to any
2606                                  * non-default partition between the datums at minoff and
2607                                  * maxoff.  Add the default partition in that case.
2608                                  */
2609                                 if (partition_bound_has_default(boundinfo))
2610                                 {
2611                                         for (i = minoff; i <= maxoff; i++)
2612                                         {
2613                                                 if (partindices[i] < 0)
2614                                                 {
2615                                                         result->scan_default = true;
2616                                                         break;
2617                                                 }
2618                                         }
2619                                 }
2620
2621                                 Assert(minoff >= 0 && maxoff >= 0);
2622                                 result->bound_offsets = bms_add_range(NULL, minoff, maxoff);
2623                         }
2624                         else if (off >= 0)      /* !is_equal */
2625                         {
2626                                 /*
2627                                  * The lookup value falls in the range between some bounds in
2628                                  * boundinfo.  'off' would be the offset of the greatest bound
2629                                  * that is <= lookup value, so add off + 1 to the result
2630                                  * instead as the offset of the upper bound of the only
2631                                  * partition that may contain the lookup value.
2632                                  */
2633                                 if (partindices[off + 1] >= 0)
2634                                         result->bound_offsets = bms_make_singleton(off + 1);
2635                                 else
2636                                         result->scan_default =
2637                                                 partition_bound_has_default(boundinfo);
2638                         }
2639                         else
2640                         {
2641                                 /*
2642                                  * off < 0: the lookup value is smaller than all bounds, so
2643                                  * only the default partition qualifies, if there is one.
2644                                  */
2645                                 result->scan_default = partition_bound_has_default(boundinfo);
2646                         }
2647
2648                         return result;
2649
2650                 case BTGreaterEqualStrategyNumber:
2651                         inclusive = true;
2652                         /* fall through */
2653                 case BTGreaterStrategyNumber:
2654
2655                         /*
2656                          * Look for the smallest bound that is > or >= lookup value and
2657                          * set minoff to its offset.
2658                          */
2659                         off = partition_range_datum_bsearch(partsupfunc,
2660                                                                                                 partcollation,
2661                                                                                                 boundinfo,
2662                                                                                                 nvalues, values,
2663                                                                                                 &is_equal);
2664                         if (off < 0)
2665                         {
2666                                 /*
2667                                  * All bounds are greater than the lookup value, so include
2668                                  * all of them in the result.
2669                                  */
2670                                 minoff = 0;
2671                         }
2672                         else
2673                         {
2674                                 if (is_equal && nvalues < partnatts)
2675                                 {
2676                                         /*
2677                                          * Since the lookup value contains only a prefix of keys,
2678                                          * we must find other bounds that may also match the
2679                                          * prefix.  partition_range_datum_bsearch() returns the
2680                                          * offset of one of them, find others by checking adjacent
2681                                          * bounds.
2682                                          *
2683                                          * Based on whether the lookup values are inclusive or
2684                                          * not, we must either include the indexes of all such
2685                                          * bounds in the result (that is, set minoff to the index
2686                                          * of smallest such bound) or find the smallest one that's
2687                                          * greater than the lookup values and set minoff to that.
2688                                          */
2689                                         while (off >= 1 && off < boundinfo->ndatums - 1)
2690                                         {
2691                                                 int32           cmpval;
2692                                                 int                     nextoff;
2693
2694                                                 nextoff = inclusive ? off - 1 : off + 1;
2695                                                 cmpval =
2696                                                         partition_rbound_datum_cmp(partsupfunc,
2697                                                                                                            partcollation,
2698                                                                                                            boundinfo->datums[nextoff],
2699                                                                                                            boundinfo->kind[nextoff],
2700                                                                                                            values, nvalues);
2701                                                 if (cmpval != 0)
2702                                                         break;
2703
2704                                                 off = nextoff;
2705                                         }
2706
2707                                         Assert(0 ==
2708                                                    partition_rbound_datum_cmp(partsupfunc,
2709                                                                                                           partcollation,
2710                                                                                                           boundinfo->datums[off],
2711                                                                                                           boundinfo->kind[off],
2712                                                                                                           values, nvalues));
2713
2714                                         minoff = inclusive ? off : off + 1;
2715                                 }
2716
2717                                 /*
2718                                  * lookup value falls in the range between some bounds in
2719                                  * boundinfo.  off would be the offset of the greatest bound
2720                                  * that is <= lookup value, so add off + 1 to the result
2721                                  * instead as the offset of the upper bound of the smallest
2722                                  * partition that may contain the lookup value.
2723                                  */
2724                                 else
2725                                         minoff = off + 1;
2726                         }
2727                         break;
2728
2729                 case BTLessEqualStrategyNumber:
2730                         inclusive = true;
2731                         /* fall through */
2732                 case BTLessStrategyNumber:
2733
2734                         /*
2735                          * Look for the greatest bound that is < or <= lookup value and
2736                          * set minoff to its offset.
2737                          */
2738                         off = partition_range_datum_bsearch(partsupfunc,
2739                                                                                                 partcollation,
2740                                                                                                 boundinfo,
2741                                                                                                 nvalues, values,
2742                                                                                                 &is_equal);
2743                         if (off < 0)
2744                         {
2745                                 /*
2746                                  * All bounds are greater than the key, so we could only
2747                                  * expect to find the lookup key in the default partition.
2748                                  */
2749                                 result->scan_default = partition_bound_has_default(boundinfo);
2750                                 return result;
2751                         }
2752                         else
2753                         {
2754                                 /*
2755                                  * See the comment above.
2756                                  */
2757                                 if (is_equal && nvalues < partnatts)
2758                                 {
2759                                         while (off >= 1 && off < boundinfo->ndatums - 1)
2760                                         {
2761                                                 int32           cmpval;
2762                                                 int                     nextoff;
2763
2764                                                 nextoff = inclusive ? off + 1 : off - 1;
2765                                                 cmpval = partition_rbound_datum_cmp(partsupfunc,
2766                                                                                                                         partcollation,
2767                                                                                                                         boundinfo->datums[nextoff],
2768                                                                                                                         boundinfo->kind[nextoff],
2769                                                                                                                         values, nvalues);
2770                                                 if (cmpval != 0)
2771                                                         break;
2772
2773                                                 off = nextoff;
2774                                         }
2775
2776                                         Assert(0 ==
2777                                                    partition_rbound_datum_cmp(partsupfunc,
2778                                                                                                           partcollation,
2779                                                                                                           boundinfo->datums[off],
2780                                                                                                           boundinfo->kind[off],
2781                                                                                                           values, nvalues));
2782
2783                                         maxoff = inclusive ? off + 1 : off;
2784                                 }
2785
2786                                 /*
2787                                  * The lookup value falls in the range between some bounds in
2788                                  * boundinfo.  'off' would be the offset of the greatest bound
2789                                  * that is <= lookup value, so add off + 1 to the result
2790                                  * instead as the offset of the upper bound of the greatest
2791                                  * partition that may contain lookup value.  If the lookup
2792                                  * value had exactly matched the bound, but it isn't
2793                                  * inclusive, no need add the adjacent partition.
2794                                  */
2795                                 else if (!is_equal || inclusive)
2796                                         maxoff = off + 1;
2797                                 else
2798                                         maxoff = off;
2799                         }
2800                         break;
2801
2802                 default:
2803                         elog(ERROR, "invalid strategy number %d", opstrategy);
2804                         break;
2805         }
2806
2807         /*
2808          * Skip a gap and when doing so, check if the bound contains a finite
2809          * value to decide if we need to add the default partition.  If it's an
2810          * infinite bound, we need not add the default partition, as having an
2811          * infinite bound means the partition in question catches any values that
2812          * would otherwise be in the default partition.
2813          */
2814         if (partindices[minoff] < 0)
2815         {
2816                 int                     lastkey = nvalues - 1;
2817
2818                 if (minoff >= 0 &&
2819                         minoff < boundinfo->ndatums &&
2820                         boundinfo->kind[minoff][lastkey] ==
2821                         PARTITION_RANGE_DATUM_VALUE)
2822                         result->scan_default = partition_bound_has_default(boundinfo);
2823
2824                 minoff++;
2825         }
2826
2827         /*
2828          * Skip a gap.  See the above comment about how we decide whether or not
2829          * to scan the default partition based whether the datum that will become
2830          * the maximum datum is finite or not.
2831          */
2832         if (maxoff >= 1 && partindices[maxoff] < 0)
2833         {
2834                 int                     lastkey = nvalues - 1;
2835
2836                 if (maxoff >= 0 &&
2837                         maxoff <= boundinfo->ndatums &&
2838                         boundinfo->kind[maxoff - 1][lastkey] ==
2839                         PARTITION_RANGE_DATUM_VALUE)
2840                         result->scan_default = partition_bound_has_default(boundinfo);
2841
2842                 maxoff--;
2843         }
2844
2845         if (partition_bound_has_default(boundinfo))
2846         {
2847                 /*
2848                  * There may exist a range of values unassigned to any non-default
2849                  * partition between the datums at minoff and maxoff.  Add the default
2850                  * partition in that case.
2851                  */
2852                 for (i = minoff; i <= maxoff; i++)
2853                 {
2854                         if (partindices[i] < 0)
2855                         {
2856                                 result->scan_default = true;
2857                                 break;
2858                         }
2859                 }
2860         }
2861
2862         Assert(minoff >= 0 && maxoff >= 0);
2863         if (minoff <= maxoff)
2864                 result->bound_offsets = bms_add_range(NULL, minoff, maxoff);
2865
2866         return result;
2867 }
2868
2869 /*
2870  * pull_exec_paramids
2871  *              Returns a Bitmapset containing the paramids of all Params with
2872  *              paramkind = PARAM_EXEC in 'expr'.
2873  */
2874 static Bitmapset *
2875 pull_exec_paramids(Expr *expr)
2876 {
2877         Bitmapset  *result = NULL;
2878
2879         (void) pull_exec_paramids_walker((Node *) expr, &result);
2880
2881         return result;
2882 }
2883
2884 static bool
2885 pull_exec_paramids_walker(Node *node, Bitmapset **context)
2886 {
2887         if (node == NULL)
2888                 return false;
2889         if (IsA(node, Param))
2890         {
2891                 Param      *param = (Param *) node;
2892
2893                 if (param->paramkind == PARAM_EXEC)
2894                         *context = bms_add_member(*context, param->paramid);
2895                 return false;
2896         }
2897         return expression_tree_walker(node, pull_exec_paramids_walker,
2898                                                                   (void *) context);
2899 }
2900
2901 /*
2902  * analyze_partkey_exprs
2903  *              Loop through all pruning steps and identify which ones require
2904  *              executor startup-time or executor run-time pruning.
2905  *
2906  * Returns true if any executor partition pruning should be attempted at this
2907  * level.  Also fills fields of *pinfo to record how to process each step.
2908  */
2909 static bool
2910 analyze_partkey_exprs(PartitionedRelPruneInfo *pinfo, List *steps,
2911                                           int partnatts)
2912 {
2913         bool            doruntimeprune = false;
2914         ListCell   *lc;
2915
2916         /*
2917          * Steps require run-time pruning if they contain EXEC_PARAM Params.
2918          * Otherwise, if their expressions aren't simple Consts, they require
2919          * startup-time pruning.
2920          */
2921         pinfo->nexprs = list_length(steps) * partnatts;
2922         pinfo->hasexecparam = (bool *) palloc0(sizeof(bool) * pinfo->nexprs);
2923         pinfo->do_initial_prune = false;
2924         pinfo->do_exec_prune = false;
2925         pinfo->execparamids = NULL;
2926
2927         foreach(lc, steps)
2928         {
2929                 PartitionPruneStepOp *step = (PartitionPruneStepOp *) lfirst(lc);
2930                 ListCell   *lc2;
2931                 int                     keyno;
2932
2933                 if (!IsA(step, PartitionPruneStepOp))
2934                         continue;
2935
2936                 keyno = 0;
2937                 foreach(lc2, step->exprs)
2938                 {
2939                         Expr       *expr = lfirst(lc2);
2940
2941                         if (!IsA(expr, Const))
2942                         {
2943                                 Bitmapset  *execparamids = pull_exec_paramids(expr);
2944                                 bool            hasexecparams;
2945                                 int                     stateidx = PruneCxtStateIdx(partnatts,
2946                                                                                                                 step->step.step_id,
2947                                                                                                                 keyno);
2948
2949                                 Assert(stateidx < pinfo->nexprs);
2950                                 hasexecparams = !bms_is_empty(execparamids);
2951                                 pinfo->hasexecparam[stateidx] = hasexecparams;
2952                                 pinfo->execparamids = bms_join(pinfo->execparamids,
2953                                                                                            execparamids);
2954
2955                                 if (hasexecparams)
2956                                         pinfo->do_exec_prune = true;
2957                                 else
2958                                         pinfo->do_initial_prune = true;
2959
2960                                 doruntimeprune = true;
2961                         }
2962                         keyno++;
2963                 }
2964         }
2965
2966         return doruntimeprune;
2967 }
2968
2969 /*
2970  * perform_pruning_base_step
2971  *              Determines the indexes of datums that satisfy conditions specified in
2972  *              'opstep'.
2973  *
2974  * Result also contains whether special null-accepting and/or default
2975  * partition need to be scanned.
2976  */
2977 static PruneStepResult *
2978 perform_pruning_base_step(PartitionPruneContext *context,
2979                                                   PartitionPruneStepOp *opstep)
2980 {
2981         ListCell   *lc1,
2982                            *lc2;
2983         int                     keyno,
2984                                 nvalues;
2985         Datum           values[PARTITION_MAX_KEYS];
2986         FmgrInfo   *partsupfunc;
2987         int                     stateidx;
2988
2989         /*
2990          * There better be the same number of expressions and compare functions.
2991          */
2992         Assert(list_length(opstep->exprs) == list_length(opstep->cmpfns));
2993
2994         nvalues = 0;
2995         lc1 = list_head(opstep->exprs);
2996         lc2 = list_head(opstep->cmpfns);
2997
2998         /*
2999          * Generate the partition lookup key that will be used by one of the
3000          * get_matching_*_bounds functions called below.
3001          */
3002         for (keyno = 0; keyno < context->partnatts; keyno++)
3003         {
3004                 /*
3005                  * For hash partitioning, it is possible that values of some keys are
3006                  * not provided in operator clauses, but instead the planner found
3007                  * that they appeared in a IS NULL clause.
3008                  */
3009                 if (bms_is_member(keyno, opstep->nullkeys))
3010                         continue;
3011
3012                 /*
3013                  * For range partitioning, we must only perform pruning with values
3014                  * for either all partition keys or a prefix thereof.
3015                  */
3016                 if (keyno > nvalues && context->strategy == PARTITION_STRATEGY_RANGE)
3017                         break;
3018
3019                 if (lc1 != NULL)
3020                 {
3021                         Expr       *expr;
3022                         Datum           datum;
3023                         bool            isnull;
3024
3025                         expr = lfirst(lc1);
3026                         stateidx = PruneCxtStateIdx(context->partnatts,
3027                                                                                 opstep->step.step_id, keyno);
3028                         if (partkey_datum_from_expr(context, expr, stateidx,
3029                                                                                 &datum, &isnull))
3030                         {
3031                                 Oid                     cmpfn;
3032
3033                                 /*
3034                                  * Since we only allow strict operators in pruning steps, any
3035                                  * null-valued comparison value must cause the comparison to
3036                                  * fail, so that no partitions could match.
3037                                  */
3038                                 if (isnull)
3039                                 {
3040                                         PruneStepResult *result;
3041
3042                                         result = (PruneStepResult *) palloc(sizeof(PruneStepResult));
3043                                         result->bound_offsets = NULL;
3044                                         result->scan_default = false;
3045                                         result->scan_null = false;
3046
3047                                         return result;
3048                                 }
3049
3050                                 /* Set up the stepcmpfuncs entry, unless we already did */
3051                                 cmpfn = lfirst_oid(lc2);
3052                                 Assert(OidIsValid(cmpfn));
3053                                 if (cmpfn != context->stepcmpfuncs[stateidx].fn_oid)
3054                                 {
3055                                         /*
3056                                          * If the needed support function is the same one cached
3057                                          * in the relation's partition key, copy the cached
3058                                          * FmgrInfo.  Otherwise (i.e., when we have a cross-type
3059                                          * comparison), an actual lookup is required.
3060                                          */
3061                                         if (cmpfn == context->partsupfunc[keyno].fn_oid)
3062                                                 fmgr_info_copy(&context->stepcmpfuncs[stateidx],
3063                                                                            &context->partsupfunc[keyno],
3064                                                                            context->ppccontext);
3065                                         else
3066                                                 fmgr_info_cxt(cmpfn, &context->stepcmpfuncs[stateidx],
3067                                                                           context->ppccontext);
3068                                 }
3069
3070                                 values[keyno] = datum;
3071                                 nvalues++;
3072                         }
3073
3074                         lc1 = lnext(lc1);
3075                         lc2 = lnext(lc2);
3076                 }
3077         }
3078
3079         /*
3080          * Point partsupfunc to the entry for the 0th key of this step; the
3081          * additional support functions, if any, follow consecutively.
3082          */
3083         stateidx = PruneCxtStateIdx(context->partnatts, opstep->step.step_id, 0);
3084         partsupfunc = &context->stepcmpfuncs[stateidx];
3085
3086         switch (context->strategy)
3087         {
3088                 case PARTITION_STRATEGY_HASH:
3089                         return get_matching_hash_bounds(context,
3090                                                                                         opstep->opstrategy,
3091                                                                                         values, nvalues,
3092                                                                                         partsupfunc,
3093                                                                                         opstep->nullkeys);
3094
3095                 case PARTITION_STRATEGY_LIST:
3096                         return get_matching_list_bounds(context,
3097                                                                                         opstep->opstrategy,
3098                                                                                         values[0], nvalues,
3099                                                                                         &partsupfunc[0],
3100                                                                                         opstep->nullkeys);
3101
3102                 case PARTITION_STRATEGY_RANGE:
3103                         return get_matching_range_bounds(context,
3104                                                                                          opstep->opstrategy,
3105                                                                                          values, nvalues,
3106                                                                                          partsupfunc,
3107                                                                                          opstep->nullkeys);
3108
3109                 default:
3110                         elog(ERROR, "unexpected partition strategy: %d",
3111                                  (int) context->strategy);
3112                         break;
3113         }
3114
3115         return NULL;
3116 }
3117
3118 /*
3119  * perform_pruning_combine_step
3120  *              Determines the indexes of datums obtained by combining those given
3121  *              by the steps identified by cstep->source_stepids using the specified
3122  *              combination method
3123  *
3124  * Since cstep may refer to the result of earlier steps, we also receive
3125  * step_results here.
3126  */
3127 static PruneStepResult *
3128 perform_pruning_combine_step(PartitionPruneContext *context,
3129                                                          PartitionPruneStepCombine *cstep,
3130                                                          PruneStepResult **step_results)
3131 {
3132         ListCell   *lc1;
3133         PruneStepResult *result = NULL;
3134         bool            firststep;
3135
3136         /*
3137          * A combine step without any source steps is an indication to not perform
3138          * any partition pruning, we just return all partitions.
3139          */
3140         result = (PruneStepResult *) palloc0(sizeof(PruneStepResult));
3141         if (list_length(cstep->source_stepids) == 0)
3142         {
3143                 PartitionBoundInfo boundinfo = context->boundinfo;
3144
3145                 result->bound_offsets = bms_add_range(NULL, 0, boundinfo->ndatums - 1);
3146                 result->scan_default = partition_bound_has_default(boundinfo);
3147                 result->scan_null = partition_bound_accepts_nulls(boundinfo);
3148                 return result;
3149         }
3150
3151         switch (cstep->combineOp)
3152         {
3153                 case PARTPRUNE_COMBINE_UNION:
3154                         foreach(lc1, cstep->source_stepids)
3155                         {
3156                                 int                     step_id = lfirst_int(lc1);
3157                                 PruneStepResult *step_result;
3158
3159                                 /*
3160                                  * step_results[step_id] must contain a valid result, which is
3161                                  * confirmed by the fact that cstep's step_id is greater than
3162                                  * step_id and the fact that results of the individual steps
3163                                  * are evaluated in sequence of their step_ids.
3164                                  */
3165                                 if (step_id >= cstep->step.step_id)
3166                                         elog(ERROR, "invalid pruning combine step argument");
3167                                 step_result = step_results[step_id];
3168                                 Assert(step_result != NULL);
3169
3170                                 /* Record any additional datum indexes from this step */
3171                                 result->bound_offsets = bms_add_members(result->bound_offsets,
3172                                                                                                                 step_result->bound_offsets);
3173
3174                                 /* Update whether to scan null and default partitions. */
3175                                 if (!result->scan_null)
3176                                         result->scan_null = step_result->scan_null;
3177                                 if (!result->scan_default)
3178                                         result->scan_default = step_result->scan_default;
3179                         }
3180                         break;
3181
3182                 case PARTPRUNE_COMBINE_INTERSECT:
3183                         firststep = true;
3184                         foreach(lc1, cstep->source_stepids)
3185                         {
3186                                 int                     step_id = lfirst_int(lc1);
3187                                 PruneStepResult *step_result;
3188
3189                                 if (step_id >= cstep->step.step_id)
3190                                         elog(ERROR, "invalid pruning combine step argument");
3191                                 step_result = step_results[step_id];
3192                                 Assert(step_result != NULL);
3193
3194                                 if (firststep)
3195                                 {
3196                                         /* Copy step's result the first time. */
3197                                         result->bound_offsets =
3198                                                 bms_copy(step_result->bound_offsets);
3199                                         result->scan_null = step_result->scan_null;
3200                                         result->scan_default = step_result->scan_default;
3201                                         firststep = false;
3202                                 }
3203                                 else
3204                                 {
3205                                         /* Record datum indexes common to both steps */
3206                                         result->bound_offsets =
3207                                                 bms_int_members(result->bound_offsets,
3208                                                                                 step_result->bound_offsets);
3209
3210                                         /* Update whether to scan null and default partitions. */
3211                                         if (result->scan_null)
3212                                                 result->scan_null = step_result->scan_null;
3213                                         if (result->scan_default)
3214                                                 result->scan_default = step_result->scan_default;
3215                                 }
3216                         }
3217                         break;
3218         }
3219
3220         return result;
3221 }
3222
3223 /*
3224  * match_boolean_partition_clause
3225  *
3226  * Sets *outconst to a Const containing true or false value and returns true if
3227  * we're able to match the clause to the partition key as specially-shaped
3228  * Boolean clause.  Returns false otherwise with *outconst set to NULL.
3229  */
3230 static bool
3231 match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
3232                                                            Expr **outconst)
3233 {
3234         Expr       *leftop;
3235
3236         *outconst = NULL;
3237
3238         if (!IsBooleanOpfamily(partopfamily))
3239                 return false;
3240
3241         if (IsA(clause, BooleanTest))
3242         {
3243                 BooleanTest *btest = (BooleanTest *) clause;
3244
3245                 /* Only IS [NOT] TRUE/FALSE are any good to us */
3246                 if (btest->booltesttype == IS_UNKNOWN ||
3247                         btest->booltesttype == IS_NOT_UNKNOWN)
3248                         return false;
3249
3250                 leftop = btest->arg;
3251                 if (IsA(leftop, RelabelType))
3252                         leftop = ((RelabelType *) leftop)->arg;
3253
3254                 if (equal(leftop, partkey))
3255                         *outconst = (btest->booltesttype == IS_TRUE ||
3256                                                  btest->booltesttype == IS_NOT_FALSE)
3257                                 ? (Expr *) makeBoolConst(true, false)
3258                                 : (Expr *) makeBoolConst(false, false);
3259
3260                 if (*outconst)
3261                         return true;
3262         }
3263         else
3264         {
3265                 bool            is_not_clause = not_clause((Node *) clause);
3266
3267                 leftop = is_not_clause ? get_notclausearg(clause) : clause;
3268
3269                 if (IsA(leftop, RelabelType))
3270                         leftop = ((RelabelType *) leftop)->arg;
3271
3272                 /* Compare to the partition key, and make up a clause ... */
3273                 if (equal(leftop, partkey))
3274                         *outconst = is_not_clause ?
3275                                 (Expr *) makeBoolConst(false, false) :
3276                                 (Expr *) makeBoolConst(true, false);
3277                 else if (equal(negate_clause((Node *) leftop), partkey))
3278                         *outconst = (Expr *) makeBoolConst(false, false);
3279
3280                 if (*outconst)
3281                         return true;
3282         }
3283
3284         return false;
3285 }
3286
3287 /*
3288  * partkey_datum_from_expr
3289  *              Evaluate expression for potential partition pruning
3290  *
3291  * Evaluate 'expr', whose ExprState is stateidx of the context exprstate
3292  * array; set *value and *isnull to the resulting Datum and nullflag.
3293  * Return true if evaluation was possible, otherwise false.
3294  *
3295  * Note that the evaluated result may be in the per-tuple memory context of
3296  * context->planstate->ps_ExprContext, and we may have leaked other memory
3297  * there too.  This memory must be recovered by resetting that ExprContext
3298  * after we're done with the pruning operation (see execPartition.c).
3299  */
3300 static bool
3301 partkey_datum_from_expr(PartitionPruneContext *context,
3302                                                 Expr *expr, int stateidx,
3303                                                 Datum *value, bool *isnull)
3304 {
3305         if (IsA(expr, Const))
3306         {
3307                 /* We can always determine the value of a constant */
3308                 Const      *con = (Const *) expr;
3309
3310                 *value = con->constvalue;
3311                 *isnull = con->constisnull;
3312                 return true;
3313         }
3314         else
3315         {
3316                 /*
3317                  * When called from the executor we'll have a valid planstate so we
3318                  * may be able to evaluate an expression which could not be folded to
3319                  * a Const during planning.  Since run-time pruning can occur both
3320                  * during initialization of the executor or while it's running, we
3321                  * must be careful here to evaluate expressions containing PARAM_EXEC
3322                  * Params only when told it's OK.
3323                  */
3324                 if (context->planstate &&
3325                         (context->evalexecparams ||
3326                          !context->exprhasexecparam[stateidx]))
3327                 {
3328                         ExprState  *exprstate;
3329                         ExprContext *ectx;
3330
3331                         exprstate = context->exprstates[stateidx];
3332                         ectx = context->planstate->ps_ExprContext;
3333                         *value = ExecEvalExprSwitchContext(exprstate, ectx, isnull);
3334                         return true;
3335                 }
3336         }
3337
3338         return false;
3339 }