/* * Executes default values for columns for which we can't map to remote * relation columns. * * This allows us to support tables which have more columns on the downstream * than on the upstream. */ static void slot_fill_defaults(LogicalRepRelMapEntry *rel, EState *estate, TupleTableSlot *slot) { TupleDesc desc = RelationGetDescr(rel->localrel); int num_phys_attrs = desc->natts; int i; int attnum, num_defaults = 0; int *defmap; ExprState **defexprs; ExprContext *econtext; econtext = GetPerTupleExprContext(estate); /* We got all the data via replication, no need to evaluate anything. */ if (num_phys_attrs == rel->remoterel.natts) return; defmap = (int *) palloc(num_phys_attrs * sizeof(int)); defexprs = (ExprState **) palloc(num_phys_attrs * sizeof(ExprState *)); for (attnum = 0; attnum < num_phys_attrs; attnum++) { Expr *defexpr; if (TupleDescAttr(desc, attnum)->attisdropped) continue; if (rel->attrmap[attnum] >= 0) continue; defexpr = (Expr *) build_column_default(rel->localrel, attnum + 1); if (defexpr != NULL) { /* Run the expression through planner */ defexpr = expression_planner(defexpr); /* Initialize executable expression in copycontext */ defexprs[num_defaults] = ExecInitExpr(defexpr, NULL); defmap[num_defaults] = attnum; num_defaults++; } } for (i = 0; i < num_defaults; i++) slot->tts_values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, &slot->tts_isnull[defmap[i]]); }
/* * Copied from src/backend/commands/indexcmds.c, not exported. * CheckMutability * Test whether given expression is mutable */ bool CheckMutability(Expr *expr) { /* * First run the expression through the planner. This has a couple of * important consequences. First, function default arguments will get * inserted, which may affect volatility (consider "default now()"). * Second, inline-able functions will get inlined, which may allow us to * conclude that the function is really less volatile than it's marked. As * an example, polymorphic functions must be marked with the most volatile * behavior that they have for any input type, but once we inline the * function we may be able to conclude that it's not so volatile for the * particular input type we're dealing with. * * We assume here that expression_planner() won't scribble on its input. */ expr = expression_planner(expr); /* Now we can search for non-immutable functions */ return contain_mutable_functions((Node *) expr); }
/* * GetStreamScanPlan */ ForeignScan * GetStreamScanPlan(PlannerInfo *root, RelOptInfo *baserel, Oid relid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan) { StreamFdwInfo *sinfo = (StreamFdwInfo *) baserel->fdw_private; List *physical_tlist = build_physical_tlist(root, baserel); RangeTblEntry *rte = NULL; int i; TableSampleClause *sample; Value *sample_cutoff = NULL; /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */ scan_clauses = extract_actual_clauses(scan_clauses, false); for (i = 1; i <= root->simple_rel_array_size; i++) { rte = root->simple_rte_array[i]; if (rte && rte->relid == relid) break; } if (!rte || rte->relid != relid) elog(ERROR, "stream RTE missing"); sample = rte->tablesample; if (sample) { double dcutoff; Datum d; ExprContext *econtext; bool isnull; Node *node; Expr *expr; ExprState *estate; ParseState *ps = make_parsestate(NULL); float4 percent; if (sample->tsmhandler != BERNOULLI_OID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("tablesample method %s is not supported by streams", get_func_name(sample->tsmhandler)), errhint("Only bernoulli tablesample method can be used with streams."))); if (sample->repeatable) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("streams don't support the REPEATABLE clause for tablesample"))); econtext = CreateStandaloneExprContext(); ps = make_parsestate(NULL); node = (Node *) linitial(sample->args); node = transformExpr(ps, node, EXPR_KIND_OTHER); expr = expression_planner((Expr *) node); estate = ExecInitExpr(expr, NULL); d = ExecEvalExpr(estate, econtext, &isnull, NULL); free_parsestate(ps); FreeExprContext(econtext, false); percent = DatumGetFloat4(d); if (percent < 0 || percent > 100 || isnan(percent)) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLESAMPLE_ARGUMENT), errmsg("sample percentage must be between 0 and 100"))); dcutoff = rint(((double) RAND_MAX + 1) * percent / 100); sample_cutoff = makeInteger((int) dcutoff); } return make_foreignscan(tlist, scan_clauses, baserel->relid, NIL, list_make3(sinfo->colnames, physical_tlist, sample_cutoff), NIL, NIL, outer_plan); }