@@ -21,7 +21,9 @@ import (
2121 "github.com/dolthub/go-mysql-server/sql/transform"
2222
2323 "github.com/dolthub/go-mysql-server/sql"
24+ "github.com/dolthub/go-mysql-server/sql/expression"
2425 "github.com/dolthub/go-mysql-server/sql/plan"
26+ "github.com/dolthub/go-mysql-server/sql/planbuilder"
2527)
2628
2729// applyForeignKeys handles the application and resolution of foreign keys and their tables.
@@ -380,7 +382,19 @@ func getForeignKeyRefActions(ctx *sql.Context, a *Analyzer, tbl sql.ForeignKeyTa
380382 if err != nil {
381383 return nil , err
382384 }
383- childTblSch := childTbl .Schema ()
385+
386+ // TODO: Foreign key information is not fully added to the plan node until these FK rules in the analyzer,
387+ // but it should be added during the binding phase, in planbuilder. Because this information is added
388+ // late, we have to do extra work here to resolve the schema defaults, which normally would happen
389+ // during binding. This extra FK information also doesn't get its exec indexes fixed up, so we have to
390+ // manually do that here. Moving all the FK information into the binding, planbuilder, phase would
391+ // clean this up. We should also fix assignExecIndexes to find all these FK schema references and fix
392+ // their exec indexes.
393+ childTblSch , err := resolveSchemaDefaults (ctx , a .Catalog , childTbl )
394+ if err != nil {
395+ return nil , err
396+ }
397+
384398 childParentMapping , err := plan .GetChildParentMapping (tblSch , childTblSch , fk )
385399 if err != nil {
386400 return nil , err
@@ -429,6 +443,40 @@ func getForeignKeyRefActions(ctx *sql.Context, a *Analyzer, tbl sql.ForeignKeyTa
429443 return fkEditor , nil
430444}
431445
446+ // resolveSchemaDefaults resolves the default values for the schema of |table|. This is primarily needed for column
447+ // default value expressions, since those don't get resolved during the planbuilder phase and assignExecIndexes
448+ // doesn't traverse through the ForeignKeyEditors and referential actions to find all of them. In addition to resolving
449+ // the expressions, this also ensures their GetField indexes are correct, knowing that those expressions will only
450+ // be evaluated in the context of a single table.
451+ func resolveSchemaDefaults (ctx * sql.Context , catalog * Catalog , table sql.Table ) (sql.Schema , error ) {
452+ // Resolve any column default expressions in tblSch
453+ builder := planbuilder .New (ctx , catalog , nil , sql .GlobalParser )
454+ childTblSch := builder .ResolveSchemaDefaults (ctx .GetCurrentDatabase (), table .Name (), table .Schema ())
455+
456+ // Field Indexes are off by one initially and don't fixed by assignExecIndexes because it doesn't traverse through
457+ // the ForeignKeyEditors and referential actions, so we correct them here. This is safe because we know these fields
458+ // will only ever be accessed within the scope of a single table, so all we have to do is decrement the index by 1.
459+ for i , col := range childTblSch {
460+ if col .Default != nil {
461+ expr := col .Default .Expr
462+ expr , identity , err := transform .Expr (expr , func (e sql.Expression ) (sql.Expression , transform.TreeIdentity , error ) {
463+ if gf , ok := e .(* expression.GetField ); ok {
464+ return gf .WithIndex (gf .Index () - 1 ), transform .NewTree , nil
465+ }
466+ return e , transform .SameTree , nil
467+ })
468+ if err != nil {
469+ return nil , err
470+ }
471+ if identity == transform .NewTree {
472+ childTblSch [i ].Default .Expr = expr
473+ }
474+ }
475+ }
476+
477+ return childTblSch , nil
478+ }
479+
432480// foreignKeyTableName is the combination of a table's database along with their name, both lowercased.
433481type foreignKeyTableName struct {
434482 dbName string
0 commit comments