/* * transformTargetEntry() * Transform any ordinary "expression-type" node into a targetlist entry. * This is exported so that parse_clause.c can generate targetlist entries * for ORDER/GROUP BY items that are not already in the targetlist. * * node the (untransformed) parse tree for the value expression. * expr the transformed expression, or NULL if caller didn't do it yet. * colname the column name to be assigned, or NULL if none yet set. * resjunk true if the target should be marked resjunk, ie, it is not * wanted in the final projected tuple. */ TargetEntry * transformTargetEntry(ParseState *pstate, Node *node, Node *expr, char *colname, bool resjunk) { /* Transform the node if caller didn't do it already */ if (expr == NULL) expr = transformExpr(pstate, node); if (colname == NULL && !resjunk) { /* * Generate a suitable column name for a column without any explicit * 'AS ColumnName' clause. */ colname = FigureColname(node); } return makeTargetEntry((Expr *) expr, (AttrNumber) pstate->p_next_resno++, colname, resjunk); }
/* * xfrm_agg_call - * Finish initial transformation of an aggregate call * * parse_func.c has recognized the function as an aggregate, and has set up * all the fields of the agg_ref_xp except args, aggorder, aggdistinct and * agglevelsup. The passed-in args list has been through standard expression * transformation, while the passed-in aggorder list hasn't been transformed * at all. * * Here we convert the args list into a targetlist by inserting tgt_entry_xp * nodes, and then transform the aggorder and agg_distinct specifications to * produce lists of SortGroupClause nodes. (That might also result in adding * resjunk expressions to the targetlist.) * * We must also determine which query level the aggregate actually belongs to, * set agglevelsup accordingly, and mark p_hasAggs true in the corresponding * pstate level. */ void xfrm_agg_call( parse_state_s* pstate, agg_ref_xp * agg, struct list *args, struct list *aggorder, bool agg_distinct) { struct list *tlist; struct list *torder; struct list *tdistinct = NIL; attr_nr_t attno; int save_next_resno; int min_varlevel; struct list_cell *lc; /* * Transform the plain list of Exprs into a targetlist. We don't bother * to assign column names to the entries. */ tlist = NIL; attno = 1; foreach(lc, args) { expr_n *arg = (expr_n *) lfirst(lc); tgt_entry_xp *tle = makeTargetEntry(arg, attno++, NULL, false); tlist = lappend(tlist, tle); }
/* * transformAggregateCall - * Finish initial transformation of an aggregate call * * parse_func.c has recognized the function as an aggregate, and has set up * all the fields of the Aggref except args, aggorder, aggdistinct and * agglevelsup. The passed-in args list has been through standard expression * transformation, while the passed-in aggorder list hasn't been transformed * at all. * * Here we convert the args list into a targetlist by inserting TargetEntry * nodes, and then transform the aggorder and agg_distinct specifications to * produce lists of SortGroupClause nodes. (That might also result in adding * resjunk expressions to the targetlist.) * * We must also determine which query level the aggregate actually belongs to, * set agglevelsup accordingly, and mark p_hasAggs true in the corresponding * pstate level. */ void transformAggregateCall(ParseState *pstate, Aggref *agg, List *args, List *aggorder, bool agg_distinct) { List *tlist; List *torder; List *tdistinct = NIL; AttrNumber attno; int save_next_resno; int min_varlevel; ListCell *lc; #ifdef PGXC HeapTuple aggTuple; Form_pg_aggregate aggform; #endif /* PGXC */ /* * Transform the plain list of Exprs into a targetlist. We don't bother * to assign column names to the entries. */ tlist = NIL; attno = 1; foreach(lc, args) { Expr *arg = (Expr *) lfirst(lc); TargetEntry *tle = makeTargetEntry(arg, attno++, NULL, false); tlist = lappend(tlist, tle); }
/* Copied from src/backend/optimizer/util/plancat.c, not exported. * * Build a targetlist representing the columns of the specified index. * Each column is represented by a Var for the corresponding base-relation * column, or an expression in base-relation Vars, as appropriate. * * There are never any dropped columns in indexes, so unlike * build_physical_tlist, we need no failure case. */ List * build_index_tlist(PlannerInfo *root, IndexOptInfo *index, Relation heapRelation) { List *tlist = NIL; Index varno = index->rel->relid; ListCell *indexpr_item; int i; indexpr_item = list_head(index->indexprs); for (i = 0; i < index->ncolumns; i++) { int indexkey = index->indexkeys[i]; Expr *indexvar; if (indexkey != 0) { /* simple column */ Form_pg_attribute att_tup; if (indexkey < 0) att_tup = SystemAttributeDefinition(indexkey, heapRelation->rd_rel->relhasoids); else #if PG_VERSION_NUM >= 110000 att_tup = TupleDescAttr(heapRelation->rd_att, indexkey - 1); #else att_tup = heapRelation->rd_att->attrs[indexkey - 1]; #endif indexvar = (Expr *) makeVar(varno, indexkey, att_tup->atttypid, att_tup->atttypmod, att_tup->attcollation, 0); } else { /* expression column */ if (indexpr_item == NULL) elog(ERROR, "wrong number of index expressions"); indexvar = (Expr *) lfirst(indexpr_item); indexpr_item = lnext(indexpr_item); } tlist = lappend(tlist, makeTargetEntry(indexvar, i + 1, NULL, false)); } if (indexpr_item != NULL) elog(ERROR, "wrong number of index expressions"); return tlist; }
void addDummyAttr (Query *query) { TargetEntry *te; Const *dummyConst; dummyConst = (Const *) makeBoolConst(false,false); te = makeTargetEntry((Expr *) dummyConst, list_length(query->targetList) + 1, "dummy1", false); query->targetList = lappend(query->targetList, te); }
/* * transformAggregateCall - * Finish initial transformation of an aggregate call * * parse_func.c has recognized the function as an aggregate, and has set up * all the fields of the Aggref except aggdirectargs, args, aggorder, * aggdistinct and agglevelsup. The passed-in args list has been through * standard expression transformation and type coercion to match the agg's * declared arg types, while the passed-in aggorder list hasn't been * transformed at all. * * Here we separate the args list into direct and aggregated args, storing the * former in agg->aggdirectargs and the latter in agg->args. The regular * args, but not the direct args, are converted into a targetlist by inserting * TargetEntry nodes. We then transform the aggorder and agg_distinct * specifications to produce lists of SortGroupClause nodes for agg->aggorder * and agg->aggdistinct. (For a regular aggregate, this might result in * adding resjunk expressions to the targetlist; but for ordered-set * aggregates the aggorder list will always be one-to-one with the aggregated * args.) * * We must also determine which query level the aggregate actually belongs to, * set agglevelsup accordingly, and mark p_hasAggs true in the corresponding * pstate level. */ void transformAggregateCall(ParseState *pstate, Aggref *agg, List *args, List *aggorder, bool agg_distinct) { List *tlist = NIL; List *torder = NIL; List *tdistinct = NIL; AttrNumber attno = 1; int save_next_resno; int min_varlevel; ListCell *lc; const char *err; bool errkind; if (AGGKIND_IS_ORDERED_SET(agg->aggkind)) { /* * For an ordered-set agg, the args list includes direct args and * aggregated args; we must split them apart. */ int numDirectArgs = list_length(args) - list_length(aggorder); List *aargs; ListCell *lc2; Assert(numDirectArgs >= 0); aargs = list_copy_tail(args, numDirectArgs); agg->aggdirectargs = list_truncate(args, numDirectArgs); /* * Build a tlist from the aggregated args, and make a sortlist entry * for each one. Note that the expressions in the SortBy nodes are * ignored (they are the raw versions of the transformed args); we are * just looking at the sort information in the SortBy nodes. */ forboth(lc, aargs, lc2, aggorder) { Expr *arg = (Expr *) lfirst(lc); SortBy *sortby = (SortBy *) lfirst(lc2); TargetEntry *tle; /* We don't bother to assign column names to the entries */ tle = makeTargetEntry(arg, attno++, NULL, false); tlist = lappend(tlist, tle); torder = addTargetToSortList(pstate, tle, torder, tlist, sortby, true /* fix unknowns */ ); }
/* * xfrm_tgt_entry() * Transform any ordinary "expression-type" node into a targetlist entry. * This is exported so that parse_clause.c can generate targetlist entries * for ORDER/GROUP BY items that are not already in the targetlist. * * node the (untransformed) parse tree for the value expression. * expr the transformed expression, or NULL if caller didn't do it yet. * colname the column name to be assigned, or NULL if none yet set. * resjunk true if the target should be marked resjunk, ie, it is not * wanted in the final projected tuple. */ tgt_entry_xp* xfrm_tgt_entry( parse_state_s* pstate, node_n* node, node_n* expr, char* colname, bool resjunk) { /* Transform the node if caller didn't do it already */ if (expr == NULL) expr = xfrm_expr(pstate, node); if (colname == NULL && !resjunk) { /* * Generate a suitable column name for a column without any explicit * 'AS ColumnName' clause. */ colname = FigureColname(node); } return makeTargetEntry((expr_n*) expr, (attr_nr_t) pstate->p_next_resno++, colname, resjunk); }
/* * CreateCitusToplevelNode creates the top-level planTree node for a * distributed statement. That top-level node is a) recognizable by the * executor hooks, allowing them to redirect execution, b) contains the * parameters required for distributed execution. * * The exact representation of the top-level node is an implementation detail * which should not be referred to outside this file, as it's likely to become * version dependant. Use GetMultiPlan() and HasCitusToplevelNode() to access. * * Internally the data is stored as arguments to a 'citus_extradata_container' * function, which has to be removed from the really executed plan tree before * query execution. */ PlannedStmt * MultiQueryContainerNode(PlannedStmt *result, MultiPlan *multiPlan) { FunctionScan *fauxFunctionScan = NULL; RangeTblFunction *fauxFunction = NULL; FuncExpr *fauxFuncExpr = NULL; Const *multiPlanData = NULL; char *serializedPlan = NULL; /* pass multiPlan serialized as a constant function argument */ serializedPlan = CitusNodeToString(multiPlan); multiPlanData = makeNode(Const); multiPlanData->consttype = CSTRINGOID; multiPlanData->constlen = strlen(serializedPlan); multiPlanData->constvalue = CStringGetDatum(serializedPlan); multiPlanData->constbyval = false; multiPlanData->location = -1; fauxFuncExpr = makeNode(FuncExpr); fauxFuncExpr->funcid = CitusExtraDataContainerFuncId(); fauxFuncExpr->funcretset = true; fauxFuncExpr->location = -1; fauxFuncExpr->args = list_make1(multiPlanData); fauxFunction = makeNode(RangeTblFunction); fauxFunction->funcexpr = (Node *) fauxFuncExpr; fauxFunctionScan = makeNode(FunctionScan); fauxFunctionScan->functions = lappend(fauxFunctionScan->functions, fauxFunction); /* copy original targetlist, accessed for RETURNING queries */ fauxFunctionScan->scan.plan.targetlist = copyObject(result->planTree->targetlist); /* * Add set returning function to target list if the original (postgres * created) plan doesn't support backward scans; doing so prevents * backward scans being supported by the new plantree as well. This is * ugly as hell, but until we can rely on custom scans (which can signal * this via CUSTOMPATH_SUPPORT_BACKWARD_SCAN), there's not really a pretty * method to achieve this. * * FIXME: This should really be done on the master select plan. */ if (!ExecSupportsBackwardScan(result->planTree)) { FuncExpr *funcExpr = makeNode(FuncExpr); TargetEntry *targetEntry = NULL; bool resjunkAttribute = true; funcExpr->funcretset = true; targetEntry = makeTargetEntry((Expr *) funcExpr, InvalidAttrNumber, NULL, resjunkAttribute); fauxFunctionScan->scan.plan.targetlist = lappend(fauxFunctionScan->scan.plan.targetlist, targetEntry); } result->planTree = (Plan *) fauxFunctionScan; return result; }
/* * Generate targetlist for a set-operation plan node * * colTypes: column datatypes for non-junk columns * flag: -1 if no flag column needed, 0 or 1 to create a const flag column * hack_constants: true to copy up constants (see comments in code) * input_tlist: targetlist of this node's input node * refnames_tlist: targetlist to take column names from */ static List * generate_setop_tlist(List *colTypes, int flag, bool hack_constants, List *input_tlist, List *refnames_tlist) { List *tlist = NIL; int resno = 1; List *i; Resdom *resdom; Node *expr; foreach(i, colTypes) { Oid colType = lfirsto(i); TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist); TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist); int32 colTypmod; Assert(inputtle->resdom->resno == resno); Assert(reftle->resdom->resno == resno); Assert(!inputtle->resdom->resjunk); Assert(!reftle->resdom->resjunk); /* * Generate columns referencing input columns and having * appropriate data types and column names. Insert datatype * coercions where necessary. * * HACK: constants in the input's targetlist are copied up as-is * rather than being referenced as subquery outputs. This is * mainly to ensure that when we try to coerce them to the output * column's datatype, the right things happen for UNKNOWN * constants. But do this only at the first level of * subquery-scan plans; we don't want phony constants appearing in * the output tlists of upper-level nodes! */ if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const)) expr = (Node *) inputtle->expr; else expr = (Node *) makeVar(0, inputtle->resdom->resno, inputtle->resdom->restype, inputtle->resdom->restypmod, 0); if (inputtle->resdom->restype == colType) { /* no coercion needed, and believe the input typmod */ colTypmod = inputtle->resdom->restypmod; } else { expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */ expr, colType, "UNION/INTERSECT/EXCEPT"); colTypmod = -1; } resdom = makeResdom((AttrNumber) resno++, colType, colTypmod, pstrdup(reftle->resdom->resname), false); tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) expr)); input_tlist = lnext(input_tlist); refnames_tlist = lnext(refnames_tlist); }
/* * Generate targetlist for a set-operation plan node * * colTypes: column datatypes for non-junk columns * flag: -1 if no flag column needed, 0 or 1 to create a const flag column * varno: varno to use in generated Vars * hack_constants: true to copy up constants (see comments in code) * input_tlist: targetlist of this node's input node * refnames_tlist: targetlist to take column names from */ static List * generate_setop_tlist(List *colTypes, int flag, Index varno, bool hack_constants, List *input_tlist, List *refnames_tlist) { List *tlist = NIL; int resno = 1; ListCell *i, *j, *k; TargetEntry *tle; Node *expr; j = list_head(input_tlist); k = list_head(refnames_tlist); foreach(i, colTypes) { Oid colType = lfirst_oid(i); TargetEntry *inputtle = (TargetEntry *) lfirst(j); TargetEntry *reftle = (TargetEntry *) lfirst(k); Assert(inputtle->resno == resno); Assert(reftle->resno == resno); Assert(!inputtle->resjunk); Assert(!reftle->resjunk); /* * Generate columns referencing input columns and having appropriate * data types and column names. Insert datatype coercions where * necessary. * * HACK: constants in the input's targetlist are copied up as-is * rather than being referenced as subquery outputs. This is mainly * to ensure that when we try to coerce them to the output column's * datatype, the right things happen for UNKNOWN constants. But do * this only at the first level of subquery-scan plans; we don't want * phony constants appearing in the output tlists of upper-level * nodes! */ if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const)) expr = (Node *) inputtle->expr; else expr = (Node *) makeVar(varno, inputtle->resno, exprType((Node *) inputtle->expr), exprTypmod((Node *) inputtle->expr), 0); if (exprType(expr) != colType) { expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */ expr, colType, "UNION/INTERSECT/EXCEPT"); } tle = makeTargetEntry((Expr *) expr, (AttrNumber) resno++, pstrdup(reftle->resname), false); tlist = lappend(tlist, tle); j = lnext(j); k = lnext(k); }