📄 parse_clause.c
字号:
if (target_result != NULL) elog(ERROR, "%s BY '%s' is ambiguous", clauseText[clause], name); else target_result = target; /* Stay in loop to check for ambiguity */ } break; case T_Ident: if (strcmp(resname, name) == 0) { /* * Check for only 1 table & ORDER BY -ambiguity does * not matter here */ if (clause == ORDER_CLAUSE && relCnt == 1) return target; if (target_result != NULL) elog(ERROR, "%s BY '%s' is ambiguous", clauseText[clause], name); else target_result = target; /* Stay in loop to check for ambiguity */ } break; case T_A_Const: if (target_pos == targetlist_pos) { /* Can't be ambigious and we got what we came for */ return target; } break; case T_FuncCall: case T_A_Expr: if (equal(expr, target->expr)) { /* * Check for only 1 table & ORDER BY -ambiguity does * not matter here */ if (clause == ORDER_CLAUSE) return target; if (target_result != NULL) elog(ERROR, "GROUP BY has ambiguous expression"); else target_result = target; } break; default: elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node)); } } /* * If no matches, construct a new target entry which is appended to * the end of the target list. This target is set to be resjunk = * TRUE so that it will not be projected into the final tuple. */ if (target_result == NULL) { switch (nodeTag(node)) { case T_Attr: target_result = MakeTargetEntryIdent(pstate, node, &((Attr *) node)->relname, NULL, ((Attr *) node)->relname, true); lappend(tlist, target_result); break; case T_Ident: target_result = MakeTargetEntryIdent(pstate, node, &((Ident *) node)->name, NULL, ((Ident *) node)->name, true); lappend(tlist, target_result); break; case T_A_Const: /* * If we got this far, then must have been an out-of-range * column number */ elog(ERROR, "%s BY position %d is not in target list", clauseText[clause], target_pos); break; case T_FuncCall: case T_A_Expr: target_result = MakeTargetEntryExpr(pstate, "resjunk", expr, false, true); lappend(tlist, target_result); break; default: elog(ERROR, "Illegal %s BY node = %d", clauseText[clause], nodeTag(node)); break; } } return target_result;}/* * transformGroupClause - * transform a Group By clause * */List *transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist){ List *glist = NIL, *gl = NIL; while (grouplist != NIL) { GroupClause *grpcl = makeNode(GroupClause); TargetEntry *restarget; Resdom *resdom; restarget = findTargetlistEntry(pstate, lfirst(grouplist), targetlist, GROUP_CLAUSE); resdom = restarget->resdom; grpcl->grpOpoid = oprid(oper("<", resdom->restype, resdom->restype, false)); if (glist == NIL) { int groupref = length(glist) + 1; restarget->resdom->resgroupref = groupref; grpcl->tleGroupref = groupref; gl = glist = lcons(grpcl, NIL); } else { List *i; foreach(i, glist) { GroupClause *gcl = (GroupClause *) lfirst(i); if (equal(get_groupclause_expr(gcl, targetlist), restarget->expr)) break; } if (i == NIL) /* not in grouplist already */ { int groupref = length(glist) + 1; restarget->resdom->resgroupref = groupref; grpcl->tleGroupref = groupref; lnext(gl) = lcons(grpcl, NIL); gl = lnext(gl); } else pfree(grpcl); /* get rid of this */ } grouplist = lnext(grouplist); } return glist;}/* * transformSortClause - * transform an Order By clause * */List *transformSortClause(ParseState *pstate, List *orderlist, List *sortlist, List *targetlist, char *uniqueFlag){ List *s = NIL; while (orderlist != NIL) { SortGroupBy *sortby = lfirst(orderlist); SortClause *sortcl = makeNode(SortClause); TargetEntry *restarget; Resdom *resdom; restarget = findTargetlistEntry(pstate, sortby->node, targetlist, ORDER_CLAUSE); sortcl->resdom = resdom = restarget->resdom; /* * if we have InvalidOid, then this is a NULL field and don't need * to sort */ if (resdom->restype == InvalidOid) resdom->restype = INT4OID; sortcl->opoid = oprid(oper(sortby->useOp, resdom->restype, resdom->restype, false)); if (sortlist == NIL) s = sortlist = lcons(sortcl, NIL); else { List *i; foreach(i, sortlist) { SortClause *scl = (SortClause *) lfirst(i); if (scl->resdom == sortcl->resdom) break; } if (i == NIL) /* not in sortlist already */ { lnext(s) = lcons(sortcl, NIL); s = lnext(s); } else pfree(sortcl); /* get rid of this */ } orderlist = lnext(orderlist); } if (uniqueFlag) { List *i; if (uniqueFlag[0] == '*') { /* * concatenate all elements from target list that are not * already in the sortby list */ foreach(i, targetlist) { TargetEntry *tlelt = (TargetEntry *) lfirst(i); s = sortlist; while (s != NIL) { SortClause *sortcl = lfirst(s); /* * We use equal() here because we are called for UNION * from the optimizer, and at that point, the sort * clause resdom pointers don't match the target list * resdom pointers */ if (equal(sortcl->resdom, tlelt->resdom)) break; s = lnext(s); } if (s == NIL) { /* not a member of the sortclauses yet */ SortClause *sortcl = makeNode(SortClause); if (tlelt->resdom->restype == InvalidOid) tlelt->resdom->restype = INT4OID; sortcl->resdom = tlelt->resdom; sortcl->opoid = any_ordering_op(tlelt->resdom->restype); sortlist = lappend(sortlist, sortcl); } } } else { TargetEntry *tlelt = NULL; char *uniqueAttrName = uniqueFlag; /* only create sort clause with the specified unique attribute */ foreach(i, targetlist) { tlelt = (TargetEntry *) lfirst(i); if (strcmp(tlelt->resdom->resname, uniqueAttrName) == 0) break; } if (i == NIL) elog(ERROR, "All fields in the UNIQUE ON clause must appear in the target list"); foreach(s, sortlist) { SortClause *sortcl = lfirst(s); if (sortcl->resdom == tlelt->resdom) break; } if (s == NIL) { /* not a member of the sortclauses yet */ SortClause *sortcl = makeNode(SortClause); sortcl->resdom = tlelt->resdom; sortcl->opoid = any_ordering_op(tlelt->resdom->restype); sortlist = lappend(sortlist, sortcl); } } } return sortlist;}/* transformUnionClause() * Transform a UNION clause. * Note that the union clause is actually a fully-formed select structure. * So, it is evaluated as a select, then the resulting target fields * are matched up to ensure correct types in the results. * The select clause parsing is done recursively, so the unions are evaluated * right-to-left. One might want to look at all columns from all clauses before * trying to coerce, but unless we keep track of the call depth we won't know * when to do this because of the recursion. * Let's just try matching in pairs for now (right to left) and see if it works. * - thomas 1998-05-22 */#ifdef NOT_USEDstatic List *transformUnionClause(List *unionClause, List *targetlist){ List *union_list = NIL; List *qlist, *qlist_item; if (unionClause) { /* recursion */ qlist = parse_analyze(unionClause, NULL); foreach(qlist_item, qlist) { Query *query = (Query *) lfirst(qlist_item); List *prev_target = targetlist; List *next_target; int prev_len = 0, next_len = 0; foreach(prev_target, targetlist) if (!((TargetEntry *) lfirst(prev_target))->resdom->resjunk) prev_len++; foreach(next_target, query->targetList) if (!((TargetEntry *) lfirst(next_target))->resdom->resjunk) next_len++; if (prev_len != next_len) elog(ERROR, "Each UNION clause must have the same number of columns"); foreach(next_target, query->targetList) { Oid itype; Oid otype; otype = ((TargetEntry *) lfirst(prev_target))->resdom->restype; itype = ((TargetEntry *) lfirst(next_target))->resdom->restype; /* one or both is a NULL column? then don't convert... */ if (otype == InvalidOid) { /* propagate a known type forward, if available */ if (itype != InvalidOid) ((TargetEntry *) lfirst(prev_target))->resdom->restype = itype;#if FALSE else { ((TargetEntry *) lfirst(prev_target))->resdom->restype = UNKNOWNOID; ((TargetEntry *) lfirst(next_target))->resdom->restype = UNKNOWNOID; }#endif } else if (itype == InvalidOid) { } /* they don't match in type? then convert... */ else if (itype != otype) { Node *expr; expr = ((TargetEntry *) lfirst(next_target))->expr; expr = CoerceTargetExpr(NULL, expr, itype, otype); if (expr == NULL) { elog(ERROR, "Unable to transform %s to %s" "\n\tEach UNION clause must have compatible target types", typeidTypeName(itype), typeidTypeName(otype)); } ((TargetEntry *) lfirst(next_target))->expr = expr; ((TargetEntry *) lfirst(next_target))->resdom->restype = otype; } /* both are UNKNOWN? then evaluate as text... */ else if (itype == UNKNOWNOID) { ((TargetEntry *) lfirst(next_target))->resdom->restype = TEXTOID; ((TargetEntry *) lfirst(prev_target))->resdom->restype = TEXTOID; } prev_target = lnext(prev_target); } union_list = lappend(union_list, query); } return union_list; } else return NIL;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -