ruleutils.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,446 行 · 第 1/5 页
C
2,446 行
}/* * deparse_context_for_plan - Build deparse context for a plan node * * When deparsing an expression in a Plan tree, we might have to resolve * OUTER or INNER references. Pass the plan nodes whose targetlists define * such references, or NULL when none are expected. (outer_plan and * inner_plan really ought to be declared as "Plan *", but we use "Node *" * to avoid having to include plannodes.h in builtins.h.) * * As a special case, when deparsing a SubqueryScan plan, pass the subplan * as inner_plan (there won't be any regular innerPlan() in this case). * * The plan's rangetable list must also be passed. We actually prefer to use * the rangetable to resolve simple Vars, but the subplan inputs are needed * for Vars that reference expressions computed in subplan target lists. */List *deparse_context_for_plan(Node *outer_plan, Node *inner_plan, List *rtable){ deparse_namespace *dpns; dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace)); dpns->rtable = rtable; dpns->outer_plan = (Plan *) outer_plan; dpns->inner_plan = (Plan *) inner_plan; /* Return a one-deep namespace stack */ return list_make1(dpns);}/* ---------- * make_ruledef - reconstruct the CREATE RULE command * for a given pg_rewrite tuple * ---------- */static voidmake_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags){ char *rulename; char ev_type; Oid ev_class; int2 ev_attr; bool is_instead; char *ev_qual; char *ev_action; List *actions = NIL; int fno; Datum dat; bool isnull; /* * Get the attribute values from the rules tuple */ fno = SPI_fnumber(rulettc, "rulename"); dat = SPI_getbinval(ruletup, rulettc, fno, &isnull); Assert(!isnull); rulename = NameStr(*(DatumGetName(dat))); fno = SPI_fnumber(rulettc, "ev_type"); dat = SPI_getbinval(ruletup, rulettc, fno, &isnull); Assert(!isnull); ev_type = DatumGetChar(dat); fno = SPI_fnumber(rulettc, "ev_class"); dat = SPI_getbinval(ruletup, rulettc, fno, &isnull); Assert(!isnull); ev_class = DatumGetObjectId(dat); fno = SPI_fnumber(rulettc, "ev_attr"); dat = SPI_getbinval(ruletup, rulettc, fno, &isnull); Assert(!isnull); ev_attr = DatumGetInt16(dat); fno = SPI_fnumber(rulettc, "is_instead"); dat = SPI_getbinval(ruletup, rulettc, fno, &isnull); Assert(!isnull); is_instead = DatumGetBool(dat); /* these could be nulls */ fno = SPI_fnumber(rulettc, "ev_qual"); ev_qual = SPI_getvalue(ruletup, rulettc, fno); fno = SPI_fnumber(rulettc, "ev_action"); ev_action = SPI_getvalue(ruletup, rulettc, fno); if (ev_action != NULL) actions = (List *) stringToNode(ev_action); /* * Build the rules definition text */ appendStringInfo(buf, "CREATE RULE %s AS", quote_identifier(rulename)); if (prettyFlags & PRETTYFLAG_INDENT) appendStringInfoString(buf, "\n ON "); else appendStringInfoString(buf, " ON "); /* The event the rule is fired for */ switch (ev_type) { case '1': appendStringInfo(buf, "SELECT"); break; case '2': appendStringInfo(buf, "UPDATE"); break; case '3': appendStringInfo(buf, "INSERT"); break; case '4': appendStringInfo(buf, "DELETE"); break; default: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("rule \"%s\" has unsupported event type %d", rulename, ev_type))); break; } /* The relation the rule is fired on */ appendStringInfo(buf, " TO %s", generate_relation_name(ev_class)); if (ev_attr > 0) appendStringInfo(buf, ".%s", quote_identifier(get_relid_attribute_name(ev_class, ev_attr))); /* If the rule has an event qualification, add it */ if (ev_qual == NULL) ev_qual = ""; if (strlen(ev_qual) > 0 && strcmp(ev_qual, "<>") != 0) { Node *qual; Query *query; deparse_context context; deparse_namespace dpns; if (prettyFlags & PRETTYFLAG_INDENT) appendStringInfoString(buf, "\n "); appendStringInfo(buf, " WHERE "); qual = stringToNode(ev_qual); /* * We need to make a context for recognizing any Vars in the qual * (which can only be references to OLD and NEW). Use the rtable of * the first query in the action list for this purpose. */ query = (Query *) linitial(actions); /* * If the action is INSERT...SELECT, OLD/NEW have been pushed down * into the SELECT, and that's what we need to look at. (Ugly kluge * ... try to fix this when we redesign querytrees.) */ query = getInsertSelectQuery(query, NULL); /* Must acquire locks right away; see notes in get_query_def() */ AcquireRewriteLocks(query); context.buf = buf; context.namespaces = list_make1(&dpns); context.varprefix = (list_length(query->rtable) != 1); context.prettyFlags = prettyFlags; context.indentLevel = PRETTYINDENT_STD; dpns.rtable = query->rtable; dpns.outer_plan = dpns.inner_plan = NULL; get_rule_expr(qual, &context, false); } appendStringInfo(buf, " DO "); /* The INSTEAD keyword (if so) */ if (is_instead) appendStringInfo(buf, "INSTEAD "); /* Finally the rules actions */ if (list_length(actions) > 1) { ListCell *action; Query *query; appendStringInfo(buf, "("); foreach(action, actions) { query = (Query *) lfirst(action); get_query_def(query, buf, NIL, NULL, prettyFlags, 0); if (prettyFlags) appendStringInfo(buf, ";\n"); else appendStringInfo(buf, "; "); } appendStringInfo(buf, ");"); } else if (list_length(actions) == 0) { appendStringInfo(buf, "NOTHING;"); } else { Query *query; query = (Query *) linitial(actions); get_query_def(query, buf, NIL, NULL, prettyFlags, 0); appendStringInfo(buf, ";"); }}/* ---------- * make_viewdef - reconstruct the SELECT part of a * view rewrite rule * ---------- */static voidmake_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags){ Query *query; char ev_type; Oid ev_class; int2 ev_attr; bool is_instead; char *ev_qual; char *ev_action; List *actions = NIL; Relation ev_relation; int fno; bool isnull; /* * Get the attribute values from the rules tuple */ fno = SPI_fnumber(rulettc, "ev_type"); ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull); fno = SPI_fnumber(rulettc, "ev_class"); ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull); fno = SPI_fnumber(rulettc, "ev_attr"); ev_attr = (int2) SPI_getbinval(ruletup, rulettc, fno, &isnull); fno = SPI_fnumber(rulettc, "is_instead"); is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull); fno = SPI_fnumber(rulettc, "ev_qual"); ev_qual = SPI_getvalue(ruletup, rulettc, fno); fno = SPI_fnumber(rulettc, "ev_action"); ev_action = SPI_getvalue(ruletup, rulettc, fno); if (ev_action != NULL) actions = (List *) stringToNode(ev_action); if (list_length(actions) != 1) { appendStringInfo(buf, "Not a view"); return; } query = (Query *) linitial(actions); if (ev_type != '1' || ev_attr >= 0 || !is_instead || strcmp(ev_qual, "<>") != 0 || query->commandType != CMD_SELECT) { appendStringInfo(buf, "Not a view"); return; } ev_relation = heap_open(ev_class, AccessShareLock); get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), prettyFlags, 0); appendStringInfo(buf, ";"); heap_close(ev_relation, AccessShareLock);}/* ---------- * get_query_def - Parse back one query parsetree * * If resultDesc is not NULL, then it is the output tuple descriptor for * the view represented by a SELECT query. * ---------- */static voidget_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, int prettyFlags, int startIndent){ deparse_context context; deparse_namespace dpns; /* * Before we begin to examine the query, acquire locks on referenced * relations, and fix up deleted columns in JOIN RTEs. This ensures * consistent results. Note we assume it's OK to scribble on the passed * querytree! */ AcquireRewriteLocks(query); context.buf = buf; context.namespaces = lcons(&dpns, list_copy(parentnamespace)); context.varprefix = (parentnamespace != NIL || list_length(query->rtable) != 1); context.prettyFlags = prettyFlags; context.indentLevel = startIndent; dpns.rtable = query->rtable; dpns.outer_plan = dpns.inner_plan = NULL; switch (query->commandType) { case CMD_SELECT: get_select_query_def(query, &context, resultDesc); break; case CMD_UPDATE: get_update_query_def(query, &context); break; case CMD_INSERT: get_insert_query_def(query, &context); break; case CMD_DELETE: get_delete_query_def(query, &context); break; case CMD_NOTHING: appendStringInfo(buf, "NOTHING"); break; case CMD_UTILITY: get_utility_query_def(query, &context); break; default: elog(ERROR, "unrecognized query command type: %d", query->commandType); break; }}/* ---------- * get_values_def - Parse back a VALUES list * ---------- */static voidget_values_def(List *values_lists, deparse_context *context){ StringInfo buf = context->buf; bool first_list = true; ListCell *vtl; appendStringInfoString(buf, "VALUES "); foreach(vtl, values_lists) { List *sublist = (List *) lfirst(vtl); bool first_col = true; ListCell *lc; if (first_list) first_list = false; else appendStringInfoString(buf, ", "); appendStringInfoChar(buf, '('); foreach(lc, sublist) { Node *col = (Node *) lfirst(lc); if (first_col) first_col = false; else appendStringInfoChar(buf, ','); /* * Strip any top-level nodes representing indirection assignments, * then print the result. */ get_rule_expr(processIndirection(col, context, false), context, false); } appendStringInfoChar(buf, ')'); }}/* ---------- * get_select_query_def - Parse back a SELECT parsetree * ---------- */static voidget_select_query_def(Query *query, deparse_context *context, TupleDesc resultDesc){ StringInfo buf = context->buf; bool force_colno; char *sep; ListCell *l; /* * If the Query node has a setOperations tree, then it's the top level of * a UNION/INTERSECT/EXCEPT query; only the ORDER BY and LIMIT fields are * interesting in the top query itself. */ if (query->setOperations) { get_setop_query(query->setOperations, query, context, resultDesc); /* ORDER BY clauses must be simple in this case */ force_colno = true; } else { get_basic_select_query(query, context, resultDesc); force_colno = false; } /* Add the ORDER BY clause if given */ if (query->sortClause != NIL) { appendContextKeyword(context, " ORDER BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); sep = ""; foreach(l, query->sortClause) { SortClause *srt = (SortClause *) lfirst(l); Node *sortexpr; Oid sortcoltype; TypeCacheEntry *typentry; appendStringInfoString(buf, sep); sortexpr = get_rule_sortgroupclause(srt, query->targetList, force_colno, context); sortcoltype = exprType(sortexpr); /* See whether operator is default < or > for datatype */ typentry = lookup_type_cache(sortcoltype, TYPECACHE_LT_OPR | TYPECACHE_GT_OPR); if (srt->sortop == typentry->lt_opr) { /* ASC is default, so emit nothing for it */ if (srt->nulls_first) appendStringInfo(buf, " NULLS FIRST"); } else if (srt->sortop == typentry->gt_opr) { appendStringInfo(buf, " DESC"); /* DESC defaults to NULLS FIRST */ if (!srt->nulls_first) appendStringInfo(buf, " NULLS LAST"); } else { appendStringInfo(buf, " USING %s", generate_operator_name(srt->sortop, sortcoltype, sortcoltype)); /* be specific to eliminate ambiguity */ if (srt->nulls_first) appendStringInfo(buf, " NULLS FIRST"); else appendStringInfo(buf, " NULLS LAST"); } sep = ", "; } } /* Add the LIMIT clause if given */ if (query->limitOffset != NULL) { appendContextKeyword(context, " OFFSET ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); get_rule_expr(query->limitOffset, context, false); } if (query->limitCount != NULL) { appendContextKeyword(context, " LIMIT ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 0); if (IsA(query->limitCount, Const) &&
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?