From d471ba92638dbf59a53a3a9e8a68dbce2db70692 Mon Sep 17 00:00:00 2001 From: Ajin Cherian Date: Wed, 13 Apr 2022 09:13:28 -0400 Subject: [PATCH 2/3] Move some ddl-deparsing code from ruleutils to extension. --- src/backend/utils/adt/format_type.c | 125 -------------- src/backend/utils/adt/ruleutils.c | 325 +----------------------------------- src/include/utils/builtins.h | 4 - src/include/utils/ruleutils.h | 17 +- 4 files changed, 8 insertions(+), 463 deletions(-) diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index 42e3af3..060fd7e 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -334,131 +334,6 @@ format_type_extended(Oid type_oid, int32 typemod, bits16 flags) } /* - * Similar to format_type_internal, except we return each bit of information - * separately: - * - * - nspid is the schema OID. For certain SQL-standard types which have weird - * typmod rules, we return InvalidOid; caller is expected to not schema- - * qualify the name nor add quotes to the type name in this case. - * - * - typename is set to the type name, without quotes - * - * - typmod is set to the typemod, if any, as a string with parens - * - * - typarray indicates whether []s must be added - * - * We don't try to decode type names to their standard-mandated names, except - * in the cases of types with unusual typmod rules. - */ -void -format_type_detailed(Oid type_oid, int32 typemod, - Oid *nspid, char **typname, char **typemodstr, - bool *typarray) -{ - HeapTuple tuple; - Form_pg_type typeform; - Oid array_base_type; - - tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for type %u", type_oid); - - typeform = (Form_pg_type) GETSTRUCT(tuple); - - /* * Special-case crock for types with strange typmod rules. - */ - if (type_oid == INTERVALOID || - type_oid == TIMESTAMPOID || - type_oid == TIMESTAMPTZOID || - type_oid == TIMEOID || - type_oid == TIMETZOID) - { - *typarray = false; - -peculiar_typmod: - switch (type_oid) - { - case INTERVALOID: - *typname = pstrdup("INTERVAL"); - break; - case TIMESTAMPTZOID: - if (typemod < 0) - { - *typname = pstrdup("TIMESTAMP WITH TIME ZONE"); - break; - } - /* otherwise, WITH TZ is added by typmod, so fall through */ - case TIMESTAMPOID: - *typname = pstrdup("TIMESTAMP"); - break; - case TIMETZOID: - if (typemod < 0) - { - *typname = pstrdup("TIME WITH TIME ZONE"); - break; - } - /* otherwise, WITH TZ is added by typmode, so fall through */ - case TIMEOID: - *typname = pstrdup("TIME"); - break; - } - *nspid = InvalidOid; - - if (typemod >= 0) - *typemodstr = printTypmod(NULL, typemod, typeform->typmodout); - else - *typemodstr = pstrdup(""); - - ReleaseSysCache(tuple); - return; - } - - /* - * Check if it's a regular (variable length) array type. As above, - * fixed-length array types such as "name" shouldn't get deconstructed. - */ - array_base_type = typeform->typelem; - - if (array_base_type != InvalidOid && - typeform->typstorage != 'p') - { - /* Switch our attention to the array element type */ - ReleaseSysCache(tuple); - tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type)); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for type %u", type_oid); - - typeform = (Form_pg_type) GETSTRUCT(tuple); - type_oid = array_base_type; - *typarray = true; - - /* - * If it's an array of one of the types with special typmod rules, - * have the element type be processed as above, but now with typarray - * set to true. - */ - if (type_oid == INTERVALOID || - type_oid == TIMESTAMPTZOID || - type_oid == TIMESTAMPOID || - type_oid == TIMETZOID || - type_oid == TIMEOID) - goto peculiar_typmod; - } - else - *typarray = false; - - *nspid = typeform->typnamespace; - *typname = pstrdup(NameStr(typeform->typname)); - - if (typemod >= 0) - *typemodstr = printTypmod(NULL, typemod, typeform->typmodout); - else - *typemodstr = pstrdup(""); - - ReleaseSysCache(tuple); -} - -/* * This version is for use within the backend in error messages, etc. * One difference is that it will fail for an invalid type. * diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index f1d6e9a..77a5b79 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -484,8 +484,6 @@ 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); @@ -499,7 +497,6 @@ 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); static void get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit); @@ -558,8 +555,8 @@ pg_get_ruledef_ext(PG_FUNCTION_ARGS) * NIL, signalling NOTHING) in actions. */ void -pg_get_ruledef_details(Datum ev_qual, Datum ev_action, - char **whereClause, List **actions) +pg_get_ruledef_detailed(Datum ev_qual, Datum ev_action, + char **whereClause, List **actions) { int prettyFlags = 0; char *qualstr = TextDatumGetCString(ev_qual); @@ -1627,250 +1624,6 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, return buf.data; } -/* - * Return an index definition, split in several pieces. - * - * There is a huge lot of code that's a dupe of pg_get_indexdef_worker, but - * control flow is different enough that it doesn't seem worth keeping them - * together. - */ -void -pg_get_indexdef_detailed(Oid indexrelid, - char **index_am, - char **definition, - char **reloptions, - char **tablespace, - char **whereClause) -{ - HeapTuple ht_idx; - HeapTuple ht_idxrel; - HeapTuple ht_am; - Form_pg_index idxrec; - Form_pg_class idxrelrec; - Form_pg_am amrec; - IndexAmRoutine *amroutine; - List *indexprs; - ListCell *indexpr_item; - List *context; - Oid indrelid; - int keyno; - Datum indcollDatum; - Datum indclassDatum; - Datum indoptionDatum; - bool isnull; - oidvector *indcollation; - oidvector *indclass; - int2vector *indoption; - StringInfoData definitionBuf; - char *sep; - - /* - * Fetch the pg_index tuple by the Oid of the index - */ - ht_idx = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexrelid)); - if (!HeapTupleIsValid(ht_idx)) - elog(ERROR, "cache lookup failed for index %u", indexrelid); - idxrec = (Form_pg_index) GETSTRUCT(ht_idx); - - indrelid = idxrec->indrelid; - Assert(indexrelid == idxrec->indexrelid); - - /* Must get indcollation, indclass, and indoption the hard way */ - indcollDatum = SysCacheGetAttr(INDEXRELID, ht_idx, - Anum_pg_index_indcollation, &isnull); - Assert(!isnull); - indcollation = (oidvector *) DatumGetPointer(indcollDatum); - - indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx, - Anum_pg_index_indclass, &isnull); - Assert(!isnull); - indclass = (oidvector *) DatumGetPointer(indclassDatum); - - indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx, - Anum_pg_index_indoption, &isnull); - Assert(!isnull); - indoption = (int2vector *) DatumGetPointer(indoptionDatum); - - /* - * Fetch the pg_class tuple of the index relation - */ - ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexrelid)); - if (!HeapTupleIsValid(ht_idxrel)) - elog(ERROR, "cache lookup failed for relation %u", indexrelid); - idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel); - - /* - * Fetch the pg_am tuple of the index' access method - */ - ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam)); - if (!HeapTupleIsValid(ht_am)) - elog(ERROR, "cache lookup failed for access method %u", - idxrelrec->relam); - amrec = (Form_pg_am) GETSTRUCT(ht_am); - - /* Fetch the index AM's API struct */ - amroutine = GetIndexAmRoutine(amrec->amhandler); - - /* - * Get the index expressions, if any. (NOTE: we do not use the relcache - * versions of the expressions and predicate, because we want to display - * non-const-folded expressions.) - */ - if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL)) - { - Datum exprsDatum; - bool isnull; - char *exprsString; - - exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx, - Anum_pg_index_indexprs, &isnull); - Assert(!isnull); - exprsString = TextDatumGetCString(exprsDatum); - indexprs = (List *) stringToNode(exprsString); - pfree(exprsString); - } - else - indexprs = NIL; - - indexpr_item = list_head(indexprs); - - context = deparse_context_for(get_relation_name(indrelid), indrelid); - - initStringInfo(&definitionBuf); - - /* output index AM */ - *index_am = pstrdup(quote_identifier(NameStr(amrec->amname))); - - /* - * Output index definition. Note the outer parens must be supplied by - * caller. - */ - sep = ""; - for (keyno = 0; keyno < idxrec->indnatts; keyno++) - { - AttrNumber attnum = idxrec->indkey.values[keyno]; - int16 opt = indoption->values[keyno]; - Oid keycoltype; - Oid keycolcollation; - - Oid indcoll; - - appendStringInfoString(&definitionBuf, sep); - sep = ", "; - - if (attnum != 0) - { - /* Simple index column */ - char *attname; - int32 keycoltypmod; - - attname = get_attname(indrelid, attnum, false); - appendStringInfoString(&definitionBuf, quote_identifier(attname)); - get_atttypetypmodcoll(indrelid, attnum, - &keycoltype, &keycoltypmod, - &keycolcollation); - } - else - { - /* expressional index */ - Node *indexkey; - char *str; - - if (indexpr_item == NULL) - elog(ERROR, "too few entries in indexprs list"); - indexkey = (Node *) lfirst(indexpr_item); - indexpr_item = lnext(indexprs, indexpr_item); - /* Deparse */ - str = deparse_expression_pretty(indexkey, context, false, false, - 0, 0); - - /* Need parens if it's not a bare function call */ - if (indexkey && IsA(indexkey, FuncExpr) && - ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL) - appendStringInfoString(&definitionBuf, str); - else - appendStringInfo(&definitionBuf, "(%s)", str); - - keycoltype = exprType(indexkey); - keycolcollation = exprCollation(indexkey); - } - - /* Add collation, even if default */ - indcoll = indcollation->values[keyno]; - if (OidIsValid(indcoll)) - appendStringInfo(&definitionBuf, " COLLATE %s", - generate_collation_name((indcoll))); - - /* Add the operator class name, even if default */ - get_opclass_name(indclass->values[keyno], InvalidOid, &definitionBuf); - - /* Add options if relevant */ - if (amroutine->amcanorder) - { - /* if it supports sort ordering, report DESC and NULLS opts */ - if (opt & INDOPTION_DESC) - { - appendStringInfoString(&definitionBuf, " DESC"); - /* NULLS FIRST is the default in this case */ - if (!(opt & INDOPTION_NULLS_FIRST)) - appendStringInfoString(&definitionBuf, " NULLS LAST"); - } - else - { - if (opt & INDOPTION_NULLS_FIRST) - appendStringInfoString(&definitionBuf, " NULLS FIRST"); - } - } - - /* XXX excludeOps thingy was here; do we need anything? */ - } - *definition = definitionBuf.data; - - /* output reloptions */ - *reloptions = flatten_reloptions(indexrelid); - - /* output tablespace */ - { - Oid tblspc; - - tblspc = get_rel_tablespace(indexrelid); - if (OidIsValid(tblspc)) - *tablespace = pstrdup(quote_identifier(get_tablespace_name(tblspc))); - else - *tablespace = NULL; - } - - /* report index predicate, if any */ - if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL)) - { - Node *node; - Datum predDatum; - bool isnull; - char *predString; - - /* Convert text string to node tree */ - predDatum = SysCacheGetAttr(INDEXRELID, ht_idx, - Anum_pg_index_indpred, &isnull); - Assert(!isnull); - predString = TextDatumGetCString(predDatum); - node = (Node *) stringToNode(predString); - pfree(predString); - - /* Deparse */ - *whereClause = - deparse_expression_pretty(node, context, false, false, - 0, 0); - } - else - *whereClause = NULL; - - /* Clean up */ - ReleaseSysCache(ht_idx); - ReleaseSysCache(ht_idxrel); - ReleaseSysCache(ht_am); - - /* all done */ -} /* ---------- * pg_get_querydef @@ -12331,7 +12084,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) { @@ -13112,7 +12865,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; @@ -13180,73 +12933,3 @@ get_range_partbound_string(List *bound_datums) return buf->data; } - - -/* - * Obtain the deparsed default value for the given column of the given table. - * - * Caller must have set a correct deparse context. - */ -char * -RelationGetColumnDefault(Relation rel, AttrNumber attno, List *dpcontext) -{ - Node *defval; - char *defstr; - - defval = build_column_default(rel, attno); - defstr = deparse_expression_pretty(defval, dpcontext, false, false, - 0, 0); - - return defstr; -} - -/* - * Return the default value of a domain. - */ -char * -DomainGetDefault(HeapTuple domTup) -{ - Datum def; - Node *defval; - char *defstr; - bool isnull; - - def = SysCacheGetAttr(TYPEOID, domTup, Anum_pg_type_typdefaultbin, - &isnull); - if (isnull) - elog(ERROR, "domain \"%s\" does not have a default value", - NameStr(((Form_pg_type) GETSTRUCT(domTup))->typname)); - defval = stringToNode(TextDatumGetCString(def)); - defstr = deparse_expression_pretty(defval, NULL /* dpcontext? */, - false, false, 0, 0); - - return defstr; -} - - -/* - * Return the defaults values of arguments to a function, as a list of - * deparsed expressions. - */ -List * -FunctionGetDefaults(text *proargdefaults) -{ - List *nodedefs; - List *strdefs = NIL; - ListCell *cell; - - nodedefs = (List *) stringToNode(TextDatumGetCString(proargdefaults)); - if (!IsA(nodedefs, List)) - elog(ERROR, "proargdefaults is not a list"); - - foreach(cell, nodedefs) - { - Node *onedef = lfirst(cell); - - strdefs = lappend(strdefs, deparse_expression_pretty(onedef, NIL, false, false, 0, 0)); - } - - return strdefs; -} - - diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index cde659f..d14bb8f 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -121,10 +121,6 @@ extern char *format_type_be_qualified(Oid type_oid); extern char *format_type_with_typemod(Oid type_oid, int32 typemod); extern int32 type_maximum_size(Oid type_oid, int32 typemod); -extern void format_type_detailed(Oid type_oid, int32 typemod, - Oid *nspid, char **typname, - char **typemodstr, bool *is_array); - /* quote.c */ extern char *quote_literal_cstr(const char *rawstr); diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h index 83c242d..e359c90 100644 --- a/src/include/utils/ruleutils.h +++ b/src/include/utils/ruleutils.h @@ -24,17 +24,11 @@ struct PlannedStmt; extern char *pg_get_indexdef_string(Oid indexrelid); extern char *pg_get_indexdef_columns(Oid indexrelid, bool pretty); -extern void pg_get_indexdef_detailed(Oid indexrelid, - char **index_am, - char **definition, - char **reloptions, - char **tablespace, - char **whereClause); extern char *pg_get_trigger_whenclause(Form_pg_trigger trigrec, Node *whenClause, bool pretty); extern char *pg_get_constraintdef_string(Oid constraintId, bool fullCommand); extern char *pg_get_constraintdef_command(Oid constraintId); -extern void pg_get_ruledef_details(Datum ev_qual, Datum ev_action, +extern void pg_get_ruledef_detailed(Datum ev_qual, Datum ev_action, char **whereClause, List **actions); extern char *pg_get_viewdef_internal(Oid viewoid); extern char *pg_get_createtableas_def(Query *query); @@ -53,13 +47,10 @@ extern List *set_deparse_context_plan(List *dpcontext, struct Plan *plan, List *ancestors); extern List *select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used); +extern void get_opclass_name(Oid opclass, Oid actual_datatype, + StringInfo buf); extern char *generate_collation_name(Oid collid); -extern List *FunctionGetDefaults(text *proargdefaults); - -extern char *RelationGetColumnDefault(Relation rel, AttrNumber attno, - List *dpcontext); - -extern char *DomainGetDefault(HeapTuple domTup); +extern char *flatten_reloptions(Oid relid); extern char *generate_opclass_name(Oid opclass); extern char *get_range_partbound_string(List *bound_datums); -- 1.8.3.1