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

Commitafc7328

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 parent580bde7 commitafc7328

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
@@ -62,6 +62,7 @@
6262
#include"parser/parser.h"
6363
#include"rewrite/rewriteDefine.h"
6464
#include"rewrite/rewriteHandler.h"
65+
#include"rewrite/rewriteManip.h"
6566
#include"storage/bufmgr.h"
6667
#include"storage/lmgr.h"
6768
#include"storage/smgr.h"
@@ -225,7 +226,6 @@ static void truncate_check_rel(Relation rel);
225226
staticList*MergeAttributes(List*schema,List*supers,boolistemp,
226227
List**supOids,List**supconstr,int*supOidCount);
227228
staticboolMergeCheckConstraint(List*constraints,char*name,Node*expr);
228-
staticboolchange_varattnos_walker(Node*node,constAttrNumber*newattno);
229229
staticvoidMergeAttributesIntoExisting(Relationchild_rel,Relationparent_rel);
230230
staticvoidMergeConstraintsIntoExisting(Relationchild_rel,Relationparent_rel);
231231
staticvoidStoreCatalogInheritance(OidrelationId,List*supers);
@@ -1353,7 +1353,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
13531353
* parents after the first one, nor if we have dropped columns.)
13541354
*/
13551355
newattno= (AttrNumber*)
1356-
palloc(tupleDesc->natts*sizeof(AttrNumber));
1356+
palloc0(tupleDesc->natts*sizeof(AttrNumber));
13571357

13581358
for (parent_attno=1;parent_attno <=tupleDesc->natts;
13591359
parent_attno++)
@@ -1367,15 +1367,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
13671367
* Ignore dropped columns in the parent.
13681368
*/
13691369
if (attribute->attisdropped)
1370-
{
1371-
/*
1372-
* change_varattnos_of_a_node asserts that this is greater
1373-
* than zero, so if anything tries to use it, we should find
1374-
* out.
1375-
*/
1376-
newattno[parent_attno-1]=0;
1377-
continue;
1378-
}
1370+
continue;/* leave newattno entry as zero */
13791371

13801372
/*
13811373
* Does it conflict with some previously inherited column?
@@ -1500,10 +1492,26 @@ MergeAttributes(List *schema, List *supers, bool istemp,
15001492
{
15011493
char*name=check[i].ccname;
15021494
Node*expr;
1495+
boolfound_whole_row;
1496+
1497+
/* Adjust Vars to match new table's column numbering */
1498+
expr=map_variable_attnos(stringToNode(check[i].ccbin),
1499+
1,0,
1500+
newattno,tupleDesc->natts,
1501+
&found_whole_row);
15031502

1504-
/* adjust varattnos of ccbin here */
1505-
expr=stringToNode(check[i].ccbin);
1506-
change_varattnos_of_a_node(expr,newattno);
1503+
/*
1504+
* For the moment we have to reject whole-row variables.
1505+
* We could convert them, if we knew the new table's rowtype
1506+
* OID, but that hasn't been assigned yet.
1507+
*/
1508+
if (found_whole_row)
1509+
ereport(ERROR,
1510+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1511+
errmsg("cannot convert whole-row table reference"),
1512+
errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
1513+
name,
1514+
RelationGetRelationName(relation))));
15071515

15081516
/* check for duplicate */
15091517
if (!MergeCheckConstraint(constraints,name,expr))
@@ -1692,101 +1700,6 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr)
16921700
}
16931701

16941702

1695-
/*
1696-
* Replace varattno values in an expression tree according to the given
1697-
* map array, that is, varattno N is replaced by newattno[N-1]. It is
1698-
* caller's responsibility to ensure that the array is long enough to
1699-
* define values for all user varattnos present in the tree. System column
1700-
* attnos remain unchanged.
1701-
*
1702-
* Note that the passed node tree is modified in-place!
1703-
*/
1704-
void
1705-
change_varattnos_of_a_node(Node*node,constAttrNumber*newattno)
1706-
{
1707-
/* no setup needed, so away we go */
1708-
(void)change_varattnos_walker(node,newattno);
1709-
}
1710-
1711-
staticbool
1712-
change_varattnos_walker(Node*node,constAttrNumber*newattno)
1713-
{
1714-
if (node==NULL)
1715-
return false;
1716-
if (IsA(node,Var))
1717-
{
1718-
Var*var= (Var*)node;
1719-
1720-
if (var->varlevelsup==0&&var->varno==1&&
1721-
var->varattno>0)
1722-
{
1723-
/*
1724-
* ??? the following may be a problem when the node is multiply
1725-
* referenced though stringToNode() doesn't create such a node
1726-
* currently.
1727-
*/
1728-
Assert(newattno[var->varattno-1]>0);
1729-
var->varattno=var->varoattno=newattno[var->varattno-1];
1730-
}
1731-
return false;
1732-
}
1733-
returnexpression_tree_walker(node,change_varattnos_walker,
1734-
(void*)newattno);
1735-
}
1736-
1737-
/*
1738-
* Generate a map for change_varattnos_of_a_node from old and new TupleDesc's,
1739-
* matching according to column name.
1740-
*/
1741-
AttrNumber*
1742-
varattnos_map(TupleDescolddesc,TupleDescnewdesc)
1743-
{
1744-
AttrNumber*attmap;
1745-
inti,
1746-
j;
1747-
1748-
attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*olddesc->natts);
1749-
for (i=1;i <=olddesc->natts;i++)
1750-
{
1751-
if (olddesc->attrs[i-1]->attisdropped)
1752-
continue;/* leave the entry as zero */
1753-
1754-
for (j=1;j <=newdesc->natts;j++)
1755-
{
1756-
if (strcmp(NameStr(olddesc->attrs[i-1]->attname),
1757-
NameStr(newdesc->attrs[j-1]->attname))==0)
1758-
{
1759-
attmap[i-1]=j;
1760-
break;
1761-
}
1762-
}
1763-
}
1764-
returnattmap;
1765-
}
1766-
1767-
/*
1768-
* Generate a map for change_varattnos_of_a_node from a TupleDesc and a list
1769-
* of ColumnDefs
1770-
*/
1771-
AttrNumber*
1772-
varattnos_map_schema(TupleDescold,List*schema)
1773-
{
1774-
AttrNumber*attmap;
1775-
inti;
1776-
1777-
attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*old->natts);
1778-
for (i=1;i <=old->natts;i++)
1779-
{
1780-
if (old->attrs[i-1]->attisdropped)
1781-
continue;/* leave the entry as zero */
1782-
1783-
attmap[i-1]=findAttrByName(NameStr(old->attrs[i-1]->attname),
1784-
schema);
1785-
}
1786-
returnattmap;
1787-
}
1788-
1789-
17901703
/*
17911704
* StoreCatalogInheritance
17921705
*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
@@ -109,7 +109,8 @@ static void transformOfType(ParseState *pstate, CreateStmtContext *cxt,
109109
TypeName*ofTypename);
110110
staticchar*chooseIndexName(constRangeVar*relation,IndexStmt*index_stmt);
111111
staticIndexStmt*generateClonedIndexStmt(CreateStmtContext*cxt,
112-
Relationparent_index,AttrNumber*attmap);
112+
Relationsource_idx,
113+
constAttrNumber*attmap,intattmap_length);
113114
staticList*get_opclass(Oidopclass,Oidactual_datatype);
114115
staticvoidtransformIndexConstraints(ParseState*pstate,
115116
CreateStmtContext*cxt);
@@ -579,6 +580,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
579580
Relationrelation;
580581
TupleDesctupleDesc;
581582
TupleConstr*constr;
583+
AttrNumber*attmap;
582584
AclResultaclresult;
583585
char*comment;
584586

@@ -602,6 +604,13 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
602604
tupleDesc=RelationGetDescr(relation);
603605
constr=tupleDesc->constr;
604606

607+
/*
608+
* Initialize column number map for map_variable_attnos(). We need this
609+
* since dropped columns in the source table aren't copied, so the new
610+
* table can have different column numbers.
611+
*/
612+
attmap= (AttrNumber*)palloc0(sizeof(AttrNumber)*tupleDesc->natts);
613+
605614
/*
606615
* Insert the copied attributes into the cxt for the new table definition.
607616
*/
@@ -613,7 +622,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
613622
ColumnDef*def;
614623

615624
/*
616-
* Ignore dropped columns in the parent.
625+
* Ignore dropped columns in the parent. attmap entry is left zero.
617626
*/
618627
if (attribute->attisdropped)
619628
continue;
@@ -640,6 +649,8 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
640649
*/
641650
cxt->columns=lappend(cxt->columns,def);
642651

652+
attmap[parent_attno-1]=list_length(cxt->columns);
653+
643654
/*
644655
* Copy default, if present and the default has been requested
645656
*/
@@ -698,22 +709,39 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
698709

699710
/*
700711
* Copy CHECK constraints if requested, being careful to adjust attribute
701-
* numbers
712+
* numbers so they match the child.
702713
*/
703714
if ((inhRelation->options&CREATE_TABLE_LIKE_CONSTRAINTS)&&
704715
tupleDesc->constr)
705716
{
706-
AttrNumber*attmap=varattnos_map_schema(tupleDesc,cxt->columns);
707717
intccnum;
708718

709719
for (ccnum=0;ccnum<tupleDesc->constr->num_check;ccnum++)
710720
{
711721
char*ccname=tupleDesc->constr->check[ccnum].ccname;
712722
char*ccbin=tupleDesc->constr->check[ccnum].ccbin;
713-
Node*ccbin_node=stringToNode(ccbin);
714723
Constraint*n=makeNode(Constraint);
724+
Node*ccbin_node;
725+
boolfound_whole_row;
726+
727+
ccbin_node=map_variable_attnos(stringToNode(ccbin),
728+
1,0,
729+
attmap,tupleDesc->natts,
730+
&found_whole_row);
715731

716-
change_varattnos_of_a_node(ccbin_node,attmap);
732+
/*
733+
* We reject whole-row variables because the whole point of LIKE
734+
* is that the new table's rowtype might later diverge from the
735+
* parent's. So, while translation might be possible right now,
736+
* it wouldn't be possible to guarantee it would work in future.
737+
*/
738+
if (found_whole_row)
739+
ereport(ERROR,
740+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
741+
errmsg("cannot convert whole-row table reference"),
742+
errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
743+
ccname,
744+
RelationGetRelationName(relation))));
717745

718746
n->contype=CONSTR_CHECK;
719747
n->location=-1;
@@ -749,7 +777,6 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
749777
if ((inhRelation->options&CREATE_TABLE_LIKE_INDEXES)&&
750778
relation->rd_rel->relhasindex)
751779
{
752-
AttrNumber*attmap=varattnos_map_schema(tupleDesc,cxt->columns);
753780
List*parent_indexes;
754781
ListCell*l;
755782

@@ -764,7 +791,8 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
764791
parent_index=index_open(parent_index_oid,AccessShareLock);
765792

766793
/* Build CREATE INDEX statement to recreate the parent_index */
767-
index_stmt=generateClonedIndexStmt(cxt,parent_index,attmap);
794+
index_stmt=generateClonedIndexStmt(cxt,parent_index,
795+
attmap,tupleDesc->natts);
768796

769797
/* Copy comment on index */
770798
if (inhRelation->options&CREATE_TABLE_LIKE_COMMENTS)
@@ -879,7 +907,7 @@ chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt)
879907
*/
880908
staticIndexStmt*
881909
generateClonedIndexStmt(CreateStmtContext*cxt,Relationsource_idx,
882-
AttrNumber*attmap)
910+
constAttrNumber*attmap,intattmap_length)
883911
{
884912
Oidsource_relid=RelationGetRelid(source_idx);
885913
Form_pg_attribute*attrs=RelationGetDescr(source_idx)->attrs;
@@ -1059,14 +1087,26 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
10591087
{
10601088
/* Expressional index */
10611089
Node*indexkey;
1090+
boolfound_whole_row;
10621091

10631092
if (indexpr_item==NULL)
10641093
elog(ERROR,"too few entries in indexprs list");
10651094
indexkey= (Node*)lfirst(indexpr_item);
10661095
indexpr_item=lnext(indexpr_item);
10671096

1068-
/* OK to modify indexkey since we are working on a private copy */
1069-
change_varattnos_of_a_node(indexkey,attmap);
1097+
/* Adjust Vars to match new table's column numbering */
1098+
indexkey=map_variable_attnos(indexkey,
1099+
1,0,
1100+
attmap,attmap_length,
1101+
&found_whole_row);
1102+
1103+
/* As in transformTableLikeClause, reject whole-row variables */
1104+
if (found_whole_row)
1105+
ereport(ERROR,
1106+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1107+
errmsg("cannot convert whole-row table reference"),
1108+
errdetail("Index \"%s\" contains a whole-row table reference.",
1109+
RelationGetRelationName(source_idx))));
10701110

10711111
iparam->name=NULL;
10721112
iparam->expr=indexkey;
@@ -1120,12 +1160,28 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
11201160
if (!isnull)
11211161
{
11221162
char*pred_str;
1163+
Node*pred_tree;
1164+
boolfound_whole_row;
11231165

11241166
/* Convert text string to node tree */
11251167
pred_str=TextDatumGetCString(datum);
1126-
index->whereClause= (Node*)stringToNode(pred_str);
1127-
/* Adjust attribute numbers */
1128-
change_varattnos_of_a_node(index->whereClause,attmap);
1168+
pred_tree= (Node*)stringToNode(pred_str);
1169+
1170+
/* Adjust Vars to match new table's column numbering */
1171+
pred_tree=map_variable_attnos(pred_tree,
1172+
1,0,
1173+
attmap,attmap_length,
1174+
&found_whole_row);
1175+
1176+
/* As in transformTableLikeClause, reject whole-row variables */
1177+
if (found_whole_row)
1178+
ereport(ERROR,
1179+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1180+
errmsg("cannot convert whole-row table reference"),
1181+
errdetail("Index \"%s\" contains a whole-row table reference.",
1182+
RelationGetRelationName(source_idx))));
1183+
1184+
index->whereClause=pred_tree;
11291185
}
11301186

11311187
/* Clean up */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp