* create_unique_path * Creates a path representing elimination of distinct rows from the * input data. Distinct-ness is defined according to the needs of the * semijoin represented by sjinfo. If it is not possible to identify * how to make the data unique, NULL is returned. * * If used at all, this is likely to be called repeatedly on the same rel; * and the input subpath should a
| 2332 | * for the rel). So we cache the result. |
| 2333 | */ |
| 2334 | UniquePath * |
| 2335 | create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, |
| 2336 | SpecialJoinInfo *sjinfo) |
| 2337 | { |
| 2338 | UniquePath *pathnode; |
| 2339 | Path sort_path; /* dummy for result of cost_sort */ |
| 2340 | Path agg_path; /* dummy for result of cost_agg */ |
| 2341 | MemoryContext oldcontext; |
| 2342 | int numCols; |
| 2343 | CdbPathLocus locus; |
| 2344 | bool add_motion = false; |
| 2345 | double numsegments; |
| 2346 | |
| 2347 | /* Caller made a mistake if subpath isn't cheapest_total ... */ |
| 2348 | Assert(subpath == rel->cheapest_total_path); |
| 2349 | Assert(subpath->parent == rel); |
| 2350 | /* ... or if SpecialJoinInfo is the wrong one */ |
| 2351 | Assert(sjinfo->jointype == JOIN_SEMI); |
| 2352 | Assert(bms_equal(rel->relids, sjinfo->syn_righthand)); |
| 2353 | |
| 2354 | /* If result already cached, return it */ |
| 2355 | if (rel->cheapest_unique_path) |
| 2356 | return (UniquePath *) rel->cheapest_unique_path; |
| 2357 | |
| 2358 | /* If it's not possible to unique-ify, return NULL */ |
| 2359 | if (!(sjinfo->semi_can_btree || sjinfo->semi_can_hash)) |
| 2360 | return NULL; |
| 2361 | |
| 2362 | /* |
| 2363 | * When called during GEQO join planning, we are in a short-lived memory |
| 2364 | * context. We must make sure that the path and any subsidiary data |
| 2365 | * structures created for a baserel survive the GEQO cycle, else the |
| 2366 | * baserel is trashed for future GEQO cycles. On the other hand, when we |
| 2367 | * are creating those for a joinrel during GEQO, we don't want them to |
| 2368 | * clutter the main planning context. Upshot is that the best solution is |
| 2369 | * to explicitly allocate memory in the same context the given RelOptInfo |
| 2370 | * is in. |
| 2371 | */ |
| 2372 | oldcontext = MemoryContextSwitchTo(GetMemoryChunkContext(rel)); |
| 2373 | |
| 2374 | /* Repartition first if duplicates might be on different QEs. */ |
| 2375 | if (!CdbPathLocus_IsBottleneck(subpath->locus) && |
| 2376 | !cdbpathlocus_is_hashed_on_exprs(subpath->locus, sjinfo->semi_rhs_exprs, false)) |
| 2377 | { |
| 2378 | int numsegments = CdbPathLocus_NumSegments(subpath->locus); |
| 2379 | |
| 2380 | List *opfamilies = NIL; |
| 2381 | List *sortrefs = NIL; |
| 2382 | ListCell *lc; |
| 2383 | |
| 2384 | foreach(lc, sjinfo->semi_rhs_exprs) |
| 2385 | { |
| 2386 | Node *expr = lfirst(lc); |
| 2387 | Oid opfamily; |
| 2388 | |
| 2389 | opfamily = cdb_default_distribution_opfamily_for_type(exprType(expr)); |
| 2390 | opfamilies = lappend_oid(opfamilies, opfamily); |
| 2391 | sortrefs = lappend_int(sortrefs, 0); |
no test coverage detected