Skip to content

Commit 04fa217

Browse files
committed
support NOT VALID on foreign key and check constraints
1 parent 973649d commit 04fa217

9 files changed

Lines changed: 49 additions & 32 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
github.com/dolthub/go-icu-regex v0.0.0-20260412212219-49724d547866
88
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71
99
github.com/dolthub/sqllogictest/go v0.0.0-20240618184124-ca47f9354216
10-
github.com/dolthub/vitess v0.0.0-20260528164423-e3f9fa81284c
10+
github.com/dolthub/vitess v0.0.0-20260602220312-6590d90756af
1111
github.com/go-sql-driver/mysql v1.9.3
1212
github.com/gocraft/dbr/v2 v2.7.2
1313
github.com/google/uuid v1.6.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTE
2020
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI=
2121
github.com/dolthub/sqllogictest/go v0.0.0-20240618184124-ca47f9354216 h1:JWkKRE4EHUcEVQCMRBej8DYxjYjRz/9MdF/NNQh0o70=
2222
github.com/dolthub/sqllogictest/go v0.0.0-20240618184124-ca47f9354216/go.mod h1:e/FIZVvT2IR53HBCAo41NjqgtEnjMJGKca3Y/dAmZaA=
23-
github.com/dolthub/vitess v0.0.0-20260528164423-e3f9fa81284c h1:DRmvqtt1OCIdtFAg8daaaIOGEe6gVWiSlhABDi+lNIg=
24-
github.com/dolthub/vitess v0.0.0-20260528164423-e3f9fa81284c/go.mod h1:dKAkzdfRkAudpc0g8JOQ0eiEjV83TYIFz/yNIEdcjXM=
23+
github.com/dolthub/vitess v0.0.0-20260602220312-6590d90756af h1:QauTjb7U3E/CioI2JrzA7M6srhorGlulI+bBtPGNAdA=
24+
github.com/dolthub/vitess v0.0.0-20260602220312-6590d90756af/go.mod h1:dKAkzdfRkAudpc0g8JOQ0eiEjV83TYIFz/yNIEdcjXM=
2525
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
2626
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
2727
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=

sql/constraints.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ type ForeignKeyConstraint struct {
8383
ParentColumns []string
8484
// IsResolved is true if the foreign key has been resolved, false otherwise
8585
IsResolved bool
86+
// IsNotValid is true when the constraint was created with NOT VALID, meaning existing rows were not checked
87+
IsNotValid bool
8688
}
8789

8890
// IsSelfReferential returns whether this foreign key represents a self-referential foreign key.
@@ -115,13 +117,15 @@ type CheckDefinition struct {
115117
Name string // The name of this check. Check names in a database are unique.
116118
CheckExpression string // String serialization of the check expression
117119
Enforced bool // Whether this constraint is enforced
120+
IsNotValid bool // Where to check existing rows
118121
}
119122

120123
// CheckConstraint declares a boolean-eval constraint.
121124
type CheckConstraint struct {
122-
Expr Expression
123-
Name string
124-
Enforced bool
125+
Expr Expression
126+
Name string
127+
Enforced bool
128+
IsNotValid bool
125129
}
126130

127131
// DebugString implements the DebugStringer interface.

sql/plan/alter_check.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ func NewCheckDefinition(ctx *sql.Context, check *sql.CheckConstraint, schemaForm
171171
Name: check.Name,
172172
CheckExpression: unqualifiedCols.String(),
173173
Enforced: check.Enforced,
174+
IsNotValid: check.IsNotValid,
174175
}, nil
175176
}
176177

sql/planbuilder/builder.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,12 @@ func (b *Builder) buildInjectedStatement(inScope *scope, n ast.InjectedStatement
465465
b.handleErr(err)
466466
return nil
467467
}
468+
if mdb, ok := stmt.(sql.MultiDatabaser); ok {
469+
stmt, err = mdb.WithDatabaseProvider(b.cat)
470+
if err != nil {
471+
b.handleErr(err)
472+
}
473+
}
468474
if sqlNode, ok := stmt.(sql.ExecSourceRel); ok {
469475
outScope = inScope.push()
470476
outScope.node = sqlNode

sql/planbuilder/ddl.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ func (b *Builder) buildConstraintsDefs(inScope *scope, tname ast.TableName, spec
838838
// Database and Table are not set. Call bindForeignKey to fill them in.
839839
func (b *Builder) fkConstraintFromDef(fkDef *ast.ForeignKeyDefinition, name string, columns []string) *sql.ForeignKeyConstraint {
840840
parentCols := make([]string, len(fkDef.ReferencedColumns))
841+
// TODO: if ReferencedColumns is empty, load all columns from parent table
841842
for i, col := range fkDef.ReferencedColumns {
842843
parentCols[i] = col.String()
843844
}
@@ -855,6 +856,7 @@ func (b *Builder) fkConstraintFromDef(fkDef *ast.ForeignKeyDefinition, name stri
855856
OnUpdate: b.buildReferentialAction(fkDef.OnUpdate),
856857
OnDelete: b.buildReferentialAction(fkDef.OnDelete),
857858
IsResolved: false,
859+
IsNotValid: fkDef.NotValid,
858860
}
859861
}
860862

@@ -972,9 +974,10 @@ func (b *Builder) convertConstraintDefinition(inScope *scope, cd *ast.Constraint
972974
}
973975

974976
return &sql.CheckConstraint{
975-
Name: cd.Name,
976-
Expr: c,
977-
Enforced: chConstraint.Enforced,
977+
Name: cd.Name,
978+
Expr: c,
979+
Enforced: chConstraint.Enforced,
980+
IsNotValid: chConstraint.NotValid,
978981
}
979982
} else if len(cd.Name) > 0 && cd.Details == nil {
980983
return namedConstraint{cd.Name}

sql/planbuilder/dml.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -798,8 +798,9 @@ func (b *Builder) buildCheckConstraint(inScope *scope, check *sql.CheckDefinitio
798798
c := b.buildScalar(inScope, ae.Expr)
799799

800800
return &sql.CheckConstraint{
801-
Name: check.Name,
802-
Expr: c,
803-
Enforced: check.Enforced,
801+
Name: check.Name,
802+
Expr: c,
803+
Enforced: check.Enforced,
804+
IsNotValid: check.IsNotValid,
804805
}
805806
}

sql/rowexec/ddl.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1595,7 +1595,7 @@ func (b *BaseBuilder) buildCreateForeignKey(ctx *sql.Context, n *plan.CreateFore
15951595
if err != nil {
15961596
return nil, err
15971597
}
1598-
err = plan.ResolveForeignKey(ctx, fkTbl, refFkTbl, *n.FkDef, true, fkChecks.(int8) == 1, true)
1598+
err = plan.ResolveForeignKey(ctx, fkTbl, refFkTbl, *n.FkDef, true, fkChecks.(int8) == 1, !n.FkDef.IsNotValid)
15991599
if err != nil {
16001600
return nil, err
16011601
}

sql/rowexec/ddl_iters.go

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,30 +1988,32 @@ func (b *BaseBuilder) executeCreateCheck(ctx *sql.Context, c *plan.CreateCheck)
19881988
return err
19891989
}
19901990

1991-
// check existing rows in table
1992-
var res interface{}
1993-
rowIter, err := b.buildNodeExec(ctx, c.Table, nil)
1994-
if err != nil {
1995-
return err
1996-
}
1997-
1998-
for {
1999-
row, err := rowIter.Next(ctx)
2000-
if err == io.EOF {
2001-
break
2002-
}
2003-
1991+
// check existing rows in table, unless the constraint was created with NOT VALID
1992+
if !c.Check.IsNotValid {
1993+
var res interface{}
1994+
rowIter, err := b.buildNodeExec(ctx, c.Table, nil)
20041995
if err != nil {
20051996
return err
20061997
}
20071998

2008-
res, err = sql.EvaluateCondition(ctx, c.Check.Expr, row)
2009-
if err != nil {
2010-
return err
2011-
}
1999+
for {
2000+
row, err := rowIter.Next(ctx)
2001+
if err == io.EOF {
2002+
break
2003+
}
2004+
2005+
if err != nil {
2006+
return err
2007+
}
2008+
2009+
res, err = sql.EvaluateCondition(ctx, c.Check.Expr, row)
2010+
if err != nil {
2011+
return err
2012+
}
20122013

2013-
if sql.IsFalse(res) {
2014-
return sql.ErrCheckConstraintViolated.New(c.Check.Name)
2014+
if sql.IsFalse(res) {
2015+
return sql.ErrCheckConstraintViolated.New(c.Check.Name)
2016+
}
20152017
}
20162018
}
20172019

0 commit comments

Comments
 (0)