コード例 #1
0
ファイル: parse_target.c プロジェクト: adunstan/pg-cvs-mirror
/*
 * 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);
}
コード例 #2
0
ファイル: parse_agg.c プロジェクト: colinet/sqlix
/*
 * 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);
	}
コード例 #3
0
ファイル: parse_agg.c プロジェクト: HunterChen/postgres-xc
/*
 * 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);
	}
コード例 #4
0
ファイル: hypopg_import.c プロジェクト: kmosolov/hypopg
/* 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;
}
コード例 #5
0
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);
}
コード例 #6
0
/*
 * 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 */ );
		}
コード例 #7
0
ファイル: parse_target.c プロジェクト: colinet/sqlix
/*
 * 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);
}
コード例 #8
0
ファイル: multi_planner.c プロジェクト: citusdata/citus
/*
 * 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;
}
コード例 #9
0
ファイル: prepunion.c プロジェクト: yangineer/cscd43-1
/*
 * 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);
    }
コード例 #10
0
/*
 * 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);
	}