| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * plancat.c |
| 4 | * routines for accessing the system catalogs |
| 5 | * |
| 6 | * |
| 7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 8 | * Portions Copyright (c) 1994, Regents of the University of California |
| 9 | * |
| 10 | * |
| 11 | * IDENTIFICATION |
| 12 | * src/backend/optimizer/util/plancat.c |
| 13 | * |
| 14 | *------------------------------------------------------------------------- |
| 15 | */ |
| 16 | #include "postgres.h" |
| 17 | |
| 18 | #include <math.h> |
| 19 | |
| 20 | #include "access/genam.h" |
| 21 | #include "access/htup_details.h" |
| 22 | #include "access/nbtree.h" |
| 23 | #include "access/tableam.h" |
| 24 | #include "access/sysattr.h" |
| 25 | #include "access/table.h" |
| 26 | #include "access/transam.h" |
| 27 | #include "access/xlog.h" |
| 28 | #include "catalog/catalog.h" |
| 29 | #include "catalog/dependency.h" |
| 30 | #include "catalog/heap.h" |
| 31 | #include "catalog/pg_am.h" |
| 32 | #include "catalog/pg_proc.h" |
| 33 | #include "catalog/pg_statistic_ext.h" |
| 34 | #include "foreign/fdwapi.h" |
| 35 | #include "miscadmin.h" |
| 36 | #include "nodes/makefuncs.h" |
| 37 | #include "nodes/supportnodes.h" |
| 38 | #include "optimizer/clauses.h" |
| 39 | #include "optimizer/cost.h" |
| 40 | #include "optimizer/optimizer.h" |
| 41 | #include "optimizer/plancat.h" |
| 42 | #include "optimizer/prep.h" |
| 43 | #include "partitioning/partdesc.h" |
| 44 | #include "parser/parse_relation.h" |
| 45 | #include "parser/parsetree.h" |
| 46 | #include "rewrite/rewriteManip.h" |
| 47 | #include "statistics/statistics.h" |
| 48 | #include "storage/bufmgr.h" |
| 49 | #include "utils/builtins.h" |
| 50 | #include "utils/lsyscache.h" |
| 51 | #include "utils/partcache.h" |
| 52 | #include "utils/rel.h" |
| 53 | #include "utils/syscache.h" |
| 54 | #include "utils/snapmgr.h" |
| 55 | |
| 56 | |
| 57 | /* GUC parameter */ |
| 58 | int constraint_exclusion = CONSTRAINT_EXCLUSION_PARTITION; |
| 59 | |
| 60 | /* Hook for plugins to get control in get_relation_info() */ |
| 61 | get_relation_info_hook_type get_relation_info_hook = NULL; |
| 62 | |
| 63 | |
| 64 | static void get_relation_foreign_keys(PlannerInfo *root, RelOptInfo *rel, |
| 65 | Relation relation, bool inhparent); |
| 66 | static bool infer_collation_opclass_match(InferenceElem *elem, Relation idxRel, |
| 67 | List *idxExprs); |
| 68 | static List *get_relation_constraints(PlannerInfo *root, |
| 69 | Oid relationObjectId, RelOptInfo *rel, |
| 70 | bool include_noinherit, |
| 71 | bool include_notnull, |
| 72 | bool include_partition); |
| 73 | static List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index, |
| 74 | Relation heapRelation); |
| 75 | static List *get_relation_statistics(RelOptInfo *rel, Relation relation); |
| 76 | static void set_relation_partition_info(PlannerInfo *root, RelOptInfo *rel, |
| 77 | Relation relation); |
| 78 | static PartitionScheme find_partition_scheme(PlannerInfo *root, Relation rel); |
| 79 | static void set_baserel_partition_key_exprs(Relation relation, |
| 80 | RelOptInfo *rel); |
| 81 | |
| 82 | /* |
| 83 | * get_relation_info - |
| 84 | * Retrieves catalog information for a given relation. |
| 85 | * |
| 86 | * Given the Oid of the relation, return the following info into fields |
| 87 | * of the RelOptInfo struct: |
| 88 | * |
| 89 | * min_attr lowest valid AttrNumber |
| 90 | * max_attr highest valid AttrNumber |
| 91 | * indexlist list of IndexOptInfos for relation's indexes |
| 92 | * statlist list of StatisticExtInfo for relation's statistic objects |
| 93 | * serverid if it's a foreign table, the server OID |
| 94 | * fdwroutine if it's a foreign table, the FDW function pointers |
| 95 | * pages number of pages |
| 96 | * tuples number of tuples |
| 97 | * rel_parallel_workers user-defined number of parallel workers |
| 98 | * |
| 99 | * Also, add information about the relation's foreign keys to root->fkey_list. |
| 100 | * |
| 101 | * Also, initialize the attr_needed[] and attr_widths[] arrays. In most |
| 102 | * cases these are left as zeroes, but sometimes we need to compute attr |
| 103 | * widths here, and we may as well cache the results for costsize.c. |
| 104 | * |
| 105 | * If inhparent is true, all we need to do is set up the attr arrays: |
| 106 | * the RelOptInfo actually represents the appendrel formed by an inheritance |
| 107 | * tree, and so the parent rel's physical size and index information isn't |
| 108 | * important for it. |
| 109 | */ |
| 110 | void |
| 111 | get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, |
| 112 | RelOptInfo *rel) |
| 113 | { |
| 114 | Index varno = rel->relid; |
| 115 | Relation relation; |
| 116 | bool hasindex; |
| 117 | List *indexinfos = NIL; |
| 118 | |
| 119 | /* |
| 120 | * We need not lock the relation since it was already locked, either by |
| 121 | * the rewriter or when expand_inherited_rtentry() added it to the query's |
| 122 | * rangetable. |
| 123 | */ |
| 124 | relation = table_open(relationObjectId, NoLock); |
| 125 | |
| 126 | /* Temporary and unlogged relations are inaccessible during recovery. */ |
| 127 | if (!RelationNeedsWAL(relation) && RecoveryInProgress()) |
| 128 | ereport(ERROR, |
| 129 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 130 | errmsg("cannot access temporary or unlogged relations during recovery" ))); |
| 131 | |
| 132 | rel->min_attr = FirstLowInvalidHeapAttributeNumber + 1; |
| 133 | rel->max_attr = RelationGetNumberOfAttributes(relation); |
| 134 | rel->reltablespace = RelationGetForm(relation)->reltablespace; |
| 135 | |
| 136 | Assert(rel->max_attr >= rel->min_attr); |
| 137 | rel->attr_needed = (Relids *) |
| 138 | palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids)); |
| 139 | rel->attr_widths = (int32 *) |
| 140 | palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32)); |
| 141 | |
| 142 | /* |
| 143 | * Estimate relation size --- unless it's an inheritance parent, in which |
| 144 | * case the size we want is not the rel's own size but the size of its |
| 145 | * inheritance tree. That will be computed in set_append_rel_size(). |
| 146 | */ |
| 147 | if (!inhparent) |
| 148 | estimate_rel_size(relation, rel->attr_widths - rel->min_attr, |
| 149 | &rel->pages, &rel->tuples, &rel->allvisfrac); |
| 150 | |
| 151 | /* Retrieve the parallel_workers reloption, or -1 if not set. */ |
| 152 | rel->rel_parallel_workers = RelationGetParallelWorkers(relation, -1); |
| 153 | |
| 154 | /* |
| 155 | * Make list of indexes. Ignore indexes on system catalogs if told to. |
| 156 | * Don't bother with indexes for an inheritance parent, either. |
| 157 | */ |
| 158 | if (inhparent || |
| 159 | (IgnoreSystemIndexes && IsSystemRelation(relation))) |
| 160 | hasindex = false; |
| 161 | else |
| 162 | hasindex = relation->rd_rel->relhasindex; |
| 163 | |
| 164 | if (hasindex) |
| 165 | { |
| 166 | List *indexoidlist; |
| 167 | LOCKMODE lmode; |
| 168 | ListCell *l; |
| 169 | |
| 170 | indexoidlist = RelationGetIndexList(relation); |
| 171 | |
| 172 | /* |
| 173 | * For each index, we get the same type of lock that the executor will |
| 174 | * need, and do not release it. This saves a couple of trips to the |
| 175 | * shared lock manager while not creating any real loss of |
| 176 | * concurrency, because no schema changes could be happening on the |
| 177 | * index while we hold lock on the parent rel, and no lock type used |
| 178 | * for queries blocks any other kind of index operation. |
| 179 | */ |
| 180 | lmode = root->simple_rte_array[varno]->rellockmode; |
| 181 | |
| 182 | foreach(l, indexoidlist) |
| 183 | { |
| 184 | Oid indexoid = lfirst_oid(l); |
| 185 | Relation indexRelation; |
| 186 | Form_pg_index index; |
| 187 | IndexAmRoutine *amroutine; |
| 188 | IndexOptInfo *info; |
| 189 | int ncolumns, |
| 190 | nkeycolumns; |
| 191 | int i; |
| 192 | |
| 193 | /* |
| 194 | * Extract info from the relation descriptor for the index. |
| 195 | */ |
| 196 | indexRelation = index_open(indexoid, lmode); |
| 197 | index = indexRelation->rd_index; |
| 198 | |
| 199 | /* |
| 200 | * Ignore invalid indexes, since they can't safely be used for |
| 201 | * queries. Note that this is OK because the data structure we |
| 202 | * are constructing is only used by the planner --- the executor |
| 203 | * still needs to insert into "invalid" indexes, if they're marked |
| 204 | * indisready. |
| 205 | */ |
| 206 | if (!index->indisvalid) |
| 207 | { |
| 208 | index_close(indexRelation, NoLock); |
| 209 | continue; |
| 210 | } |
| 211 | |
| 212 | /* |
| 213 | * Ignore partitioned indexes, since they are not usable for |
| 214 | * queries. |
| 215 | */ |
| 216 | if (indexRelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) |
| 217 | { |
| 218 | index_close(indexRelation, NoLock); |
| 219 | continue; |
| 220 | } |
| 221 | |
| 222 | /* |
| 223 | * If the index is valid, but cannot yet be used, ignore it; but |
| 224 | * mark the plan we are generating as transient. See |
| 225 | * src/backend/access/heap/README.HOT for discussion. |
| 226 | */ |
| 227 | if (index->indcheckxmin && |
| 228 | !TransactionIdPrecedes(HeapTupleHeaderGetXmin(indexRelation->rd_indextuple->t_data), |
| 229 | TransactionXmin)) |
| 230 | { |
| 231 | root->glob->transientPlan = true; |
| 232 | index_close(indexRelation, NoLock); |
| 233 | continue; |
| 234 | } |
| 235 | |
| 236 | info = makeNode(IndexOptInfo); |
| 237 | |
| 238 | info->indexoid = index->indexrelid; |
| 239 | info->reltablespace = |
| 240 | RelationGetForm(indexRelation)->reltablespace; |
| 241 | info->rel = rel; |
| 242 | info->ncolumns = ncolumns = index->indnatts; |
| 243 | info->nkeycolumns = nkeycolumns = index->indnkeyatts; |
| 244 | |
| 245 | info->indexkeys = (int *) palloc(sizeof(int) * ncolumns); |
| 246 | info->indexcollations = (Oid *) palloc(sizeof(Oid) * nkeycolumns); |
| 247 | info->opfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns); |
| 248 | info->opcintype = (Oid *) palloc(sizeof(Oid) * nkeycolumns); |
| 249 | info->canreturn = (bool *) palloc(sizeof(bool) * ncolumns); |
| 250 | |
| 251 | for (i = 0; i < ncolumns; i++) |
| 252 | { |
| 253 | info->indexkeys[i] = index->indkey.values[i]; |
| 254 | info->canreturn[i] = index_can_return(indexRelation, i + 1); |
| 255 | } |
| 256 | |
| 257 | for (i = 0; i < nkeycolumns; i++) |
| 258 | { |
| 259 | info->opfamily[i] = indexRelation->rd_opfamily[i]; |
| 260 | info->opcintype[i] = indexRelation->rd_opcintype[i]; |
| 261 | info->indexcollations[i] = indexRelation->rd_indcollation[i]; |
| 262 | } |
| 263 | |
| 264 | info->relam = indexRelation->rd_rel->relam; |
| 265 | |
| 266 | /* We copy just the fields we need, not all of rd_indam */ |
| 267 | amroutine = indexRelation->rd_indam; |
| 268 | info->amcanorderbyop = amroutine->amcanorderbyop; |
| 269 | info->amoptionalkey = amroutine->amoptionalkey; |
| 270 | info->amsearcharray = amroutine->amsearcharray; |
| 271 | info->amsearchnulls = amroutine->amsearchnulls; |
| 272 | info->amcanparallel = amroutine->amcanparallel; |
| 273 | info->amhasgettuple = (amroutine->amgettuple != NULL); |
| 274 | info->amhasgetbitmap = amroutine->amgetbitmap != NULL && |
| 275 | relation->rd_tableam->scan_bitmap_next_block != NULL; |
| 276 | info->amcostestimate = amroutine->amcostestimate; |
| 277 | Assert(info->amcostestimate != NULL); |
| 278 | |
| 279 | /* |
| 280 | * Fetch the ordering information for the index, if any. |
| 281 | */ |
| 282 | if (info->relam == BTREE_AM_OID) |
| 283 | { |
| 284 | /* |
| 285 | * If it's a btree index, we can use its opfamily OIDs |
| 286 | * directly as the sort ordering opfamily OIDs. |
| 287 | */ |
| 288 | Assert(amroutine->amcanorder); |
| 289 | |
| 290 | info->sortopfamily = info->opfamily; |
| 291 | info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns); |
| 292 | info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns); |
| 293 | |
| 294 | for (i = 0; i < nkeycolumns; i++) |
| 295 | { |
| 296 | int16 opt = indexRelation->rd_indoption[i]; |
| 297 | |
| 298 | info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0; |
| 299 | info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0; |
| 300 | } |
| 301 | } |
| 302 | else if (amroutine->amcanorder) |
| 303 | { |
| 304 | /* |
| 305 | * Otherwise, identify the corresponding btree opfamilies by |
| 306 | * trying to map this index's "<" operators into btree. Since |
| 307 | * "<" uniquely defines the behavior of a sort order, this is |
| 308 | * a sufficient test. |
| 309 | * |
| 310 | * XXX This method is rather slow and also requires the |
| 311 | * undesirable assumption that the other index AM numbers its |
| 312 | * strategies the same as btree. It'd be better to have a way |
| 313 | * to explicitly declare the corresponding btree opfamily for |
| 314 | * each opfamily of the other index type. But given the lack |
| 315 | * of current or foreseeable amcanorder index types, it's not |
| 316 | * worth expending more effort on now. |
| 317 | */ |
| 318 | info->sortopfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns); |
| 319 | info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns); |
| 320 | info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns); |
| 321 | |
| 322 | for (i = 0; i < nkeycolumns; i++) |
| 323 | { |
| 324 | int16 opt = indexRelation->rd_indoption[i]; |
| 325 | Oid ltopr; |
| 326 | Oid btopfamily; |
| 327 | Oid btopcintype; |
| 328 | int16 btstrategy; |
| 329 | |
| 330 | info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0; |
| 331 | info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0; |
| 332 | |
| 333 | ltopr = get_opfamily_member(info->opfamily[i], |
| 334 | info->opcintype[i], |
| 335 | info->opcintype[i], |
| 336 | BTLessStrategyNumber); |
| 337 | if (OidIsValid(ltopr) && |
| 338 | get_ordering_op_properties(ltopr, |
| 339 | &btopfamily, |
| 340 | &btopcintype, |
| 341 | &btstrategy) && |
| 342 | btopcintype == info->opcintype[i] && |
| 343 | btstrategy == BTLessStrategyNumber) |
| 344 | { |
| 345 | /* Successful mapping */ |
| 346 | info->sortopfamily[i] = btopfamily; |
| 347 | } |
| 348 | else |
| 349 | { |
| 350 | /* Fail ... quietly treat index as unordered */ |
| 351 | info->sortopfamily = NULL; |
| 352 | info->reverse_sort = NULL; |
| 353 | info->nulls_first = NULL; |
| 354 | break; |
| 355 | } |
| 356 | } |
| 357 | } |
| 358 | else |
| 359 | { |
| 360 | info->sortopfamily = NULL; |
| 361 | info->reverse_sort = NULL; |
| 362 | info->nulls_first = NULL; |
| 363 | } |
| 364 | |
| 365 | /* |
| 366 | * Fetch the index expressions and predicate, if any. We must |
| 367 | * modify the copies we obtain from the relcache to have the |
| 368 | * correct varno for the parent relation, so that they match up |
| 369 | * correctly against qual clauses. |
| 370 | */ |
| 371 | info->indexprs = RelationGetIndexExpressions(indexRelation); |
| 372 | info->indpred = RelationGetIndexPredicate(indexRelation); |
| 373 | if (info->indexprs && varno != 1) |
| 374 | ChangeVarNodes((Node *) info->indexprs, 1, varno, 0); |
| 375 | if (info->indpred && varno != 1) |
| 376 | ChangeVarNodes((Node *) info->indpred, 1, varno, 0); |
| 377 | |
| 378 | /* Build targetlist using the completed indexprs data */ |
| 379 | info->indextlist = build_index_tlist(root, info, relation); |
| 380 | |
| 381 | info->indrestrictinfo = NIL; /* set later, in indxpath.c */ |
| 382 | info->predOK = false; /* set later, in indxpath.c */ |
| 383 | info->unique = index->indisunique; |
| 384 | info->immediate = index->indimmediate; |
| 385 | info->hypothetical = false; |
| 386 | |
| 387 | /* |
| 388 | * Estimate the index size. If it's not a partial index, we lock |
| 389 | * the number-of-tuples estimate to equal the parent table; if it |
| 390 | * is partial then we have to use the same methods as we would for |
| 391 | * a table, except we can be sure that the index is not larger |
| 392 | * than the table. |
| 393 | */ |
| 394 | if (info->indpred == NIL) |
| 395 | { |
| 396 | info->pages = RelationGetNumberOfBlocks(indexRelation); |
| 397 | info->tuples = rel->tuples; |
| 398 | } |
| 399 | else |
| 400 | { |
| 401 | double allvisfrac; /* dummy */ |
| 402 | |
| 403 | estimate_rel_size(indexRelation, NULL, |
| 404 | &info->pages, &info->tuples, &allvisfrac); |
| 405 | if (info->tuples > rel->tuples) |
| 406 | info->tuples = rel->tuples; |
| 407 | } |
| 408 | |
| 409 | if (info->relam == BTREE_AM_OID) |
| 410 | { |
| 411 | /* For btrees, get tree height while we have the index open */ |
| 412 | info->tree_height = _bt_getrootheight(indexRelation); |
| 413 | } |
| 414 | else |
| 415 | { |
| 416 | /* For other index types, just set it to "unknown" for now */ |
| 417 | info->tree_height = -1; |
| 418 | } |
| 419 | |
| 420 | index_close(indexRelation, NoLock); |
| 421 | |
| 422 | indexinfos = lcons(info, indexinfos); |
| 423 | } |
| 424 | |
| 425 | list_free(indexoidlist); |
| 426 | } |
| 427 | |
| 428 | rel->indexlist = indexinfos; |
| 429 | |
| 430 | rel->statlist = get_relation_statistics(rel, relation); |
| 431 | |
| 432 | /* Grab foreign-table info using the relcache, while we have it */ |
| 433 | if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE) |
| 434 | { |
| 435 | rel->serverid = GetForeignServerIdByRelId(RelationGetRelid(relation)); |
| 436 | rel->fdwroutine = GetFdwRoutineForRelation(relation, true); |
| 437 | } |
| 438 | else |
| 439 | { |
| 440 | rel->serverid = InvalidOid; |
| 441 | rel->fdwroutine = NULL; |
| 442 | } |
| 443 | |
| 444 | /* Collect info about relation's foreign keys, if relevant */ |
| 445 | get_relation_foreign_keys(root, rel, relation, inhparent); |
| 446 | |
| 447 | /* |
| 448 | * Collect info about relation's partitioning scheme, if any. Only |
| 449 | * inheritance parents may be partitioned. |
| 450 | */ |
| 451 | if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) |
| 452 | set_relation_partition_info(root, rel, relation); |
| 453 | |
| 454 | table_close(relation, NoLock); |
| 455 | |
| 456 | /* |
| 457 | * Allow a plugin to editorialize on the info we obtained from the |
| 458 | * catalogs. Actions might include altering the assumed relation size, |
| 459 | * removing an index, or adding a hypothetical index to the indexlist. |
| 460 | */ |
| 461 | if (get_relation_info_hook) |
| 462 | (*get_relation_info_hook) (root, relationObjectId, inhparent, rel); |
| 463 | } |
| 464 | |
| 465 | /* |
| 466 | * get_relation_foreign_keys - |
| 467 | * Retrieves foreign key information for a given relation. |
| 468 | * |
| 469 | * ForeignKeyOptInfos for relevant foreign keys are created and added to |
| 470 | * root->fkey_list. We do this now while we have the relcache entry open. |
| 471 | * We could sometimes avoid making useless ForeignKeyOptInfos if we waited |
| 472 | * until all RelOptInfos have been built, but the cost of re-opening the |
| 473 | * relcache entries would probably exceed any savings. |
| 474 | */ |
| 475 | static void |
| 476 | get_relation_foreign_keys(PlannerInfo *root, RelOptInfo *rel, |
| 477 | Relation relation, bool inhparent) |
| 478 | { |
| 479 | List *rtable = root->parse->rtable; |
| 480 | List *cachedfkeys; |
| 481 | ListCell *lc; |
| 482 | |
| 483 | /* |
| 484 | * If it's not a baserel, we don't care about its FKs. Also, if the query |
| 485 | * references only a single relation, we can skip the lookup since no FKs |
| 486 | * could satisfy the requirements below. |
| 487 | */ |
| 488 | if (rel->reloptkind != RELOPT_BASEREL || |
| 489 | list_length(rtable) < 2) |
| 490 | return; |
| 491 | |
| 492 | /* |
| 493 | * If it's the parent of an inheritance tree, ignore its FKs. We could |
| 494 | * make useful FK-based deductions if we found that all members of the |
| 495 | * inheritance tree have equivalent FK constraints, but detecting that |
| 496 | * would require code that hasn't been written. |
| 497 | */ |
| 498 | if (inhparent) |
| 499 | return; |
| 500 | |
| 501 | /* |
| 502 | * Extract data about relation's FKs from the relcache. Note that this |
| 503 | * list belongs to the relcache and might disappear in a cache flush, so |
| 504 | * we must not do any further catalog access within this function. |
| 505 | */ |
| 506 | cachedfkeys = RelationGetFKeyList(relation); |
| 507 | |
| 508 | /* |
| 509 | * Figure out which FKs are of interest for this query, and create |
| 510 | * ForeignKeyOptInfos for them. We want only FKs that reference some |
| 511 | * other RTE of the current query. In queries containing self-joins, |
| 512 | * there might be more than one other RTE for a referenced table, and we |
| 513 | * should make a ForeignKeyOptInfo for each occurrence. |
| 514 | * |
| 515 | * Ideally, we would ignore RTEs that correspond to non-baserels, but it's |
| 516 | * too hard to identify those here, so we might end up making some useless |
| 517 | * ForeignKeyOptInfos. If so, match_foreign_keys_to_quals() will remove |
| 518 | * them again. |
| 519 | */ |
| 520 | foreach(lc, cachedfkeys) |
| 521 | { |
| 522 | ForeignKeyCacheInfo *cachedfk = (ForeignKeyCacheInfo *) lfirst(lc); |
| 523 | Index rti; |
| 524 | ListCell *lc2; |
| 525 | |
| 526 | /* conrelid should always be that of the table we're considering */ |
| 527 | Assert(cachedfk->conrelid == RelationGetRelid(relation)); |
| 528 | |
| 529 | /* Scan to find other RTEs matching confrelid */ |
| 530 | rti = 0; |
| 531 | foreach(lc2, rtable) |
| 532 | { |
| 533 | RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2); |
| 534 | ForeignKeyOptInfo *info; |
| 535 | |
| 536 | rti++; |
| 537 | /* Ignore if not the correct table */ |
| 538 | if (rte->rtekind != RTE_RELATION || |
| 539 | rte->relid != cachedfk->confrelid) |
| 540 | continue; |
| 541 | /* Ignore if it's an inheritance parent; doesn't really match */ |
| 542 | if (rte->inh) |
| 543 | continue; |
| 544 | /* Ignore self-referential FKs; we only care about joins */ |
| 545 | if (rti == rel->relid) |
| 546 | continue; |
| 547 | |
| 548 | /* OK, let's make an entry */ |
| 549 | info = makeNode(ForeignKeyOptInfo); |
| 550 | info->con_relid = rel->relid; |
| 551 | info->ref_relid = rti; |
| 552 | info->nkeys = cachedfk->nkeys; |
| 553 | memcpy(info->conkey, cachedfk->conkey, sizeof(info->conkey)); |
| 554 | memcpy(info->confkey, cachedfk->confkey, sizeof(info->confkey)); |
| 555 | memcpy(info->conpfeqop, cachedfk->conpfeqop, sizeof(info->conpfeqop)); |
| 556 | /* zero out fields to be filled by match_foreign_keys_to_quals */ |
| 557 | info->nmatched_ec = 0; |
| 558 | info->nmatched_rcols = 0; |
| 559 | info->nmatched_ri = 0; |
| 560 | memset(info->eclass, 0, sizeof(info->eclass)); |
| 561 | memset(info->rinfos, 0, sizeof(info->rinfos)); |
| 562 | |
| 563 | root->fkey_list = lappend(root->fkey_list, info); |
| 564 | } |
| 565 | } |
| 566 | } |
| 567 | |
| 568 | /* |
| 569 | * infer_arbiter_indexes - |
| 570 | * Determine the unique indexes used to arbitrate speculative insertion. |
| 571 | * |
| 572 | * Uses user-supplied inference clause expressions and predicate to match a |
| 573 | * unique index from those defined and ready on the heap relation (target). |
| 574 | * An exact match is required on columns/expressions (although they can appear |
| 575 | * in any order). However, the predicate given by the user need only restrict |
| 576 | * insertion to a subset of some part of the table covered by some particular |
| 577 | * unique index (in particular, a partial unique index) in order to be |
| 578 | * inferred. |
| 579 | * |
| 580 | * The implementation does not consider which B-Tree operator class any |
| 581 | * particular available unique index attribute uses, unless one was specified |
| 582 | * in the inference specification. The same is true of collations. In |
| 583 | * particular, there is no system dependency on the default operator class for |
| 584 | * the purposes of inference. If no opclass (or collation) is specified, then |
| 585 | * all matching indexes (that may or may not match the default in terms of |
| 586 | * each attribute opclass/collation) are used for inference. |
| 587 | */ |
| 588 | List * |
| 589 | infer_arbiter_indexes(PlannerInfo *root) |
| 590 | { |
| 591 | OnConflictExpr *onconflict = root->parse->onConflict; |
| 592 | |
| 593 | /* Iteration state */ |
| 594 | RangeTblEntry *rte; |
| 595 | Relation relation; |
| 596 | Oid indexOidFromConstraint = InvalidOid; |
| 597 | List *indexList; |
| 598 | ListCell *l; |
| 599 | |
| 600 | /* Normalized inference attributes and inference expressions: */ |
| 601 | Bitmapset *inferAttrs = NULL; |
| 602 | List *inferElems = NIL; |
| 603 | |
| 604 | /* Results */ |
| 605 | List *results = NIL; |
| 606 | |
| 607 | /* |
| 608 | * Quickly return NIL for ON CONFLICT DO NOTHING without an inference |
| 609 | * specification or named constraint. ON CONFLICT DO UPDATE statements |
| 610 | * must always provide one or the other (but parser ought to have caught |
| 611 | * that already). |
| 612 | */ |
| 613 | if (onconflict->arbiterElems == NIL && |
| 614 | onconflict->constraint == InvalidOid) |
| 615 | return NIL; |
| 616 | |
| 617 | /* |
| 618 | * We need not lock the relation since it was already locked, either by |
| 619 | * the rewriter or when expand_inherited_rtentry() added it to the query's |
| 620 | * rangetable. |
| 621 | */ |
| 622 | rte = rt_fetch(root->parse->resultRelation, root->parse->rtable); |
| 623 | |
| 624 | relation = table_open(rte->relid, NoLock); |
| 625 | |
| 626 | /* |
| 627 | * Build normalized/BMS representation of plain indexed attributes, as |
| 628 | * well as a separate list of expression items. This simplifies matching |
| 629 | * the cataloged definition of indexes. |
| 630 | */ |
| 631 | foreach(l, onconflict->arbiterElems) |
| 632 | { |
| 633 | InferenceElem *elem = (InferenceElem *) lfirst(l); |
| 634 | Var *var; |
| 635 | int attno; |
| 636 | |
| 637 | if (!IsA(elem->expr, Var)) |
| 638 | { |
| 639 | /* If not a plain Var, just shove it in inferElems for now */ |
| 640 | inferElems = lappend(inferElems, elem->expr); |
| 641 | continue; |
| 642 | } |
| 643 | |
| 644 | var = (Var *) elem->expr; |
| 645 | attno = var->varattno; |
| 646 | |
| 647 | if (attno == 0) |
| 648 | ereport(ERROR, |
| 649 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 650 | errmsg("whole row unique index inference specifications are not supported" ))); |
| 651 | |
| 652 | inferAttrs = bms_add_member(inferAttrs, |
| 653 | attno - FirstLowInvalidHeapAttributeNumber); |
| 654 | } |
| 655 | |
| 656 | /* |
| 657 | * Lookup named constraint's index. This is not immediately returned |
| 658 | * because some additional sanity checks are required. |
| 659 | */ |
| 660 | if (onconflict->constraint != InvalidOid) |
| 661 | { |
| 662 | indexOidFromConstraint = get_constraint_index(onconflict->constraint); |
| 663 | |
| 664 | if (indexOidFromConstraint == InvalidOid) |
| 665 | ereport(ERROR, |
| 666 | (errcode(ERRCODE_WRONG_OBJECT_TYPE), |
| 667 | errmsg("constraint in ON CONFLICT clause has no associated index" ))); |
| 668 | } |
| 669 | |
| 670 | /* |
| 671 | * Using that representation, iterate through the list of indexes on the |
| 672 | * target relation to try and find a match |
| 673 | */ |
| 674 | indexList = RelationGetIndexList(relation); |
| 675 | |
| 676 | foreach(l, indexList) |
| 677 | { |
| 678 | Oid indexoid = lfirst_oid(l); |
| 679 | Relation idxRel; |
| 680 | Form_pg_index idxForm; |
| 681 | Bitmapset *indexedAttrs; |
| 682 | List *idxExprs; |
| 683 | List *predExprs; |
| 684 | AttrNumber natt; |
| 685 | ListCell *el; |
| 686 | |
| 687 | /* |
| 688 | * Extract info from the relation descriptor for the index. Obtain |
| 689 | * the same lock type that the executor will ultimately use. |
| 690 | * |
| 691 | * Let executor complain about !indimmediate case directly, because |
| 692 | * enforcement needs to occur there anyway when an inference clause is |
| 693 | * omitted. |
| 694 | */ |
| 695 | idxRel = index_open(indexoid, rte->rellockmode); |
| 696 | idxForm = idxRel->rd_index; |
| 697 | |
| 698 | if (!idxForm->indisvalid) |
| 699 | goto next; |
| 700 | |
| 701 | /* |
| 702 | * Note that we do not perform a check against indcheckxmin (like e.g. |
| 703 | * get_relation_info()) here to eliminate candidates, because |
| 704 | * uniqueness checking only cares about the most recently committed |
| 705 | * tuple versions. |
| 706 | */ |
| 707 | |
| 708 | /* |
| 709 | * Look for match on "ON constraint_name" variant, which may not be |
| 710 | * unique constraint. This can only be a constraint name. |
| 711 | */ |
| 712 | if (indexOidFromConstraint == idxForm->indexrelid) |
| 713 | { |
| 714 | if (!idxForm->indisunique && onconflict->action == ONCONFLICT_UPDATE) |
| 715 | ereport(ERROR, |
| 716 | (errcode(ERRCODE_WRONG_OBJECT_TYPE), |
| 717 | errmsg("ON CONFLICT DO UPDATE not supported with exclusion constraints" ))); |
| 718 | |
| 719 | results = lappend_oid(results, idxForm->indexrelid); |
| 720 | list_free(indexList); |
| 721 | index_close(idxRel, NoLock); |
| 722 | table_close(relation, NoLock); |
| 723 | return results; |
| 724 | } |
| 725 | else if (indexOidFromConstraint != InvalidOid) |
| 726 | { |
| 727 | /* No point in further work for index in named constraint case */ |
| 728 | goto next; |
| 729 | } |
| 730 | |
| 731 | /* |
| 732 | * Only considering conventional inference at this point (not named |
| 733 | * constraints), so index under consideration can be immediately |
| 734 | * skipped if it's not unique |
| 735 | */ |
| 736 | if (!idxForm->indisunique) |
| 737 | goto next; |
| 738 | |
| 739 | /* Build BMS representation of plain (non expression) index attrs */ |
| 740 | indexedAttrs = NULL; |
| 741 | for (natt = 0; natt < idxForm->indnkeyatts; natt++) |
| 742 | { |
| 743 | int attno = idxRel->rd_index->indkey.values[natt]; |
| 744 | |
| 745 | if (attno != 0) |
| 746 | indexedAttrs = bms_add_member(indexedAttrs, |
| 747 | attno - FirstLowInvalidHeapAttributeNumber); |
| 748 | } |
| 749 | |
| 750 | /* Non-expression attributes (if any) must match */ |
| 751 | if (!bms_equal(indexedAttrs, inferAttrs)) |
| 752 | goto next; |
| 753 | |
| 754 | /* Expression attributes (if any) must match */ |
| 755 | idxExprs = RelationGetIndexExpressions(idxRel); |
| 756 | foreach(el, onconflict->arbiterElems) |
| 757 | { |
| 758 | InferenceElem *elem = (InferenceElem *) lfirst(el); |
| 759 | |
| 760 | /* |
| 761 | * Ensure that collation/opclass aspects of inference expression |
| 762 | * element match. Even though this loop is primarily concerned |
| 763 | * with matching expressions, it is a convenient point to check |
| 764 | * this for both expressions and ordinary (non-expression) |
| 765 | * attributes appearing as inference elements. |
| 766 | */ |
| 767 | if (!infer_collation_opclass_match(elem, idxRel, idxExprs)) |
| 768 | goto next; |
| 769 | |
| 770 | /* |
| 771 | * Plain Vars don't factor into count of expression elements, and |
| 772 | * the question of whether or not they satisfy the index |
| 773 | * definition has already been considered (they must). |
| 774 | */ |
| 775 | if (IsA(elem->expr, Var)) |
| 776 | continue; |
| 777 | |
| 778 | /* |
| 779 | * Might as well avoid redundant check in the rare cases where |
| 780 | * infer_collation_opclass_match() is required to do real work. |
| 781 | * Otherwise, check that element expression appears in cataloged |
| 782 | * index definition. |
| 783 | */ |
| 784 | if (elem->infercollid != InvalidOid || |
| 785 | elem->inferopclass != InvalidOid || |
| 786 | list_member(idxExprs, elem->expr)) |
| 787 | continue; |
| 788 | |
| 789 | goto next; |
| 790 | } |
| 791 | |
| 792 | /* |
| 793 | * Now that all inference elements were matched, ensure that the |
| 794 | * expression elements from inference clause are not missing any |
| 795 | * cataloged expressions. This does the right thing when unique |
| 796 | * indexes redundantly repeat the same attribute, or if attributes |
| 797 | * redundantly appear multiple times within an inference clause. |
| 798 | */ |
| 799 | if (list_difference(idxExprs, inferElems) != NIL) |
| 800 | goto next; |
| 801 | |
| 802 | /* |
| 803 | * If it's a partial index, its predicate must be implied by the ON |
| 804 | * CONFLICT's WHERE clause. |
| 805 | */ |
| 806 | predExprs = RelationGetIndexPredicate(idxRel); |
| 807 | |
| 808 | if (!predicate_implied_by(predExprs, (List *) onconflict->arbiterWhere, false)) |
| 809 | goto next; |
| 810 | |
| 811 | results = lappend_oid(results, idxForm->indexrelid); |
| 812 | next: |
| 813 | index_close(idxRel, NoLock); |
| 814 | } |
| 815 | |
| 816 | list_free(indexList); |
| 817 | table_close(relation, NoLock); |
| 818 | |
| 819 | if (results == NIL) |
| 820 | ereport(ERROR, |
| 821 | (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), |
| 822 | errmsg("there is no unique or exclusion constraint matching the ON CONFLICT specification" ))); |
| 823 | |
| 824 | return results; |
| 825 | } |
| 826 | |
| 827 | /* |
| 828 | * infer_collation_opclass_match - ensure infer element opclass/collation match |
| 829 | * |
| 830 | * Given unique index inference element from inference specification, if |
| 831 | * collation was specified, or if opclass was specified, verify that there is |
| 832 | * at least one matching indexed attribute (occasionally, there may be more). |
| 833 | * Skip this in the common case where inference specification does not include |
| 834 | * collation or opclass (instead matching everything, regardless of cataloged |
| 835 | * collation/opclass of indexed attribute). |
| 836 | * |
| 837 | * At least historically, Postgres has not offered collations or opclasses |
| 838 | * with alternative-to-default notions of equality, so these additional |
| 839 | * criteria should only be required infrequently. |
| 840 | * |
| 841 | * Don't give up immediately when an inference element matches some attribute |
| 842 | * cataloged as indexed but not matching additional opclass/collation |
| 843 | * criteria. This is done so that the implementation is as forgiving as |
| 844 | * possible of redundancy within cataloged index attributes (or, less |
| 845 | * usefully, within inference specification elements). If collations actually |
| 846 | * differ between apparently redundantly indexed attributes (redundant within |
| 847 | * or across indexes), then there really is no redundancy as such. |
| 848 | * |
| 849 | * Note that if an inference element specifies an opclass and a collation at |
| 850 | * once, both must match in at least one particular attribute within index |
| 851 | * catalog definition in order for that inference element to be considered |
| 852 | * inferred/satisfied. |
| 853 | */ |
| 854 | static bool |
| 855 | infer_collation_opclass_match(InferenceElem *elem, Relation idxRel, |
| 856 | List *idxExprs) |
| 857 | { |
| 858 | AttrNumber natt; |
| 859 | Oid inferopfamily = InvalidOid; /* OID of opclass opfamily */ |
| 860 | Oid inferopcinputtype = InvalidOid; /* OID of opclass input type */ |
| 861 | int nplain = 0; /* # plain attrs observed */ |
| 862 | |
| 863 | /* |
| 864 | * If inference specification element lacks collation/opclass, then no |
| 865 | * need to check for exact match. |
| 866 | */ |
| 867 | if (elem->infercollid == InvalidOid && elem->inferopclass == InvalidOid) |
| 868 | return true; |
| 869 | |
| 870 | /* |
| 871 | * Lookup opfamily and input type, for matching indexes |
| 872 | */ |
| 873 | if (elem->inferopclass) |
| 874 | { |
| 875 | inferopfamily = get_opclass_family(elem->inferopclass); |
| 876 | inferopcinputtype = get_opclass_input_type(elem->inferopclass); |
| 877 | } |
| 878 | |
| 879 | for (natt = 1; natt <= idxRel->rd_att->natts; natt++) |
| 880 | { |
| 881 | Oid opfamily = idxRel->rd_opfamily[natt - 1]; |
| 882 | Oid opcinputtype = idxRel->rd_opcintype[natt - 1]; |
| 883 | Oid collation = idxRel->rd_indcollation[natt - 1]; |
| 884 | int attno = idxRel->rd_index->indkey.values[natt - 1]; |
| 885 | |
| 886 | if (attno != 0) |
| 887 | nplain++; |
| 888 | |
| 889 | if (elem->inferopclass != InvalidOid && |
| 890 | (inferopfamily != opfamily || inferopcinputtype != opcinputtype)) |
| 891 | { |
| 892 | /* Attribute needed to match opclass, but didn't */ |
| 893 | continue; |
| 894 | } |
| 895 | |
| 896 | if (elem->infercollid != InvalidOid && |
| 897 | elem->infercollid != collation) |
| 898 | { |
| 899 | /* Attribute needed to match collation, but didn't */ |
| 900 | continue; |
| 901 | } |
| 902 | |
| 903 | /* If one matching index att found, good enough -- return true */ |
| 904 | if (IsA(elem->expr, Var)) |
| 905 | { |
| 906 | if (((Var *) elem->expr)->varattno == attno) |
| 907 | return true; |
| 908 | } |
| 909 | else if (attno == 0) |
| 910 | { |
| 911 | Node *nattExpr = list_nth(idxExprs, (natt - 1) - nplain); |
| 912 | |
| 913 | /* |
| 914 | * Note that unlike routines like match_index_to_operand() we |
| 915 | * don't need to care about RelabelType. Neither the index |
| 916 | * definition nor the inference clause should contain them. |
| 917 | */ |
| 918 | if (equal(elem->expr, nattExpr)) |
| 919 | return true; |
| 920 | } |
| 921 | } |
| 922 | |
| 923 | return false; |
| 924 | } |
| 925 | |
| 926 | /* |
| 927 | * estimate_rel_size - estimate # pages and # tuples in a table or index |
| 928 | * |
| 929 | * We also estimate the fraction of the pages that are marked all-visible in |
| 930 | * the visibility map, for use in estimation of index-only scans. |
| 931 | * |
| 932 | * If attr_widths isn't NULL, it points to the zero-index entry of the |
| 933 | * relation's attr_widths[] cache; we fill this in if we have need to compute |
| 934 | * the attribute widths for estimation purposes. |
| 935 | */ |
| 936 | void |
| 937 | estimate_rel_size(Relation rel, int32 *attr_widths, |
| 938 | BlockNumber *pages, double *tuples, double *allvisfrac) |
| 939 | { |
| 940 | BlockNumber curpages; |
| 941 | BlockNumber relpages; |
| 942 | double reltuples; |
| 943 | BlockNumber relallvisible; |
| 944 | double density; |
| 945 | |
| 946 | switch (rel->rd_rel->relkind) |
| 947 | { |
| 948 | case RELKIND_RELATION: |
| 949 | case RELKIND_MATVIEW: |
| 950 | case RELKIND_TOASTVALUE: |
| 951 | table_relation_estimate_size(rel, attr_widths, pages, tuples, |
| 952 | allvisfrac); |
| 953 | break; |
| 954 | |
| 955 | case RELKIND_INDEX: |
| 956 | |
| 957 | /* |
| 958 | * XXX: It'd probably be good to move this into a callback, |
| 959 | * individual index types e.g. know if they have a metapage. |
| 960 | */ |
| 961 | |
| 962 | /* it has storage, ok to call the smgr */ |
| 963 | curpages = RelationGetNumberOfBlocks(rel); |
| 964 | |
| 965 | /* coerce values in pg_class to more desirable types */ |
| 966 | relpages = (BlockNumber) rel->rd_rel->relpages; |
| 967 | reltuples = (double) rel->rd_rel->reltuples; |
| 968 | relallvisible = (BlockNumber) rel->rd_rel->relallvisible; |
| 969 | |
| 970 | /* report estimated # pages */ |
| 971 | *pages = curpages; |
| 972 | /* quick exit if rel is clearly empty */ |
| 973 | if (curpages == 0) |
| 974 | { |
| 975 | *tuples = 0; |
| 976 | *allvisfrac = 0; |
| 977 | break; |
| 978 | } |
| 979 | /* coerce values in pg_class to more desirable types */ |
| 980 | relpages = (BlockNumber) rel->rd_rel->relpages; |
| 981 | reltuples = (double) rel->rd_rel->reltuples; |
| 982 | relallvisible = (BlockNumber) rel->rd_rel->relallvisible; |
| 983 | |
| 984 | /* |
| 985 | * Discount the metapage while estimating the number of tuples. |
| 986 | * This is a kluge because it assumes more than it ought to about |
| 987 | * index structure. Currently it's OK for btree, hash, and GIN |
| 988 | * indexes but suspect for GiST indexes. |
| 989 | */ |
| 990 | if (relpages > 0) |
| 991 | { |
| 992 | curpages--; |
| 993 | relpages--; |
| 994 | } |
| 995 | |
| 996 | /* estimate number of tuples from previous tuple density */ |
| 997 | if (relpages > 0) |
| 998 | density = reltuples / (double) relpages; |
| 999 | else |
| 1000 | { |
| 1001 | /* |
| 1002 | * When we have no data because the relation was truncated, |
| 1003 | * estimate tuple width from attribute datatypes. We assume |
| 1004 | * here that the pages are completely full, which is OK for |
| 1005 | * tables (since they've presumably not been VACUUMed yet) but |
| 1006 | * is probably an overestimate for indexes. Fortunately |
| 1007 | * get_relation_info() can clamp the overestimate to the |
| 1008 | * parent table's size. |
| 1009 | * |
| 1010 | * Note: this code intentionally disregards alignment |
| 1011 | * considerations, because (a) that would be gilding the lily |
| 1012 | * considering how crude the estimate is, and (b) it creates |
| 1013 | * platform dependencies in the default plans which are kind |
| 1014 | * of a headache for regression testing. |
| 1015 | * |
| 1016 | * XXX: Should this logic be more index specific? |
| 1017 | */ |
| 1018 | int32 tuple_width; |
| 1019 | |
| 1020 | tuple_width = get_rel_data_width(rel, attr_widths); |
| 1021 | tuple_width += MAXALIGN(SizeofHeapTupleHeader); |
| 1022 | tuple_width += sizeof(ItemIdData); |
| 1023 | /* note: integer division is intentional here */ |
| 1024 | density = (BLCKSZ - SizeOfPageHeaderData) / tuple_width; |
| 1025 | } |
| 1026 | *tuples = rint(density * (double) curpages); |
| 1027 | |
| 1028 | /* |
| 1029 | * We use relallvisible as-is, rather than scaling it up like we |
| 1030 | * do for the pages and tuples counts, on the theory that any |
| 1031 | * pages added since the last VACUUM are most likely not marked |
| 1032 | * all-visible. But costsize.c wants it converted to a fraction. |
| 1033 | */ |
| 1034 | if (relallvisible == 0 || curpages <= 0) |
| 1035 | *allvisfrac = 0; |
| 1036 | else if ((double) relallvisible >= curpages) |
| 1037 | *allvisfrac = 1; |
| 1038 | else |
| 1039 | *allvisfrac = (double) relallvisible / curpages; |
| 1040 | break; |
| 1041 | |
| 1042 | case RELKIND_SEQUENCE: |
| 1043 | /* Sequences always have a known size */ |
| 1044 | *pages = 1; |
| 1045 | *tuples = 1; |
| 1046 | *allvisfrac = 0; |
| 1047 | break; |
| 1048 | case RELKIND_FOREIGN_TABLE: |
| 1049 | /* Just use whatever's in pg_class */ |
| 1050 | *pages = rel->rd_rel->relpages; |
| 1051 | *tuples = rel->rd_rel->reltuples; |
| 1052 | *allvisfrac = 0; |
| 1053 | break; |
| 1054 | default: |
| 1055 | /* else it has no disk storage; probably shouldn't get here? */ |
| 1056 | *pages = 0; |
| 1057 | *tuples = 0; |
| 1058 | *allvisfrac = 0; |
| 1059 | break; |
| 1060 | } |
| 1061 | } |
| 1062 | |
| 1063 | |
| 1064 | /* |
| 1065 | * get_rel_data_width |
| 1066 | * |
| 1067 | * Estimate the average width of (the data part of) the relation's tuples. |
| 1068 | * |
| 1069 | * If attr_widths isn't NULL, it points to the zero-index entry of the |
| 1070 | * relation's attr_widths[] cache; use and update that cache as appropriate. |
| 1071 | * |
| 1072 | * Currently we ignore dropped columns. Ideally those should be included |
| 1073 | * in the result, but we haven't got any way to get info about them; and |
| 1074 | * since they might be mostly NULLs, treating them as zero-width is not |
| 1075 | * necessarily the wrong thing anyway. |
| 1076 | */ |
| 1077 | int32 |
| 1078 | get_rel_data_width(Relation rel, int32 *attr_widths) |
| 1079 | { |
| 1080 | int32 tuple_width = 0; |
| 1081 | int i; |
| 1082 | |
| 1083 | for (i = 1; i <= RelationGetNumberOfAttributes(rel); i++) |
| 1084 | { |
| 1085 | Form_pg_attribute att = TupleDescAttr(rel->rd_att, i - 1); |
| 1086 | int32 item_width; |
| 1087 | |
| 1088 | if (att->attisdropped) |
| 1089 | continue; |
| 1090 | |
| 1091 | /* use previously cached data, if any */ |
| 1092 | if (attr_widths != NULL && attr_widths[i] > 0) |
| 1093 | { |
| 1094 | tuple_width += attr_widths[i]; |
| 1095 | continue; |
| 1096 | } |
| 1097 | |
| 1098 | /* This should match set_rel_width() in costsize.c */ |
| 1099 | item_width = get_attavgwidth(RelationGetRelid(rel), i); |
| 1100 | if (item_width <= 0) |
| 1101 | { |
| 1102 | item_width = get_typavgwidth(att->atttypid, att->atttypmod); |
| 1103 | Assert(item_width > 0); |
| 1104 | } |
| 1105 | if (attr_widths != NULL) |
| 1106 | attr_widths[i] = item_width; |
| 1107 | tuple_width += item_width; |
| 1108 | } |
| 1109 | |
| 1110 | return tuple_width; |
| 1111 | } |
| 1112 | |
| 1113 | /* |
| 1114 | * get_relation_data_width |
| 1115 | * |
| 1116 | * External API for get_rel_data_width: same behavior except we have to |
| 1117 | * open the relcache entry. |
| 1118 | */ |
| 1119 | int32 |
| 1120 | get_relation_data_width(Oid relid, int32 *attr_widths) |
| 1121 | { |
| 1122 | int32 result; |
| 1123 | Relation relation; |
| 1124 | |
| 1125 | /* As above, assume relation is already locked */ |
| 1126 | relation = table_open(relid, NoLock); |
| 1127 | |
| 1128 | result = get_rel_data_width(relation, attr_widths); |
| 1129 | |
| 1130 | table_close(relation, NoLock); |
| 1131 | |
| 1132 | return result; |
| 1133 | } |
| 1134 | |
| 1135 | |
| 1136 | /* |
| 1137 | * get_relation_constraints |
| 1138 | * |
| 1139 | * Retrieve the applicable constraint expressions of the given relation. |
| 1140 | * |
| 1141 | * Returns a List (possibly empty) of constraint expressions. Each one |
| 1142 | * has been canonicalized, and its Vars are changed to have the varno |
| 1143 | * indicated by rel->relid. This allows the expressions to be easily |
| 1144 | * compared to expressions taken from WHERE. |
| 1145 | * |
| 1146 | * If include_noinherit is true, it's okay to include constraints that |
| 1147 | * are marked NO INHERIT. |
| 1148 | * |
| 1149 | * If include_notnull is true, "col IS NOT NULL" expressions are generated |
| 1150 | * and added to the result for each column that's marked attnotnull. |
| 1151 | * |
| 1152 | * If include_partition is true, and the relation is a partition, |
| 1153 | * also include the partitioning constraints. |
| 1154 | * |
| 1155 | * Note: at present this is invoked at most once per relation per planner |
| 1156 | * run, and in many cases it won't be invoked at all, so there seems no |
| 1157 | * point in caching the data in RelOptInfo. |
| 1158 | */ |
| 1159 | static List * |
| 1160 | get_relation_constraints(PlannerInfo *root, |
| 1161 | Oid relationObjectId, RelOptInfo *rel, |
| 1162 | bool include_noinherit, |
| 1163 | bool include_notnull, |
| 1164 | bool include_partition) |
| 1165 | { |
| 1166 | List *result = NIL; |
| 1167 | Index varno = rel->relid; |
| 1168 | Relation relation; |
| 1169 | TupleConstr *constr; |
| 1170 | |
| 1171 | /* |
| 1172 | * We assume the relation has already been safely locked. |
| 1173 | */ |
| 1174 | relation = table_open(relationObjectId, NoLock); |
| 1175 | |
| 1176 | constr = relation->rd_att->constr; |
| 1177 | if (constr != NULL) |
| 1178 | { |
| 1179 | int num_check = constr->num_check; |
| 1180 | int i; |
| 1181 | |
| 1182 | for (i = 0; i < num_check; i++) |
| 1183 | { |
| 1184 | Node *cexpr; |
| 1185 | |
| 1186 | /* |
| 1187 | * If this constraint hasn't been fully validated yet, we must |
| 1188 | * ignore it here. Also ignore if NO INHERIT and we weren't told |
| 1189 | * that that's safe. |
| 1190 | */ |
| 1191 | if (!constr->check[i].ccvalid) |
| 1192 | continue; |
| 1193 | if (constr->check[i].ccnoinherit && !include_noinherit) |
| 1194 | continue; |
| 1195 | |
| 1196 | cexpr = stringToNode(constr->check[i].ccbin); |
| 1197 | |
| 1198 | /* |
| 1199 | * Run each expression through const-simplification and |
| 1200 | * canonicalization. This is not just an optimization, but is |
| 1201 | * necessary, because we will be comparing it to |
| 1202 | * similarly-processed qual clauses, and may fail to detect valid |
| 1203 | * matches without this. This must match the processing done to |
| 1204 | * qual clauses in preprocess_expression()! (We can skip the |
| 1205 | * stuff involving subqueries, however, since we don't allow any |
| 1206 | * in check constraints.) |
| 1207 | */ |
| 1208 | cexpr = eval_const_expressions(root, cexpr); |
| 1209 | |
| 1210 | cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true); |
| 1211 | |
| 1212 | /* Fix Vars to have the desired varno */ |
| 1213 | if (varno != 1) |
| 1214 | ChangeVarNodes(cexpr, 1, varno, 0); |
| 1215 | |
| 1216 | /* |
| 1217 | * Finally, convert to implicit-AND format (that is, a List) and |
| 1218 | * append the resulting item(s) to our output list. |
| 1219 | */ |
| 1220 | result = list_concat(result, |
| 1221 | make_ands_implicit((Expr *) cexpr)); |
| 1222 | } |
| 1223 | |
| 1224 | /* Add NOT NULL constraints in expression form, if requested */ |
| 1225 | if (include_notnull && constr->has_not_null) |
| 1226 | { |
| 1227 | int natts = relation->rd_att->natts; |
| 1228 | |
| 1229 | for (i = 1; i <= natts; i++) |
| 1230 | { |
| 1231 | Form_pg_attribute att = TupleDescAttr(relation->rd_att, i - 1); |
| 1232 | |
| 1233 | if (att->attnotnull && !att->attisdropped) |
| 1234 | { |
| 1235 | NullTest *ntest = makeNode(NullTest); |
| 1236 | |
| 1237 | ntest->arg = (Expr *) makeVar(varno, |
| 1238 | i, |
| 1239 | att->atttypid, |
| 1240 | att->atttypmod, |
| 1241 | att->attcollation, |
| 1242 | 0); |
| 1243 | ntest->nulltesttype = IS_NOT_NULL; |
| 1244 | |
| 1245 | /* |
| 1246 | * argisrow=false is correct even for a composite column, |
| 1247 | * because attnotnull does not represent a SQL-spec IS NOT |
| 1248 | * NULL test in such a case, just IS DISTINCT FROM NULL. |
| 1249 | */ |
| 1250 | ntest->argisrow = false; |
| 1251 | ntest->location = -1; |
| 1252 | result = lappend(result, ntest); |
| 1253 | } |
| 1254 | } |
| 1255 | } |
| 1256 | } |
| 1257 | |
| 1258 | /* |
| 1259 | * Add partitioning constraints, if requested. |
| 1260 | */ |
| 1261 | if (include_partition && relation->rd_rel->relispartition) |
| 1262 | { |
| 1263 | List *pcqual = RelationGetPartitionQual(relation); |
| 1264 | |
| 1265 | if (pcqual) |
| 1266 | { |
| 1267 | /* |
| 1268 | * Run the partition quals through const-simplification similar to |
| 1269 | * check constraints. We skip canonicalize_qual, though, because |
| 1270 | * partition quals should be in canonical form already; also, |
| 1271 | * since the qual is in implicit-AND format, we'd have to |
| 1272 | * explicitly convert it to explicit-AND format and back again. |
| 1273 | */ |
| 1274 | pcqual = (List *) eval_const_expressions(root, (Node *) pcqual); |
| 1275 | |
| 1276 | /* Fix Vars to have the desired varno */ |
| 1277 | if (varno != 1) |
| 1278 | ChangeVarNodes((Node *) pcqual, 1, varno, 0); |
| 1279 | |
| 1280 | result = list_concat(result, pcqual); |
| 1281 | } |
| 1282 | } |
| 1283 | |
| 1284 | table_close(relation, NoLock); |
| 1285 | |
| 1286 | return result; |
| 1287 | } |
| 1288 | |
| 1289 | /* |
| 1290 | * get_relation_statistics |
| 1291 | * Retrieve extended statistics defined on the table. |
| 1292 | * |
| 1293 | * Returns a List (possibly empty) of StatisticExtInfo objects describing |
| 1294 | * the statistics. Note that this doesn't load the actual statistics data, |
| 1295 | * just the identifying metadata. Only stats actually built are considered. |
| 1296 | */ |
| 1297 | static List * |
| 1298 | get_relation_statistics(RelOptInfo *rel, Relation relation) |
| 1299 | { |
| 1300 | List *statoidlist; |
| 1301 | List *stainfos = NIL; |
| 1302 | ListCell *l; |
| 1303 | |
| 1304 | statoidlist = RelationGetStatExtList(relation); |
| 1305 | |
| 1306 | foreach(l, statoidlist) |
| 1307 | { |
| 1308 | Oid statOid = lfirst_oid(l); |
| 1309 | Form_pg_statistic_ext staForm; |
| 1310 | HeapTuple htup; |
| 1311 | HeapTuple dtup; |
| 1312 | Bitmapset *keys = NULL; |
| 1313 | int i; |
| 1314 | |
| 1315 | htup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statOid)); |
| 1316 | if (!HeapTupleIsValid(htup)) |
| 1317 | elog(ERROR, "cache lookup failed for statistics object %u" , statOid); |
| 1318 | staForm = (Form_pg_statistic_ext) GETSTRUCT(htup); |
| 1319 | |
| 1320 | dtup = SearchSysCache1(STATEXTDATASTXOID, ObjectIdGetDatum(statOid)); |
| 1321 | if (!HeapTupleIsValid(dtup)) |
| 1322 | elog(ERROR, "cache lookup failed for statistics object %u" , statOid); |
| 1323 | |
| 1324 | /* |
| 1325 | * First, build the array of columns covered. This is ultimately |
| 1326 | * wasted if no stats within the object have actually been built, but |
| 1327 | * it doesn't seem worth troubling over that case. |
| 1328 | */ |
| 1329 | for (i = 0; i < staForm->stxkeys.dim1; i++) |
| 1330 | keys = bms_add_member(keys, staForm->stxkeys.values[i]); |
| 1331 | |
| 1332 | /* add one StatisticExtInfo for each kind built */ |
| 1333 | if (statext_is_kind_built(dtup, STATS_EXT_NDISTINCT)) |
| 1334 | { |
| 1335 | StatisticExtInfo *info = makeNode(StatisticExtInfo); |
| 1336 | |
| 1337 | info->statOid = statOid; |
| 1338 | info->rel = rel; |
| 1339 | info->kind = STATS_EXT_NDISTINCT; |
| 1340 | info->keys = bms_copy(keys); |
| 1341 | |
| 1342 | stainfos = lcons(info, stainfos); |
| 1343 | } |
| 1344 | |
| 1345 | if (statext_is_kind_built(dtup, STATS_EXT_DEPENDENCIES)) |
| 1346 | { |
| 1347 | StatisticExtInfo *info = makeNode(StatisticExtInfo); |
| 1348 | |
| 1349 | info->statOid = statOid; |
| 1350 | info->rel = rel; |
| 1351 | info->kind = STATS_EXT_DEPENDENCIES; |
| 1352 | info->keys = bms_copy(keys); |
| 1353 | |
| 1354 | stainfos = lcons(info, stainfos); |
| 1355 | } |
| 1356 | |
| 1357 | if (statext_is_kind_built(dtup, STATS_EXT_MCV)) |
| 1358 | { |
| 1359 | StatisticExtInfo *info = makeNode(StatisticExtInfo); |
| 1360 | |
| 1361 | info->statOid = statOid; |
| 1362 | info->rel = rel; |
| 1363 | info->kind = STATS_EXT_MCV; |
| 1364 | info->keys = bms_copy(keys); |
| 1365 | |
| 1366 | stainfos = lcons(info, stainfos); |
| 1367 | } |
| 1368 | |
| 1369 | ReleaseSysCache(htup); |
| 1370 | ReleaseSysCache(dtup); |
| 1371 | bms_free(keys); |
| 1372 | } |
| 1373 | |
| 1374 | list_free(statoidlist); |
| 1375 | |
| 1376 | return stainfos; |
| 1377 | } |
| 1378 | |
| 1379 | /* |
| 1380 | * relation_excluded_by_constraints |
| 1381 | * |
| 1382 | * Detect whether the relation need not be scanned because it has either |
| 1383 | * self-inconsistent restrictions, or restrictions inconsistent with the |
| 1384 | * relation's applicable constraints. |
| 1385 | * |
| 1386 | * Note: this examines only rel->relid, rel->reloptkind, and |
| 1387 | * rel->baserestrictinfo; therefore it can be called before filling in |
| 1388 | * other fields of the RelOptInfo. |
| 1389 | */ |
| 1390 | bool |
| 1391 | relation_excluded_by_constraints(PlannerInfo *root, |
| 1392 | RelOptInfo *rel, RangeTblEntry *rte) |
| 1393 | { |
| 1394 | bool include_noinherit; |
| 1395 | bool include_notnull; |
| 1396 | bool include_partition = false; |
| 1397 | List *safe_restrictions; |
| 1398 | List *constraint_pred; |
| 1399 | List *safe_constraints; |
| 1400 | ListCell *lc; |
| 1401 | |
| 1402 | /* As of now, constraint exclusion works only with simple relations. */ |
| 1403 | Assert(IS_SIMPLE_REL(rel)); |
| 1404 | |
| 1405 | /* |
| 1406 | * If there are no base restriction clauses, we have no hope of proving |
| 1407 | * anything below, so fall out quickly. |
| 1408 | */ |
| 1409 | if (rel->baserestrictinfo == NIL) |
| 1410 | return false; |
| 1411 | |
| 1412 | /* |
| 1413 | * Regardless of the setting of constraint_exclusion, detect |
| 1414 | * constant-FALSE-or-NULL restriction clauses. Because const-folding will |
| 1415 | * reduce "anything AND FALSE" to just "FALSE", any such case should |
| 1416 | * result in exactly one baserestrictinfo entry. This doesn't fire very |
| 1417 | * often, but it seems cheap enough to be worth doing anyway. (Without |
| 1418 | * this, we'd miss some optimizations that 9.5 and earlier found via much |
| 1419 | * more roundabout methods.) |
| 1420 | */ |
| 1421 | if (list_length(rel->baserestrictinfo) == 1) |
| 1422 | { |
| 1423 | RestrictInfo *rinfo = (RestrictInfo *) linitial(rel->baserestrictinfo); |
| 1424 | Expr *clause = rinfo->clause; |
| 1425 | |
| 1426 | if (clause && IsA(clause, Const) && |
| 1427 | (((Const *) clause)->constisnull || |
| 1428 | !DatumGetBool(((Const *) clause)->constvalue))) |
| 1429 | return true; |
| 1430 | } |
| 1431 | |
| 1432 | /* |
| 1433 | * Skip further tests, depending on constraint_exclusion. |
| 1434 | */ |
| 1435 | switch (constraint_exclusion) |
| 1436 | { |
| 1437 | case CONSTRAINT_EXCLUSION_OFF: |
| 1438 | /* In 'off' mode, never make any further tests */ |
| 1439 | return false; |
| 1440 | |
| 1441 | case CONSTRAINT_EXCLUSION_PARTITION: |
| 1442 | |
| 1443 | /* |
| 1444 | * When constraint_exclusion is set to 'partition' we only handle |
| 1445 | * appendrel members. Normally, they are RELOPT_OTHER_MEMBER_REL |
| 1446 | * relations, but we also consider inherited target relations as |
| 1447 | * appendrel members for the purposes of constraint exclusion |
| 1448 | * (since, indeed, they were appendrel members earlier in |
| 1449 | * inheritance_planner). |
| 1450 | * |
| 1451 | * In both cases, partition pruning was already applied, so there |
| 1452 | * is no need to consider the rel's partition constraints here. |
| 1453 | */ |
| 1454 | if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL || |
| 1455 | (rel->relid == root->parse->resultRelation && |
| 1456 | root->inhTargetKind != INHKIND_NONE)) |
| 1457 | break; /* appendrel member, so process it */ |
| 1458 | return false; |
| 1459 | |
| 1460 | case CONSTRAINT_EXCLUSION_ON: |
| 1461 | |
| 1462 | /* |
| 1463 | * In 'on' mode, always apply constraint exclusion. If we are |
| 1464 | * considering a baserel that is a partition (i.e., it was |
| 1465 | * directly named rather than expanded from a parent table), then |
| 1466 | * its partition constraints haven't been considered yet, so |
| 1467 | * include them in the processing here. |
| 1468 | */ |
| 1469 | if (rel->reloptkind == RELOPT_BASEREL && |
| 1470 | !(rel->relid == root->parse->resultRelation && |
| 1471 | root->inhTargetKind != INHKIND_NONE)) |
| 1472 | include_partition = true; |
| 1473 | break; /* always try to exclude */ |
| 1474 | } |
| 1475 | |
| 1476 | /* |
| 1477 | * Check for self-contradictory restriction clauses. We dare not make |
| 1478 | * deductions with non-immutable functions, but any immutable clauses that |
| 1479 | * are self-contradictory allow us to conclude the scan is unnecessary. |
| 1480 | * |
| 1481 | * Note: strip off RestrictInfo because predicate_refuted_by() isn't |
| 1482 | * expecting to see any in its predicate argument. |
| 1483 | */ |
| 1484 | safe_restrictions = NIL; |
| 1485 | foreach(lc, rel->baserestrictinfo) |
| 1486 | { |
| 1487 | RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); |
| 1488 | |
| 1489 | if (!contain_mutable_functions((Node *) rinfo->clause)) |
| 1490 | safe_restrictions = lappend(safe_restrictions, rinfo->clause); |
| 1491 | } |
| 1492 | |
| 1493 | /* |
| 1494 | * We can use weak refutation here, since we're comparing restriction |
| 1495 | * clauses with restriction clauses. |
| 1496 | */ |
| 1497 | if (predicate_refuted_by(safe_restrictions, safe_restrictions, true)) |
| 1498 | return true; |
| 1499 | |
| 1500 | /* |
| 1501 | * Only plain relations have constraints, so stop here for other rtekinds. |
| 1502 | */ |
| 1503 | if (rte->rtekind != RTE_RELATION) |
| 1504 | return false; |
| 1505 | |
| 1506 | /* |
| 1507 | * If we are scanning just this table, we can use NO INHERIT constraints, |
| 1508 | * but not if we're scanning its children too. (Note that partitioned |
| 1509 | * tables should never have NO INHERIT constraints; but it's not necessary |
| 1510 | * for us to assume that here.) |
| 1511 | */ |
| 1512 | include_noinherit = !rte->inh; |
| 1513 | |
| 1514 | /* |
| 1515 | * Currently, attnotnull constraints must be treated as NO INHERIT unless |
| 1516 | * this is a partitioned table. In future we might track their |
| 1517 | * inheritance status more accurately, allowing this to be refined. |
| 1518 | */ |
| 1519 | include_notnull = (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE); |
| 1520 | |
| 1521 | /* |
| 1522 | * Fetch the appropriate set of constraint expressions. |
| 1523 | */ |
| 1524 | constraint_pred = get_relation_constraints(root, rte->relid, rel, |
| 1525 | include_noinherit, |
| 1526 | include_notnull, |
| 1527 | include_partition); |
| 1528 | |
| 1529 | /* |
| 1530 | * We do not currently enforce that CHECK constraints contain only |
| 1531 | * immutable functions, so it's necessary to check here. We daren't draw |
| 1532 | * conclusions from plan-time evaluation of non-immutable functions. Since |
| 1533 | * they're ANDed, we can just ignore any mutable constraints in the list, |
| 1534 | * and reason about the rest. |
| 1535 | */ |
| 1536 | safe_constraints = NIL; |
| 1537 | foreach(lc, constraint_pred) |
| 1538 | { |
| 1539 | Node *pred = (Node *) lfirst(lc); |
| 1540 | |
| 1541 | if (!contain_mutable_functions(pred)) |
| 1542 | safe_constraints = lappend(safe_constraints, pred); |
| 1543 | } |
| 1544 | |
| 1545 | /* |
| 1546 | * The constraints are effectively ANDed together, so we can just try to |
| 1547 | * refute the entire collection at once. This may allow us to make proofs |
| 1548 | * that would fail if we took them individually. |
| 1549 | * |
| 1550 | * Note: we use rel->baserestrictinfo, not safe_restrictions as might seem |
| 1551 | * an obvious optimization. Some of the clauses might be OR clauses that |
| 1552 | * have volatile and nonvolatile subclauses, and it's OK to make |
| 1553 | * deductions with the nonvolatile parts. |
| 1554 | * |
| 1555 | * We need strong refutation because we have to prove that the constraints |
| 1556 | * would yield false, not just NULL. |
| 1557 | */ |
| 1558 | if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false)) |
| 1559 | return true; |
| 1560 | |
| 1561 | return false; |
| 1562 | } |
| 1563 | |
| 1564 | |
| 1565 | /* |
| 1566 | * build_physical_tlist |
| 1567 | * |
| 1568 | * Build a targetlist consisting of exactly the relation's user attributes, |
| 1569 | * in order. The executor can special-case such tlists to avoid a projection |
| 1570 | * step at runtime, so we use such tlists preferentially for scan nodes. |
| 1571 | * |
| 1572 | * Exception: if there are any dropped or missing columns, we punt and return |
| 1573 | * NIL. Ideally we would like to handle these cases too. However this |
| 1574 | * creates problems for ExecTypeFromTL, which may be asked to build a tupdesc |
| 1575 | * for a tlist that includes vars of no-longer-existent types. In theory we |
| 1576 | * could dig out the required info from the pg_attribute entries of the |
| 1577 | * relation, but that data is not readily available to ExecTypeFromTL. |
| 1578 | * For now, we don't apply the physical-tlist optimization when there are |
| 1579 | * dropped cols. |
| 1580 | * |
| 1581 | * We also support building a "physical" tlist for subqueries, functions, |
| 1582 | * values lists, table expressions, and CTEs, since the same optimization can |
| 1583 | * occur in SubqueryScan, FunctionScan, ValuesScan, CteScan, TableFunc, |
| 1584 | * NamedTuplestoreScan, and WorkTableScan nodes. |
| 1585 | */ |
| 1586 | List * |
| 1587 | build_physical_tlist(PlannerInfo *root, RelOptInfo *rel) |
| 1588 | { |
| 1589 | List *tlist = NIL; |
| 1590 | Index varno = rel->relid; |
| 1591 | RangeTblEntry *rte = planner_rt_fetch(varno, root); |
| 1592 | Relation relation; |
| 1593 | Query *subquery; |
| 1594 | Var *var; |
| 1595 | ListCell *l; |
| 1596 | int attrno, |
| 1597 | numattrs; |
| 1598 | List *colvars; |
| 1599 | |
| 1600 | switch (rte->rtekind) |
| 1601 | { |
| 1602 | case RTE_RELATION: |
| 1603 | /* Assume we already have adequate lock */ |
| 1604 | relation = table_open(rte->relid, NoLock); |
| 1605 | |
| 1606 | numattrs = RelationGetNumberOfAttributes(relation); |
| 1607 | for (attrno = 1; attrno <= numattrs; attrno++) |
| 1608 | { |
| 1609 | Form_pg_attribute att_tup = TupleDescAttr(relation->rd_att, |
| 1610 | attrno - 1); |
| 1611 | |
| 1612 | if (att_tup->attisdropped || att_tup->atthasmissing) |
| 1613 | { |
| 1614 | /* found a dropped or missing col, so punt */ |
| 1615 | tlist = NIL; |
| 1616 | break; |
| 1617 | } |
| 1618 | |
| 1619 | var = makeVar(varno, |
| 1620 | attrno, |
| 1621 | att_tup->atttypid, |
| 1622 | att_tup->atttypmod, |
| 1623 | att_tup->attcollation, |
| 1624 | 0); |
| 1625 | |
| 1626 | tlist = lappend(tlist, |
| 1627 | makeTargetEntry((Expr *) var, |
| 1628 | attrno, |
| 1629 | NULL, |
| 1630 | false)); |
| 1631 | } |
| 1632 | |
| 1633 | table_close(relation, NoLock); |
| 1634 | break; |
| 1635 | |
| 1636 | case RTE_SUBQUERY: |
| 1637 | subquery = rte->subquery; |
| 1638 | foreach(l, subquery->targetList) |
| 1639 | { |
| 1640 | TargetEntry *tle = (TargetEntry *) lfirst(l); |
| 1641 | |
| 1642 | /* |
| 1643 | * A resjunk column of the subquery can be reflected as |
| 1644 | * resjunk in the physical tlist; we need not punt. |
| 1645 | */ |
| 1646 | var = makeVarFromTargetEntry(varno, tle); |
| 1647 | |
| 1648 | tlist = lappend(tlist, |
| 1649 | makeTargetEntry((Expr *) var, |
| 1650 | tle->resno, |
| 1651 | NULL, |
| 1652 | tle->resjunk)); |
| 1653 | } |
| 1654 | break; |
| 1655 | |
| 1656 | case RTE_FUNCTION: |
| 1657 | case RTE_TABLEFUNC: |
| 1658 | case RTE_VALUES: |
| 1659 | case RTE_CTE: |
| 1660 | case RTE_NAMEDTUPLESTORE: |
| 1661 | case RTE_RESULT: |
| 1662 | /* Not all of these can have dropped cols, but share code anyway */ |
| 1663 | expandRTE(rte, varno, 0, -1, true /* include dropped */ , |
| 1664 | NULL, &colvars); |
| 1665 | foreach(l, colvars) |
| 1666 | { |
| 1667 | var = (Var *) lfirst(l); |
| 1668 | |
| 1669 | /* |
| 1670 | * A non-Var in expandRTE's output means a dropped column; |
| 1671 | * must punt. |
| 1672 | */ |
| 1673 | if (!IsA(var, Var)) |
| 1674 | { |
| 1675 | tlist = NIL; |
| 1676 | break; |
| 1677 | } |
| 1678 | |
| 1679 | tlist = lappend(tlist, |
| 1680 | makeTargetEntry((Expr *) var, |
| 1681 | var->varattno, |
| 1682 | NULL, |
| 1683 | false)); |
| 1684 | } |
| 1685 | break; |
| 1686 | |
| 1687 | default: |
| 1688 | /* caller error */ |
| 1689 | elog(ERROR, "unsupported RTE kind %d in build_physical_tlist" , |
| 1690 | (int) rte->rtekind); |
| 1691 | break; |
| 1692 | } |
| 1693 | |
| 1694 | return tlist; |
| 1695 | } |
| 1696 | |
| 1697 | /* |
| 1698 | * build_index_tlist |
| 1699 | * |
| 1700 | * Build a targetlist representing the columns of the specified index. |
| 1701 | * Each column is represented by a Var for the corresponding base-relation |
| 1702 | * column, or an expression in base-relation Vars, as appropriate. |
| 1703 | * |
| 1704 | * There are never any dropped columns in indexes, so unlike |
| 1705 | * build_physical_tlist, we need no failure case. |
| 1706 | */ |
| 1707 | static List * |
| 1708 | build_index_tlist(PlannerInfo *root, IndexOptInfo *index, |
| 1709 | Relation heapRelation) |
| 1710 | { |
| 1711 | List *tlist = NIL; |
| 1712 | Index varno = index->rel->relid; |
| 1713 | ListCell *indexpr_item; |
| 1714 | int i; |
| 1715 | |
| 1716 | indexpr_item = list_head(index->indexprs); |
| 1717 | for (i = 0; i < index->ncolumns; i++) |
| 1718 | { |
| 1719 | int indexkey = index->indexkeys[i]; |
| 1720 | Expr *indexvar; |
| 1721 | |
| 1722 | if (indexkey != 0) |
| 1723 | { |
| 1724 | /* simple column */ |
| 1725 | const FormData_pg_attribute *att_tup; |
| 1726 | |
| 1727 | if (indexkey < 0) |
| 1728 | att_tup = SystemAttributeDefinition(indexkey); |
| 1729 | else |
| 1730 | att_tup = TupleDescAttr(heapRelation->rd_att, indexkey - 1); |
| 1731 | |
| 1732 | indexvar = (Expr *) makeVar(varno, |
| 1733 | indexkey, |
| 1734 | att_tup->atttypid, |
| 1735 | att_tup->atttypmod, |
| 1736 | att_tup->attcollation, |
| 1737 | 0); |
| 1738 | } |
| 1739 | else |
| 1740 | { |
| 1741 | /* expression column */ |
| 1742 | if (indexpr_item == NULL) |
| 1743 | elog(ERROR, "wrong number of index expressions" ); |
| 1744 | indexvar = (Expr *) lfirst(indexpr_item); |
| 1745 | indexpr_item = lnext(indexpr_item); |
| 1746 | } |
| 1747 | |
| 1748 | tlist = lappend(tlist, |
| 1749 | makeTargetEntry(indexvar, |
| 1750 | i + 1, |
| 1751 | NULL, |
| 1752 | false)); |
| 1753 | } |
| 1754 | if (indexpr_item != NULL) |
| 1755 | elog(ERROR, "wrong number of index expressions" ); |
| 1756 | |
| 1757 | return tlist; |
| 1758 | } |
| 1759 | |
| 1760 | /* |
| 1761 | * restriction_selectivity |
| 1762 | * |
| 1763 | * Returns the selectivity of a specified restriction operator clause. |
| 1764 | * This code executes registered procedures stored in the |
| 1765 | * operator relation, by calling the function manager. |
| 1766 | * |
| 1767 | * See clause_selectivity() for the meaning of the additional parameters. |
| 1768 | */ |
| 1769 | Selectivity |
| 1770 | restriction_selectivity(PlannerInfo *root, |
| 1771 | Oid operatorid, |
| 1772 | List *args, |
| 1773 | Oid inputcollid, |
| 1774 | int varRelid) |
| 1775 | { |
| 1776 | RegProcedure oprrest = get_oprrest(operatorid); |
| 1777 | float8 result; |
| 1778 | |
| 1779 | /* |
| 1780 | * if the oprrest procedure is missing for whatever reason, use a |
| 1781 | * selectivity of 0.5 |
| 1782 | */ |
| 1783 | if (!oprrest) |
| 1784 | return (Selectivity) 0.5; |
| 1785 | |
| 1786 | result = DatumGetFloat8(OidFunctionCall4Coll(oprrest, |
| 1787 | inputcollid, |
| 1788 | PointerGetDatum(root), |
| 1789 | ObjectIdGetDatum(operatorid), |
| 1790 | PointerGetDatum(args), |
| 1791 | Int32GetDatum(varRelid))); |
| 1792 | |
| 1793 | if (result < 0.0 || result > 1.0) |
| 1794 | elog(ERROR, "invalid restriction selectivity: %f" , result); |
| 1795 | |
| 1796 | return (Selectivity) result; |
| 1797 | } |
| 1798 | |
| 1799 | /* |
| 1800 | * join_selectivity |
| 1801 | * |
| 1802 | * Returns the selectivity of a specified join operator clause. |
| 1803 | * This code executes registered procedures stored in the |
| 1804 | * operator relation, by calling the function manager. |
| 1805 | * |
| 1806 | * See clause_selectivity() for the meaning of the additional parameters. |
| 1807 | */ |
| 1808 | Selectivity |
| 1809 | join_selectivity(PlannerInfo *root, |
| 1810 | Oid operatorid, |
| 1811 | List *args, |
| 1812 | Oid inputcollid, |
| 1813 | JoinType jointype, |
| 1814 | SpecialJoinInfo *sjinfo) |
| 1815 | { |
| 1816 | RegProcedure oprjoin = get_oprjoin(operatorid); |
| 1817 | float8 result; |
| 1818 | |
| 1819 | /* |
| 1820 | * if the oprjoin procedure is missing for whatever reason, use a |
| 1821 | * selectivity of 0.5 |
| 1822 | */ |
| 1823 | if (!oprjoin) |
| 1824 | return (Selectivity) 0.5; |
| 1825 | |
| 1826 | result = DatumGetFloat8(OidFunctionCall5Coll(oprjoin, |
| 1827 | inputcollid, |
| 1828 | PointerGetDatum(root), |
| 1829 | ObjectIdGetDatum(operatorid), |
| 1830 | PointerGetDatum(args), |
| 1831 | Int16GetDatum(jointype), |
| 1832 | PointerGetDatum(sjinfo))); |
| 1833 | |
| 1834 | if (result < 0.0 || result > 1.0) |
| 1835 | elog(ERROR, "invalid join selectivity: %f" , result); |
| 1836 | |
| 1837 | return (Selectivity) result; |
| 1838 | } |
| 1839 | |
| 1840 | /* |
| 1841 | * function_selectivity |
| 1842 | * |
| 1843 | * Returns the selectivity of a specified boolean function clause. |
| 1844 | * This code executes registered procedures stored in the |
| 1845 | * pg_proc relation, by calling the function manager. |
| 1846 | * |
| 1847 | * See clause_selectivity() for the meaning of the additional parameters. |
| 1848 | */ |
| 1849 | Selectivity |
| 1850 | function_selectivity(PlannerInfo *root, |
| 1851 | Oid funcid, |
| 1852 | List *args, |
| 1853 | Oid inputcollid, |
| 1854 | bool is_join, |
| 1855 | int varRelid, |
| 1856 | JoinType jointype, |
| 1857 | SpecialJoinInfo *sjinfo) |
| 1858 | { |
| 1859 | RegProcedure prosupport = get_func_support(funcid); |
| 1860 | SupportRequestSelectivity req; |
| 1861 | SupportRequestSelectivity *sresult; |
| 1862 | |
| 1863 | /* |
| 1864 | * If no support function is provided, use our historical default |
| 1865 | * estimate, 0.3333333. This seems a pretty unprincipled choice, but |
| 1866 | * Postgres has been using that estimate for function calls since 1992. |
| 1867 | * The hoariness of this behavior suggests that we should not be in too |
| 1868 | * much hurry to use another value. |
| 1869 | */ |
| 1870 | if (!prosupport) |
| 1871 | return (Selectivity) 0.3333333; |
| 1872 | |
| 1873 | req.type = T_SupportRequestSelectivity; |
| 1874 | req.root = root; |
| 1875 | req.funcid = funcid; |
| 1876 | req.args = args; |
| 1877 | req.inputcollid = inputcollid; |
| 1878 | req.is_join = is_join; |
| 1879 | req.varRelid = varRelid; |
| 1880 | req.jointype = jointype; |
| 1881 | req.sjinfo = sjinfo; |
| 1882 | req.selectivity = -1; /* to catch failure to set the value */ |
| 1883 | |
| 1884 | sresult = (SupportRequestSelectivity *) |
| 1885 | DatumGetPointer(OidFunctionCall1(prosupport, |
| 1886 | PointerGetDatum(&req))); |
| 1887 | |
| 1888 | /* If support function fails, use default */ |
| 1889 | if (sresult != &req) |
| 1890 | return (Selectivity) 0.3333333; |
| 1891 | |
| 1892 | if (req.selectivity < 0.0 || req.selectivity > 1.0) |
| 1893 | elog(ERROR, "invalid function selectivity: %f" , req.selectivity); |
| 1894 | |
| 1895 | return (Selectivity) req.selectivity; |
| 1896 | } |
| 1897 | |
| 1898 | /* |
| 1899 | * add_function_cost |
| 1900 | * |
| 1901 | * Get an estimate of the execution cost of a function, and *add* it to |
| 1902 | * the contents of *cost. The estimate may include both one-time and |
| 1903 | * per-tuple components, since QualCost does. |
| 1904 | * |
| 1905 | * The funcid must always be supplied. If it is being called as the |
| 1906 | * implementation of a specific parsetree node (FuncExpr, OpExpr, |
| 1907 | * WindowFunc, etc), pass that as "node", else pass NULL. |
| 1908 | * |
| 1909 | * In some usages root might be NULL, too. |
| 1910 | */ |
| 1911 | void |
| 1912 | add_function_cost(PlannerInfo *root, Oid funcid, Node *node, |
| 1913 | QualCost *cost) |
| 1914 | { |
| 1915 | HeapTuple proctup; |
| 1916 | Form_pg_proc procform; |
| 1917 | |
| 1918 | proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); |
| 1919 | if (!HeapTupleIsValid(proctup)) |
| 1920 | elog(ERROR, "cache lookup failed for function %u" , funcid); |
| 1921 | procform = (Form_pg_proc) GETSTRUCT(proctup); |
| 1922 | |
| 1923 | if (OidIsValid(procform->prosupport)) |
| 1924 | { |
| 1925 | SupportRequestCost req; |
| 1926 | SupportRequestCost *sresult; |
| 1927 | |
| 1928 | req.type = T_SupportRequestCost; |
| 1929 | req.root = root; |
| 1930 | req.funcid = funcid; |
| 1931 | req.node = node; |
| 1932 | |
| 1933 | /* Initialize cost fields so that support function doesn't have to */ |
| 1934 | req.startup = 0; |
| 1935 | req.per_tuple = 0; |
| 1936 | |
| 1937 | sresult = (SupportRequestCost *) |
| 1938 | DatumGetPointer(OidFunctionCall1(procform->prosupport, |
| 1939 | PointerGetDatum(&req))); |
| 1940 | |
| 1941 | if (sresult == &req) |
| 1942 | { |
| 1943 | /* Success, so accumulate support function's estimate into *cost */ |
| 1944 | cost->startup += req.startup; |
| 1945 | cost->per_tuple += req.per_tuple; |
| 1946 | ReleaseSysCache(proctup); |
| 1947 | return; |
| 1948 | } |
| 1949 | } |
| 1950 | |
| 1951 | /* No support function, or it failed, so rely on procost */ |
| 1952 | cost->per_tuple += procform->procost * cpu_operator_cost; |
| 1953 | |
| 1954 | ReleaseSysCache(proctup); |
| 1955 | } |
| 1956 | |
| 1957 | /* |
| 1958 | * get_function_rows |
| 1959 | * |
| 1960 | * Get an estimate of the number of rows returned by a set-returning function. |
| 1961 | * |
| 1962 | * The funcid must always be supplied. In current usage, the calling node |
| 1963 | * will always be supplied, and will be either a FuncExpr or OpExpr. |
| 1964 | * But it's a good idea to not fail if it's NULL. |
| 1965 | * |
| 1966 | * In some usages root might be NULL, too. |
| 1967 | * |
| 1968 | * Note: this returns the unfiltered result of the support function, if any. |
| 1969 | * It's usually a good idea to apply clamp_row_est() to the result, but we |
| 1970 | * leave it to the caller to do so. |
| 1971 | */ |
| 1972 | double |
| 1973 | get_function_rows(PlannerInfo *root, Oid funcid, Node *node) |
| 1974 | { |
| 1975 | HeapTuple proctup; |
| 1976 | Form_pg_proc procform; |
| 1977 | double result; |
| 1978 | |
| 1979 | proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); |
| 1980 | if (!HeapTupleIsValid(proctup)) |
| 1981 | elog(ERROR, "cache lookup failed for function %u" , funcid); |
| 1982 | procform = (Form_pg_proc) GETSTRUCT(proctup); |
| 1983 | |
| 1984 | Assert(procform->proretset); /* else caller error */ |
| 1985 | |
| 1986 | if (OidIsValid(procform->prosupport)) |
| 1987 | { |
| 1988 | SupportRequestRows req; |
| 1989 | SupportRequestRows *sresult; |
| 1990 | |
| 1991 | req.type = T_SupportRequestRows; |
| 1992 | req.root = root; |
| 1993 | req.funcid = funcid; |
| 1994 | req.node = node; |
| 1995 | |
| 1996 | req.rows = 0; /* just for sanity */ |
| 1997 | |
| 1998 | sresult = (SupportRequestRows *) |
| 1999 | DatumGetPointer(OidFunctionCall1(procform->prosupport, |
| 2000 | PointerGetDatum(&req))); |
| 2001 | |
| 2002 | if (sresult == &req) |
| 2003 | { |
| 2004 | /* Success */ |
| 2005 | ReleaseSysCache(proctup); |
| 2006 | return req.rows; |
| 2007 | } |
| 2008 | } |
| 2009 | |
| 2010 | /* No support function, or it failed, so rely on prorows */ |
| 2011 | result = procform->prorows; |
| 2012 | |
| 2013 | ReleaseSysCache(proctup); |
| 2014 | |
| 2015 | return result; |
| 2016 | } |
| 2017 | |
| 2018 | /* |
| 2019 | * has_unique_index |
| 2020 | * |
| 2021 | * Detect whether there is a unique index on the specified attribute |
| 2022 | * of the specified relation, thus allowing us to conclude that all |
| 2023 | * the (non-null) values of the attribute are distinct. |
| 2024 | * |
| 2025 | * This function does not check the index's indimmediate property, which |
| 2026 | * means that uniqueness may transiently fail to hold intra-transaction. |
| 2027 | * That's appropriate when we are making statistical estimates, but beware |
| 2028 | * of using this for any correctness proofs. |
| 2029 | */ |
| 2030 | bool |
| 2031 | has_unique_index(RelOptInfo *rel, AttrNumber attno) |
| 2032 | { |
| 2033 | ListCell *ilist; |
| 2034 | |
| 2035 | foreach(ilist, rel->indexlist) |
| 2036 | { |
| 2037 | IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist); |
| 2038 | |
| 2039 | /* |
| 2040 | * Note: ignore partial indexes, since they don't allow us to conclude |
| 2041 | * that all attr values are distinct, *unless* they are marked predOK |
| 2042 | * which means we know the index's predicate is satisfied by the |
| 2043 | * query. We don't take any interest in expressional indexes either. |
| 2044 | * Also, a multicolumn unique index doesn't allow us to conclude that |
| 2045 | * just the specified attr is unique. |
| 2046 | */ |
| 2047 | if (index->unique && |
| 2048 | index->nkeycolumns == 1 && |
| 2049 | index->indexkeys[0] == attno && |
| 2050 | (index->indpred == NIL || index->predOK)) |
| 2051 | return true; |
| 2052 | } |
| 2053 | return false; |
| 2054 | } |
| 2055 | |
| 2056 | |
| 2057 | /* |
| 2058 | * has_row_triggers |
| 2059 | * |
| 2060 | * Detect whether the specified relation has any row-level triggers for event. |
| 2061 | */ |
| 2062 | bool |
| 2063 | has_row_triggers(PlannerInfo *root, Index rti, CmdType event) |
| 2064 | { |
| 2065 | RangeTblEntry *rte = planner_rt_fetch(rti, root); |
| 2066 | Relation relation; |
| 2067 | TriggerDesc *trigDesc; |
| 2068 | bool result = false; |
| 2069 | |
| 2070 | /* Assume we already have adequate lock */ |
| 2071 | relation = table_open(rte->relid, NoLock); |
| 2072 | |
| 2073 | trigDesc = relation->trigdesc; |
| 2074 | switch (event) |
| 2075 | { |
| 2076 | case CMD_INSERT: |
| 2077 | if (trigDesc && |
| 2078 | (trigDesc->trig_insert_after_row || |
| 2079 | trigDesc->trig_insert_before_row)) |
| 2080 | result = true; |
| 2081 | break; |
| 2082 | case CMD_UPDATE: |
| 2083 | if (trigDesc && |
| 2084 | (trigDesc->trig_update_after_row || |
| 2085 | trigDesc->trig_update_before_row)) |
| 2086 | result = true; |
| 2087 | break; |
| 2088 | case CMD_DELETE: |
| 2089 | if (trigDesc && |
| 2090 | (trigDesc->trig_delete_after_row || |
| 2091 | trigDesc->trig_delete_before_row)) |
| 2092 | result = true; |
| 2093 | break; |
| 2094 | default: |
| 2095 | elog(ERROR, "unrecognized CmdType: %d" , (int) event); |
| 2096 | break; |
| 2097 | } |
| 2098 | |
| 2099 | table_close(relation, NoLock); |
| 2100 | return result; |
| 2101 | } |
| 2102 | |
| 2103 | bool |
| 2104 | has_stored_generated_columns(PlannerInfo *root, Index rti) |
| 2105 | { |
| 2106 | RangeTblEntry *rte = planner_rt_fetch(rti, root); |
| 2107 | Relation relation; |
| 2108 | TupleDesc tupdesc; |
| 2109 | bool result = false; |
| 2110 | |
| 2111 | /* Assume we already have adequate lock */ |
| 2112 | relation = heap_open(rte->relid, NoLock); |
| 2113 | |
| 2114 | tupdesc = RelationGetDescr(relation); |
| 2115 | result = tupdesc->constr && tupdesc->constr->has_generated_stored; |
| 2116 | |
| 2117 | heap_close(relation, NoLock); |
| 2118 | |
| 2119 | return result; |
| 2120 | } |
| 2121 | |
| 2122 | /* |
| 2123 | * set_relation_partition_info |
| 2124 | * |
| 2125 | * Set partitioning scheme and related information for a partitioned table. |
| 2126 | */ |
| 2127 | static void |
| 2128 | set_relation_partition_info(PlannerInfo *root, RelOptInfo *rel, |
| 2129 | Relation relation) |
| 2130 | { |
| 2131 | PartitionDesc partdesc; |
| 2132 | |
| 2133 | /* Create the PartitionDirectory infrastructure if we didn't already */ |
| 2134 | if (root->glob->partition_directory == NULL) |
| 2135 | root->glob->partition_directory = |
| 2136 | CreatePartitionDirectory(CurrentMemoryContext); |
| 2137 | |
| 2138 | partdesc = PartitionDirectoryLookup(root->glob->partition_directory, |
| 2139 | relation); |
| 2140 | rel->part_scheme = find_partition_scheme(root, relation); |
| 2141 | Assert(partdesc != NULL && rel->part_scheme != NULL); |
| 2142 | rel->boundinfo = partdesc->boundinfo; |
| 2143 | rel->nparts = partdesc->nparts; |
| 2144 | set_baserel_partition_key_exprs(relation, rel); |
| 2145 | rel->partition_qual = RelationGetPartitionQual(relation); |
| 2146 | } |
| 2147 | |
| 2148 | /* |
| 2149 | * find_partition_scheme |
| 2150 | * |
| 2151 | * Find or create a PartitionScheme for this Relation. |
| 2152 | */ |
| 2153 | static PartitionScheme |
| 2154 | find_partition_scheme(PlannerInfo *root, Relation relation) |
| 2155 | { |
| 2156 | PartitionKey partkey = RelationGetPartitionKey(relation); |
| 2157 | ListCell *lc; |
| 2158 | int partnatts, |
| 2159 | i; |
| 2160 | PartitionScheme part_scheme; |
| 2161 | |
| 2162 | /* A partitioned table should have a partition key. */ |
| 2163 | Assert(partkey != NULL); |
| 2164 | |
| 2165 | partnatts = partkey->partnatts; |
| 2166 | |
| 2167 | /* Search for a matching partition scheme and return if found one. */ |
| 2168 | foreach(lc, root->part_schemes) |
| 2169 | { |
| 2170 | part_scheme = lfirst(lc); |
| 2171 | |
| 2172 | /* Match partitioning strategy and number of keys. */ |
| 2173 | if (partkey->strategy != part_scheme->strategy || |
| 2174 | partnatts != part_scheme->partnatts) |
| 2175 | continue; |
| 2176 | |
| 2177 | /* Match partition key type properties. */ |
| 2178 | if (memcmp(partkey->partopfamily, part_scheme->partopfamily, |
| 2179 | sizeof(Oid) * partnatts) != 0 || |
| 2180 | memcmp(partkey->partopcintype, part_scheme->partopcintype, |
| 2181 | sizeof(Oid) * partnatts) != 0 || |
| 2182 | memcmp(partkey->partcollation, part_scheme->partcollation, |
| 2183 | sizeof(Oid) * partnatts) != 0) |
| 2184 | continue; |
| 2185 | |
| 2186 | /* |
| 2187 | * Length and byval information should match when partopcintype |
| 2188 | * matches. |
| 2189 | */ |
| 2190 | Assert(memcmp(partkey->parttyplen, part_scheme->parttyplen, |
| 2191 | sizeof(int16) * partnatts) == 0); |
| 2192 | Assert(memcmp(partkey->parttypbyval, part_scheme->parttypbyval, |
| 2193 | sizeof(bool) * partnatts) == 0); |
| 2194 | |
| 2195 | /* |
| 2196 | * If partopfamily and partopcintype matched, must have the same |
| 2197 | * partition comparison functions. Note that we cannot reliably |
| 2198 | * Assert the equality of function structs themselves for they might |
| 2199 | * be different across PartitionKey's, so just Assert for the function |
| 2200 | * OIDs. |
| 2201 | */ |
| 2202 | #ifdef USE_ASSERT_CHECKING |
| 2203 | for (i = 0; i < partkey->partnatts; i++) |
| 2204 | Assert(partkey->partsupfunc[i].fn_oid == |
| 2205 | part_scheme->partsupfunc[i].fn_oid); |
| 2206 | #endif |
| 2207 | |
| 2208 | /* Found matching partition scheme. */ |
| 2209 | return part_scheme; |
| 2210 | } |
| 2211 | |
| 2212 | /* |
| 2213 | * Did not find matching partition scheme. Create one copying relevant |
| 2214 | * information from the relcache. We need to copy the contents of the |
| 2215 | * array since the relcache entry may not survive after we have closed the |
| 2216 | * relation. |
| 2217 | */ |
| 2218 | part_scheme = (PartitionScheme) palloc0(sizeof(PartitionSchemeData)); |
| 2219 | part_scheme->strategy = partkey->strategy; |
| 2220 | part_scheme->partnatts = partkey->partnatts; |
| 2221 | |
| 2222 | part_scheme->partopfamily = (Oid *) palloc(sizeof(Oid) * partnatts); |
| 2223 | memcpy(part_scheme->partopfamily, partkey->partopfamily, |
| 2224 | sizeof(Oid) * partnatts); |
| 2225 | |
| 2226 | part_scheme->partopcintype = (Oid *) palloc(sizeof(Oid) * partnatts); |
| 2227 | memcpy(part_scheme->partopcintype, partkey->partopcintype, |
| 2228 | sizeof(Oid) * partnatts); |
| 2229 | |
| 2230 | part_scheme->partcollation = (Oid *) palloc(sizeof(Oid) * partnatts); |
| 2231 | memcpy(part_scheme->partcollation, partkey->partcollation, |
| 2232 | sizeof(Oid) * partnatts); |
| 2233 | |
| 2234 | part_scheme->parttyplen = (int16 *) palloc(sizeof(int16) * partnatts); |
| 2235 | memcpy(part_scheme->parttyplen, partkey->parttyplen, |
| 2236 | sizeof(int16) * partnatts); |
| 2237 | |
| 2238 | part_scheme->parttypbyval = (bool *) palloc(sizeof(bool) * partnatts); |
| 2239 | memcpy(part_scheme->parttypbyval, partkey->parttypbyval, |
| 2240 | sizeof(bool) * partnatts); |
| 2241 | |
| 2242 | part_scheme->partsupfunc = (FmgrInfo *) |
| 2243 | palloc(sizeof(FmgrInfo) * partnatts); |
| 2244 | for (i = 0; i < partnatts; i++) |
| 2245 | fmgr_info_copy(&part_scheme->partsupfunc[i], &partkey->partsupfunc[i], |
| 2246 | CurrentMemoryContext); |
| 2247 | |
| 2248 | /* Add the partitioning scheme to PlannerInfo. */ |
| 2249 | root->part_schemes = lappend(root->part_schemes, part_scheme); |
| 2250 | |
| 2251 | return part_scheme; |
| 2252 | } |
| 2253 | |
| 2254 | /* |
| 2255 | * set_baserel_partition_key_exprs |
| 2256 | * |
| 2257 | * Builds partition key expressions for the given base relation and sets them |
| 2258 | * in given RelOptInfo. Any single column partition keys are converted to Var |
| 2259 | * nodes. All Var nodes are restamped with the relid of given relation. |
| 2260 | */ |
| 2261 | static void |
| 2262 | set_baserel_partition_key_exprs(Relation relation, |
| 2263 | RelOptInfo *rel) |
| 2264 | { |
| 2265 | PartitionKey partkey = RelationGetPartitionKey(relation); |
| 2266 | int partnatts; |
| 2267 | int cnt; |
| 2268 | List **partexprs; |
| 2269 | ListCell *lc; |
| 2270 | Index varno = rel->relid; |
| 2271 | |
| 2272 | Assert(IS_SIMPLE_REL(rel) && rel->relid > 0); |
| 2273 | |
| 2274 | /* A partitioned table should have a partition key. */ |
| 2275 | Assert(partkey != NULL); |
| 2276 | |
| 2277 | partnatts = partkey->partnatts; |
| 2278 | partexprs = (List **) palloc(sizeof(List *) * partnatts); |
| 2279 | lc = list_head(partkey->partexprs); |
| 2280 | |
| 2281 | for (cnt = 0; cnt < partnatts; cnt++) |
| 2282 | { |
| 2283 | Expr *partexpr; |
| 2284 | AttrNumber attno = partkey->partattrs[cnt]; |
| 2285 | |
| 2286 | if (attno != InvalidAttrNumber) |
| 2287 | { |
| 2288 | /* Single column partition key is stored as a Var node. */ |
| 2289 | Assert(attno > 0); |
| 2290 | |
| 2291 | partexpr = (Expr *) makeVar(varno, attno, |
| 2292 | partkey->parttypid[cnt], |
| 2293 | partkey->parttypmod[cnt], |
| 2294 | partkey->parttypcoll[cnt], 0); |
| 2295 | } |
| 2296 | else |
| 2297 | { |
| 2298 | if (lc == NULL) |
| 2299 | elog(ERROR, "wrong number of partition key expressions" ); |
| 2300 | |
| 2301 | /* Re-stamp the expression with given varno. */ |
| 2302 | partexpr = (Expr *) copyObject(lfirst(lc)); |
| 2303 | ChangeVarNodes((Node *) partexpr, 1, varno, 0); |
| 2304 | lc = lnext(lc); |
| 2305 | } |
| 2306 | |
| 2307 | partexprs[cnt] = list_make1(partexpr); |
| 2308 | } |
| 2309 | |
| 2310 | rel->partexprs = partexprs; |
| 2311 | |
| 2312 | /* |
| 2313 | * A base relation can not have nullable partition key expressions. We |
| 2314 | * still allocate array of empty expressions lists to keep partition key |
| 2315 | * expression handling code simple. See build_joinrel_partition_info() and |
| 2316 | * match_expr_to_partition_keys(). |
| 2317 | */ |
| 2318 | rel->nullable_partexprs = (List **) palloc0(sizeof(List *) * partnatts); |
| 2319 | } |
| 2320 | |