diff options
Diffstat (limited to 'src/backend/parser/parse_utilcmd.c')
| -rw-r--r-- | src/backend/parser/parse_utilcmd.c | 84 |
1 files changed, 70 insertions, 14 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index d1e1dac3a1e..afd38c3ef98 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -109,7 +109,8 @@ static void transformOfType(ParseState *pstate, 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_opclass(Oid opclass, Oid actual_datatype); static void transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt); @@ -579,6 +580,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, Relation relation; TupleDesc tupleDesc; TupleConstr *constr; + AttrNumber *attmap; AclResult aclresult; char *comment; @@ -603,6 +605,13 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, 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; @@ -613,7 +622,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, ColumnDef *def; /* - * Ignore dropped columns in the parent. + * Ignore dropped columns in the parent. attmap entry is left zero. */ if (attribute->attisdropped) continue; @@ -640,6 +649,8 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, */ cxt->columns = lappend(cxt->columns, def); + attmap[parent_attno - 1] = list_length(cxt->columns); + /* * Copy default, if present and the default has been requested */ @@ -698,22 +709,39 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, /* * Copy CHECK constraints if requested, being careful to adjust attribute - * numbers + * numbers so they match the child. */ if ((inhRelation->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; @@ -749,7 +777,6 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, if ((inhRelation->options & CREATE_TABLE_LIKE_INDEXES) && relation->rd_rel->relhasindex) { - AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns); List *parent_indexes; ListCell *l; @@ -764,7 +791,8 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt, 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 (inhRelation->options & CREATE_TABLE_LIKE_COMMENTS) @@ -879,7 +907,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; @@ -1059,14 +1087,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; @@ -1120,12 +1160,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 */ |
