Skip to content

Commit 6f7eec1

Browse files
committed
Show 'AS "?column?"' explicitly when it's important.
ruleutils.c was coded to suppress the AS label for a SELECT output expression if the column name is "?column?", which is the parser's fallback if it can't think of something better. This is fine, and avoids ugly clutter, so long as (1) nothing further up in the parse tree relies on that column name or (2) the same fallback would be assigned when the rule or view definition is reloaded. Unfortunately (2) is far from certain, both because ruleutils.c might print the expression in a different form from how it was originally written and because FigureColname's rules might change in future releases. So we shouldn't rely on that. Detecting exactly whether there is any outer-level use of a SELECT column name would be rather expensive. This patch takes the simpler approach of just passing down a flag indicating whether there *could* be any outer use; for example, the output column names of a SubLink are not referenceable, and we also do not care about the names exposed by the right-hand side of a setop. This is sufficient to suppress unwanted clutter in all but one case in the regression tests. That seems like reasonable evidence that it won't be too much in users' faces, while still fixing the cases we need to fix. Per bug #17486 from Nicolas Lutic. This issue is ancient, so back-patch to all supported branches. Discussion: https://postgr.es/m/17486-1ad6fd786728b8af@postgresql.org
1 parent 7f798e8 commit 6f7eec1

File tree

2 files changed

+68
-40
lines changed

2 files changed

+68
-40
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -390,26 +390,29 @@ static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
390390
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
391391
int prettyFlags, int wrapColumn);
392392
static void get_query_def(Query *query, StringInfo buf, List *parentnamespace,
393-
TupleDesc resultDesc,
393+
TupleDesc resultDesc, bool colNamesVisible,
394394
int prettyFlags, int wrapColumn, int startIndent);
395395
static void get_values_def(List *values_lists, deparse_context *context);
396396
static void get_with_clause(Query *query, deparse_context *context);
397397
static void get_select_query_def(Query *query, deparse_context *context,
398-
TupleDesc resultDesc);
399-
static void get_insert_query_def(Query *query, deparse_context *context);
400-
static void get_update_query_def(Query *query, deparse_context *context);
398+
TupleDesc resultDesc, bool colNamesVisible);
399+
static void get_insert_query_def(Query *query, deparse_context *context,
400+
bool colNamesVisible);
401+
static void get_update_query_def(Query *query, deparse_context *context,
402+
bool colNamesVisible);
401403
static void get_update_query_targetlist_def(Query *query, List *targetList,
402404
deparse_context *context,
403405
RangeTblEntry *rte);
404-
static void get_delete_query_def(Query *query, deparse_context *context);
406+
static void get_delete_query_def(Query *query, deparse_context *context,
407+
bool colNamesVisible);
405408
static void get_utility_query_def(Query *query, deparse_context *context);
406409
static void get_basic_select_query(Query *query, deparse_context *context,
407-
TupleDesc resultDesc);
410+
TupleDesc resultDesc, bool colNamesVisible);
408411
static void get_target_list(List *targetList, deparse_context *context,
409-
TupleDesc resultDesc);
412+
TupleDesc resultDesc, bool colNamesVisible);
410413
static void get_setop_query(Node *setOp, Query *query,
411414
deparse_context *context,
412-
TupleDesc resultDesc);
415+
TupleDesc resultDesc, bool colNamesVisible);
413416
static Node *get_rule_sortgroupclause(Index ref, List *tlist,
414417
bool force_colno,
415418
deparse_context *context);
@@ -3445,7 +3448,7 @@ print_function_sqlbody(StringInfo buf, HeapTuple proctup)
34453448

34463449
/* It seems advisable to get at least AccessShareLock on rels */
34473450
AcquireRewriteLocks(query, false, false);
3448-
get_query_def(query, buf, list_make1(&dpns), NULL,
3451+
get_query_def(query, buf, list_make1(&dpns), NULL, false,
34493452
PRETTYFLAG_INDENT, WRAP_COLUMN_DEFAULT, 1);
34503453
appendStringInfoChar(buf, ';');
34513454
appendStringInfoChar(buf, '\n');
@@ -3459,7 +3462,7 @@ print_function_sqlbody(StringInfo buf, HeapTuple proctup)
34593462

34603463
/* It seems advisable to get at least AccessShareLock on rels */
34613464
AcquireRewriteLocks(query, false, false);
3462-
get_query_def(query, buf, list_make1(&dpns), NULL,
3465+
get_query_def(query, buf, list_make1(&dpns), NULL, false,
34633466
0, WRAP_COLUMN_DEFAULT, 0);
34643467
}
34653468
}
@@ -5189,7 +5192,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
51895192
foreach(action, actions)
51905193
{
51915194
query = (Query *) lfirst(action);
5192-
get_query_def(query, buf, NIL, viewResultDesc,
5195+
get_query_def(query, buf, NIL, viewResultDesc, true,
51935196
prettyFlags, WRAP_COLUMN_DEFAULT, 0);
51945197
if (prettyFlags)
51955198
appendStringInfoString(buf, ";\n");
@@ -5203,7 +5206,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
52035206
Query *query;
52045207

52055208
query = (Query *) linitial(actions);
5206-
get_query_def(query, buf, NIL, viewResultDesc,
5209+
get_query_def(query, buf, NIL, viewResultDesc, true,
52075210
prettyFlags, WRAP_COLUMN_DEFAULT, 0);
52085211
appendStringInfoChar(buf, ';');
52095212
}
@@ -5277,7 +5280,7 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
52775280

52785281
ev_relation = table_open(ev_class, AccessShareLock);
52795282

5280-
get_query_def(query, buf, NIL, RelationGetDescr(ev_relation),
5283+
get_query_def(query, buf, NIL, RelationGetDescr(ev_relation), true,
52815284
prettyFlags, wrapColumn, 0);
52825285
appendStringInfoChar(buf, ';');
52835286

@@ -5288,13 +5291,23 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
52885291
/* ----------
52895292
* get_query_def - Parse back one query parsetree
52905293
*
5291-
* If resultDesc is not NULL, then it is the output tuple descriptor for
5292-
* the view represented by a SELECT query.
5294+
* query: parsetree to be displayed
5295+
* buf: output text is appended to buf
5296+
* parentnamespace: list (initially empty) of outer-level deparse_namespace's
5297+
* resultDesc: if not NULL, the output tuple descriptor for the view
5298+
* represented by a SELECT query. We use the column names from it
5299+
* to label SELECT output columns, in preference to names in the query
5300+
* colNamesVisible: true if the surrounding context cares about the output
5301+
* column names at all (as, for example, an EXISTS() context does not);
5302+
* when false, we can suppress dummy column labels such as "?column?"
5303+
* prettyFlags: bitmask of PRETTYFLAG_XXX options
5304+
* wrapColumn: maximum line length, or -1 to disable wrapping
5305+
* startIndent: initial indentation amount
52935306
* ----------
52945307
*/
52955308
static void
52965309
get_query_def(Query *query, StringInfo buf, List *parentnamespace,
5297-
TupleDesc resultDesc,
5310+
TupleDesc resultDesc, bool colNamesVisible,
52985311
int prettyFlags, int wrapColumn, int startIndent)
52995312
{
53005313
deparse_context context;
@@ -5332,19 +5345,19 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace,
53325345
switch (query->commandType)
53335346
{
53345347
case CMD_SELECT:
5335-
get_select_query_def(query, &context, resultDesc);
5348+
get_select_query_def(query, &context, resultDesc, colNamesVisible);
53365349
break;
53375350

53385351
case CMD_UPDATE:
5339-
get_update_query_def(query, &context);
5352+
get_update_query_def(query, &context, colNamesVisible);
53405353
break;
53415354

53425355
case CMD_INSERT:
5343-
get_insert_query_def(query, &context);
5356+
get_insert_query_def(query, &context, colNamesVisible);
53445357
break;
53455358

53465359
case CMD_DELETE:
5347-
get_delete_query_def(query, &context);
5360+
get_delete_query_def(query, &context, colNamesVisible);
53485361
break;
53495362

53505363
case CMD_NOTHING:
@@ -5468,6 +5481,7 @@ get_with_clause(Query *query, deparse_context *context)
54685481
if (PRETTY_INDENT(context))
54695482
appendContextKeyword(context, "", 0, 0, 0);
54705483
get_query_def((Query *) cte->ctequery, buf, context->namespaces, NULL,
5484+
true,
54715485
context->prettyFlags, context->wrapColumn,
54725486
context->indentLevel);
54735487
if (PRETTY_INDENT(context))
@@ -5549,7 +5563,7 @@ get_with_clause(Query *query, deparse_context *context)
55495563
*/
55505564
static void
55515565
get_select_query_def(Query *query, deparse_context *context,
5552-
TupleDesc resultDesc)
5566+
TupleDesc resultDesc, bool colNamesVisible)
55535567
{
55545568
StringInfo buf = context->buf;
55555569
List *save_windowclause;
@@ -5573,13 +5587,14 @@ get_select_query_def(Query *query, deparse_context *context,
55735587
*/
55745588
if (query->setOperations)
55755589
{
5576-
get_setop_query(query->setOperations, query, context, resultDesc);
5590+
get_setop_query(query->setOperations, query, context, resultDesc,
5591+
colNamesVisible);
55775592
/* ORDER BY clauses must be simple in this case */
55785593
force_colno = true;
55795594
}
55805595
else
55815596
{
5582-
get_basic_select_query(query, context, resultDesc);
5597+
get_basic_select_query(query, context, resultDesc, colNamesVisible);
55835598
force_colno = false;
55845599
}
55855600

@@ -5749,7 +5764,7 @@ get_simple_values_rte(Query *query, TupleDesc resultDesc)
57495764

57505765
static void
57515766
get_basic_select_query(Query *query, deparse_context *context,
5752-
TupleDesc resultDesc)
5767+
TupleDesc resultDesc, bool colNamesVisible)
57535768
{
57545769
StringInfo buf = context->buf;
57555770
RangeTblEntry *values_rte;
@@ -5805,7 +5820,7 @@ get_basic_select_query(Query *query, deparse_context *context,
58055820
}
58065821

58075822
/* Then we tell what to select (the targetlist) */
5808-
get_target_list(query->targetList, context, resultDesc);
5823+
get_target_list(query->targetList, context, resultDesc, colNamesVisible);
58095824

58105825
/* Add the FROM clause if needed */
58115826
get_from_clause(query, " FROM ", context);
@@ -5877,11 +5892,13 @@ get_basic_select_query(Query *query, deparse_context *context,
58775892
* get_target_list - Parse back a SELECT target list
58785893
*
58795894
* This is also used for RETURNING lists in INSERT/UPDATE/DELETE.
5895+
*
5896+
* resultDesc and colNamesVisible are as for get_query_def()
58805897
* ----------
58815898
*/
58825899
static void
58835900
get_target_list(List *targetList, deparse_context *context,
5884-
TupleDesc resultDesc)
5901+
TupleDesc resultDesc, bool colNamesVisible)
58855902
{
58865903
StringInfo buf = context->buf;
58875904
StringInfoData targetbuf;
@@ -5932,8 +5949,13 @@ get_target_list(List *targetList, deparse_context *context,
59325949
else
59335950
{
59345951
get_rule_expr((Node *) tle->expr, context, true);
5935-
/* We'll show the AS name unless it's this: */
5936-
attname = "?column?";
5952+
5953+
/*
5954+
* When colNamesVisible is true, we should always show the
5955+
* assigned column name explicitly. Otherwise, show it only if
5956+
* it's not FigureColname's fallback.
5957+
*/
5958+
attname = colNamesVisible ? NULL : "?column?";
59375959
}
59385960

59395961
/*
@@ -6012,7 +6034,7 @@ get_target_list(List *targetList, deparse_context *context,
60126034

60136035
static void
60146036
get_setop_query(Node *setOp, Query *query, deparse_context *context,
6015-
TupleDesc resultDesc)
6037+
TupleDesc resultDesc, bool colNamesVisible)
60166038
{
60176039
StringInfo buf = context->buf;
60186040
bool need_paren;
@@ -6038,6 +6060,7 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context,
60386060
if (need_paren)
60396061
appendStringInfoChar(buf, '(');
60406062
get_query_def(subquery, buf, context->namespaces, resultDesc,
6063+
colNamesVisible,
60416064
context->prettyFlags, context->wrapColumn,
60426065
context->indentLevel);
60436066
if (need_paren)
@@ -6080,7 +6103,7 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context,
60806103
else
60816104
subindent = 0;
60826105

6083-
get_setop_query(op->larg, query, context, resultDesc);
6106+
get_setop_query(op->larg, query, context, resultDesc, colNamesVisible);
60846107

60856108
if (need_paren)
60866109
appendContextKeyword(context, ") ", -subindent, 0, 0);
@@ -6124,7 +6147,7 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context,
61246147
subindent = 0;
61256148
appendContextKeyword(context, "", subindent, 0, 0);
61266149

6127-
get_setop_query(op->rarg, query, context, resultDesc);
6150+
get_setop_query(op->rarg, query, context, resultDesc, false);
61286151

61296152
if (PRETTY_INDENT(context))
61306153
context->indentLevel -= subindent;
@@ -6459,7 +6482,8 @@ get_rule_windowspec(WindowClause *wc, List *targetList,
64596482
* ----------
64606483
*/
64616484
static void
6462-
get_insert_query_def(Query *query, deparse_context *context)
6485+
get_insert_query_def(Query *query, deparse_context *context,
6486+
bool colNamesVisible)
64636487
{
64646488
StringInfo buf = context->buf;
64656489
RangeTblEntry *select_rte = NULL;
@@ -6569,6 +6593,7 @@ get_insert_query_def(Query *query, deparse_context *context)
65696593
{
65706594
/* Add the SELECT */
65716595
get_query_def(select_rte->subquery, buf, context->namespaces, NULL,
6596+
false,
65726597
context->prettyFlags, context->wrapColumn,
65736598
context->indentLevel);
65746599
}
@@ -6662,7 +6687,7 @@ get_insert_query_def(Query *query, deparse_context *context)
66626687
{
66636688
appendContextKeyword(context, " RETURNING",
66646689
-PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6665-
get_target_list(query->returningList, context, NULL);
6690+
get_target_list(query->returningList, context, NULL, colNamesVisible);
66666691
}
66676692
}
66686693

@@ -6672,7 +6697,8 @@ get_insert_query_def(Query *query, deparse_context *context)
66726697
* ----------
66736698
*/
66746699
static void
6675-
get_update_query_def(Query *query, deparse_context *context)
6700+
get_update_query_def(Query *query, deparse_context *context,
6701+
bool colNamesVisible)
66766702
{
66776703
StringInfo buf = context->buf;
66786704
RangeTblEntry *rte;
@@ -6717,7 +6743,7 @@ get_update_query_def(Query *query, deparse_context *context)
67176743
{
67186744
appendContextKeyword(context, " RETURNING",
67196745
-PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6720-
get_target_list(query->returningList, context, NULL);
6746+
get_target_list(query->returningList, context, NULL, colNamesVisible);
67216747
}
67226748
}
67236749

@@ -6879,7 +6905,8 @@ get_update_query_targetlist_def(Query *query, List *targetList,
68796905
* ----------
68806906
*/
68816907
static void
6882-
get_delete_query_def(Query *query, deparse_context *context)
6908+
get_delete_query_def(Query *query, deparse_context *context,
6909+
bool colNamesVisible)
68836910
{
68846911
StringInfo buf = context->buf;
68856912
RangeTblEntry *rte;
@@ -6920,7 +6947,7 @@ get_delete_query_def(Query *query, deparse_context *context)
69206947
{
69216948
appendContextKeyword(context, " RETURNING",
69226949
-PRETTYINDENT_STD, PRETTYINDENT_STD, 1);
6923-
get_target_list(query->returningList, context, NULL);
6950+
get_target_list(query->returningList, context, NULL, colNamesVisible);
69246951
}
69256952
}
69266953

@@ -10532,7 +10559,7 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
1053210559
if (need_paren)
1053310560
appendStringInfoChar(buf, '(');
1053410561

10535-
get_query_def(query, buf, context->namespaces, NULL,
10562+
get_query_def(query, buf, context->namespaces, NULL, false,
1053610563
context->prettyFlags, context->wrapColumn,
1053710564
context->indentLevel);
1053810565

@@ -10778,6 +10805,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
1077810805
/* Subquery RTE */
1077910806
appendStringInfoChar(buf, '(');
1078010807
get_query_def(rte->subquery, buf, context->namespaces, NULL,
10808+
true,
1078110809
context->prettyFlags, context->wrapColumn,
1078210810
context->indentLevel);
1078310811
appendStringInfoChar(buf, ')');

src/test/regress/expected/matview.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ CREATE VIEW mvtest_vt2 AS SELECT moo, 2*moo FROM mvtest_vt1 UNION ALL SELECT moo
347347
?column? | integer | | | | plain |
348348
View definition:
349349
SELECT mvtest_vt1.moo,
350-
2 * mvtest_vt1.moo
350+
2 * mvtest_vt1.moo AS "?column?"
351351
FROM mvtest_vt1
352352
UNION ALL
353353
SELECT mvtest_vt1.moo,
@@ -363,7 +363,7 @@ CREATE MATERIALIZED VIEW mv_test2 AS SELECT moo, 2*moo FROM mvtest_vt2 UNION ALL
363363
?column? | integer | | | | plain | |
364364
View definition:
365365
SELECT mvtest_vt2.moo,
366-
2 * mvtest_vt2.moo
366+
2 * mvtest_vt2.moo AS "?column?"
367367
FROM mvtest_vt2
368368
UNION ALL
369369
SELECT mvtest_vt2.moo,

0 commit comments

Comments
 (0)