Skip to content

Commit

Permalink
sql: support expressions in unique constraints
Browse files Browse the repository at this point in the history
Postgres does not allow expressions in unique constraints, but it does
allow expressions in unique indexes. For now we allow expressions in
unique constraints, because we cannot differentiate between a unique
constraint and a unique index table definition: they are both parsed
into the same struct, `tree.UniqueConstraintTableDef`.

In the long term we may want to disallow expression in unique
constraints to be consistent with Postgres. We could do this by changing
the parser so that `UNIQUE ((a + b))` does not parse successfully.
See cockroachdb#65825.

Release note: None
  • Loading branch information
mgartner committed Jul 6, 2021
1 parent d5c08cf commit 5f8aef3
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 10 deletions.
39 changes: 30 additions & 9 deletions pkg/sql/alter_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,19 +228,41 @@ func (n *alterTableNode) startExec(params runParams) error {
continue
}

if err := validateColumnsAreAccessible(n.tableDesc, d.Columns); err != nil {
return err
}

tableName, err := params.p.getQualifiedTableName(params.ctx, n.tableDesc)
if err != nil {
return err
}

if err := replaceExpressionElemsWithVirtualCols(
params.ctx,
n.tableDesc,
tableName,
d.Columns,
false, /* isInverted */
false, /* isNewTable */
params.p.SemaCtx(),
params.EvalContext(),
params.SessionData(),
); err != nil {
return err
}

// Check if the columns exist on the table.
for _, column := range d.Columns {
col, err := n.tableDesc.FindColumnWithName(column.Column)
if column.Expr != nil {
return pgerror.New(
pgcode.InvalidTableDefinition,
"cannot create a unique constraint on an expression, use UNIQUE INDEX instead",
)
}
_, err := n.tableDesc.FindColumnWithName(column.Column)
if err != nil {
return err
}
if col.IsInaccessible() {
return pgerror.Newf(
pgcode.UndefinedColumn,
"column %q is inaccessible and cannot be referenced by a unique constraint",
column.Column,
)
}
}
// If the index is named, ensure that the name is unique.
// Unnamed indexes will be given a unique auto-generated name later on.
Expand All @@ -256,7 +278,6 @@ func (n *alterTableNode) startExec(params runParams) error {
return err
}

var err error
idx, err = params.p.configureIndexDescForNewIndexPartitioning(
params.ctx,
n.tableDesc,
Expand Down
14 changes: 13 additions & 1 deletion pkg/sql/logictest/testdata/logic_test/expression_index
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,18 @@ CREATE TABLE err (a INT, INDEX ((a + z)))
statement error index element expression cannot reference computed columns
CREATE TABLE err (a INT, comp INT AS (a + 10) STORED, INDEX ((comp + 10)))

# TODO(mgartner): Postgres does not allow unique constraints with expressions,
# but does allow unique indexes with expressions. We may want to err in this
# case to be consistent with Postgres. See #65825.
statement ok
CREATE TABLE err (a INT, UNIQUE ((a + 10)))

# TODO(mgartner): Postgres does not allow unique constraints with expressions,
# but does allow unique indexes with expressions. We may want to err in this
# case to be consistent with Postgres. See #65825.
statement ok
ALTER TABLE t ADD CONSTRAINT err UNIQUE ((a + 10))

statement ok
DROP TABLE t

Expand Down Expand Up @@ -186,7 +198,7 @@ statement error column \"crdb_internal_idx_expr_4\" is inaccessible and cannot b
ALTER TABLE t ALTER COLUMN crdb_internal_idx_expr_4 SET NOT NULL

# Referencing an inaccessible column in a UNIQUE constraint is not allowed.
statement error column \"crdb_internal_idx_expr_4\" is inaccessible and cannot be referenced by a unique constraint
statement error column \"crdb_internal_idx_expr_4\" is inaccessible and cannot be referenced
ALTER TABLE t ADD CONSTRAINT err UNIQUE (crdb_internal_idx_expr_4)

# Referencing an inaccessible column in a computed column expression is not
Expand Down

0 comments on commit 5f8aef3

Please sign in to comment.