ruleutils.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,475 行 · 第 1/5 页
C
2,475 行
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 *) lfirst(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); context.buf = buf; context.namespaces = makeList1(&dpns); context.varprefix = (length(query->rtable) != 1); context.prettyFlags = prettyFlags; context.indentLevel = PRETTYINDENT_STD; dpns.rtable = query->rtable; dpns.outer_varno = dpns.inner_varno = 0; dpns.outer_rte = dpns.inner_rte = 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 (length(actions) > 1) { List *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 (length(actions) == 0) { appendStringInfo(buf, "NOTHING;"); } else { Query *query; query = (Query *) lfirst(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 (length(actions) != 1) { appendStringInfo(buf, "Not a view"); return; } query = (Query *) lfirst(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; context.buf = buf; context.namespaces = lcons(&dpns, parentnamespace); context.varprefix = (parentnamespace != NIL || length(query->rtable) != 1); context.prettyFlags = prettyFlags; context.indentLevel = startIndent; dpns.rtable = query->rtable; dpns.outer_varno = dpns.inner_varno = 0; dpns.outer_rte = dpns.inner_rte = 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_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; List *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; appendStringInfo(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 */ ; else if (srt->sortop == typentry->gt_opr) appendStringInfo(buf, " DESC"); else appendStringInfo(buf, " USING %s", generate_operator_name(srt->sortop, sortcoltype, sortcoltype)); 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) && ((Const *) query->limitCount)->constisnull) appendStringInfo(buf, "ALL"); else get_rule_expr(query->limitCount, context, false); }}static voidget_basic_select_query(Query *query, deparse_context *context, TupleDesc resultDesc){ StringInfo buf = context->buf; char *sep; List *l; int colno; /* * Build up the query string - first we say SELECT */ if (PRETTY_INDENT(context)) { context->indentLevel += PRETTYINDENT_STD; appendStringInfoChar(buf, ' '); } 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); appendStringInfo(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) */ sep = " "; colno = 0; foreach(l, query->targetList) { TargetEntry *tle = (TargetEntry *) lfirst(l); char *colname; if (tle->resdom->resjunk) continue; /* ignore junk entries */ appendStringInfo(buf, sep); sep = ", "; colno++; get_rule_expr((Node *) tle->expr, context, true); /* * 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->resdom->resname; if (colname) /* resname could be NULL */ { /* Check if we must say AS ... */ bool tell_as; if (!IsA(tle->expr, Var)) tell_as = (strcmp(colname, "?column?") != 0); else { Var *var = (Var *) (tle->expr); char *schemaname; char *refname; char *attname; get_names_for_var(var, context, &schemaname, &refname, &attname); tell_as = (attname == NULL || strcmp(attname, colname) != 0); } /* and do if so */ if (tell_as) appendStringInfo(buf, " AS %s", quote_identifier(colname)); } } /* Add the FROM clause if needed */ get_from_clause(query, 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); appendStringInfo(buf, sep); get_rule_sortgroupclause(grp, query->targetList, false, context); sep = ", "; } } /* Add the HAVING clause if given */ if (query->havingQual != NULL)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?