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

Commit81aa961

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 parentb6fe2df commit81aa961

File tree

5 files changed

+210
-127
lines changed

5 files changed

+210
-127
lines changed

‎src/backend/commands/tablecmds.c

Lines changed: 22 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include"parser/parser.h"
6868
#include"rewrite/rewriteDefine.h"
6969
#include"rewrite/rewriteHandler.h"
70+
#include"rewrite/rewriteManip.h"
7071
#include"storage/bufmgr.h"
7172
#include"storage/lmgr.h"
7273
#include"storage/lock.h"
@@ -245,7 +246,6 @@ static void truncate_check_rel(Relation rel);
245246
staticList*MergeAttributes(List*schema,List*supers,charrelpersistence,
246247
List**supOids,List**supconstr,int*supOidCount);
247248
staticboolMergeCheckConstraint(List*constraints,char*name,Node*expr);
248-
staticboolchange_varattnos_walker(Node*node,constAttrNumber*newattno);
249249
staticvoidMergeAttributesIntoExisting(Relationchild_rel,Relationparent_rel);
250250
staticvoidMergeConstraintsIntoExisting(Relationchild_rel,Relationparent_rel);
251251
staticvoidStoreCatalogInheritance(OidrelationId,List*supers);
@@ -1398,7 +1398,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
13981398
* parents after the first one, nor if we have dropped columns.)
13991399
*/
14001400
newattno= (AttrNumber*)
1401-
palloc(tupleDesc->natts*sizeof(AttrNumber));
1401+
palloc0(tupleDesc->natts*sizeof(AttrNumber));
14021402

14031403
for (parent_attno=1;parent_attno <=tupleDesc->natts;
14041404
parent_attno++)
@@ -1412,15 +1412,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
14121412
* Ignore dropped columns in the parent.
14131413
*/
14141414
if (attribute->attisdropped)
1415-
{
1416-
/*
1417-
* change_varattnos_of_a_node asserts that this is greater
1418-
* than zero, so if anything tries to use it, we should find
1419-
* out.
1420-
*/
1421-
newattno[parent_attno-1]=0;
1422-
continue;
1423-
}
1415+
continue;/* leave newattno entry as zero */
14241416

14251417
/*
14261418
* Does it conflict with some previously inherited column?
@@ -1558,10 +1550,26 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
15581550
{
15591551
char*name=check[i].ccname;
15601552
Node*expr;
1553+
boolfound_whole_row;
1554+
1555+
/* Adjust Vars to match new table's column numbering */
1556+
expr=map_variable_attnos(stringToNode(check[i].ccbin),
1557+
1,0,
1558+
newattno,tupleDesc->natts,
1559+
&found_whole_row);
15611560

1562-
/* adjust varattnos of ccbin here */
1563-
expr=stringToNode(check[i].ccbin);
1564-
change_varattnos_of_a_node(expr,newattno);
1561+
/*
1562+
* For the moment we have to reject whole-row variables.
1563+
* We could convert them, if we knew the new table's rowtype
1564+
* OID, but that hasn't been assigned yet.
1565+
*/
1566+
if (found_whole_row)
1567+
ereport(ERROR,
1568+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1569+
errmsg("cannot convert whole-row table reference"),
1570+
errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
1571+
name,
1572+
RelationGetRelationName(relation))));
15651573

15661574
/* check for duplicate */
15671575
if (!MergeCheckConstraint(constraints,name,expr))
@@ -1762,101 +1770,6 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr)
17621770
}
17631771

17641772

1765-
/*
1766-
* Replace varattno values in an expression tree according to the given
1767-
* map array, that is, varattno N is replaced by newattno[N-1]. It is
1768-
* caller's responsibility to ensure that the array is long enough to
1769-
* define values for all user varattnos present in the tree. System column
1770-
* attnos remain unchanged.
1771-
*
1772-
* Note that the passed node tree is modified in-place!
1773-
*/
1774-
void
1775-
change_varattnos_of_a_node(Node*node,constAttrNumber*newattno)
1776-
{
1777-
/* no setup needed, so away we go */
1778-
(void)change_varattnos_walker(node,newattno);
1779-
}
1780-
1781-
staticbool
1782-
change_varattnos_walker(Node*node,constAttrNumber*newattno)
1783-
{
1784-
if (node==NULL)
1785-
return false;
1786-
if (IsA(node,Var))
1787-
{
1788-
Var*var= (Var*)node;
1789-
1790-
if (var->varlevelsup==0&&var->varno==1&&
1791-
var->varattno>0)
1792-
{
1793-
/*
1794-
* ??? the following may be a problem when the node is multiply
1795-
* referenced though stringToNode() doesn't create such a node
1796-
* currently.
1797-
*/
1798-
Assert(newattno[var->varattno-1]>0);
1799-
var->varattno=var->varoattno=newattno[var->varattno-1];
1800-
}
1801-
return false;
1802-
}
1803-
returnexpression_tree_walker(node,change_varattnos_walker,
1804-
(void*)newattno);
1805-
}
1806-
1807-
/*
1808-
* Generate a map for change_varattnos_of_a_node from old and new TupleDesc's,
1809-
* matching according to column name.
1810-
*/
1811-
AttrNumber*
1812-
varattnos_map(TupleDescolddesc,TupleDescnewdesc)
1813-
{
1814-
AttrNumber*attmap;
1815-
inti,
1816-
j;
1817-
1818-
attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*olddesc->natts);
1819-
for (i=1;i <=olddesc->natts;i++)
1820-
{
1821-
if (olddesc->attrs[i-1]->attisdropped)
1822-
continue;/* leave the entry as zero */
1823-
1824-
for (j=1;j <=newdesc->natts;j++)
1825-
{
1826-
if (strcmp(NameStr(olddesc->attrs[i-1]->attname),
1827-
NameStr(newdesc->attrs[j-1]->attname))==0)
1828-
{
1829-
attmap[i-1]=j;
1830-
break;
1831-
}
1832-
}
1833-
}
1834-
returnattmap;
1835-
}
1836-
1837-
/*
1838-
* Generate a map for change_varattnos_of_a_node from a TupleDesc and a list
1839-
* of ColumnDefs
1840-
*/
1841-
AttrNumber*
1842-
varattnos_map_schema(TupleDescold,List*schema)
1843-
{
1844-
AttrNumber*attmap;
1845-
inti;
1846-
1847-
attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*old->natts);
1848-
for (i=1;i <=old->natts;i++)
1849-
{
1850-
if (old->attrs[i-1]->attisdropped)
1851-
continue;/* leave the entry as zero */
1852-
1853-
attmap[i-1]=findAttrByName(NameStr(old->attrs[i-1]->attname),
1854-
schema);
1855-
}
1856-
returnattmap;
1857-
}
1858-
1859-
18601773
/*
18611774
* StoreCatalogInheritance
18621775
*Updates the system catalogs with proper inheritance information.

‎src/backend/parser/parse_utilcmd.c

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ static void transformOfType(CreateStmtContext *cxt,
111111
TypeName*ofTypename);
112112
staticchar*chooseIndexName(constRangeVar*relation,IndexStmt*index_stmt);
113113
staticIndexStmt*generateClonedIndexStmt(CreateStmtContext*cxt,
114-
Relationparent_index,AttrNumber*attmap);
114+
Relationsource_idx,
115+
constAttrNumber*attmap,intattmap_length);
115116
staticList*get_collation(Oidcollation,Oidactual_datatype);
116117
staticList*get_opclass(Oidopclass,Oidactual_datatype);
117118
staticvoidtransformIndexConstraints(CreateStmtContext*cxt);
@@ -609,6 +610,7 @@ transformInhRelation(CreateStmtContext *cxt, InhRelation *inhRelation)
609610
Relationrelation;
610611
TupleDesctupleDesc;
611612
TupleConstr*constr;
613+
AttrNumber*attmap;
612614
AclResultaclresult;
613615
char*comment;
614616

@@ -633,6 +635,13 @@ transformInhRelation(CreateStmtContext *cxt, InhRelation *inhRelation)
633635
tupleDesc=RelationGetDescr(relation);
634636
constr=tupleDesc->constr;
635637

638+
/*
639+
* Initialize column number map for map_variable_attnos(). We need this
640+
* since dropped columns in the source table aren't copied, so the new
641+
* table can have different column numbers.
642+
*/
643+
attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*tupleDesc->natts);
644+
636645
/*
637646
* Insert the copied attributes into the cxt for the new table definition.
638647
*/
@@ -644,7 +653,7 @@ transformInhRelation(CreateStmtContext *cxt, InhRelation *inhRelation)
644653
ColumnDef*def;
645654

646655
/*
647-
* Ignore dropped columns in the parent.
656+
* Ignore dropped columns in the parent. attmap entry is left zero.
648657
*/
649658
if (attribute->attisdropped)
650659
continue;
@@ -675,6 +684,8 @@ transformInhRelation(CreateStmtContext *cxt, InhRelation *inhRelation)
675684
*/
676685
cxt->columns=lappend(cxt->columns,def);
677686

687+
attmap[parent_attno-1]=list_length(cxt->columns);
688+
678689
/*
679690
* Copy default, if present and the default has been requested
680691
*/
@@ -733,22 +744,39 @@ transformInhRelation(CreateStmtContext *cxt, InhRelation *inhRelation)
733744

734745
/*
735746
* Copy CHECK constraints if requested, being careful to adjust attribute
736-
* numbers
747+
* numbers so they match the child.
737748
*/
738749
if ((inhRelation->options&CREATE_TABLE_LIKE_CONSTRAINTS)&&
739750
tupleDesc->constr)
740751
{
741-
AttrNumber*attmap=varattnos_map_schema(tupleDesc,cxt->columns);
742752
intccnum;
743753

744754
for (ccnum=0;ccnum<tupleDesc->constr->num_check;ccnum++)
745755
{
746756
char*ccname=tupleDesc->constr->check[ccnum].ccname;
747757
char*ccbin=tupleDesc->constr->check[ccnum].ccbin;
748-
Node*ccbin_node=stringToNode(ccbin);
749758
Constraint*n=makeNode(Constraint);
759+
Node*ccbin_node;
760+
boolfound_whole_row;
761+
762+
ccbin_node=map_variable_attnos(stringToNode(ccbin),
763+
1,0,
764+
attmap,tupleDesc->natts,
765+
&found_whole_row);
750766

751-
change_varattnos_of_a_node(ccbin_node,attmap);
767+
/*
768+
* We reject whole-row variables because the whole point of LIKE
769+
* is that the new table's rowtype might later diverge from the
770+
* parent's. So, while translation might be possible right now,
771+
* it wouldn't be possible to guarantee it would work in future.
772+
*/
773+
if (found_whole_row)
774+
ereport(ERROR,
775+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
776+
errmsg("cannot convert whole-row table reference"),
777+
errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
778+
ccname,
779+
RelationGetRelationName(relation))));
752780

753781
n->contype=CONSTR_CHECK;
754782
n->location=-1;
@@ -784,7 +812,6 @@ transformInhRelation(CreateStmtContext *cxt, InhRelation *inhRelation)
784812
if ((inhRelation->options&CREATE_TABLE_LIKE_INDEXES)&&
785813
relation->rd_rel->relhasindex)
786814
{
787-
AttrNumber*attmap=varattnos_map_schema(tupleDesc,cxt->columns);
788815
List*parent_indexes;
789816
ListCell*l;
790817

@@ -799,7 +826,8 @@ transformInhRelation(CreateStmtContext *cxt, InhRelation *inhRelation)
799826
parent_index=index_open(parent_index_oid,AccessShareLock);
800827

801828
/* Build CREATE INDEX statement to recreate the parent_index */
802-
index_stmt=generateClonedIndexStmt(cxt,parent_index,attmap);
829+
index_stmt=generateClonedIndexStmt(cxt,parent_index,
830+
attmap,tupleDesc->natts);
803831

804832
/* Copy comment on index */
805833
if (inhRelation->options&CREATE_TABLE_LIKE_COMMENTS)
@@ -918,7 +946,7 @@ chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt)
918946
*/
919947
staticIndexStmt*
920948
generateClonedIndexStmt(CreateStmtContext*cxt,Relationsource_idx,
921-
AttrNumber*attmap)
949+
constAttrNumber*attmap,intattmap_length)
922950
{
923951
Oidsource_relid=RelationGetRelid(source_idx);
924952
Form_pg_attribute*attrs=RelationGetDescr(source_idx)->attrs;
@@ -1106,14 +1134,26 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
11061134
{
11071135
/* Expressional index */
11081136
Node*indexkey;
1137+
boolfound_whole_row;
11091138

11101139
if (indexpr_item==NULL)
11111140
elog(ERROR,"too few entries in indexprs list");
11121141
indexkey= (Node*)lfirst(indexpr_item);
11131142
indexpr_item=lnext(indexpr_item);
11141143

1115-
/* OK to modify indexkey since we are working on a private copy */
1116-
change_varattnos_of_a_node(indexkey,attmap);
1144+
/* Adjust Vars to match new table's column numbering */
1145+
indexkey=map_variable_attnos(indexkey,
1146+
1,0,
1147+
attmap,attmap_length,
1148+
&found_whole_row);
1149+
1150+
/* As in transformTableLikeClause, reject whole-row variables */
1151+
if (found_whole_row)
1152+
ereport(ERROR,
1153+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1154+
errmsg("cannot convert whole-row table reference"),
1155+
errdetail("Index \"%s\" contains a whole-row table reference.",
1156+
RelationGetRelationName(source_idx))));
11171157

11181158
iparam->name=NULL;
11191159
iparam->expr=indexkey;
@@ -1170,12 +1210,28 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
11701210
if (!isnull)
11711211
{
11721212
char*pred_str;
1213+
Node*pred_tree;
1214+
boolfound_whole_row;
11731215

11741216
/* Convert text string to node tree */
11751217
pred_str=TextDatumGetCString(datum);
1176-
index->whereClause= (Node*)stringToNode(pred_str);
1177-
/* Adjust attribute numbers */
1178-
change_varattnos_of_a_node(index->whereClause,attmap);
1218+
pred_tree= (Node*)stringToNode(pred_str);
1219+
1220+
/* Adjust Vars to match new table's column numbering */
1221+
pred_tree=map_variable_attnos(pred_tree,
1222+
1,0,
1223+
attmap,attmap_length,
1224+
&found_whole_row);
1225+
1226+
/* As in transformTableLikeClause, reject whole-row variables */
1227+
if (found_whole_row)
1228+
ereport(ERROR,
1229+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1230+
errmsg("cannot convert whole-row table reference"),
1231+
errdetail("Index \"%s\" contains a whole-row table reference.",
1232+
RelationGetRelationName(source_idx))));
1233+
1234+
index->whereClause=pred_tree;
11791235
}
11801236

11811237
/* Clean up */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp