From 9dafb02698c5d0e320abcbcbcbcc4be4424c15c0 Mon Sep 17 00:00:00 2001 From: Ajin Cherian Date: Thu, 9 Feb 2023 03:15:22 -0500 Subject: [PATCH v67 1/7] Infrastructure to support DDL deparsing. Infrastructure to support DDL deparsing. 1) Some of the event trigger structures were moved from event_trigger.c to event_trigger.h as these will be required for publication event trigger creation. 2) Some of the prototypes and structures were moved from pg_publication.h to publicationcmds.h. This was because one of the later patch required the inclusion of pg_publication.h and these prototype had references to server header files. 3) Change the object identity to match with the syntax in objectaddress.c This is so that the deparse logic can use this identity directly in the deparse logic. --- src/backend/catalog/aclchk.c | 9 +- src/backend/catalog/objectaddress.c | 2 +- src/backend/commands/collationcmds.c | 10 +- src/backend/commands/event_trigger.c | 40 +---- src/backend/commands/seclabel.c | 3 + src/backend/commands/sequence.c | 32 ++++ src/backend/replication/pgoutput/pgoutput.c | 1 + src/backend/tcop/utility.c | 94 +++++++++- src/backend/utils/adt/format_type.c | 4 +- src/backend/utils/adt/regproc.c | 53 ++++++ src/backend/utils/adt/ruleutils.c | 258 ++++++++++++++++++++------- src/include/catalog/pg_publication.h | 17 +- src/include/commands/collationcmds.h | 3 +- src/include/commands/event_trigger.h | 39 ++++ src/include/commands/publicationcmds.h | 14 ++ src/include/commands/sequence.h | 1 + src/include/tcop/utility.h | 2 + src/include/utils/acl.h | 2 + src/include/utils/aclchk_internal.h | 1 + src/include/utils/builtins.h | 2 + src/include/utils/rel.h | 2 + src/include/utils/ruleutils.h | 19 ++ src/test/regress/expected/object_address.out | 2 +- 23 files changed, 475 insertions(+), 135 deletions(-) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index c423234..36a6677 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -129,7 +129,6 @@ static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm, AclMode *col_privileges, int num_col_privileges); static AclMode string_to_privilege(const char *privname); -static const char *privilege_to_string(AclMode privilege); static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, AclMode privileges, Oid objectId, Oid grantorId, @@ -385,11 +384,10 @@ ExecuteGrantStmt(GrantStmt *stmt) ListCell *cell; const char *errormsg; AclMode all_privileges; + Oid grantor = InvalidOid; if (stmt->grantor) { - Oid grantor; - grantor = get_rolespec_oid(stmt->grantor, false); /* @@ -408,6 +406,9 @@ ExecuteGrantStmt(GrantStmt *stmt) istmt.is_grant = stmt->is_grant; istmt.objtype = stmt->objtype; + /* Copy the grantor id needed for DDL deparsing of Grant */ + istmt.grantor_uid = grantor; + /* Collect the OIDs of the target objects */ switch (stmt->targtype) { @@ -2628,7 +2629,7 @@ string_to_privilege(const char *privname) return 0; /* appease compiler */ } -static const char * +const char * privilege_to_string(AclMode privilege) { switch (privilege) diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 25c50d6..2f68816 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -5922,7 +5922,7 @@ getObjectIdentityParts(const ObjectAddress *object, transformType = format_type_be_qualified(transform->trftype); transformLang = get_language_name(transform->trflang, false); - appendStringInfo(&buffer, "for %s on language %s", + appendStringInfo(&buffer, "for %s language %s", transformType, transformLang); if (objname) diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c index eb62d28..f43de14 100644 --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -52,7 +52,8 @@ typedef struct * CREATE COLLATION */ ObjectAddress -DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists) +DefineCollation(ParseState *pstate, List *names, List *parameters, + bool if_not_exists, ObjectAddress *from_existing_collid) { char *collName; Oid collNamespace; @@ -139,6 +140,13 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e if (!HeapTupleIsValid(tp)) elog(ERROR, "cache lookup failed for collation %u", collid); + /* + * Make from existing collationid available to callers for statements such as + * CREATE COLLATION any_name FROM any_name + */ + if (from_existing_collid && OidIsValid(collid)) + ObjectAddressSet(*from_existing_collid, CollationRelationId, collid); + collprovider = ((Form_pg_collation) GETSTRUCT(tp))->collprovider; collisdeterministic = ((Form_pg_collation) GETSTRUCT(tp))->collisdeterministic; collencoding = ((Form_pg_collation) GETSTRUCT(tp))->collencoding; diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index d4b00d1..6902709 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -48,45 +48,7 @@ #include "utils/rel.h" #include "utils/syscache.h" -typedef struct EventTriggerQueryState -{ - /* memory context for this state's objects */ - MemoryContext cxt; - - /* sql_drop */ - slist_head SQLDropList; - bool in_sql_drop; - - /* table_rewrite */ - Oid table_rewrite_oid; /* InvalidOid, or set for table_rewrite - * event */ - int table_rewrite_reason; /* AT_REWRITE reason */ - - /* Support for command collection */ - bool commandCollectionInhibited; - CollectedCommand *currentCommand; - List *commandList; /* list of CollectedCommand; see - * deparse_utility.h */ - struct EventTriggerQueryState *previous; -} EventTriggerQueryState; - -static EventTriggerQueryState *currentEventTriggerState = NULL; - -/* Support for dropped objects */ -typedef struct SQLDropObject -{ - ObjectAddress address; - const char *schemaname; - const char *objname; - const char *objidentity; - const char *objecttype; - List *addrnames; - List *addrargs; - bool original; - bool normal; - bool istemp; - slist_node next; -} SQLDropObject; +EventTriggerQueryState *currentEventTriggerState = NULL; static void AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c index 7ff16e3..1e831ff 100644 --- a/src/backend/commands/seclabel.c +++ b/src/backend/commands/seclabel.c @@ -134,6 +134,9 @@ ExecSecLabelStmt(SecLabelStmt *stmt) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("must specify provider when multiple security label providers have been loaded"))); provider = (LabelProvider *) linitial(label_provider_list); + + /* Copy the provider name to the parsetree, needed for DDL deparsing of SecLabelStmt */ + stmt->provider = pstrdup(provider->provider_name); } else { diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index bfe279c..29cf70e 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -1708,6 +1708,38 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity) relation_close(tablerel, NoLock); } +/* + * Return sequence parameters, detailed + */ +Form_pg_sequence_data +get_sequence_values(Oid sequenceId) +{ + Buffer buf; + SeqTable elm; + Relation seqrel; + HeapTupleData seqtuple; + Form_pg_sequence_data seq; + Form_pg_sequence_data retSeq = palloc(sizeof(FormData_pg_sequence_data)); + + /* Open and AccessShareLock sequence */ + init_sequence(sequenceId, &elm, &seqrel); + + if (pg_class_aclcheck(sequenceId, GetUserId(), + ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied for sequence %s", + RelationGetRelationName(seqrel)))); + + seq = read_seq_tuple(seqrel, &buf, &seqtuple); + + memcpy(retSeq, seq, sizeof(FormData_pg_sequence_data)); + + UnlockReleaseBuffer(buf); + relation_close(seqrel, NoLock); + + return retSeq; +} /* * Return sequence parameters in a list of the form created by the parser. diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c index 73b0800..f6290d6 100644 --- a/src/backend/replication/pgoutput/pgoutput.c +++ b/src/backend/replication/pgoutput/pgoutput.c @@ -18,6 +18,7 @@ #include "catalog/pg_publication_rel.h" #include "catalog/pg_subscription.h" #include "commands/defrem.h" +#include "commands/publicationcmds.h" #include "commands/subscriptioncmds.h" #include "executor/executor.h" #include "fmgr.h" diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index c7d9d96..731a9e2 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1446,7 +1446,8 @@ ProcessUtilitySlow(ParseState *pstate, address = DefineCollation(pstate, stmt->defnames, stmt->definition, - stmt->if_not_exists); + stmt->if_not_exists, + &secondaryObject); break; default: elog(ERROR, "unrecognized define stmt type: %d", @@ -2196,6 +2197,97 @@ UtilityContainsQuery(Node *parsetree) } } +/* + * Return the given object type as a string. + * If isgrant is true, then this function is called + * while deparsing GRANT statement and some object + * names are replaced. + */ +const char * +stringify_objtype(ObjectType objtype, bool isgrant) +{ + switch (objtype) + { + case OBJECT_AGGREGATE: + return "AGGREGATE"; + case OBJECT_CAST: + return "CAST"; + case OBJECT_COLLATION: + return "COLLATION"; + case OBJECT_COLUMN: + return isgrant ? "TABLE" : "COLUMN"; + case OBJECT_CONVERSION: + return "CONVERSION"; + case OBJECT_DATABASE: + return "DATABASE"; + case OBJECT_DOMAIN: + return "DOMAIN"; + case OBJECT_EVENT_TRIGGER: + return "EVENT TRIGGER"; + case OBJECT_EXTENSION: + return "EXTENSION"; + case OBJECT_FDW: + return "FOREIGN DATA WRAPPER"; + case OBJECT_FOREIGN_SERVER: + return isgrant ? "FOREIGN SERVER" : "SERVER"; + case OBJECT_FOREIGN_TABLE: + return "FOREIGN TABLE"; + case OBJECT_FUNCTION: + return "FUNCTION"; + case OBJECT_INDEX: + return "INDEX"; + case OBJECT_LANGUAGE: + return "LANGUAGE"; + case OBJECT_LARGEOBJECT: + return "LARGE OBJECT"; + case OBJECT_MATVIEW: + return "MATERIALIZED VIEW"; + case OBJECT_OPCLASS: + return "OPERATOR CLASS"; + case OBJECT_OPERATOR: + return "OPERATOR"; + case OBJECT_OPFAMILY: + return "OPERATOR FAMILY"; + case OBJECT_POLICY: + return "POLICY"; + case OBJECT_PROCEDURE: + return "PROCEDURE"; + case OBJECT_ROLE: + return "ROLE"; + case OBJECT_ROUTINE: + return "ROUTINE"; + case OBJECT_RULE: + return "RULE"; + case OBJECT_SCHEMA: + return "SCHEMA"; + case OBJECT_SEQUENCE: + return "SEQUENCE"; + case OBJECT_STATISTIC_EXT: + return "STATISTICS"; + case OBJECT_TABLE: + return "TABLE"; + case OBJECT_TABLESPACE: + return "TABLESPACE"; + case OBJECT_TRIGGER: + return "TRIGGER"; + case OBJECT_TSCONFIGURATION: + return "TEXT SEARCH CONFIGURATION"; + case OBJECT_TSDICTIONARY: + return "TEXT SEARCH DICTIONARY"; + case OBJECT_TSPARSER: + return "TEXT SEARCH PARSER"; + case OBJECT_TSTEMPLATE: + return "TEXT SEARCH TEMPLATE"; + case OBJECT_TYPE: + return "TYPE"; + case OBJECT_USER_MAPPING: + return "USER MAPPING"; + case OBJECT_VIEW: + return "VIEW"; + default: + elog(ERROR, "unsupported object type %d", objtype); + } +} /* * AlterObjectTypeCommandTag diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index 12402a0..7b476ad 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -27,8 +27,6 @@ #include "utils/numeric.h" #include "utils/syscache.h" -static char *printTypmod(const char *typname, int32 typmod, Oid typmodout); - /* * SQL function: format_type(type_oid, typemod) @@ -363,7 +361,7 @@ format_type_with_typemod(Oid type_oid, int32 typemod) /* * Add typmod decoration to the basic type name */ -static char * +char * printTypmod(const char *typname, int32 typmod, Oid typmodout) { char *res; diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 296930e..ab1af55 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -49,6 +49,8 @@ static bool parseNameAndArgTypes(const char *string, bool allowNone, List **names, int *nargs, Oid *argtypes, Node *escontext); +static void format_procedure_args_internal(Form_pg_proc procform, + StringInfo buf, bool force_qualify); /***************************************************************************** * USER I/O ROUTINES * @@ -308,6 +310,29 @@ format_procedure_qualified(Oid procedure_oid) } /* + * format_procedure_args - converts proc OID to "(args)" + */ +char * +format_procedure_args(Oid procedure_oid, bool force_qualify) +{ + StringInfoData buf; + HeapTuple proctup; + Form_pg_proc procform; + + proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid)); + if (!HeapTupleIsValid(proctup)) + elog(ERROR, "cache lookup failed for procedure %u", procedure_oid); + procform = (Form_pg_proc) GETSTRUCT(proctup); + + initStringInfo(&buf); + format_procedure_args_internal(procform, &buf, force_qualify); + + ReleaseSysCache(proctup); + + return buf.data; +} + +/* * format_procedure_extended - converts procedure OID to "pro_name(args)" * * This exports the useful functionality of regprocedureout for use @@ -2016,3 +2041,31 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, return true; } + +/* + * Append the parenthesized arguments of the given pg_proc row into the output + * buffer. force_qualify indicates whether to schema-qualify type names + * regardless of visibility. + */ +static void +format_procedure_args_internal(Form_pg_proc procform, StringInfo buf, + bool force_qualify) +{ + int i; + char* (*func[2])(Oid) = {format_type_be, format_type_be_qualified}; + + appendStringInfoChar(buf, '('); + for (i = 0; i < procform->pronargs; i++) + { + Oid thisargtype = procform->proargtypes.values[i]; + char *argtype; + + if (i > 0) + appendStringInfoChar(buf, ','); + + argtype = func[force_qualify](thisargtype); + appendStringInfoString(buf, argtype); + pfree(argtype); + } + appendStringInfoChar(buf, ')'); +} diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9ac42ef..62d7f7c 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -35,6 +35,7 @@ #include "catalog/pg_operator.h" #include "catalog/pg_partitioned_table.h" #include "catalog/pg_proc.h" +#include "catalog/pg_rewrite.h" #include "catalog/pg_statistic_ext.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" @@ -358,7 +359,6 @@ static int print_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults); static void print_function_rettype(StringInfo buf, HeapTuple proctup); static void print_function_trftypes(StringInfo buf, HeapTuple proctup); -static void print_function_sqlbody(StringInfo buf, HeapTuple proctup); static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces, Bitmapset *rels_used); static void set_deparse_for_query(deparse_namespace *dpns, Query *query, @@ -482,22 +482,15 @@ static void get_from_clause_coldeflist(RangeTblFunction *rtfunc, deparse_context *context); static void get_tablesample_def(TableSampleClause *tablesample, 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(SubscriptingRef *sbsref, deparse_context *context); static char *get_relation_name(Oid relid); static char *generate_relation_name(Oid relid, List *namespaces); static char *generate_qualified_relation_name(Oid relid); -static char *generate_function_name(Oid funcid, int nargs, - List *argnames, Oid *argtypes, - bool has_variadic, bool *use_variadic_p, - ParseExprKind special_exprkind); static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2); static void add_cast_to(StringInfo buf, Oid typid); static char *generate_qualified_type_name(Oid typid); static text *string_to_text(char *str); -static char *flatten_reloptions(Oid relid); static void get_reloptions(StringInfo buf, Datum reloptions); #define only_marker(rte) ((rte)->inh ? "" : "ONLY ") @@ -545,6 +538,104 @@ pg_get_ruledef_ext(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(string_to_text(res)); } +/* + * Given a pair of Datum corresponding to a rule's pg_rewrite.ev_qual and + * ev_action columns, return their text representation; ev_qual as a single + * string in whereClause and ev_action as a List of strings (which might be + * NIL, signalling NOTHING) in actions. + */ +void +pg_get_ruledef_detailed(Datum ev_qual, Datum ev_action, + char **whereClause, List **actions) +{ + int prettyFlags = 0; + char *qualstr = TextDatumGetCString(ev_qual); + char *actionstr = TextDatumGetCString(ev_action); + List *actionNodeList = (List *) stringToNode(actionstr); + StringInfoData buf; + + *whereClause = NULL; + *actions = NIL; + initStringInfo(&buf); + if (*qualstr && strcmp(qualstr, "<>") != 0) + { + Node *qual; + Query *query; + deparse_context context; + deparse_namespace dpns; + + qual = stringToNode(qualstr); + + query = (Query *) linitial(actionNodeList); + query = getInsertSelectQuery(query, NULL); + + AcquireRewriteLocks(query, false, false); + + context.buf = &buf; + context.namespaces = list_make1(&dpns); + context.windowClause = NIL; + context.windowTList = NIL; + context.varprefix = (list_length(query->rtable) != 1); + context.prettyFlags = prettyFlags; + context.wrapColumn = WRAP_COLUMN_DEFAULT; + context.indentLevel = PRETTYINDENT_STD; + + set_deparse_for_query(&dpns, query, NIL); + + get_rule_expr(qual, &context, false); + + *whereClause = pstrdup(buf.data); + } + + if (list_length(actionNodeList) > 0) + { + ListCell *cell; + + foreach(cell, actionNodeList) + { + Query *query = (Query *) lfirst(cell); + + if (query->commandType == CMD_NOTHING) + continue; + + resetStringInfo(&buf); + get_query_def(query, &buf, NIL, NULL, true, + prettyFlags, WRAP_COLUMN_DEFAULT, 0); + *actions = lappend(*actions, pstrdup(buf.data)); + } + } +} + +/* + * To get the rewrite rule of a view when the CREATE VIEW command execution is + * still in progress: we search the system cache RULERELNAME to get the rewrite + * rule of the view as opposed to querying pg_rewrite as in pg_get_viewdef_worker(), + * which will return empty result. + */ +char * +pg_get_viewdef_internal(Oid viewoid) +{ + StringInfoData buf; + Relation pg_rewrite; + HeapTuple ruletup; + TupleDesc rulettc; + + initStringInfo(&buf); + pg_rewrite = table_open(RewriteRelationId, AccessShareLock); + + ruletup = SearchSysCache2(RULERELNAME, + ObjectIdGetDatum(viewoid), + PointerGetDatum(ViewSelectRuleName)); + if (!HeapTupleIsValid(ruletup)) + elog(ERROR, "cache lookup failed for rewrite rule for view with OID %u", viewoid); + + rulettc = pg_rewrite->rd_att; + make_viewdef(&buf, ruletup, rulettc, 0, WRAP_COLUMN_DEFAULT); + ReleaseSysCache(ruletup); + table_close(pg_rewrite, AccessShareLock); + + return buf.data; +} static char * pg_get_ruledef_worker(Oid ruleoid, int prettyFlags) @@ -1015,65 +1106,12 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) if (!isnull) { Node *qual; - char relkind; - deparse_context context; - deparse_namespace dpns; - RangeTblEntry *oldrte; - RangeTblEntry *newrte; - - appendStringInfoString(&buf, "WHEN ("); + char *qualstr; qual = stringToNode(TextDatumGetCString(value)); + qualstr = pg_get_trigger_whenclause(trigrec, qual, pretty); - relkind = get_rel_relkind(trigrec->tgrelid); - - /* Build minimal OLD and NEW RTEs for the rel */ - oldrte = makeNode(RangeTblEntry); - oldrte->rtekind = RTE_RELATION; - oldrte->relid = trigrec->tgrelid; - oldrte->relkind = relkind; - oldrte->rellockmode = AccessShareLock; - oldrte->alias = makeAlias("old", NIL); - oldrte->eref = oldrte->alias; - oldrte->lateral = false; - oldrte->inh = false; - oldrte->inFromCl = true; - - newrte = makeNode(RangeTblEntry); - newrte->rtekind = RTE_RELATION; - newrte->relid = trigrec->tgrelid; - newrte->relkind = relkind; - newrte->rellockmode = AccessShareLock; - newrte->alias = makeAlias("new", NIL); - newrte->eref = newrte->alias; - newrte->lateral = false; - newrte->inh = false; - newrte->inFromCl = true; - - /* Build two-element rtable */ - memset(&dpns, 0, sizeof(dpns)); - dpns.rtable = list_make2(oldrte, newrte); - dpns.subplans = NIL; - dpns.ctes = NIL; - dpns.appendrels = NULL; - set_rtable_names(&dpns, NIL, NULL); - set_simple_column_names(&dpns); - - /* Set up context with one-deep namespace stack */ - context.buf = &buf; - context.namespaces = list_make1(&dpns); - context.windowClause = NIL; - context.windowTList = NIL; - context.varprefix = true; - context.prettyFlags = GET_PRETTY_FLAGS(pretty); - context.wrapColumn = WRAP_COLUMN_DEFAULT; - context.indentLevel = PRETTYINDENT_STD; - context.special_exprkind = EXPR_KIND_NONE; - context.appendparents = NULL; - - get_rule_expr(qual, &context, false); - - appendStringInfoString(&buf, ") "); + appendStringInfo(&buf, "WHEN (%s) ", qualstr); } appendStringInfo(&buf, "EXECUTE FUNCTION %s(", @@ -1114,6 +1152,69 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) return buf.data; } +/* + * Pass back the TriggerWhen clause of a trigger given the pg_trigger record and + * the expression tree (in nodeToString() representation) from pg_trigger.tgqual + * for the trigger's WHEN condition. + */ +char * +pg_get_trigger_whenclause(Form_pg_trigger trigrec, Node *whenClause, bool pretty) +{ + StringInfoData buf; + char relkind; + deparse_context context; + deparse_namespace dpns; + RangeTblEntry *oldrte; + RangeTblEntry *newrte; + + initStringInfo(&buf); + + relkind = get_rel_relkind(trigrec->tgrelid); + + /* Build minimal OLD and NEW RTEs for the rel */ + oldrte = makeNode(RangeTblEntry); + oldrte->rtekind = RTE_RELATION; + oldrte->relid = trigrec->tgrelid; + oldrte->relkind = relkind; + oldrte->alias = makeAlias("old", NIL); + oldrte->eref = oldrte->alias; + oldrte->lateral = false; + oldrte->inh = false; + oldrte->inFromCl = true; + + newrte = makeNode(RangeTblEntry); + newrte->rtekind = RTE_RELATION; + newrte->relid = trigrec->tgrelid; + newrte->relkind = relkind; + newrte->alias = makeAlias("new", NIL); + newrte->eref = newrte->alias; + newrte->lateral = false; + newrte->inh = false; + newrte->inFromCl = true; + + /* Build two-element rtable */ + memset(&dpns, 0, sizeof(dpns)); + dpns.rtable = list_make2(oldrte, newrte); + dpns.ctes = NIL; + set_rtable_names(&dpns, NIL, NULL); + set_simple_column_names(&dpns); + + /* Set up context with one-deep namespace stack */ + context.buf = &buf; + context.namespaces = list_make1(&dpns); + context.windowClause = NIL; + context.windowTList = NIL; + context.varprefix = true; + context.prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT; + context.wrapColumn = WRAP_COLUMN_DEFAULT; + context.indentLevel = PRETTYINDENT_STD; + context.special_exprkind = EXPR_KIND_NONE; + + get_rule_expr(whenClause, &context, false); + + return buf.data; +} + /* ---------- * pg_get_indexdef - Get the definition of an index * @@ -1880,6 +1981,13 @@ pg_get_partkeydef_columns(Oid relid, bool pretty) return pg_get_partkeydef_worker(relid, prettyFlags, true, false); } +/* Internal version that reports the full partition key definition */ +char * +pg_get_partkeydef_simple(Oid relid) +{ + return pg_get_partkeydef_worker(relid, 0, false, false); +} + /* * Internal workhorse to decompile a partition key definition. */ @@ -2132,6 +2240,15 @@ pg_get_constraintdef_ext(PG_FUNCTION_ARGS) } /* + * Internal version that returns the definition of a CONSTRAINT command + */ +char * +pg_get_constraintdef_command_simple(Oid constraintId) +{ + return pg_get_constraintdef_worker(constraintId, false, 0, false); +} + +/* * Internal version that returns a full ALTER TABLE ... ADD CONSTRAINT command */ char * @@ -3501,7 +3618,12 @@ pg_get_function_arg_default(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(string_to_text(str)); } -static void +/* + * Produce the formatted SQL body (not the whole function definition) + * of a function given the pg_proc tuple. Save the formatted SQL in the + * given StringInfo. + */ +void print_function_sqlbody(StringInfo buf, HeapTuple proctup) { int numargs; @@ -11357,7 +11479,7 @@ get_tablesample_def(TableSampleClause *tablesample, deparse_context *context) * actual_datatype. (If you don't want this behavior, just pass * InvalidOid for actual_datatype.) */ -static void +void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf) { @@ -11751,7 +11873,7 @@ generate_qualified_relation_name(Oid relid) * * The result includes all necessary quoting and schema-prefixing. */ -static char * +char * generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, bool has_variadic, bool *use_variadic_p, ParseExprKind special_exprkind) @@ -12137,7 +12259,7 @@ get_reloptions(StringInfo buf, Datum reloptions) /* * Generate a C string representing a relation's reloptions, or NULL if none. */ -static char * +char * flatten_reloptions(Oid relid) { char *result = NULL; diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index 6ecaa2a..715f2a2 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -18,8 +18,8 @@ #define PG_PUBLICATION_H #include "catalog/genbki.h" -#include "catalog/objectaddress.h" #include "catalog/pg_publication_d.h" +#include "nodes/pg_list.h" /* ---------------- * pg_publication definition. cpp turns this into @@ -103,12 +103,6 @@ typedef struct Publication PublicationActions pubactions; } Publication; -typedef struct PublicationRelInfo -{ - Relation relation; - Node *whereClause; - List *columns; -} PublicationRelInfo; extern Publication *GetPublication(Oid pubid); extern Publication *GetPublicationByName(const char *pubname, bool missing_ok); @@ -144,15 +138,6 @@ extern List *GetPubPartitionOptionRelations(List *result, Oid relid); extern Oid GetTopMostAncestorInPublication(Oid puboid, List *ancestors, int *ancestor_level); - -extern bool is_publishable_relation(Relation rel); extern bool is_schema_publication(Oid pubid); -extern ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri, - bool if_not_exists); -extern ObjectAddress publication_add_schema(Oid pubid, Oid schemaid, - bool if_not_exists); - -extern Bitmapset *pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, - MemoryContext mcxt); #endif /* PG_PUBLICATION_H */ diff --git a/src/include/commands/collationcmds.h b/src/include/commands/collationcmds.h index b76c7b3..53c4a1a 100644 --- a/src/include/commands/collationcmds.h +++ b/src/include/commands/collationcmds.h @@ -18,7 +18,8 @@ #include "catalog/objectaddress.h" #include "parser/parse_node.h" -extern ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists); +extern ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, + bool if_not_exists, ObjectAddress *from_collid); extern void IsThereCollationInNamespace(const char *collname, Oid nspOid); extern ObjectAddress AlterCollation(AlterCollationStmt *stmt); diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h index 5ed6ece..48c65ef 100644 --- a/src/include/commands/event_trigger.h +++ b/src/include/commands/event_trigger.h @@ -16,6 +16,7 @@ #include "catalog/dependency.h" #include "catalog/objectaddress.h" #include "catalog/pg_event_trigger.h" +#include "lib/ilist.h" #include "nodes/parsenodes.h" #include "tcop/cmdtag.h" #include "tcop/deparse_utility.h" @@ -29,6 +30,44 @@ typedef struct EventTriggerData CommandTag tag; } EventTriggerData; +typedef struct EventTriggerQueryState +{ + /* memory context for this state's objects */ + MemoryContext cxt; + + /* sql_drop */ + slist_head SQLDropList; + bool in_sql_drop; + + /* table_rewrite */ + Oid table_rewrite_oid; /* InvalidOid, or set for table_rewrite + * event */ + int table_rewrite_reason; /* AT_REWRITE reason */ + + /* Support for command collection */ + bool commandCollectionInhibited; + CollectedCommand *currentCommand; + List *commandList; /* list of CollectedCommand; see + * deparse_utility.h */ + struct EventTriggerQueryState *previous; +} EventTriggerQueryState; + +/* Support for dropped objects */ +typedef struct SQLDropObject +{ + ObjectAddress address; + const char *schemaname; + const char *objname; + const char *objidentity; + const char *objecttype; + List *addrnames; + List *addrargs; + bool original; + bool normal; + bool istemp; + slist_node next; +} SQLDropObject; + #define AT_REWRITE_ALTER_PERSISTENCE 0x01 #define AT_REWRITE_DEFAULT_VAL 0x02 #define AT_REWRITE_COLUMN_REWRITE 0x04 diff --git a/src/include/commands/publicationcmds.h b/src/include/commands/publicationcmds.h index 70d5e36..a3fca9e 100644 --- a/src/include/commands/publicationcmds.h +++ b/src/include/commands/publicationcmds.h @@ -22,6 +22,13 @@ /* Same as MAXNUMMESSAGES in sinvaladt.c */ #define MAX_RELCACHE_INVAL_MSGS 4096 +typedef struct PublicationRelInfo +{ + Relation relation; + Node *whereClause; + List *columns; +} PublicationRelInfo; + extern ObjectAddress CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt); extern void AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt); extern void RemovePublicationById(Oid pubid); @@ -35,5 +42,12 @@ extern bool pub_rf_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot); extern bool pub_collist_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot); +extern Bitmapset *pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, + MemoryContext mcxt); +extern ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri, + bool if_not_exists); +extern ObjectAddress publication_add_schema(Oid pubid, Oid schemaid, + bool if_not_exists); +extern bool is_publishable_relation(Relation rel); #endif /* PUBLICATIONCMDS_H */ diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 7db7b3d..309da0c 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -54,6 +54,7 @@ typedef struct xl_seq_rec extern int64 nextval_internal(Oid relid, bool check_permissions); extern Datum nextval(PG_FUNCTION_ARGS); extern List *sequence_options(Oid relid); +extern Form_pg_sequence_data get_sequence_values(Oid sequenceId); extern ObjectAddress DefineSequence(ParseState *pstate, CreateSeqStmt *seq); extern ObjectAddress AlterSequence(ParseState *pstate, AlterSeqStmt *stmt); diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h index 59e64ae..a68ce3d 100644 --- a/src/include/tcop/utility.h +++ b/src/include/tcop/utility.h @@ -99,6 +99,8 @@ extern Query *UtilityContainsQuery(Node *parsetree); extern CommandTag CreateCommandTag(Node *parsetree); +extern const char *stringify_objtype(ObjectType objtype, bool isgrant); + static inline const char * CreateCommandName(Node *parsetree) { diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index f8e1238..f05578d 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -209,6 +209,8 @@ extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how); extern int aclmembers(const Acl *acl, Oid **roleids); +extern const char *privilege_to_string(AclMode privilege); + extern bool has_privs_of_role(Oid member, Oid role); extern bool member_can_set_role(Oid member, Oid role); extern void check_can_set_role(Oid member, Oid role); diff --git a/src/include/utils/aclchk_internal.h b/src/include/utils/aclchk_internal.h index 55af624..946545f 100644 --- a/src/include/utils/aclchk_internal.h +++ b/src/include/utils/aclchk_internal.h @@ -39,6 +39,7 @@ typedef struct List *grantees; bool grant_option; DropBehavior behavior; + Oid grantor_uid; } InternalGrant; diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 2f8b46d..48b8bfd 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -123,10 +123,12 @@ extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS); #define FORMAT_TYPE_FORCE_QUALIFY 0x04 /* force qualification of type */ #define FORMAT_TYPE_INVALID_AS_NULL 0x08 /* NULL if undefined */ extern char *format_type_extended(Oid type_oid, int32 typemod, bits16 flags); +extern char *format_procedure_args(Oid procedure_oid, bool force_qualify); extern char *format_type_be(Oid type_oid); extern char *format_type_be_qualified(Oid type_oid); extern char *format_type_with_typemod(Oid type_oid, int32 typemod); +extern char *printTypmod(const char *typname, int32 typmod, Oid typmodout); extern int32 type_maximum_size(Oid type_oid, int32 typemod); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index af97850..103b392 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -16,10 +16,12 @@ #include "access/tupdesc.h" #include "access/xlog.h" +#include "catalog/objectaddress.h" #include "catalog/pg_class.h" #include "catalog/pg_index.h" #include "catalog/pg_publication.h" #include "nodes/bitmapset.h" +#include "nodes/lockoptions.h" #include "partitioning/partdefs.h" #include "rewrite/prs2lock.h" #include "storage/block.h" diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h index 1a42d9f..c33c8d0 100644 --- a/src/include/utils/ruleutils.h +++ b/src/include/utils/ruleutils.h @@ -13,9 +13,12 @@ #ifndef RULEUTILS_H #define RULEUTILS_H +#include "access/htup.h" +#include "catalog/pg_trigger.h" #include "nodes/nodes.h" #include "nodes/parsenodes.h" #include "nodes/pg_list.h" +#include "parser/parse_node.h" struct Plan; /* avoid including plannodes.h here */ struct PlannedStmt; @@ -23,12 +26,20 @@ struct PlannedStmt; extern char *pg_get_indexdef_string(Oid indexrelid); extern char *pg_get_indexdef_columns(Oid indexrelid, bool pretty); +extern char *pg_get_trigger_whenclause(Form_pg_trigger trigrec, + Node *whenClause, bool pretty); extern char *pg_get_querydef(Query *query, bool pretty); +extern char *pg_get_viewdef_internal(Oid viewoid); extern char *pg_get_partkeydef_columns(Oid relid, bool pretty); +extern char *pg_get_partkeydef_simple(Oid relid); extern char *pg_get_partconstrdef_string(Oid partitionId, char *aliasname); extern char *pg_get_constraintdef_command(Oid constraintId); +extern char *pg_get_constraintdef_command_simple(Oid constraintId); +extern void pg_get_ruledef_detailed(Datum ev_qual, Datum ev_action, + char **whereClause, List **actions); + extern char *deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit); extern List *deparse_context_for(const char *aliasname, Oid relid); @@ -40,8 +51,16 @@ extern List *select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used); extern char *generate_collation_name(Oid collid); extern char *generate_opclass_name(Oid opclass); +extern char *generate_function_name(Oid funcid, int nargs, List *argnames, + Oid *argtypes, bool has_variadic, + bool *use_variadic_p, + ParseExprKind special_exprkind); extern char *get_range_partbound_string(List *bound_datums); +extern void get_opclass_name(Oid opclass, Oid actual_datatype, + StringInfo buf); +extern char *flatten_reloptions(Oid relid); extern char *pg_get_statisticsobjdef_string(Oid statextid); +extern void print_function_sqlbody(StringInfo buf, HeapTuple proctup); #endif /* RULEUTILS_H */ diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 25c174f..fc42d41 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -496,7 +496,7 @@ operator family|pg_catalog|integer_ops|pg_catalog.integer_ops USING btree|t policy|NULL|NULL|genpol on addr_nsp.gentable|t statistics object|addr_nsp|gentable_stat|addr_nsp.gentable_stat|t collation|pg_catalog|"default"|pg_catalog."default"|t -transform|NULL|NULL|for integer on language sql|t +transform|NULL|NULL|for integer language sql|t text search dictionary|addr_nsp|addr_ts_dict|addr_nsp.addr_ts_dict|t text search parser|addr_nsp|addr_ts_prs|addr_nsp.addr_ts_prs|t text search configuration|addr_nsp|addr_ts_conf|addr_nsp.addr_ts_conf|t -- 1.8.3.1