Skip to content

Commit

Permalink
sql: implement VALIDATE of CHECK constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
dt committed Sep 8, 2016
1 parent 8c6a277 commit 919f042
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 6 deletions.
41 changes: 37 additions & 4 deletions sql/alter_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package sql

import (
"bytes"
"fmt"

"github.com/cockroachdb/cockroach/sql/parser"
Expand Down Expand Up @@ -248,16 +249,35 @@ func (n *alterTableNode) Start() error {
return err
}
name := string(t.Constraint)
details, ok := info[name]
constraint, ok := info[name]
if !ok {
return errors.Errorf("constraint %q does not exist", t.Constraint)
}
if !details.Unvalidated {
if !constraint.Unvalidated {
continue
}
switch details.Kind {
switch constraint.Kind {
case sqlbase.ConstraintTypeCheck:
found := false
var idx int
for idx = range n.tableDesc.Checks {
if n.tableDesc.Checks[idx].Name == name {
found = true
break
}
}
if !found {
panic("constrint returned by GetConstraintInfo not found")
}
ck := n.tableDesc.Checks[idx]
if err := n.p.validateCheckExpr(ck.Expr, &n.n.Table, n.tableDesc); err != nil {
return err
}
n.tableDesc.Checks[idx].Validity = sqlbase.ConstraintValidity_Validated
descriptorChanged = true

default:
return errors.Errorf("validating %s constraint %q unsupported", details.Kind, t.Constraint)
return errors.Errorf("validating %s constraint %q unsupported", constraint.Kind, t.Constraint)
}

case parser.ColumnMutationCmd:
Expand Down Expand Up @@ -371,3 +391,16 @@ func applyColumnMutation(col *sqlbase.ColumnDescriptor, mut parser.ColumnMutatio
}
return nil
}

func labeledRowValues(cols []sqlbase.ColumnDescriptor, values parser.DTuple) string {
var s bytes.Buffer
for i := range cols {
if i != 0 {
s.WriteString(`, `)
}
s.WriteString(cols[i].Name)
s.WriteString(`=`)
s.WriteString(values[i].String())
}
return s.String()
}
38 changes: 38 additions & 0 deletions sql/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/cockroachdb/cockroach/sql/parser"
"github.com/cockroachdb/cockroach/sql/sqlbase"
"github.com/pkg/errors"
)

type checkHelper struct {
Expand Down Expand Up @@ -89,3 +90,40 @@ func (c *checkHelper) check(ctx *parser.EvalContext) error {
}
return nil
}

func (p *planner) validateCheckExpr(
exprStr string,
tableName parser.TableExpr,
tableDesc *sqlbase.TableDescriptor,
) error {
expr, err := parser.ParseExprTraditional(exprStr)
if err != nil {
return err
}
sel := &parser.SelectClause{
Exprs: sqlbase.ColumnsSelectors(tableDesc.Columns),
From: &parser.From{Tables: parser.TableExprs{tableName}},
Where: &parser.Where{Expr: &parser.NotExpr{Expr: expr}},
}
lim := &parser.Limit{Count: parser.NewDInt(1)}
// This could potentially use a variant of planner.SelectClause that could
// use the tableDesc we have, but this is a rare operation and be benefit
// would be marginal compared to the work of the actual query, so the added
// complexity seems unjustified.
rows, err := p.SelectClause(sel, nil, lim, nil, publicColumns)
if err := rows.expandPlan(); err != nil {
return err
}
if err := rows.Start(); err != nil {
return err
}
next, err := rows.Next()
if err != nil {
return err
}
if next {
return errors.Errorf("validation of CHECK %q failed on row: %s",
expr.String(), labeledRowValues(tableDesc.Columns, rows.Values()))
}
return nil
}
2 changes: 1 addition & 1 deletion sql/parser/sql.y
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ opt_validate_behavior:
}
| /* EMPTY */
{
$$.val = ValidationDefault
$$.val = ValidationDefault
}

opt_collate_clause:
Expand Down
17 changes: 16 additions & 1 deletion sql/testdata/alter_table
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,27 @@ t fk_f_ref_other FOREIGN KEY f other.[b]
t foo UNIQUE b NULL
t primary PRIMARY KEY a NULL

statement error validating CHECK constraint "check_a" unsupported
statement error constraint "typo" does not exist
ALTER TABLE t VALIDATE CONSTRAINT typo

statement error validation of CHECK "a > 0" failed on row: a=-2, f=9, b=NULL, c=NULL
ALTER TABLE t VALIDATE CONSTRAINT check_a

statement ok
DELETE FROM t WHERE a = -2

statement ok
ALTER TABLE t VALIDATE CONSTRAINT check_a

query TTTTT
SHOW CONSTRAINTS FROM t
----
t check_a CHECK NULL a > 0
t check_a1 CHECK (UNVALIDATED) NULL a > 0
t fk_f_ref_other FOREIGN KEY f other.[b]
t foo UNIQUE b NULL
t primary PRIMARY KEY a NULL

statement ok
ALTER TABLE t DROP CONSTRAINT check_a, DROP CONSTRAINT check_a1

Expand Down

0 comments on commit 919f042

Please sign in to comment.