ruleutils.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,446 行 · 第 1/5 页
C
2,446 行
((Const *) query->limitCount)->constisnull) appendStringInfo(buf, "ALL"); else get_rule_expr(query->limitCount, context, false); } /* Add FOR UPDATE/SHARE clauses if present */ foreach(l, query->rowMarks) { RowMarkClause *rc = (RowMarkClause *) lfirst(l); RangeTblEntry *rte = rt_fetch(rc->rti, query->rtable); if (rc->forUpdate) appendContextKeyword(context, " FOR UPDATE", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); else appendContextKeyword(context, " FOR SHARE", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); appendStringInfo(buf, " OF %s", quote_identifier(rte->eref->aliasname)); if (rc->noWait) appendStringInfo(buf, " NOWAIT"); }}static voidget_basic_select_query(Query *query, deparse_context *context, TupleDesc resultDesc){ StringInfo buf = context->buf; char *sep; ListCell *l; if (PRETTY_INDENT(context)) { context->indentLevel += PRETTYINDENT_STD; appendStringInfoChar(buf, ' '); } /* * If the query looks like SELECT * FROM (VALUES ...), then print just the * VALUES part. This reverses what transformValuesClause() did at parse * time. If the jointree contains just a single VALUES RTE, we assume * this case applies (without looking at the targetlist...) */ if (list_length(query->jointree->fromlist) == 1) { RangeTblRef *rtr = (RangeTblRef *) linitial(query->jointree->fromlist); if (IsA(rtr, RangeTblRef)) { RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable); if (rte->rtekind == RTE_VALUES) { get_values_def(rte->values_lists, context); return; } } } /* * Build up the query string - first we say SELECT */ appendStringInfo(buf, "SELECT"); /* Add the DISTINCT clause if given */ if (query->distinctClause != NIL) { if (has_distinct_on_clause(query)) { appendStringInfo(buf, " DISTINCT ON ("); sep = ""; foreach(l, query->distinctClause) { SortClause *srt = (SortClause *) lfirst(l); appendStringInfoString(buf, sep); get_rule_sortgroupclause(srt, query->targetList, false, context); sep = ", "; } appendStringInfo(buf, ")"); } else appendStringInfo(buf, " DISTINCT"); } /* Then we tell what to select (the targetlist) */ get_target_list(query->targetList, context, resultDesc); /* Add the FROM clause if needed */ get_from_clause(query, " FROM ", context); /* Add the WHERE clause if given */ if (query->jointree->quals != NULL) { appendContextKeyword(context, " WHERE ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); get_rule_expr(query->jointree->quals, context, false); } /* Add the GROUP BY clause if given */ if (query->groupClause != NULL) { appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); sep = ""; foreach(l, query->groupClause) { GroupClause *grp = (GroupClause *) lfirst(l); appendStringInfoString(buf, sep); get_rule_sortgroupclause(grp, query->targetList, false, context); sep = ", "; } } /* Add the HAVING clause if given */ if (query->havingQual != NULL) { appendContextKeyword(context, " HAVING ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); get_rule_expr(query->havingQual, context, false); }}/* ---------- * get_target_list - Parse back a SELECT target list * * This is also used for RETURNING lists in INSERT/UPDATE/DELETE. * ---------- */static voidget_target_list(List *targetList, deparse_context *context, TupleDesc resultDesc){ StringInfo buf = context->buf; char *sep; int colno; ListCell *l; sep = " "; colno = 0; foreach(l, targetList) { TargetEntry *tle = (TargetEntry *) lfirst(l); char *colname; char *attname; if (tle->resjunk) continue; /* ignore junk entries */ appendStringInfoString(buf, sep); sep = ", "; colno++; /* * We special-case Var nodes rather than using get_rule_expr. This is * needed because get_rule_expr will display a whole-row Var as * "foo.*", which is the preferred notation in most contexts, but at * the top level of a SELECT list it's not right (the parser will * expand that notation into multiple columns, yielding behavior * different from a whole-row Var). We want just "foo", instead. */ if (tle->expr && IsA(tle->expr, Var)) { attname = get_variable((Var *) tle->expr, 0, false, context); } else { get_rule_expr((Node *) tle->expr, context, true); /* We'll show the AS name unless it's this: */ attname = "?column?"; } /* * Figure out what the result column should be called. In the context * of a view, use the view's tuple descriptor (so as to pick up the * effects of any column RENAME that's been done on the view). * Otherwise, just use what we can find in the TLE. */ if (resultDesc && colno <= resultDesc->natts) colname = NameStr(resultDesc->attrs[colno - 1]->attname); else colname = tle->resname; /* Show AS unless the column's name is correct as-is */ if (colname) /* resname could be NULL */ { if (attname == NULL || strcmp(attname, colname) != 0) appendStringInfo(buf, " AS %s", quote_identifier(colname)); } }}static voidget_setop_query(Node *setOp, Query *query, deparse_context *context, TupleDesc resultDesc){ StringInfo buf = context->buf; bool need_paren; if (IsA(setOp, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) setOp; RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable); Query *subquery = rte->subquery; Assert(subquery != NULL); Assert(subquery->setOperations == NULL); /* Need parens if ORDER BY, FOR UPDATE, or LIMIT; see gram.y */ need_paren = (subquery->sortClause || subquery->rowMarks || subquery->limitOffset || subquery->limitCount); if (need_paren) appendStringInfoChar(buf, '('); get_query_def(subquery, buf, context->namespaces, resultDesc, context->prettyFlags, context->indentLevel); if (need_paren) appendStringInfoChar(buf, ')'); } else if (IsA(setOp, SetOperationStmt)) { SetOperationStmt *op = (SetOperationStmt *) setOp; /* * We force parens whenever nesting two SetOperationStmts. There are * some cases in which parens are needed around a leaf query too, but * those are more easily handled at the next level down (see code * above). */ need_paren = !IsA(op->larg, RangeTblRef); if (need_paren) appendStringInfoChar(buf, '('); get_setop_query(op->larg, query, context, resultDesc); if (need_paren) appendStringInfoChar(buf, ')'); if (!PRETTY_INDENT(context)) appendStringInfoChar(buf, ' '); switch (op->op) { case SETOP_UNION: appendContextKeyword(context, "UNION ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); break; case SETOP_INTERSECT: appendContextKeyword(context, "INTERSECT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); break; case SETOP_EXCEPT: appendContextKeyword(context, "EXCEPT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); break; default: elog(ERROR, "unrecognized set op: %d", (int) op->op); } if (op->all) appendStringInfo(buf, "ALL "); if (PRETTY_INDENT(context)) appendContextKeyword(context, "", 0, 0, 0); need_paren = !IsA(op->rarg, RangeTblRef); if (need_paren) appendStringInfoChar(buf, '('); get_setop_query(op->rarg, query, context, resultDesc); if (need_paren) appendStringInfoChar(buf, ')'); } else { elog(ERROR, "unrecognized node type: %d", (int) nodeTag(setOp)); }}/* * Display a sort/group clause. * * Also returns the expression tree, so caller need not find it again. */static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist, bool force_colno, deparse_context *context){ StringInfo buf = context->buf; TargetEntry *tle; Node *expr; tle = get_sortgroupclause_tle(srt, tlist); expr = (Node *) tle->expr; /* * Use column-number form if requested by caller. Otherwise, if * expression is a constant, force it to be dumped with an explicit * cast as decoration --- this is because a simple integer constant * is ambiguous (and will be misinterpreted by findTargetlistEntry()) * if we dump it without any decoration. Otherwise, just dump the * expression normally. */ if (force_colno) { Assert(!tle->resjunk); appendStringInfo(buf, "%d", tle->resno); } else if (expr && IsA(expr, Const)) get_const_expr((Const *) expr, context, 1); else get_rule_expr(expr, context, true); return expr;}/* ---------- * get_insert_query_def - Parse back an INSERT parsetree * ---------- */static voidget_insert_query_def(Query *query, deparse_context *context){ StringInfo buf = context->buf; RangeTblEntry *select_rte = NULL; RangeTblEntry *values_rte = NULL; RangeTblEntry *rte; char *sep; ListCell *values_cell; ListCell *l; List *strippedexprs; /* * If it's an INSERT ... SELECT or VALUES (...), (...), ... there will be * a single RTE for the SELECT or VALUES. */ foreach(l, query->rtable) { rte = (RangeTblEntry *) lfirst(l); if (rte->rtekind == RTE_SUBQUERY) { if (select_rte) elog(ERROR, "too many subquery RTEs in INSERT"); select_rte = rte; } if (rte->rtekind == RTE_VALUES) { if (values_rte) elog(ERROR, "too many values RTEs in INSERT"); values_rte = rte; } } if (select_rte && values_rte) elog(ERROR, "both subquery and values RTEs in INSERT"); /* * Start the query with INSERT INTO relname */ rte = rt_fetch(query->resultRelation, query->rtable); Assert(rte->rtekind == RTE_RELATION); if (PRETTY_INDENT(context)) { context->indentLevel += PRETTYINDENT_STD; appendStringInfoChar(buf, ' '); } appendStringInfo(buf, "INSERT INTO %s (", generate_relation_name(rte->relid)); /* * Add the insert-column-names list. To handle indirection properly, we * need to look for indirection nodes in the top targetlist (if it's * INSERT ... SELECT or INSERT ... single VALUES), or in the first * expression list of the VALUES RTE (if it's INSERT ... multi VALUES). We * assume that all the expression lists will have similar indirection in * the latter case. */ if (values_rte) values_cell = list_head((List *) linitial(values_rte->values_lists)); else values_cell = NULL; strippedexprs = NIL; sep = ""; foreach(l, query->targetList) { TargetEntry *tle = (TargetEntry *) lfirst(l); if (tle->resjunk) continue; /* ignore junk entries */ appendStringInfoString(buf, sep); sep = ", "; /* * Put out name of target column; look in the catalogs, not at * tle->resname, since resname will fail to track RENAME. */ appendStringInfoString(buf, quote_identifier(get_relid_attribute_name(rte->relid, tle->resno))); /* * Print any indirection needed (subfields or subscripts), and strip * off the top-level nodes representing the indirection assignments. */ if (values_cell) { /* we discard the stripped expression in this case */ processIndirection((Node *) lfirst(values_cell), context, true); values_cell = lnext(values_cell); } else { /* we keep a list of the stripped expressions in this case */ strippedexprs = lappend(strippedexprs, processIndirection((Node *) tle->expr, context, true)); } } appendStringInfo(buf, ") "); if (select_rte) { /* Add the SELECT */ get_query_def(select_rte->subquery, buf, NIL, NULL, context->prettyFlags, context->indentLevel); } else if (values_rte) { /* Add the multi-VALUES expression lists */ get_values_def(values_rte->values_lists, context); } else { /* Add the single-VALUES expression list */ appendContextKeyword(context, "VALUES (", -PRETTYINDENT_STD, PRETTYINDENT_STD, 2); get_rule_expr((Node *) strippedexprs, context, false); appendStringInfoChar(buf, ')'); } /* Add RETURNING if present */ if (query->returningList) { appendContextKeyword(context, " RETURNING", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); get_target_list(query->returningList, context, NULL); }}/* ---------- * get_update_query_def - Parse back an UPDATE parsetree * ---------- */static voidget_update_query_def(Query *query, deparse_context *context){ StringInfo buf = context->buf; char *sep; RangeTblEntry *rte; ListCell *l; /* * Start the query with UPDATE relname SET */ rte = rt_fetch(query->resultRelation, query->rtable); Assert(rte->rtekind == RTE_RELATION); if (PRETTY_INDENT(context)) { appendStringInfoChar(buf, ' '); context->indentLevel += PRETTYINDENT_STD; } appendStringInfo(buf, "UPDATE %s%s", only_marker(rte), generate_relation_name(rte->relid)); if (rte->alias != NULL) appendStringInfo(buf, " %s", quote_identifier(rte->alias->aliasname)); appendStringInfoString(buf, "
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?