Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3dd287c

Browse files
committed
Print the correct aliases for DML target tables in ruleutils.
ruleutils.c blindly printed the user-given alias (or nothing if therehadn't been one) for the target table of INSERT/UPDATE/DELETE queries.That works a large percentage of the time, but not always: for queriesappearing in WITH, it's possible that we chose a different alias toavoid conflict with outer-scope names. Since the chosen alias wouldbe used in any Var references to the target table, this'd lead to aninconsistent printout with consequences such as dump/restore failures.The correct logic for printing (or not) a relation alias was embeddedin get_from_clause_item. Factor it out to a separate function so thatwe don't need a jointree node to use it. (Only a limited part of thatfunction can be reached from these new call sites, but this seems likethe cleanest non-duplicative factorization.)In passing, I got rid of a redundant "\d+ rules_src" step in rules.sql.Initial report from Jonathan Katz; thanks to Vignesh C for analysis.This has been broken for a long time, so back-patch to all supportedbranches.Discussion:https://postgr.es/m/e947fa21-24b2-f922-375a-d4f763ef3e4b@postgresql.orgDiscussion:https://postgr.es/m/CALDaNm1MMntjmT_NJGp-Z=xbF02qHGAyuSHfYHias3TqQbPF2w@mail.gmail.com
1 parenta40e7b7 commit3dd287c

File tree

3 files changed

+126
-79
lines changed

3 files changed

+126
-79
lines changed

‎src/backend/utils/adt/ruleutils.c

Lines changed: 84 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ static void get_from_clause(Query *query, const char *prefix,
452452
deparse_context*context);
453453
staticvoidget_from_clause_item(Node*jtnode,Query*query,
454454
deparse_context*context);
455+
staticvoidget_rte_alias(RangeTblEntry*rte,intvarno,booluse_as,
456+
deparse_context*context);
455457
staticvoidget_column_alias_list(deparse_columns*colinfo,
456458
deparse_context*context);
457459
staticvoidget_from_clause_coldeflist(RangeTblFunction*rtfunc,
@@ -6255,12 +6257,14 @@ get_insert_query_def(Query *query, deparse_context *context,
62556257
context->indentLevel+=PRETTYINDENT_STD;
62566258
appendStringInfoChar(buf,' ');
62576259
}
6258-
appendStringInfo(buf,"INSERT INTO %s",
6260+
appendStringInfo(buf,"INSERT INTO %s",
62596261
generate_relation_name(rte->relid,NIL));
6260-
/* INSERT requires AS keyword for target alias */
6261-
if (rte->alias!=NULL)
6262-
appendStringInfo(buf,"AS %s ",
6263-
quote_identifier(rte->alias->aliasname));
6262+
6263+
/* Print the relation alias, if needed; INSERT requires explicit AS */
6264+
get_rte_alias(rte,query->resultRelation, true,context);
6265+
6266+
/* always want a space here */
6267+
appendStringInfoChar(buf,' ');
62646268

62656269
/*
62666270
* Add the insert-column-names list. Any indirection decoration needed on
@@ -6442,9 +6446,10 @@ get_update_query_def(Query *query, deparse_context *context,
64426446
appendStringInfo(buf,"UPDATE %s%s",
64436447
only_marker(rte),
64446448
generate_relation_name(rte->relid,NIL));
6445-
if (rte->alias!=NULL)
6446-
appendStringInfo(buf," %s",
6447-
quote_identifier(rte->alias->aliasname));
6449+
6450+
/* Print the relation alias, if needed */
6451+
get_rte_alias(rte,query->resultRelation, false,context);
6452+
64486453
appendStringInfoString(buf," SET ");
64496454

64506455
/* Deparse targetlist */
@@ -6651,9 +6656,9 @@ get_delete_query_def(Query *query, deparse_context *context,
66516656
appendStringInfo(buf,"DELETE FROM %s%s",
66526657
only_marker(rte),
66536658
generate_relation_name(rte->relid,NIL));
6654-
if (rte->alias!=NULL)
6655-
appendStringInfo(buf," %s",
6656-
quote_identifier(rte->alias->aliasname));
6659+
6660+
/* Print the relation alias, if needed */
6661+
get_rte_alias(rte,query->resultRelation, false,context);
66576662

66586663
/* Add the USING clause if given */
66596664
get_from_clause(query," USING ",context);
@@ -10105,10 +10110,8 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
1010510110
{
1010610111
intvarno= ((RangeTblRef*)jtnode)->rtindex;
1010710112
RangeTblEntry*rte=rt_fetch(varno,query->rtable);
10108-
char*refname=get_rtable_name(varno,context);
1010910113
deparse_columns*colinfo=deparse_columns_fetch(varno,dpns);
1011010114
RangeTblFunction*rtfunc1=NULL;
10111-
boolprintalias;
1011210115

1011310116
if (rte->lateral)
1011410117
appendStringInfoString(buf,"LATERAL ");
@@ -10245,54 +10248,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
1024510248
}
1024610249

1024710250
/* Print the relation alias, if needed */
10248-
printalias= false;
10249-
if (rte->alias!=NULL)
10250-
{
10251-
/* Always print alias if user provided one */
10252-
printalias= true;
10253-
}
10254-
elseif (colinfo->printaliases)
10255-
{
10256-
/* Always print alias if we need to print column aliases */
10257-
printalias= true;
10258-
}
10259-
elseif (rte->rtekind==RTE_RELATION)
10260-
{
10261-
/*
10262-
* No need to print alias if it's same as relation name (this
10263-
* would normally be the case, but not if set_rtable_names had to
10264-
* resolve a conflict).
10265-
*/
10266-
if (strcmp(refname,get_relation_name(rte->relid))!=0)
10267-
printalias= true;
10268-
}
10269-
elseif (rte->rtekind==RTE_FUNCTION)
10270-
{
10271-
/*
10272-
* For a function RTE, always print alias. This covers possible
10273-
* renaming of the function and/or instability of the
10274-
* FigureColname rules for things that aren't simple functions.
10275-
* Note we'd need to force it anyway for the columndef list case.
10276-
*/
10277-
printalias= true;
10278-
}
10279-
elseif (rte->rtekind==RTE_VALUES)
10280-
{
10281-
/* Alias is syntactically required for VALUES */
10282-
printalias= true;
10283-
}
10284-
elseif (rte->rtekind==RTE_CTE)
10285-
{
10286-
/*
10287-
* No need to print alias if it's same as CTE name (this would
10288-
* normally be the case, but not if set_rtable_names had to
10289-
* resolve a conflict).
10290-
*/
10291-
if (strcmp(refname,rte->ctename)!=0)
10292-
printalias= true;
10293-
}
10294-
if (printalias)
10295-
appendStringInfo(buf," %s",quote_identifier(refname));
10251+
get_rte_alias(rte,varno, false,context);
1029610252

1029710253
/* Print the column definitions or aliases, if needed */
1029810254
if (rtfunc1&&rtfunc1->funccolnames!=NIL)
@@ -10426,6 +10382,73 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
1042610382
(int)nodeTag(jtnode));
1042710383
}
1042810384

10385+
/*
10386+
* get_rte_alias - print the relation's alias, if needed
10387+
*
10388+
* If printed, the alias is preceded by a space, or by " AS " if use_as is true.
10389+
*/
10390+
staticvoid
10391+
get_rte_alias(RangeTblEntry*rte,intvarno,booluse_as,
10392+
deparse_context*context)
10393+
{
10394+
deparse_namespace*dpns= (deparse_namespace*)linitial(context->namespaces);
10395+
char*refname=get_rtable_name(varno,context);
10396+
deparse_columns*colinfo=deparse_columns_fetch(varno,dpns);
10397+
boolprintalias= false;
10398+
10399+
if (rte->alias!=NULL)
10400+
{
10401+
/* Always print alias if user provided one */
10402+
printalias= true;
10403+
}
10404+
elseif (colinfo->printaliases)
10405+
{
10406+
/* Always print alias if we need to print column aliases */
10407+
printalias= true;
10408+
}
10409+
elseif (rte->rtekind==RTE_RELATION)
10410+
{
10411+
/*
10412+
* No need to print alias if it's same as relation name (this would
10413+
* normally be the case, but not if set_rtable_names had to resolve a
10414+
* conflict).
10415+
*/
10416+
if (strcmp(refname,get_relation_name(rte->relid))!=0)
10417+
printalias= true;
10418+
}
10419+
elseif (rte->rtekind==RTE_FUNCTION)
10420+
{
10421+
/*
10422+
* For a function RTE, always print alias. This covers possible
10423+
* renaming of the function and/or instability of the FigureColname
10424+
* rules for things that aren't simple functions. Note we'd need to
10425+
* force it anyway for the columndef list case.
10426+
*/
10427+
printalias= true;
10428+
}
10429+
elseif (rte->rtekind==RTE_SUBQUERY||
10430+
rte->rtekind==RTE_VALUES)
10431+
{
10432+
/* Alias is syntactically required for SUBQUERY and VALUES */
10433+
printalias= true;
10434+
}
10435+
elseif (rte->rtekind==RTE_CTE)
10436+
{
10437+
/*
10438+
* No need to print alias if it's same as CTE name (this would
10439+
* normally be the case, but not if set_rtable_names had to resolve a
10440+
* conflict).
10441+
*/
10442+
if (strcmp(refname,rte->ctename)!=0)
10443+
printalias= true;
10444+
}
10445+
10446+
if (printalias)
10447+
appendStringInfo(context->buf,"%s%s",
10448+
use_as ?" AS " :" ",
10449+
quote_identifier(refname));
10450+
}
10451+
1042910452
/*
1043010453
* get_column_alias_list - print column alias list for an RTE
1043110454
*

‎src/test/regress/expected/rules.out

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2971,28 +2971,21 @@ select * from rules_log;
29712971
(16 rows)
29722972

29732973
create rule r4 as on delete to rules_src do notify rules_src_deletion;
2974-
\d+ rules_src
2975-
Table "public.rules_src"
2976-
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
2977-
--------+---------+-----------+----------+---------+---------+--------------+-------------
2978-
f1 | integer | | | | plain | |
2979-
f2 | integer | | | 0 | plain | |
2980-
Rules:
2981-
r1 AS
2982-
ON UPDATE TO rules_src DO INSERT INTO rules_log (f1, f2, tag, id) VALUES (old.f1,old.f2,'old'::text,DEFAULT), (new.f1,new.f2,'new'::text,DEFAULT)
2983-
r2 AS
2984-
ON UPDATE TO rules_src DO VALUES (old.f1,old.f2,'old'::text), (new.f1,new.f2,'new'::text)
2985-
r3 AS
2986-
ON INSERT TO rules_src DO INSERT INTO rules_log (f1, f2, tag, id) VALUES (NULL::integer,NULL::integer,'-'::text,DEFAULT), (new.f1,new.f2,'new'::text,DEFAULT)
2987-
r4 AS
2988-
ON DELETE TO rules_src DO
2989-
NOTIFY rules_src_deletion
2990-
29912974
--
29922975
-- Ensure an aliased target relation for insert is correctly deparsed.
29932976
--
29942977
create rule r5 as on insert to rules_src do instead insert into rules_log AS trgt SELECT NEW.* RETURNING trgt.f1, trgt.f2;
29952978
create rule r6 as on update to rules_src do instead UPDATE rules_log AS trgt SET tag = 'updated' WHERE trgt.f1 = new.f1;
2979+
--
2980+
-- Check deparse disambiguation of INSERT/UPDATE/DELETE targets.
2981+
--
2982+
create rule r7 as on delete to rules_src do instead
2983+
with wins as (insert into int4_tbl as trgt values (0) returning *),
2984+
wupd as (update int4_tbl trgt set f1 = f1+1 returning *),
2985+
wdel as (delete from int4_tbl trgt where f1 = 0 returning *)
2986+
insert into rules_log AS trgt select old.* from wins, wupd, wdel
2987+
returning trgt.f1, trgt.f2;
2988+
-- check display of all rules added above
29962989
\d+ rules_src
29972990
Table "public.rules_src"
29982991
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
@@ -3017,6 +3010,26 @@ Rules:
30173010
r6 AS
30183011
ON UPDATE TO rules_src DO INSTEAD UPDATE rules_log trgt SET tag = 'updated'::text
30193012
WHERE trgt.f1 = new.f1
3013+
r7 AS
3014+
ON DELETE TO rules_src DO INSTEAD WITH wins AS (
3015+
INSERT INTO int4_tbl AS trgt_1 (f1)
3016+
VALUES (0)
3017+
RETURNING trgt_1.f1
3018+
), wupd AS (
3019+
UPDATE int4_tbl trgt_1 SET f1 = trgt_1.f1 + 1
3020+
RETURNING trgt_1.f1
3021+
), wdel AS (
3022+
DELETE FROM int4_tbl trgt_1
3023+
WHERE trgt_1.f1 = 0
3024+
RETURNING trgt_1.f1
3025+
)
3026+
INSERT INTO rules_log AS trgt (f1, f2) SELECT old.f1,
3027+
old.f2
3028+
FROM wins,
3029+
wupd,
3030+
wdel
3031+
RETURNING trgt.f1,
3032+
trgt.f2
30203033

30213034
--
30223035
-- check alter rename rule

‎src/test/regress/sql/rules.sql

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,13 +1034,24 @@ insert into rules_src values(22,23), (33,default);
10341034
select*from rules_src;
10351035
select*from rules_log;
10361036
createruler4ason delete to rules_src do notify rules_src_deletion;
1037-
\d+ rules_src
10381037

10391038
--
10401039
-- Ensure an aliased target relation for insert is correctly deparsed.
10411040
--
10421041
createruler5ason insert to rules_src do insteadinsert into rules_logAS trgtSELECT NEW.* RETURNINGtrgt.f1,trgt.f2;
10431042
createruler6asonupdate to rules_src do insteadUPDATE rules_logAS trgtSET tag='updated'WHEREtrgt.f1=new.f1;
1043+
1044+
--
1045+
-- Check deparse disambiguation of INSERT/UPDATE/DELETE targets.
1046+
--
1047+
createruler7ason delete to rules_src do instead
1048+
with winsas (insert into int4_tblas trgtvalues (0) returning*),
1049+
wupdas (update int4_tbl trgtset f1= f1+1 returning*),
1050+
wdelas (deletefrom int4_tbl trgtwhere f1=0 returning*)
1051+
insert into rules_logAS trgtselect old.*from wins, wupd, wdel
1052+
returningtrgt.f1,trgt.f2;
1053+
1054+
-- check display of all rules added above
10441055
\d+ rules_src
10451056

10461057
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp