From bacc5fb61d9e787f077e4db9f185cf8e7bf2afa3 Mon Sep 17 00:00:00 2001 From: Oleksandr Shulgin Date: Thu, 30 Jul 2015 12:07:16 +0200 Subject: [PATCH 2/5] Move some ddl-deparsing code from ruleutils to extension. --- src/backend/utils/adt/format_type.c | 127 -------------- src/backend/utils/adt/ruleutils.c | 322 +----------------------------------- src/include/utils/builtins.h | 3 - src/include/utils/ruleutils.h | 20 +-- 4 files changed, 12 insertions(+), 460 deletions(-) diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index a8aacfb..a851983 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -328,133 +328,6 @@ format_type_internal(Oid type_oid, int32 typemod, /* - * 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); -} - - -/* * Add typmod decoration to the basic type name */ static char * diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 28de88b..19ce290 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -289,9 +289,6 @@ bool quote_all_identifiers = false; * 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, int wrapColumn); static char *pg_get_triggerdef_worker(Oid trigid, bool pretty); @@ -415,8 +412,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, bool printit); static void printSubscripts(ArrayRef *aref, deparse_context *context); @@ -428,7 +423,6 @@ static char *generate_function_name(Oid funcid, int nargs, ParseExprKind special_exprkind); static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2); static text *string_to_text(char *str); -static char *flatten_reloptions(Oid relid); #define only_marker(rte) ((rte)->inh ? "" : "ONLY ") @@ -468,8 +462,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); @@ -1377,246 +1371,6 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, } /* - * 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; - 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); - - /* - * 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)) - { - 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_relid_attribute_name(indrelid, attnum); - 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(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 (amrec->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)) - { - 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_constraintdef * * Returns the definition for the constraint, ie, everything that needs to @@ -2838,7 +2592,7 @@ deparse_expression(Node *expr, List *dpcontext, * The result is a palloc'd string. * ---------- */ -static char * +char * deparse_expression_pretty(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit, int prettyFlags, int startIndent) @@ -9509,7 +9263,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) { @@ -10057,7 +9811,7 @@ string_to_text(char *str) /* * Generate a C string representing a relation's reloptions, or NULL if none. */ -static char * +char * flatten_reloptions(Oid relid) { char *result = NULL; @@ -10091,69 +9845,3 @@ flatten_reloptions(Oid relid) return result; } - -/* - * 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 16e51dc..c3ff3d7 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -1108,9 +1108,6 @@ extern char *format_type_be_qualified(Oid type_oid); extern char *format_type_with_typemod(Oid type_oid, int32 typemod); extern Datum oidvectortypes(PG_FUNCTION_ARGS); 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 Datum quote_ident(PG_FUNCTION_ARGS); diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h index 8ff6a0c..73b19d2 100644 --- a/src/include/utils/ruleutils.h +++ b/src/include/utils/ruleutils.h @@ -19,18 +19,15 @@ #include "nodes/pg_list.h" +extern char *deparse_expression_pretty(Node *expr, List *dpcontext, + bool forceprefix, bool showimplicit, + int prettyFlags, int startIndent); 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 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); @@ -43,12 +40,9 @@ extern List *set_deparse_context_planstate(List *dpcontext, Node *planstate, 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); #endif /* RULEUTILS_H */ -- 2.1.4