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

Commit541ffa6

Browse files
committed
Prevent CREATE TABLE LIKE/INHERITS from (mis) copying whole-row Vars.
If a CHECK constraint or index definition contained a whole-row Var (thatis, "table.*"), an attempt to copy that definition via CREATE TABLE LIKE ortable inheritance produced incorrect results: the copied Var still claimedto have the rowtype of the source table, rather than the created table.For the LIKE case, it seems reasonable to just throw error for thissituation, since the point of LIKE is that the new table is not permanentlycoupled to the old, so there's no reason to assume its rowtype will staycompatible. In the inheritance case, we should ideally allow suchconstraints, but doing so will require nontrivial refactoring of CREATETABLE processing (because we'd need to know the OID of the new table'srowtype before we adjust inherited CHECK constraints). In view of the lackof previous complaints, that doesn't seem worth the risk in a back-patchedbug fix, so just make it throw error for the inheritance case as well.Along the way, replace change_varattnos_of_a_node() with a more robustfunction map_variable_attnos(), which is capable of being extended tohandle insertion of ConvertRowtypeExpr whenever we get around to fixingthe inheritance case nicely, and in the meantime it returns a failureindication to the caller so that a helpful message with some context can bethrown. Also, this code will do the right thing with subselects (if weever allow them in CHECK or indexes), and it range-checks varattnos beforeusing them to index into the map array.Per report from Sergey Konoplev. Back-patch to all supported branches.
1 parente4ffa86 commit541ffa6

File tree

5 files changed

+215
-132
lines changed

5 files changed

+215
-132
lines changed

‎src/backend/commands/tablecmds.c

Lines changed: 22 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#include"parser/parser.h"
6969
#include"rewrite/rewriteDefine.h"
7070
#include"rewrite/rewriteHandler.h"
71+
#include"rewrite/rewriteManip.h"
7172
#include"storage/bufmgr.h"
7273
#include"storage/lmgr.h"
7374
#include"storage/lock.h"
@@ -253,7 +254,6 @@ static void truncate_check_rel(Relation rel);
253254
staticList*MergeAttributes(List*schema,List*supers,charrelpersistence,
254255
List**supOids,List**supconstr,int*supOidCount);
255256
staticboolMergeCheckConstraint(List*constraints,char*name,Node*expr);
256-
staticboolchange_varattnos_walker(Node*node,constAttrNumber*newattno);
257257
staticvoidMergeAttributesIntoExisting(Relationchild_rel,Relationparent_rel);
258258
staticvoidMergeConstraintsIntoExisting(Relationchild_rel,Relationparent_rel);
259259
staticvoidStoreCatalogInheritance(OidrelationId,List*supers);
@@ -1496,7 +1496,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
14961496
* parents after the first one, nor if we have dropped columns.)
14971497
*/
14981498
newattno= (AttrNumber*)
1499-
palloc(tupleDesc->natts*sizeof(AttrNumber));
1499+
palloc0(tupleDesc->natts*sizeof(AttrNumber));
15001500

15011501
for (parent_attno=1;parent_attno <=tupleDesc->natts;
15021502
parent_attno++)
@@ -1510,15 +1510,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
15101510
* Ignore dropped columns in the parent.
15111511
*/
15121512
if (attribute->attisdropped)
1513-
{
1514-
/*
1515-
* change_varattnos_of_a_node asserts that this is greater
1516-
* than zero, so if anything tries to use it, we should find
1517-
* out.
1518-
*/
1519-
newattno[parent_attno-1]=0;
1520-
continue;
1521-
}
1513+
continue;/* leave newattno entry as zero */
15221514

15231515
/*
15241516
* Does it conflict with some previously inherited column?
@@ -1656,14 +1648,30 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
16561648
{
16571649
char*name=check[i].ccname;
16581650
Node*expr;
1651+
boolfound_whole_row;
16591652

16601653
/* ignore if the constraint is non-inheritable */
16611654
if (check[i].ccnoinherit)
16621655
continue;
16631656

1664-
/* adjust varattnos of ccbin here */
1665-
expr=stringToNode(check[i].ccbin);
1666-
change_varattnos_of_a_node(expr,newattno);
1657+
/* Adjust Vars to match new table's column numbering */
1658+
expr=map_variable_attnos(stringToNode(check[i].ccbin),
1659+
1,0,
1660+
newattno,tupleDesc->natts,
1661+
&found_whole_row);
1662+
1663+
/*
1664+
* For the moment we have to reject whole-row variables.
1665+
* We could convert them, if we knew the new table's rowtype
1666+
* OID, but that hasn't been assigned yet.
1667+
*/
1668+
if (found_whole_row)
1669+
ereport(ERROR,
1670+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1671+
errmsg("cannot convert whole-row table reference"),
1672+
errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
1673+
name,
1674+
RelationGetRelationName(relation))));
16671675

16681676
/* check for duplicate */
16691677
if (!MergeCheckConstraint(constraints,name,expr))
@@ -1866,101 +1874,6 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr)
18661874
}
18671875

18681876

1869-
/*
1870-
* Replace varattno values in an expression tree according to the given
1871-
* map array, that is, varattno N is replaced by newattno[N-1]. It is
1872-
* caller's responsibility to ensure that the array is long enough to
1873-
* define values for all user varattnos present in the tree. System column
1874-
* attnos remain unchanged.
1875-
*
1876-
* Note that the passed node tree is modified in-place!
1877-
*/
1878-
void
1879-
change_varattnos_of_a_node(Node*node,constAttrNumber*newattno)
1880-
{
1881-
/* no setup needed, so away we go */
1882-
(void)change_varattnos_walker(node,newattno);
1883-
}
1884-
1885-
staticbool
1886-
change_varattnos_walker(Node*node,constAttrNumber*newattno)
1887-
{
1888-
if (node==NULL)
1889-
return false;
1890-
if (IsA(node,Var))
1891-
{
1892-
Var*var= (Var*)node;
1893-
1894-
if (var->varlevelsup==0&&var->varno==1&&
1895-
var->varattno>0)
1896-
{
1897-
/*
1898-
* ??? the following may be a problem when the node is multiply
1899-
* referenced though stringToNode() doesn't create such a node
1900-
* currently.
1901-
*/
1902-
Assert(newattno[var->varattno-1]>0);
1903-
var->varattno=var->varoattno=newattno[var->varattno-1];
1904-
}
1905-
return false;
1906-
}
1907-
returnexpression_tree_walker(node,change_varattnos_walker,
1908-
(void*)newattno);
1909-
}
1910-
1911-
/*
1912-
* Generate a map for change_varattnos_of_a_node from old and new TupleDesc's,
1913-
* matching according to column name.
1914-
*/
1915-
AttrNumber*
1916-
varattnos_map(TupleDescolddesc,TupleDescnewdesc)
1917-
{
1918-
AttrNumber*attmap;
1919-
inti,
1920-
j;
1921-
1922-
attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*olddesc->natts);
1923-
for (i=1;i <=olddesc->natts;i++)
1924-
{
1925-
if (olddesc->attrs[i-1]->attisdropped)
1926-
continue;/* leave the entry as zero */
1927-
1928-
for (j=1;j <=newdesc->natts;j++)
1929-
{
1930-
if (strcmp(NameStr(olddesc->attrs[i-1]->attname),
1931-
NameStr(newdesc->attrs[j-1]->attname))==0)
1932-
{
1933-
attmap[i-1]=j;
1934-
break;
1935-
}
1936-
}
1937-
}
1938-
returnattmap;
1939-
}
1940-
1941-
/*
1942-
* Generate a map for change_varattnos_of_a_node from a TupleDesc and a list
1943-
* of ColumnDefs
1944-
*/
1945-
AttrNumber*
1946-
varattnos_map_schema(TupleDescold,List*schema)
1947-
{
1948-
AttrNumber*attmap;
1949-
inti;
1950-
1951-
attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*old->natts);
1952-
for (i=1;i <=old->natts;i++)
1953-
{
1954-
if (old->attrs[i-1]->attisdropped)
1955-
continue;/* leave the entry as zero */
1956-
1957-
attmap[i-1]=findAttrByName(NameStr(old->attrs[i-1]->attname),
1958-
schema);
1959-
}
1960-
returnattmap;
1961-
}
1962-
1963-
19641877
/*
19651878
* StoreCatalogInheritance
19661879
*Updates the system catalogs with proper inheritance information.

‎src/backend/parser/parse_utilcmd.c

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ static void transformOfType(CreateStmtContext *cxt,
108108
TypeName*ofTypename);
109109
staticchar*chooseIndexName(constRangeVar*relation,IndexStmt*index_stmt);
110110
staticIndexStmt*generateClonedIndexStmt(CreateStmtContext*cxt,
111-
Relationparent_index,AttrNumber*attmap);
111+
Relationsource_idx,
112+
constAttrNumber*attmap,intattmap_length);
112113
staticList*get_collation(Oidcollation,Oidactual_datatype);
113114
staticList*get_opclass(Oidopclass,Oidactual_datatype);
114115
staticvoidtransformIndexConstraints(CreateStmtContext*cxt);
@@ -634,6 +635,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
634635
Relationrelation;
635636
TupleDesctupleDesc;
636637
TupleConstr*constr;
638+
AttrNumber*attmap;
637639
AclResultaclresult;
638640
char*comment;
639641
ParseCallbackStatepcbstate;
@@ -642,14 +644,14 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
642644

643645
relation=relation_openrv(table_like_clause->relation,AccessShareLock);
644646

645-
if (relation->rd_rel->relkind!=RELKIND_RELATION
646-
&&relation->rd_rel->relkind!=RELKIND_VIEW
647-
&&relation->rd_rel->relkind!=RELKIND_FOREIGN_TABLE
648-
&&relation->rd_rel->relkind!=RELKIND_COMPOSITE_TYPE)
647+
if (relation->rd_rel->relkind!=RELKIND_RELATION&&
648+
relation->rd_rel->relkind!=RELKIND_VIEW&&
649+
relation->rd_rel->relkind!=RELKIND_COMPOSITE_TYPE&&
650+
relation->rd_rel->relkind!=RELKIND_FOREIGN_TABLE)
649651
ereport(ERROR,
650652
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
651653
errmsg("\"%s\" is not a table, view, composite type, or foreign table",
652-
table_like_clause->relation->relname)));
654+
RelationGetRelationName(relation))));
653655

654656
cancel_parser_errposition_callback(&pcbstate);
655657

@@ -676,6 +678,13 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
676678
tupleDesc=RelationGetDescr(relation);
677679
constr=tupleDesc->constr;
678680

681+
/*
682+
* Initialize column number map for map_variable_attnos(). We need this
683+
* since dropped columns in the source table aren't copied, so the new
684+
* table can have different column numbers.
685+
*/
686+
attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*tupleDesc->natts);
687+
679688
/*
680689
* Insert the copied attributes into the cxt for the new table definition.
681690
*/
@@ -687,7 +696,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
687696
ColumnDef*def;
688697

689698
/*
690-
* Ignore dropped columns in the parent.
699+
* Ignore dropped columns in the parent. attmap entry is left zero.
691700
*/
692701
if (attribute->attisdropped)
693702
continue;
@@ -718,6 +727,8 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
718727
*/
719728
cxt->columns=lappend(cxt->columns,def);
720729

730+
attmap[parent_attno-1]=list_length(cxt->columns);
731+
721732
/*
722733
* Copy default, if present and the default has been requested
723734
*/
@@ -776,22 +787,39 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
776787

777788
/*
778789
* Copy CHECK constraints if requested, being careful to adjust attribute
779-
* numbers
790+
* numbers so they match the child.
780791
*/
781792
if ((table_like_clause->options&CREATE_TABLE_LIKE_CONSTRAINTS)&&
782793
tupleDesc->constr)
783794
{
784-
AttrNumber*attmap=varattnos_map_schema(tupleDesc,cxt->columns);
785795
intccnum;
786796

787797
for (ccnum=0;ccnum<tupleDesc->constr->num_check;ccnum++)
788798
{
789799
char*ccname=tupleDesc->constr->check[ccnum].ccname;
790800
char*ccbin=tupleDesc->constr->check[ccnum].ccbin;
791-
Node*ccbin_node=stringToNode(ccbin);
792801
Constraint*n=makeNode(Constraint);
802+
Node*ccbin_node;
803+
boolfound_whole_row;
804+
805+
ccbin_node=map_variable_attnos(stringToNode(ccbin),
806+
1,0,
807+
attmap,tupleDesc->natts,
808+
&found_whole_row);
793809

794-
change_varattnos_of_a_node(ccbin_node,attmap);
810+
/*
811+
* We reject whole-row variables because the whole point of LIKE
812+
* is that the new table's rowtype might later diverge from the
813+
* parent's. So, while translation might be possible right now,
814+
* it wouldn't be possible to guarantee it would work in future.
815+
*/
816+
if (found_whole_row)
817+
ereport(ERROR,
818+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
819+
errmsg("cannot convert whole-row table reference"),
820+
errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
821+
ccname,
822+
RelationGetRelationName(relation))));
795823

796824
n->contype=CONSTR_CHECK;
797825
n->location=-1;
@@ -827,7 +855,6 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
827855
if ((table_like_clause->options&CREATE_TABLE_LIKE_INDEXES)&&
828856
relation->rd_rel->relhasindex)
829857
{
830-
AttrNumber*attmap=varattnos_map_schema(tupleDesc,cxt->columns);
831858
List*parent_indexes;
832859
ListCell*l;
833860

@@ -842,7 +869,8 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
842869
parent_index=index_open(parent_index_oid,AccessShareLock);
843870

844871
/* Build CREATE INDEX statement to recreate the parent_index */
845-
index_stmt=generateClonedIndexStmt(cxt,parent_index,attmap);
872+
index_stmt=generateClonedIndexStmt(cxt,parent_index,
873+
attmap,tupleDesc->natts);
846874

847875
/* Copy comment on index */
848876
if (table_like_clause->options&CREATE_TABLE_LIKE_COMMENTS)
@@ -961,7 +989,7 @@ chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt)
961989
*/
962990
staticIndexStmt*
963991
generateClonedIndexStmt(CreateStmtContext*cxt,Relationsource_idx,
964-
AttrNumber*attmap)
992+
constAttrNumber*attmap,intattmap_length)
965993
{
966994
Oidsource_relid=RelationGetRelid(source_idx);
967995
Form_pg_attribute*attrs=RelationGetDescr(source_idx)->attrs;
@@ -1149,14 +1177,26 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
11491177
{
11501178
/* Expressional index */
11511179
Node*indexkey;
1180+
boolfound_whole_row;
11521181

11531182
if (indexpr_item==NULL)
11541183
elog(ERROR,"too few entries in indexprs list");
11551184
indexkey= (Node*)lfirst(indexpr_item);
11561185
indexpr_item=lnext(indexpr_item);
11571186

1158-
/* OK to modify indexkey since we are working on a private copy */
1159-
change_varattnos_of_a_node(indexkey,attmap);
1187+
/* Adjust Vars to match new table's column numbering */
1188+
indexkey=map_variable_attnos(indexkey,
1189+
1,0,
1190+
attmap,attmap_length,
1191+
&found_whole_row);
1192+
1193+
/* As in transformTableLikeClause, reject whole-row variables */
1194+
if (found_whole_row)
1195+
ereport(ERROR,
1196+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1197+
errmsg("cannot convert whole-row table reference"),
1198+
errdetail("Index \"%s\" contains a whole-row table reference.",
1199+
RelationGetRelationName(source_idx))));
11601200

11611201
iparam->name=NULL;
11621202
iparam->expr=indexkey;
@@ -1213,12 +1253,28 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
12131253
if (!isnull)
12141254
{
12151255
char*pred_str;
1256+
Node*pred_tree;
1257+
boolfound_whole_row;
12161258

12171259
/* Convert text string to node tree */
12181260
pred_str=TextDatumGetCString(datum);
1219-
index->whereClause= (Node*)stringToNode(pred_str);
1220-
/* Adjust attribute numbers */
1221-
change_varattnos_of_a_node(index->whereClause,attmap);
1261+
pred_tree= (Node*)stringToNode(pred_str);
1262+
1263+
/* Adjust Vars to match new table's column numbering */
1264+
pred_tree=map_variable_attnos(pred_tree,
1265+
1,0,
1266+
attmap,attmap_length,
1267+
&found_whole_row);
1268+
1269+
/* As in transformTableLikeClause, reject whole-row variables */
1270+
if (found_whole_row)
1271+
ereport(ERROR,
1272+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1273+
errmsg("cannot convert whole-row table reference"),
1274+
errdetail("Index \"%s\" contains a whole-row table reference.",
1275+
RelationGetRelationName(source_idx))));
1276+
1277+
index->whereClause=pred_tree;
12221278
}
12231279

12241280
/* Clean up */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp