diff options
Diffstat (limited to 'src/backend/nodes/makefuncs.c')
-rw-r--r-- | src/backend/nodes/makefuncs.c | 817 |
1 files changed, 817 insertions, 0 deletions
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c new file mode 100644 index 0000000..01c110c --- /dev/null +++ b/src/backend/nodes/makefuncs.c @@ -0,0 +1,817 @@ +/*------------------------------------------------------------------------- + * + * makefuncs.c + * creator functions for various nodes. The functions here are for the + * most frequently created nodes. + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/nodes/makefuncs.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "catalog/pg_class.h" +#include "catalog/pg_type.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" +#include "utils/lsyscache.h" + + +/* + * makeA_Expr - + * makes an A_Expr node + */ +A_Expr * +makeA_Expr(A_Expr_Kind kind, List *name, + Node *lexpr, Node *rexpr, int location) +{ + A_Expr *a = makeNode(A_Expr); + + a->kind = kind; + a->name = name; + a->lexpr = lexpr; + a->rexpr = rexpr; + a->location = location; + return a; +} + +/* + * makeSimpleA_Expr - + * As above, given a simple (unqualified) operator name + */ +A_Expr * +makeSimpleA_Expr(A_Expr_Kind kind, char *name, + Node *lexpr, Node *rexpr, int location) +{ + A_Expr *a = makeNode(A_Expr); + + a->kind = kind; + a->name = list_make1(makeString((char *) name)); + a->lexpr = lexpr; + a->rexpr = rexpr; + a->location = location; + return a; +} + +/* + * makeVar - + * creates a Var node + */ +Var * +makeVar(Index varno, + AttrNumber varattno, + Oid vartype, + int32 vartypmod, + Oid varcollid, + Index varlevelsup) +{ + Var *var = makeNode(Var); + + var->varno = varno; + var->varattno = varattno; + var->vartype = vartype; + var->vartypmod = vartypmod; + var->varcollid = varcollid; + var->varlevelsup = varlevelsup; + + /* + * Only a few callers need to make Var nodes with varnosyn/varattnosyn + * different from varno/varattno. We don't provide separate arguments for + * them, but just initialize them to the given varno/varattno. This + * reduces code clutter and chance of error for most callers. + */ + var->varnosyn = varno; + var->varattnosyn = varattno; + + /* Likewise, we just set location to "unknown" here */ + var->location = -1; + + return var; +} + +/* + * makeVarFromTargetEntry - + * convenience function to create a same-level Var node from a + * TargetEntry + */ +Var * +makeVarFromTargetEntry(Index varno, + TargetEntry *tle) +{ + return makeVar(varno, + tle->resno, + exprType((Node *) tle->expr), + exprTypmod((Node *) tle->expr), + exprCollation((Node *) tle->expr), + 0); +} + +/* + * makeWholeRowVar - + * creates a Var node representing a whole row of the specified RTE + * + * A whole-row reference is a Var with varno set to the correct range + * table entry, and varattno == 0 to signal that it references the whole + * tuple. (Use of zero here is unclean, since it could easily be confused + * with error cases, but it's not worth changing now.) The vartype indicates + * a rowtype; either a named composite type, or a domain over a named + * composite type (only possible if the RTE is a function returning that), + * or RECORD. This function encapsulates the logic for determining the + * correct rowtype OID to use. + * + * If allowScalar is true, then for the case where the RTE is a single function + * returning a non-composite result type, we produce a normal Var referencing + * the function's result directly, instead of the single-column composite + * value that the whole-row notation might otherwise suggest. + */ +Var * +makeWholeRowVar(RangeTblEntry *rte, + Index varno, + Index varlevelsup, + bool allowScalar) +{ + Var *result; + Oid toid; + Node *fexpr; + + switch (rte->rtekind) + { + case RTE_RELATION: + /* relation: the rowtype is a named composite type */ + toid = get_rel_type_id(rte->relid); + if (!OidIsValid(toid)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("relation \"%s\" does not have a composite type", + get_rel_name(rte->relid)))); + result = makeVar(varno, + InvalidAttrNumber, + toid, + -1, + InvalidOid, + varlevelsup); + break; + + case RTE_FUNCTION: + + /* + * If there's more than one function, or ordinality is requested, + * force a RECORD result, since there's certainly more than one + * column involved and it can't be a known named type. + */ + if (rte->funcordinality || list_length(rte->functions) != 1) + { + /* always produces an anonymous RECORD result */ + result = makeVar(varno, + InvalidAttrNumber, + RECORDOID, + -1, + InvalidOid, + varlevelsup); + break; + } + + fexpr = ((RangeTblFunction *) linitial(rte->functions))->funcexpr; + toid = exprType(fexpr); + if (type_is_rowtype(toid)) + { + /* func returns composite; same as relation case */ + result = makeVar(varno, + InvalidAttrNumber, + toid, + -1, + InvalidOid, + varlevelsup); + } + else if (allowScalar) + { + /* func returns scalar; just return its output as-is */ + result = makeVar(varno, + 1, + toid, + -1, + exprCollation(fexpr), + varlevelsup); + } + else + { + /* func returns scalar, but we want a composite result */ + result = makeVar(varno, + InvalidAttrNumber, + RECORDOID, + -1, + InvalidOid, + varlevelsup); + } + break; + + default: + + /* + * RTE is a join, subselect, tablefunc, or VALUES. We represent + * this as a whole-row Var of RECORD type. (Note that in most + * cases the Var will be expanded to a RowExpr during planning, + * but that is not our concern here.) + */ + result = makeVar(varno, + InvalidAttrNumber, + RECORDOID, + -1, + InvalidOid, + varlevelsup); + break; + } + + return result; +} + +/* + * makeTargetEntry - + * creates a TargetEntry node + */ +TargetEntry * +makeTargetEntry(Expr *expr, + AttrNumber resno, + char *resname, + bool resjunk) +{ + TargetEntry *tle = makeNode(TargetEntry); + + tle->expr = expr; + tle->resno = resno; + tle->resname = resname; + + /* + * We always set these fields to 0. If the caller wants to change them he + * must do so explicitly. Few callers do that, so omitting these + * arguments reduces the chance of error. + */ + tle->ressortgroupref = 0; + tle->resorigtbl = InvalidOid; + tle->resorigcol = 0; + + tle->resjunk = resjunk; + + return tle; +} + +/* + * flatCopyTargetEntry - + * duplicate a TargetEntry, but don't copy substructure + * + * This is commonly used when we just want to modify the resno or substitute + * a new expression. + */ +TargetEntry * +flatCopyTargetEntry(TargetEntry *src_tle) +{ + TargetEntry *tle = makeNode(TargetEntry); + + Assert(IsA(src_tle, TargetEntry)); + memcpy(tle, src_tle, sizeof(TargetEntry)); + return tle; +} + +/* + * makeFromExpr - + * creates a FromExpr node + */ +FromExpr * +makeFromExpr(List *fromlist, Node *quals) +{ + FromExpr *f = makeNode(FromExpr); + + f->fromlist = fromlist; + f->quals = quals; + return f; +} + +/* + * makeConst - + * creates a Const node + */ +Const * +makeConst(Oid consttype, + int32 consttypmod, + Oid constcollid, + int constlen, + Datum constvalue, + bool constisnull, + bool constbyval) +{ + Const *cnst = makeNode(Const); + + /* + * If it's a varlena value, force it to be in non-expanded (non-toasted) + * format; this avoids any possible dependency on external values and + * improves consistency of representation, which is important for equal(). + */ + if (!constisnull && constlen == -1) + constvalue = PointerGetDatum(PG_DETOAST_DATUM(constvalue)); + + cnst->consttype = consttype; + cnst->consttypmod = consttypmod; + cnst->constcollid = constcollid; + cnst->constlen = constlen; + cnst->constvalue = constvalue; + cnst->constisnull = constisnull; + cnst->constbyval = constbyval; + cnst->location = -1; /* "unknown" */ + + return cnst; +} + +/* + * makeNullConst - + * creates a Const node representing a NULL of the specified type/typmod + * + * This is a convenience routine that just saves a lookup of the type's + * storage properties. + */ +Const * +makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid) +{ + int16 typLen; + bool typByVal; + + get_typlenbyval(consttype, &typLen, &typByVal); + return makeConst(consttype, + consttypmod, + constcollid, + (int) typLen, + (Datum) 0, + true, + typByVal); +} + +/* + * makeBoolConst - + * creates a Const node representing a boolean value (can be NULL too) + */ +Node * +makeBoolConst(bool value, bool isnull) +{ + /* note that pg_type.h hardwires size of bool as 1 ... duplicate it */ + return (Node *) makeConst(BOOLOID, -1, InvalidOid, 1, + BoolGetDatum(value), isnull, true); +} + +/* + * makeBoolExpr - + * creates a BoolExpr node + */ +Expr * +makeBoolExpr(BoolExprType boolop, List *args, int location) +{ + BoolExpr *b = makeNode(BoolExpr); + + b->boolop = boolop; + b->args = args; + b->location = location; + + return (Expr *) b; +} + +/* + * makeAlias - + * creates an Alias node + * + * NOTE: the given name is copied, but the colnames list (if any) isn't. + */ +Alias * +makeAlias(const char *aliasname, List *colnames) +{ + Alias *a = makeNode(Alias); + + a->aliasname = pstrdup(aliasname); + a->colnames = colnames; + + return a; +} + +/* + * makeRelabelType - + * creates a RelabelType node + */ +RelabelType * +makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, + CoercionForm rformat) +{ + RelabelType *r = makeNode(RelabelType); + + r->arg = arg; + r->resulttype = rtype; + r->resulttypmod = rtypmod; + r->resultcollid = rcollid; + r->relabelformat = rformat; + r->location = -1; + + return r; +} + +/* + * makeRangeVar - + * creates a RangeVar node (rather oversimplified case) + */ +RangeVar * +makeRangeVar(char *schemaname, char *relname, int location) +{ + RangeVar *r = makeNode(RangeVar); + + r->catalogname = NULL; + r->schemaname = schemaname; + r->relname = relname; + r->inh = true; + r->relpersistence = RELPERSISTENCE_PERMANENT; + r->alias = NULL; + r->location = location; + + return r; +} + +/* + * makeTypeName - + * build a TypeName node for an unqualified name. + * + * typmod is defaulted, but can be changed later by caller. + */ +TypeName * +makeTypeName(char *typnam) +{ + return makeTypeNameFromNameList(list_make1(makeString(typnam))); +} + +/* + * makeTypeNameFromNameList - + * build a TypeName node for a String list representing a qualified name. + * + * typmod is defaulted, but can be changed later by caller. + */ +TypeName * +makeTypeNameFromNameList(List *names) +{ + TypeName *n = makeNode(TypeName); + + n->names = names; + n->typmods = NIL; + n->typemod = -1; + n->location = -1; + return n; +} + +/* + * makeTypeNameFromOid - + * build a TypeName node to represent a type already known by OID/typmod. + */ +TypeName * +makeTypeNameFromOid(Oid typeOid, int32 typmod) +{ + TypeName *n = makeNode(TypeName); + + n->typeOid = typeOid; + n->typemod = typmod; + n->location = -1; + return n; +} + +/* + * makeColumnDef - + * build a ColumnDef node to represent a simple column definition. + * + * Type and collation are specified by OID. + * Other properties are all basic to start with. + */ +ColumnDef * +makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid) +{ + ColumnDef *n = makeNode(ColumnDef); + + n->colname = pstrdup(colname); + n->typeName = makeTypeNameFromOid(typeOid, typmod); + n->inhcount = 0; + n->is_local = true; + n->is_not_null = false; + n->is_from_type = false; + n->storage = 0; + n->raw_default = NULL; + n->cooked_default = NULL; + n->collClause = NULL; + n->collOid = collOid; + n->constraints = NIL; + n->fdwoptions = NIL; + n->location = -1; + + return n; +} + +/* + * makeFuncExpr - + * build an expression tree representing a function call. + * + * The argument expressions must have been transformed already. + */ +FuncExpr * +makeFuncExpr(Oid funcid, Oid rettype, List *args, + Oid funccollid, Oid inputcollid, CoercionForm fformat) +{ + FuncExpr *funcexpr; + + funcexpr = makeNode(FuncExpr); + funcexpr->funcid = funcid; + funcexpr->funcresulttype = rettype; + funcexpr->funcretset = false; /* only allowed case here */ + funcexpr->funcvariadic = false; /* only allowed case here */ + funcexpr->funcformat = fformat; + funcexpr->funccollid = funccollid; + funcexpr->inputcollid = inputcollid; + funcexpr->args = args; + funcexpr->location = -1; + + return funcexpr; +} + +/* + * makeDefElem - + * build a DefElem node + * + * This is sufficient for the "typical" case with an unqualified option name + * and no special action. + */ +DefElem * +makeDefElem(char *name, Node *arg, int location) +{ + DefElem *res = makeNode(DefElem); + + res->defnamespace = NULL; + res->defname = name; + res->arg = arg; + res->defaction = DEFELEM_UNSPEC; + res->location = location; + + return res; +} + +/* + * makeDefElemExtended - + * build a DefElem node with all fields available to be specified + */ +DefElem * +makeDefElemExtended(char *nameSpace, char *name, Node *arg, + DefElemAction defaction, int location) +{ + DefElem *res = makeNode(DefElem); + + res->defnamespace = nameSpace; + res->defname = name; + res->arg = arg; + res->defaction = defaction; + res->location = location; + + return res; +} + +/* + * makeFuncCall - + * + * Initialize a FuncCall struct with the information every caller must + * supply. Any non-default parameters have to be inserted by the caller. + */ +FuncCall * +makeFuncCall(List *name, List *args, CoercionForm funcformat, int location) +{ + FuncCall *n = makeNode(FuncCall); + + n->funcname = name; + n->args = args; + n->agg_order = NIL; + n->agg_filter = NULL; + n->over = NULL; + n->agg_within_group = false; + n->agg_star = false; + n->agg_distinct = false; + n->func_variadic = false; + n->funcformat = funcformat; + n->location = location; + return n; +} + +/* + * make_opclause + * Creates an operator clause given its operator info, left operand + * and right operand (pass NULL to create single-operand clause), + * and collation info. + */ +Expr * +make_opclause(Oid opno, Oid opresulttype, bool opretset, + Expr *leftop, Expr *rightop, + Oid opcollid, Oid inputcollid) +{ + OpExpr *expr = makeNode(OpExpr); + + expr->opno = opno; + expr->opfuncid = InvalidOid; + expr->opresulttype = opresulttype; + expr->opretset = opretset; + expr->opcollid = opcollid; + expr->inputcollid = inputcollid; + if (rightop) + expr->args = list_make2(leftop, rightop); + else + expr->args = list_make1(leftop); + expr->location = -1; + return (Expr *) expr; +} + +/* + * make_andclause + * + * Creates an 'and' clause given a list of its subclauses. + */ +Expr * +make_andclause(List *andclauses) +{ + BoolExpr *expr = makeNode(BoolExpr); + + expr->boolop = AND_EXPR; + expr->args = andclauses; + expr->location = -1; + return (Expr *) expr; +} + +/* + * make_orclause + * + * Creates an 'or' clause given a list of its subclauses. + */ +Expr * +make_orclause(List *orclauses) +{ + BoolExpr *expr = makeNode(BoolExpr); + + expr->boolop = OR_EXPR; + expr->args = orclauses; + expr->location = -1; + return (Expr *) expr; +} + +/* + * make_notclause + * + * Create a 'not' clause given the expression to be negated. + */ +Expr * +make_notclause(Expr *notclause) +{ + BoolExpr *expr = makeNode(BoolExpr); + + expr->boolop = NOT_EXPR; + expr->args = list_make1(notclause); + expr->location = -1; + return (Expr *) expr; +} + +/* + * make_and_qual + * + * Variant of make_andclause for ANDing two qual conditions together. + * Qual conditions have the property that a NULL nodetree is interpreted + * as 'true'. + * + * NB: this makes no attempt to preserve AND/OR flatness; so it should not + * be used on a qual that has already been run through prepqual.c. + */ +Node * +make_and_qual(Node *qual1, Node *qual2) +{ + if (qual1 == NULL) + return qual2; + if (qual2 == NULL) + return qual1; + return (Node *) make_andclause(list_make2(qual1, qual2)); +} + +/* + * The planner and executor usually represent qualification expressions + * as lists of boolean expressions with implicit AND semantics. + * + * These functions convert between an AND-semantics expression list and the + * ordinary representation of a boolean expression. + * + * Note that an empty list is considered equivalent to TRUE. + */ +Expr * +make_ands_explicit(List *andclauses) +{ + if (andclauses == NIL) + return (Expr *) makeBoolConst(true, false); + else if (list_length(andclauses) == 1) + return (Expr *) linitial(andclauses); + else + return make_andclause(andclauses); +} + +List * +make_ands_implicit(Expr *clause) +{ + /* + * NB: because the parser sets the qual field to NULL in a query that has + * no WHERE clause, we must consider a NULL input clause as TRUE, even + * though one might more reasonably think it FALSE. + */ + if (clause == NULL) + return NIL; /* NULL -> NIL list == TRUE */ + else if (is_andclause(clause)) + return ((BoolExpr *) clause)->args; + else if (IsA(clause, Const) && + !((Const *) clause)->constisnull && + DatumGetBool(((Const *) clause)->constvalue)) + return NIL; /* constant TRUE input -> NIL list */ + else + return list_make1(clause); +} + +/* + * makeIndexInfo + * create an IndexInfo node + */ +IndexInfo * +makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, + List *predicates, bool unique, bool isready, bool concurrent) +{ + IndexInfo *n = makeNode(IndexInfo); + + n->ii_NumIndexAttrs = numattrs; + n->ii_NumIndexKeyAttrs = numkeyattrs; + Assert(n->ii_NumIndexKeyAttrs != 0); + Assert(n->ii_NumIndexKeyAttrs <= n->ii_NumIndexAttrs); + n->ii_Unique = unique; + n->ii_ReadyForInserts = isready; + n->ii_Concurrent = concurrent; + + /* expressions */ + n->ii_Expressions = expressions; + n->ii_ExpressionsState = NIL; + + /* predicates */ + n->ii_Predicate = predicates; + n->ii_PredicateState = NULL; + + /* exclusion constraints */ + n->ii_ExclusionOps = NULL; + n->ii_ExclusionProcs = NULL; + n->ii_ExclusionStrats = NULL; + + /* opclass options */ + n->ii_OpclassOptions = NULL; + + /* speculative inserts */ + n->ii_UniqueOps = NULL; + n->ii_UniqueProcs = NULL; + n->ii_UniqueStrats = NULL; + + /* initialize index-build state to default */ + n->ii_BrokenHotChain = false; + n->ii_ParallelWorkers = 0; + + /* set up for possible use by index AM */ + n->ii_Am = amoid; + n->ii_AmCache = NULL; + n->ii_Context = CurrentMemoryContext; + + return n; +} + +/* + * makeGroupingSet + * + */ +GroupingSet * +makeGroupingSet(GroupingSetKind kind, List *content, int location) +{ + GroupingSet *n = makeNode(GroupingSet); + + n->kind = kind; + n->content = content; + n->location = location; + return n; +} + +/* + * makeVacuumRelation - + * create a VacuumRelation node + */ +VacuumRelation * +makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols) +{ + VacuumRelation *v = makeNode(VacuumRelation); + + v->relation = relation; + v->oid = oid; + v->va_cols = va_cols; + return v; +} |