ruleutils.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,434 行 · 第 1/5 页
C
2,434 行
/********************************************************************** * ruleutils.c - Functions to convert stored expressions/querytrees * back to source text * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.207.2.5 2006/01/26 17:08:26 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * * The author hereby grants permission to use, copy, modify, * distribute, and license this software and its documentation * for any purpose, provided that existing copyright notices are * retained in all copies and that this notice is included * verbatim in any distributions. No written agreement, license, * or royalty fee is required for any of the authorized uses. * Modifications to this software may be copyrighted by their * author and need not follow the licensing terms described * here, provided that the new terms are clearly indicated on * the first page of each file where they apply. * * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN * IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON * AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, * ENHANCEMENTS, OR MODIFICATIONS. * **********************************************************************/#include "postgres.h"#include <unistd.h>#include <fcntl.h>#include "access/genam.h"#include "catalog/dependency.h"#include "catalog/heap.h"#include "catalog/index.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_authid.h"#include "catalog/pg_cast.h"#include "catalog/pg_constraint.h"#include "catalog/pg_depend.h"#include "catalog/pg_index.h"#include "catalog/pg_opclass.h"#include "catalog/pg_operator.h"#include "catalog/pg_trigger.h"#include "executor/spi.h"#include "funcapi.h"#include "lib/stringinfo.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/tlist.h"#include "parser/keywords.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_oper.h"#include "parser/parse_type.h"#include "parser/parsetree.h"#include "rewrite/rewriteHandler.h"#include "rewrite/rewriteManip.h"#include "rewrite/rewriteSupport.h"#include "utils/array.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/typcache.h"/* ---------- * Pretty formatting constants * ---------- *//* Indent counts */#define PRETTYINDENT_STD 8#define PRETTYINDENT_JOIN 13#define PRETTYINDENT_JOIN_ON (PRETTYINDENT_JOIN-PRETTYINDENT_STD)#define PRETTYINDENT_VAR 4/* Pretty flags */#define PRETTYFLAG_PAREN 1#define PRETTYFLAG_INDENT 2/* macro to test if pretty action needed */#define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)#define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)/* ---------- * Local data types * ---------- *//* Context info needed for invoking a recursive querytree display routine */typedef struct{ StringInfo buf; /* output buffer to append to */ List *namespaces; /* List of deparse_namespace nodes */ int prettyFlags; /* enabling of pretty-print functions */ int indentLevel; /* current indent level for prettyprint */ bool varprefix; /* TRUE to print prefixes on Vars */} deparse_context;/* * Each level of query context around a subtree needs a level of Var namespace. * A Var having varlevelsup=N refers to the N'th item (counting from 0) in * the current context's namespaces list. * * The rangetable is the list of actual RTEs from the query tree. * * For deparsing plan trees, we allow two special RTE entries that are not * part of the rtable list (mainly because they don't have consecutively * allocated varnos). */typedef struct{ List *rtable; /* List of RangeTblEntry nodes */ int outer_varno; /* varno for outer_rte */ RangeTblEntry *outer_rte; /* special RangeTblEntry, or NULL */ int inner_varno; /* varno for inner_rte */ RangeTblEntry *inner_rte; /* special RangeTblEntry, or NULL */} deparse_namespace;/* ---------- * Global data * ---------- */static void *plan_getrulebyoid = NULL;static char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1";static void *plan_getviewrule = NULL;static char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2";/* ---------- * Local functions * * Most of these functions used to use fixed-size buffers to build their * results. Now, they take an (already initialized) StringInfo object * as a parameter, and append their text output to its contents. * ---------- */static char *deparse_expression_pretty(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent);static char *pg_get_viewdef_worker(Oid viewoid, int prettyFlags);static void decompile_column_index_array(Datum column_index_array, Oid relId, StringInfo buf);static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);static char *pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags);static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, int prettyFlags);static char *pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags);static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags);static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags);static void get_query_def(Query *query, StringInfo buf, List *parentnamespace, TupleDesc resultDesc, int prettyFlags, int startIndent);static void get_select_query_def(Query *query, deparse_context *context, TupleDesc resultDesc);static void get_insert_query_def(Query *query, deparse_context *context);static void get_update_query_def(Query *query, deparse_context *context);static void get_delete_query_def(Query *query, deparse_context *context);static void get_utility_query_def(Query *query, deparse_context *context);static void get_basic_select_query(Query *query, deparse_context *context, TupleDesc resultDesc);static void get_setop_query(Node *setOp, Query *query, deparse_context *context, TupleDesc resultDesc);static Node *get_rule_sortgroupclause(SortClause *srt, List *tlist, bool force_colno, deparse_context *context);static void get_names_for_var(Var *var, int levelsup, deparse_context *context, char **schemaname, char **refname, char **attname);static RangeTblEntry *find_rte_by_refname(const char *refname, deparse_context *context);static const char *get_simple_binary_op_name(OpExpr *expr);static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);static void appendStringInfoSpaces(StringInfo buf, int count);static void appendContextKeyword(deparse_context *context, const char *str, int indentBefore, int indentAfter, int indentPlus);static void get_rule_expr(Node *node, deparse_context *context, bool showimplicit);static void get_oper_expr(OpExpr *expr, deparse_context *context);static void get_func_expr(FuncExpr *expr, deparse_context *context, bool showimplicit);static void get_agg_expr(Aggref *aggref, deparse_context *context);static void get_const_expr(Const *constval, deparse_context *context);static void get_sublink_expr(SubLink *sublink, deparse_context *context);static void get_from_clause(Query *query, const char *prefix, deparse_context *context);static void get_from_clause_item(Node *jtnode, Query *query, deparse_context *context);static void get_from_clause_alias(Alias *alias, RangeTblEntry *rte, deparse_context *context);static void get_from_clause_coldeflist(List *coldeflist, deparse_context *context);static void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf);static Node *processIndirection(Node *node, deparse_context *context);static void printSubscripts(ArrayRef *aref, deparse_context *context);static char *generate_relation_name(Oid relid);static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes);static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);static void print_operator_name(StringInfo buf, List *opname);static text *string_to_text(char *str);#define only_marker(rte) ((rte)->inh ? "" : "ONLY ")/* ---------- * get_ruledef - Do it all and return a text * that could be used as a statement * to recreate the rule * ---------- */Datumpg_get_ruledef(PG_FUNCTION_ARGS){ Oid ruleoid = PG_GETARG_OID(0); PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, 0)));}Datumpg_get_ruledef_ext(PG_FUNCTION_ARGS){ Oid ruleoid = PG_GETARG_OID(0); bool pretty = PG_GETARG_BOOL(1); int prettyFlags; prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0; PG_RETURN_TEXT_P(string_to_text(pg_get_ruledef_worker(ruleoid, prettyFlags)));}static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags){ Datum args[1]; char nulls[1]; int spirc; HeapTuple ruletup; TupleDesc rulettc; StringInfoData buf; /* * Do this first so that string is alloc'd in outer context not SPI's. */ initStringInfo(&buf); /* * Connect to SPI manager */ if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed"); /* * On the first call prepare the plan to lookup pg_rewrite. We read * pg_rewrite over the SPI manager instead of using the syscache to be * checked for read access on pg_rewrite. */ if (plan_getrulebyoid == NULL) { Oid argtypes[1]; void *plan; argtypes[0] = OIDOID; plan = SPI_prepare(query_getrulebyoid, 1, argtypes); if (plan == NULL) elog(ERROR, "SPI_prepare failed for \"%s\"", query_getrulebyoid); plan_getrulebyoid = SPI_saveplan(plan); } /* * Get the pg_rewrite tuple for this rule */ args[0] = ObjectIdGetDatum(ruleoid); nulls[0] = ' '; spirc = SPI_execute_plan(plan_getrulebyoid, args, nulls, true, 1); if (spirc != SPI_OK_SELECT) elog(ERROR, "failed to get pg_rewrite tuple for rule %u", ruleoid); if (SPI_processed != 1) appendStringInfo(&buf, "-"); else { /* * Get the rules definition and put it into executors memory */ ruletup = SPI_tuptable->vals[0]; rulettc = SPI_tuptable->tupdesc; make_ruledef(&buf, ruletup, rulettc, prettyFlags); } /* * Disconnect from SPI manager */ if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed"); return buf.data;}/* ---------- * get_viewdef - Mainly the same thing, but we * only return the SELECT part of a view * ---------- */Datumpg_get_viewdef(PG_FUNCTION_ARGS){ /* By OID */ Oid viewoid = PG_GETARG_OID(0); PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));}Datumpg_get_viewdef_ext(PG_FUNCTION_ARGS){ /* By OID */ Oid viewoid = PG_GETARG_OID(0); bool pretty = PG_GETARG_BOOL(1); int prettyFlags; prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0; PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));}Datumpg_get_viewdef_name(PG_FUNCTION_ARGS){ /* By qualified name */ text *viewname = PG_GETARG_TEXT_P(0); RangeVar *viewrel; Oid viewoid; viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname)); viewoid = RangeVarGetRelid(viewrel, false); PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, 0)));}Datumpg_get_viewdef_name_ext(PG_FUNCTION_ARGS){ /* By qualified name */ text *viewname = PG_GETARG_TEXT_P(0); bool pretty = PG_GETARG_BOOL(1); int prettyFlags; RangeVar *viewrel; Oid viewoid; prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0; viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname)); viewoid = RangeVarGetRelid(viewrel, false); PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags)));}/* * Common code for by-OID and by-name variants of pg_get_viewdef */static char *pg_get_viewdef_worker(Oid viewoid, int prettyFlags){ Datum args[2]; char nulls[2]; int spirc; HeapTuple ruletup; TupleDesc rulettc; StringInfoData buf; /* * Do this first so that string is alloc'd in outer context not SPI's. */ initStringInfo(&buf); /* * Connect to SPI manager */ if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "SPI_connect failed"); /* * On the first call prepare the plan to lookup pg_rewrite. We read * pg_rewrite over the SPI manager instead of using the syscache to be * checked for read access on pg_rewrite. */ if (plan_getviewrule == NULL) { Oid argtypes[2]; void *plan; argtypes[0] = OIDOID; argtypes[1] = NAMEOID; plan = SPI_prepare(query_getviewrule, 2, argtypes); if (plan == NULL) elog(ERROR, "SPI_prepare failed for \"%s\"", query_getviewrule); plan_getviewrule = SPI_saveplan(plan); } /* * Get the pg_rewrite tuple for the view's SELECT rule */ args[0] = ObjectIdGetDatum(viewoid); args[1] = PointerGetDatum(ViewSelectRuleName); nulls[0] = ' '; nulls[1] = ' '; spirc = SPI_execute_plan(plan_getviewrule, args, nulls, true, 2); if (spirc != SPI_OK_SELECT) elog(ERROR, "failed to get pg_rewrite tuple for view %u", viewoid); if (SPI_processed != 1) appendStringInfo(&buf, "Not a view"); else { /* * Get the rules definition and put it into executors memory */ ruletup = SPI_tuptable->vals[0]; rulettc = SPI_tuptable->tupdesc; make_viewdef(&buf, ruletup, rulettc, prettyFlags); } /* * Disconnect from SPI manager */ if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed"); return buf.data;}/* ---------- * get_triggerdef - Get the definition of a trigger * ---------- */Datumpg_get_triggerdef(PG_FUNCTION_ARGS){ Oid trigid = PG_GETARG_OID(0); HeapTuple ht_trig; Form_pg_trigger trigrec; StringInfoData buf; Relation tgrel; ScanKeyData skey[1]; SysScanDesc tgscan; int findx = 0; char *tgname; /* * Fetch the pg_trigger tuple by the Oid of the trigger */ tgrel = heap_open(TriggerRelationId, AccessShareLock); ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(trigid)); tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true, SnapshotNow, 1, skey); ht_trig = systable_getnext(tgscan); if (!HeapTupleIsValid(ht_trig)) elog(ERROR, "could not find tuple for trigger %u", trigid); trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?