📄 parse_clause.c
字号:
r_colvar = list_nth(r_colvars, r_index); r_usingvars = lappend(r_usingvars, r_colvar); res_colnames = lappend(res_colnames, lfirst(ucol)); res_colvars = lappend(res_colvars, buildMergedJoinVar(pstate, j->jointype, l_colvar, r_colvar)); } j->quals = transformJoinUsingClause(pstate, l_usingvars, r_usingvars); } else if (j->quals) { /* User-written ON-condition; transform it */ j->quals = transformJoinOnClause(pstate, j, l_rte, r_rte, my_relnamespace, my_containedRels); } else { /* CROSS JOIN: no quals */ } /* Add remaining columns from each side to the output columns */ extractRemainingColumns(res_colnames, l_colnames, l_colvars, &l_colnames, &l_colvars); extractRemainingColumns(res_colnames, r_colnames, r_colvars, &r_colnames, &r_colvars); res_colnames = list_concat(res_colnames, l_colnames); res_colvars = list_concat(res_colvars, l_colvars); res_colnames = list_concat(res_colnames, r_colnames); res_colvars = list_concat(res_colvars, r_colvars); /* * Check alias (AS clause), if any. */ if (j->alias) { if (j->alias->colnames != NIL) { if (list_length(j->alias->colnames) > list_length(res_colnames)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("column alias list for \"%s\" has too many entries", j->alias->aliasname))); } } /* * Now build an RTE for the result of the join */ rte = addRangeTableEntryForJoin(pstate, res_colnames, j->jointype, res_colvars, j->alias, true); /* assume new rte is at end */ j->rtindex = list_length(pstate->p_rtable); Assert(rte == rt_fetch(j->rtindex, pstate->p_rtable)); *top_rte = rte; *top_rti = j->rtindex; /* * Prepare returned namespace list. If the JOIN has an alias then it * hides the contained RTEs as far as the relnamespace goes; * otherwise, put the contained RTEs and *not* the JOIN into * relnamespace. */ if (j->alias) { *relnamespace = list_make1(rte); list_free(my_relnamespace); } else *relnamespace = my_relnamespace; /* * Include join RTE in returned containedRels set */ *containedRels = bms_add_member(my_containedRels, j->rtindex); return (Node *) j; } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n)); return NULL; /* can't get here, keep compiler quiet */}/* * buildMergedJoinVar - * generate a suitable replacement expression for a merged join column */static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype, Var *l_colvar, Var *r_colvar){ Oid outcoltype; int32 outcoltypmod; Node *l_node, *r_node, *res_node; /* * Choose output type if input types are dissimilar. */ outcoltype = l_colvar->vartype; outcoltypmod = l_colvar->vartypmod; if (outcoltype != r_colvar->vartype) { outcoltype = select_common_type(list_make2_oid(l_colvar->vartype, r_colvar->vartype), "JOIN/USING"); outcoltypmod = -1; /* ie, unknown */ } else if (outcoltypmod != r_colvar->vartypmod) { /* same type, but not same typmod */ outcoltypmod = -1; /* ie, unknown */ } /* * Insert coercion functions if needed. Note that a difference in typmod * can only happen if input has typmod but outcoltypmod is -1. In that * case we insert a RelabelType to clearly mark that result's typmod is * not same as input. We never need coerce_type_typmod. */ if (l_colvar->vartype != outcoltype) l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype, outcoltype, outcoltypmod, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); else if (l_colvar->vartypmod != outcoltypmod) l_node = (Node *) makeRelabelType((Expr *) l_colvar, outcoltype, outcoltypmod, COERCE_IMPLICIT_CAST); else l_node = (Node *) l_colvar; if (r_colvar->vartype != outcoltype) r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype, outcoltype, outcoltypmod, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); else if (r_colvar->vartypmod != outcoltypmod) r_node = (Node *) makeRelabelType((Expr *) r_colvar, outcoltype, outcoltypmod, COERCE_IMPLICIT_CAST); else r_node = (Node *) r_colvar; /* * Choose what to emit */ switch (jointype) { case JOIN_INNER: /* * We can use either var; prefer non-coerced one if available. */ if (IsA(l_node, Var)) res_node = l_node; else if (IsA(r_node, Var)) res_node = r_node; else res_node = l_node; break; case JOIN_LEFT: /* Always use left var */ res_node = l_node; break; case JOIN_RIGHT: /* Always use right var */ res_node = r_node; break; case JOIN_FULL: { /* * Here we must build a COALESCE expression to ensure that the * join output is non-null if either input is. */ CoalesceExpr *c = makeNode(CoalesceExpr); c->coalescetype = outcoltype; c->args = list_make2(l_node, r_node); res_node = (Node *) c; break; } default: elog(ERROR, "unrecognized join type: %d", (int) jointype); res_node = NULL; /* keep compiler quiet */ break; } return res_node;}/* * transformWhereClause - * Transform the qualification and make sure it is of type boolean. * Used for WHERE and allied clauses. * * constructName does not affect the semantics, but is used in error messages */Node *transformWhereClause(ParseState *pstate, Node *clause, const char *constructName){ Node *qual; if (clause == NULL) return NULL; qual = transformExpr(pstate, clause); qual = coerce_to_boolean(pstate, qual, constructName); return qual;}/* * transformLimitClause - * Transform the expression and make sure it is of type integer. * Used for LIMIT and allied clauses. * * constructName does not affect the semantics, but is used in error messages */Node *transformLimitClause(ParseState *pstate, Node *clause, const char *constructName){ Node *qual; if (clause == NULL) return NULL; qual = transformExpr(pstate, clause); qual = coerce_to_integer(pstate, qual, constructName); /* * LIMIT can't refer to any vars or aggregates of the current query; we * don't allow subselects either (though that case would at least be * sensible) */ if (contain_vars_of_level(qual, 0)) { ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), /* translator: %s is name of a SQL construct, eg LIMIT */ errmsg("argument of %s must not contain variables", constructName))); } if (checkExprHasAggs(qual)) { ereport(ERROR, (errcode(ERRCODE_GROUPING_ERROR), /* translator: %s is name of a SQL construct, eg LIMIT */ errmsg("argument of %s must not contain aggregates", constructName))); } if (contain_subplans(qual)) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is name of a SQL construct, eg LIMIT */ errmsg("argument of %s must not contain subqueries", constructName))); } return qual;}/* * findTargetlistEntry - * Returns the targetlist entry matching the given (untransformed) node. * If no matching entry exists, one is created and appended to the target * list as a "resjunk" node. * * node the ORDER BY, GROUP BY, or DISTINCT ON expression to be matched * tlist the target list (passed by reference so we can append to it) * clause identifies clause type being processed */static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause){ TargetEntry *target_result = NULL; ListCell *tl; Node *expr; /*---------- * Handle two special cases as mandated by the SQL92 spec: * * 1. Bare ColumnName (no qualifier or subscripts) * For a bare identifier, we search for a matching column name * in the existing target list. Multiple matches are an error * unless they refer to identical values; for example, * we allow SELECT a, a FROM table ORDER BY a * but not SELECT a AS b, b FROM table ORDER BY b * If no match is found, we fall through and treat the identifier * as an expression. * For GROUP BY, it is incorrect to match the grouping item against * targetlist entries: according to SQL92, an identifier in GROUP BY * is a reference to a column name exposed by FROM, not to a target * list column. However, many implementations (including pre-7.0 * PostgreSQL) accept this anyway. So for GROUP BY, we look first * to see if the identifier matches any FROM column name, and only * try for a targetlist name if it doesn't. This ensures that we * adhere to the spec in the case where the name could be both. * DISTINCT ON isn't in the standard, so we can do what we like there; * we choose to make it work like ORDER BY, on the rather flimsy * grounds that ordinary DISTINCT works on targetlist entries. * * 2. IntegerConstant * This means to use the n'th item in the existing target list. * Note that it would make no sense to order/group/distinct by an * actual constant, so this does not create a conflict with our * extension to order/group by an expression. * GROUP BY column-number is not allowed by SQL92, but since * the standard has no other behavior defined for this syntax, * we may as well accept this common extension. * * Note that pre-existing resjunk targets must not be used in either case, * since the user didn't write them in his SELECT list. * * If neither special case applies, fall through to treat the item as * an expression. *---------- */ if (IsA(node, ColumnRef) && list_length(((ColumnRef *) node)->fields) == 1) { char *name = strVal(linitial(((ColumnRef *) node)->fields)); if (clause == GROUP_CLAUSE) { /* * In GROUP BY, we must prefer a match against a FROM-clause * column to one against the targetlist. Look to see if there is * a matching column. If so, fall through to let transformExpr() * do the rest. NOTE: if name could refer ambiguously to more * than one column name exposed by FROM, colNameToVar will * ereport(ERROR). That's just what we want here. * * Small tweak for 7.4.3: ignore matches in upper query levels. * This effectively changes the search order for bare names to (1) * local FROM variables, (2) local targetlist aliases, (3) outer * FROM variables, whereas before it was (1) (3) (2). SQL92 and * SQL99 do not allow GROUPing BY an outer reference, so this * breaks no cases that are legal per spec, and it seems a more * self-consistent behavior. */ if (colNameToVar(pstate, name, true) != NULL) name = NULL; } if (name != NULL) { foreach(tl, *tlist) { TargetEntry *tle = (TargetEntry *) lfirst(tl); if (!tle->resjunk && strcmp(tle->resname, name) == 0) { if (target_result != NULL) { if (!equal(target_result->expr, tle->expr)) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_COLUMN), /* * translator: first %s is name of a SQL * construct, eg ORDER BY */ errmsg("%s \"%s\" is ambiguous", clauseText[clause], name))); } else target_result = tle; /* Stay in loop to check for ambiguity */ } } if (target_result != NULL) return target_result; /* return the first match */ } } if (IsA(node, A_Const)) { Value *val = &((A_Const *) node)->val; int targetlist_pos = 0; int target_pos; if (!IsA(val, Integer)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), /* translator: %s is name of a SQL construct, eg ORDER BY */ errmsg("non-integer constant in %s", clauseText[clause]))); target_pos = intVal(val); foreach(tl, *tlist) { TargetEntry *tle = (TargetEntry *) lfirst(tl); if (!tle->resjunk) { if (++targetlist_pos == target_pos) return tle; /* return the unique match */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -