From 554723f44b6c152bded961137e267fc827de0f00 Mon Sep 17 00:00:00 2001 From: Ajin Cherian Date: Fri, 3 Feb 2023 07:20:31 -0500 Subject: [PATCH v66 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 prototype and structures were moved from pg_publication.h to publicationcmds.h as one of the later patch requires inclusion of pg_publication.h and these prototype had references to server header files. --- 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 | 33 +++ src/backend/replication/pgoutput/pgoutput.c | 1 + src/backend/tcop/utility.c | 91 ++++++- 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/replication/logicalrelation.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 +- 24 files changed, 474 insertions(+), 135 deletions(-) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index c4232344aa..36a6677113 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 25c50d66fd..2f688166e1 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 6a4311cc63..ab2af2d277 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 statement 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 d4b00d1a82..6902709956 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 7ff16e3276..1e831ff720 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 bfe279cddf..3049e0e902 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -1708,6 +1708,39 @@ 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; + + /* 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); + retSeq = palloc(sizeof(FormData_pg_sequence_data)); + + 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 1a80d67bb9..a0ec3e5030 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 c7d9d96b45..1e83cfe393 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,94 @@ UtilityContainsQuery(Node *parsetree) } } +/* + * Return the given object type as a string. + */ +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 12402a0637..7b476adb23 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 296930eb3b..128c1795a1 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 * @@ -307,6 +309,29 @@ format_procedure_qualified(Oid procedure_oid) return format_procedure_extended(procedure_oid, FORMAT_PROC_FORCE_QUALIFY); } +/* + * 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)" * @@ -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 = NULL; + + 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 9ac42efdbc..1f41206618 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 (strlen(qualstr) > 0 && 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; } +/* + * Parse 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. */ @@ -2131,6 +2239,15 @@ pg_get_constraintdef_ext(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(string_to_text(res)); } +/* + * 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 */ @@ -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 6ecaa2a01e..715f2a2e36 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 b76c7b3dc3..53c4a1a8c2 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 5ed6ece555..48c65ef53c 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 70d5e3680a..a3fca9e64c 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 7db7b3da7b..309da0ce38 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/replication/logicalrelation.h b/src/include/replication/logicalrelation.h index 9c34054bb7..471c5357a9 100644 --- a/src/include/replication/logicalrelation.h +++ b/src/include/replication/logicalrelation.h @@ -14,6 +14,7 @@ #include "access/attmap.h" #include "replication/logicalproto.h" +#include "storage/lockdefs.h" typedef struct LogicalRepRelMapEntry { diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h index 59e64aea07..a68ce3d336 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 f8e1238fa2..f05578d322 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 55af624fb3..946545f53f 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 2f8b46d6da..48b8bfd79a 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 af9785038d..103b392b73 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 1a42d9f39b..c33c8d0650 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 25c174f275..fc42d418bf 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 -- 2.34.1