diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 236a60a688..e8e637bf31 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -13828,7 +13828,8 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); <row> <entry><literal><function>pg_get_viewdef(<parameter>view_name</parameter>, <parameter>pretty_bool</>)</function></literal></entry> <entry><type>text</type></entry> - <entry>get underlying <command>SELECT</command> command for view (<emphasis>deprecated</emphasis>)</entry> + <entry>get underlying <command>SELECT</command> command for view, + lines with fields are wrapped to 80 columns if pretty_bool is true (<emphasis>deprecated</emphasis>)</entry> </row> <row> <entry><literal><function>pg_get_viewdef(<parameter>view_oid</parameter>)</function></literal></entry> @@ -13838,7 +13839,14 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); <row> <entry><literal><function>pg_get_viewdef(<parameter>view_oid</parameter>, <parameter>pretty_bool</>)</function></literal></entry> <entry><type>text</type></entry> - <entry>get underlying <command>SELECT</command> command for view</entry> + <entry>get underlying <command>SELECT</command> command for view, + lines with fields are wrapped to 80 columns if pretty_bool is true</entry> + </row> + <row> + <entry><literal><function>pg_get_viewdef(<parameter>view_oid</parameter>, <parameter>wrap_int</>)</function></literal></entry> + <entry><type>text</type></entry> + <entry>get underlying <command>SELECT</command> command for view, + wrapping lines with fields as specified, pretty printing is implied</entry> </row> <row> <entry><literal><function>pg_options_to_table(<parameter>reloptions</parameter>)</function></literal></entry> diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9ad54c5dec..64ba8ec891 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -73,6 +73,8 @@ #define PRETTYFLAG_PAREN 1 #define PRETTYFLAG_INDENT 2 +#define PRETTY_WRAP_DEFAULT 79 + /* macro to test if pretty action needed */ #define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN) #define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT) @@ -136,6 +138,7 @@ static SPIPlanPtr plan_getrulebyoid = NULL; static const char *query_getrulebyoid = "SELECT * FROM pg_catalog.pg_rewrite WHERE oid = $1"; static SPIPlanPtr plan_getviewrule = NULL; static const char *query_getviewrule = "SELECT * FROM pg_catalog.pg_rewrite WHERE ev_class = $1 AND rulename = $2"; +static int pretty_wrap = PRETTY_WRAP_DEFAULT; /* GUC parameters */ bool quote_all_identifiers = false; @@ -380,6 +383,23 @@ pg_get_viewdef_ext(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(string_to_text(pg_get_viewdef_worker(viewoid, prettyFlags))); } +Datum +pg_get_viewdef_wrap(PG_FUNCTION_ARGS) +{ + /* By OID */ + Oid viewoid = PG_GETARG_OID(0); + int wrap = PG_GETARG_INT32(1); + int prettyFlags; + char *result; + + /* calling this implies we want pretty printing */ + prettyFlags = PRETTYFLAG_PAREN | PRETTYFLAG_INDENT; + pretty_wrap = wrap; + result = pg_get_viewdef_worker(viewoid, prettyFlags); + pretty_wrap = PRETTY_WRAP_DEFAULT; + PG_RETURN_TEXT_P(string_to_text(result)); +} + Datum pg_get_viewdef_name(PG_FUNCTION_ARGS) { @@ -3013,6 +3033,7 @@ get_target_list(List *targetList, deparse_context *context, char *sep; int colno; ListCell *l; + bool last_was_multiline = false; sep = " "; colno = 0; @@ -3021,6 +3042,10 @@ get_target_list(List *targetList, deparse_context *context, TargetEntry *tle = (TargetEntry *) lfirst(l); char *colname; char *attname; + StringInfoData targetbuf; + int leading_nl_pos = -1; + char *trailing_nl; + int pos; if (tle->resjunk) continue; /* ignore junk entries */ @@ -3029,6 +3054,15 @@ get_target_list(List *targetList, deparse_context *context, sep = ", "; colno++; + /* + * Put the new field spec into targetbuf so we can + * decide after we've got it whether or not it needs + * to go on a new line. + */ + + initStringInfo(&targetbuf); + context->buf = &targetbuf; + /* * We special-case Var nodes rather than using get_rule_expr. This is * needed because get_rule_expr will display a whole-row Var as @@ -3063,8 +3097,66 @@ get_target_list(List *targetList, deparse_context *context, if (colname) /* resname could be NULL */ { if (attname == NULL || strcmp(attname, colname) != 0) - appendStringInfo(buf, " AS %s", quote_identifier(colname)); + appendStringInfo(&targetbuf, " AS %s", quote_identifier(colname)); } + + /* Restore context buffer */ + + context->buf = buf; + + /* Does the new field start with whitespace plus a new line? */ + + for (pos=0; pos < targetbuf.len; pos++) + { + if (targetbuf.data[pos] == '\n') + { + leading_nl_pos = pos; + break; + } + if (targetbuf.data[pos] > ' ') + break; + } + + /* Locate the start of the current line in the buffer */ + + trailing_nl = (strrchr(buf->data,'\n')); + if (trailing_nl == NULL) + trailing_nl = buf->data; + else + trailing_nl++; + + /* + * If the field we're adding is the first in the list, or it already + * has a leading newline, or wrap mode is disabled (pretty_wrap < 0), + * don't add anything. + * Otherwise, add a newline, plus some indentation, if either the + * new field would cause an overflow or the last field used more than + * one line. + */ + + if (colno > 1 && + leading_nl_pos == -1 && + pretty_wrap >= 0 && + ((strlen(trailing_nl) + strlen(targetbuf.data) > pretty_wrap) || + last_was_multiline)) + { + appendContextKeyword(context, "", -PRETTYINDENT_STD, + PRETTYINDENT_STD, PRETTYINDENT_VAR); + } + + /* Add the new field */ + + appendStringInfoString(buf, targetbuf.data); + + + /* Keep track of this field's status for next iteration */ + + last_was_multiline = + (strchr(targetbuf.data + leading_nl_pos + 1,'\n') != NULL); + + /* cleanup */ + + pfree (targetbuf.data); } } @@ -6445,11 +6537,52 @@ get_from_clause(Query *query, const char *prefix, deparse_context *context) appendContextKeyword(context, prefix, -PRETTYINDENT_STD, PRETTYINDENT_STD, 2); first = false; + + get_from_clause_item(jtnode, query, context); } else - appendStringInfoString(buf, ", "); + { + StringInfoData targetbuf; + char *trailing_nl; + + appendStringInfoString(buf, ", "); + + initStringInfo(&targetbuf); + context->buf = &targetbuf; + + get_from_clause_item(jtnode, query, context); + + context->buf = buf; + + /* Locate the start of the current line in the buffer */ + + trailing_nl = (strrchr(buf->data,'\n')); + if (trailing_nl == NULL) + trailing_nl = buf->data; + else + trailing_nl++; + + /* + * Add a newline, plus some indentation, if pretty_wrap is on and the + * new from-clause item would cause an overflow. + */ + + if (pretty_wrap >= 0 && + (strlen(trailing_nl) + strlen(targetbuf.data) > pretty_wrap)) + { + appendContextKeyword(context, "", -PRETTYINDENT_STD, + PRETTYINDENT_STD, PRETTYINDENT_VAR); + } + + /* Add the new item */ + + appendStringInfoString(buf, targetbuf.data); + + /* cleanup */ + + pfree (targetbuf.data); + } - get_from_clause_item(jtnode, query, context); } } diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 7a54a74757..6100472d94 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201202141 +#define CATALOG_VERSION_NO 201202191 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index fb2923f94d..8700d0d958 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3743,6 +3743,8 @@ DATA(insert OID = 2505 ( pg_get_viewdef PGNSP PGUID 12 1 0 0 0 f f f f t f s DESCR("select statement of a view with pretty-print option"); DATA(insert OID = 2506 ( pg_get_viewdef PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 25 "26 16" _null_ _null_ _null_ _null_ pg_get_viewdef_ext _null_ _null_ _null_ )); DESCR("select statement of a view with pretty-print option"); +DATA(insert OID = 3159 ( pg_get_viewdef PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 25 "26 23" _null_ _null_ _null_ _null_ pg_get_viewdef_wrap _null_ _null_ _null_ )); +DESCR("select statement of a view with pretty-printing and specified line wrapping"); DATA(insert OID = 2507 ( pg_get_indexdef PGNSP PGUID 12 1 0 0 0 f f f f t f s 3 0 25 "26 23 16" _null_ _null_ _null_ _null_ pg_get_indexdef_ext _null_ _null_ _null_ )); DESCR("index description (full create statement or single expression) with pretty-print option"); DATA(insert OID = 2508 ( pg_get_constraintdef PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 25 "26 16" _null_ _null_ _null_ _null_ pg_get_constraintdef_ext _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 2c331ce5eb..fe253bcc7c 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -624,6 +624,7 @@ extern Datum pg_get_ruledef(PG_FUNCTION_ARGS); extern Datum pg_get_ruledef_ext(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef_ext(PG_FUNCTION_ARGS); +extern Datum pg_get_viewdef_wrap(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef_name(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef_name_ext(PG_FUNCTION_ARGS); extern Datum pg_get_indexdef(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out index cb3d756290..1e879532f8 100644 --- a/src/test/regress/expected/polymorphism.out +++ b/src/test/regress/expected/polymorphism.out @@ -1381,7 +1381,9 @@ select * from dfview; c3 | bigint | | plain | c4 | bigint | | plain | View definition: - SELECT int8_tbl.q1, int8_tbl.q2, dfunc(int8_tbl.q1, int8_tbl.q2, flag := int8_tbl.q1 > int8_tbl.q2) AS c3, dfunc(int8_tbl.q1, flag := int8_tbl.q1 < int8_tbl.q2, b := int8_tbl.q2) AS c4 + SELECT int8_tbl.q1, int8_tbl.q2, + dfunc(int8_tbl.q1, int8_tbl.q2, flag := int8_tbl.q1 > int8_tbl.q2) AS c3, + dfunc(int8_tbl.q1, flag := int8_tbl.q1 < int8_tbl.q2, b := int8_tbl.q2) AS c4 FROM int8_tbl; drop view dfview; diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index f67b8dc3f4..0275a0e120 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1568,3 +1568,36 @@ select * from only t1_2; 19 (10 rows) +-- test various flavors of pg_get_viewdef() +select pg_get_viewdef('shoe'::regclass) as unpretty; + unpretty +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + SELECT sh.shoename, sh.sh_avail, sh.slcolor, sh.slminlen, (sh.slminlen * un.un_fact) AS slminlen_cm, sh.slmaxlen, (sh.slmaxlen * un.un_fact) AS slmaxlen_cm, sh.slunit FROM shoe_data sh, unit un WHERE (sh.slunit = un.un_name); +(1 row) + +select pg_get_viewdef('shoe'::regclass,true) as pretty; + pretty +------------------------------------------------------------- + SELECT sh.shoename, sh.sh_avail, sh.slcolor, sh.slminlen, + + sh.slminlen * un.un_fact AS slminlen_cm, sh.slmaxlen, + + sh.slmaxlen * un.un_fact AS slmaxlen_cm, sh.slunit + + FROM shoe_data sh, unit un + + WHERE sh.slunit = un.un_name; +(1 row) + +select pg_get_viewdef('shoe'::regclass,0) as prettier; + prettier +----------------------------------------------- + SELECT sh.shoename, + + sh.sh_avail, + + sh.slcolor, + + sh.slminlen, + + sh.slminlen * un.un_fact AS slminlen_cm, + + sh.slmaxlen, + + sh.slmaxlen * un.un_fact AS slmaxlen_cm, + + sh.slunit + + FROM shoe_data sh, + + unit un + + WHERE sh.slunit = un.un_name; +(1 row) + diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out index a58739b68e..fae92cd37b 100644 --- a/src/test/regress/expected/with.out +++ b/src/test/regress/expected/with.out @@ -277,18 +277,19 @@ SELECT pg_get_viewdef('vsubdepartment'::regclass); (1 row) SELECT pg_get_viewdef('vsubdepartment'::regclass, true); - pg_get_viewdef --------------------------------------------------------------------------------------- - WITH RECURSIVE subdepartment AS ( + - SELECT department.id, department.parent_department, department.name+ - FROM department + - WHERE department.name = 'A'::text + - UNION ALL + - SELECT d.id, d.parent_department, d.name + - FROM department d, subdepartment sd + - WHERE d.parent_department = sd.id + - ) + - SELECT subdepartment.id, subdepartment.parent_department, subdepartment.name + + pg_get_viewdef +------------------------------------------------------------------------------- + WITH RECURSIVE subdepartment AS ( + + SELECT department.id, department.parent_department, + + department.name + + FROM department + + WHERE department.name = 'A'::text + + UNION ALL + + SELECT d.id, d.parent_department, d.name + + FROM department d, subdepartment sd + + WHERE d.parent_department = sd.id + + ) + + SELECT subdepartment.id, subdepartment.parent_department, subdepartment.name+ FROM subdepartment; (1 row) diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql index 16dc106ab0..ea665a3c8b 100644 --- a/src/test/regress/sql/rules.sql +++ b/src/test/regress/sql/rules.sql @@ -927,3 +927,9 @@ update t1 set a = 4 where a = 5; select * from only t1; select * from only t1_1; select * from only t1_2; + +-- test various flavors of pg_get_viewdef() + +select pg_get_viewdef('shoe'::regclass) as unpretty; +select pg_get_viewdef('shoe'::regclass,true) as pretty; +select pg_get_viewdef('shoe'::regclass,0) as prettier;