aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_utilcmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_utilcmd.c')
-rw-r--r--src/backend/parser/parse_utilcmd.c94
1 files changed, 75 insertions, 19 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index adc0d5b775e..55a74eeaf44 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -108,7 +108,8 @@ static void transformOfType(CreateStmtContext *cxt,
TypeName *ofTypename);
static char *chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt);
static IndexStmt *generateClonedIndexStmt(CreateStmtContext *cxt,
- Relation parent_index, AttrNumber *attmap);
+ Relation source_idx,
+ const AttrNumber *attmap, int attmap_length);
static List *get_collation(Oid collation, Oid actual_datatype);
static List *get_opclass(Oid opclass, Oid actual_datatype);
static void transformIndexConstraints(CreateStmtContext *cxt);
@@ -634,6 +635,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
Relation relation;
TupleDesc tupleDesc;
TupleConstr *constr;
+ AttrNumber *attmap;
AclResult aclresult;
char *comment;
ParseCallbackState pcbstate;
@@ -642,14 +644,14 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
relation = relation_openrv(table_like_clause->relation, AccessShareLock);
- if (relation->rd_rel->relkind != RELKIND_RELATION
- && relation->rd_rel->relkind != RELKIND_VIEW
- && relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE
- && relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
+ if (relation->rd_rel->relkind != RELKIND_RELATION &&
+ relation->rd_rel->relkind != RELKIND_VIEW &&
+ relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
+ relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a table, view, composite type, or foreign table",
- table_like_clause->relation->relname)));
+ RelationGetRelationName(relation))));
cancel_parser_errposition_callback(&pcbstate);
@@ -677,6 +679,13 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
constr = tupleDesc->constr;
/*
+ * Initialize column number map for map_variable_attnos(). We need this
+ * since dropped columns in the source table aren't copied, so the new
+ * table can have different column numbers.
+ */
+ attmap = (AttrNumber *) palloc0(sizeof(AttrNumber) * tupleDesc->natts);
+
+ /*
* Insert the copied attributes into the cxt for the new table definition.
*/
for (parent_attno = 1; parent_attno <= tupleDesc->natts;
@@ -687,7 +696,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
ColumnDef *def;
/*
- * Ignore dropped columns in the parent.
+ * Ignore dropped columns in the parent. attmap entry is left zero.
*/
if (attribute->attisdropped)
continue;
@@ -718,6 +727,8 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
*/
cxt->columns = lappend(cxt->columns, def);
+ attmap[parent_attno - 1] = list_length(cxt->columns);
+
/*
* Copy default, if present and the default has been requested
*/
@@ -776,22 +787,39 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
/*
* Copy CHECK constraints if requested, being careful to adjust attribute
- * numbers
+ * numbers so they match the child.
*/
if ((table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) &&
tupleDesc->constr)
{
- AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns);
int ccnum;
for (ccnum = 0; ccnum < tupleDesc->constr->num_check; ccnum++)
{
char *ccname = tupleDesc->constr->check[ccnum].ccname;
char *ccbin = tupleDesc->constr->check[ccnum].ccbin;
- Node *ccbin_node = stringToNode(ccbin);
Constraint *n = makeNode(Constraint);
+ Node *ccbin_node;
+ bool found_whole_row;
+
+ ccbin_node = map_variable_attnos(stringToNode(ccbin),
+ 1, 0,
+ attmap, tupleDesc->natts,
+ &found_whole_row);
- change_varattnos_of_a_node(ccbin_node, attmap);
+ /*
+ * We reject whole-row variables because the whole point of LIKE
+ * is that the new table's rowtype might later diverge from the
+ * parent's. So, while translation might be possible right now,
+ * it wouldn't be possible to guarantee it would work in future.
+ */
+ if (found_whole_row)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot convert whole-row table reference"),
+ errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
+ ccname,
+ RelationGetRelationName(relation))));
n->contype = CONSTR_CHECK;
n->location = -1;
@@ -827,7 +855,6 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
if ((table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) &&
relation->rd_rel->relhasindex)
{
- AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns);
List *parent_indexes;
ListCell *l;
@@ -842,7 +869,8 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
parent_index = index_open(parent_index_oid, AccessShareLock);
/* Build CREATE INDEX statement to recreate the parent_index */
- index_stmt = generateClonedIndexStmt(cxt, parent_index, attmap);
+ index_stmt = generateClonedIndexStmt(cxt, parent_index,
+ attmap, tupleDesc->natts);
/* Copy comment on index */
if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
@@ -961,7 +989,7 @@ chooseIndexName(const RangeVar *relation, IndexStmt *index_stmt)
*/
static IndexStmt *
generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
- AttrNumber *attmap)
+ const AttrNumber *attmap, int attmap_length)
{
Oid source_relid = RelationGetRelid(source_idx);
Form_pg_attribute *attrs = RelationGetDescr(source_idx)->attrs;
@@ -1149,14 +1177,26 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
{
/* Expressional index */
Node *indexkey;
+ bool found_whole_row;
if (indexpr_item == NULL)
elog(ERROR, "too few entries in indexprs list");
indexkey = (Node *) lfirst(indexpr_item);
indexpr_item = lnext(indexpr_item);
- /* OK to modify indexkey since we are working on a private copy */
- change_varattnos_of_a_node(indexkey, attmap);
+ /* Adjust Vars to match new table's column numbering */
+ indexkey = map_variable_attnos(indexkey,
+ 1, 0,
+ attmap, attmap_length,
+ &found_whole_row);
+
+ /* As in transformTableLikeClause, reject whole-row variables */
+ if (found_whole_row)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot convert whole-row table reference"),
+ errdetail("Index \"%s\" contains a whole-row table reference.",
+ RelationGetRelationName(source_idx))));
iparam->name = NULL;
iparam->expr = indexkey;
@@ -1213,12 +1253,28 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
if (!isnull)
{
char *pred_str;
+ Node *pred_tree;
+ bool found_whole_row;
/* Convert text string to node tree */
pred_str = TextDatumGetCString(datum);
- index->whereClause = (Node *) stringToNode(pred_str);
- /* Adjust attribute numbers */
- change_varattnos_of_a_node(index->whereClause, attmap);
+ pred_tree = (Node *) stringToNode(pred_str);
+
+ /* Adjust Vars to match new table's column numbering */
+ pred_tree = map_variable_attnos(pred_tree,
+ 1, 0,
+ attmap, attmap_length,
+ &found_whole_row);
+
+ /* As in transformTableLikeClause, reject whole-row variables */
+ if (found_whole_row)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot convert whole-row table reference"),
+ errdetail("Index \"%s\" contains a whole-row table reference.",
+ RelationGetRelationName(source_idx))));
+
+ index->whereClause = pred_tree;
}
/* Clean up */