Skip to content

Commit abc950c

Browse files
authored
Merge pull request #3062 from dolthub/elianddb/9438-allow-default-update-val
Allow DEFAULT keyword in UPDATE for generated columns (issue #9438)
2 parents ffdc4a9 + 2cfb9cb commit abc950c

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

enginetest/queries/generated_columns.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,47 @@ var GeneratedColumnTests = []ScriptTest{
9595
},
9696
},
9797
},
98+
{
99+
Name: "generated column with DEFAULT in UPDATE clause (issue #9438)",
100+
SetUpScript: []string{
101+
"create table t (i int primary key, j int generated always as (i + 10))",
102+
"insert into t (i) values (1), (2), (3)",
103+
},
104+
Assertions: []ScriptTestAssertion{
105+
{
106+
Query: "select * from t order by i",
107+
Expected: []sql.Row{{1, 11}, {2, 12}, {3, 13}},
108+
},
109+
{
110+
Query: "update t set j = default",
111+
Expected: []sql.Row{{NewUpdateResult(3, 0)}}, // 3 rows matched, 0 changed (values already correct)
112+
},
113+
{
114+
Query: "select * from t order by i",
115+
Expected: []sql.Row{{1, 11}, {2, 12}, {3, 13}}, // Values should remain the same
116+
},
117+
{
118+
Query: "update t set i = 5 where i = 1", // This should update both i and j (through generation)
119+
Expected: []sql.Row{{NewUpdateResult(1, 1)}},
120+
},
121+
{
122+
Query: "select * from t order by i",
123+
Expected: []sql.Row{{2, 12}, {3, 13}, {5, 15}}, // j should be updated to i + 10 = 15
124+
},
125+
{
126+
Query: "update t set j = default where i = 5", // Explicit DEFAULT on specific row
127+
Expected: []sql.Row{{NewUpdateResult(1, 0)}}, // 1 row matched, 0 changed (value already correct)
128+
},
129+
{
130+
Query: "select * from t where i = 5",
131+
Expected: []sql.Row{{5, 15}}, // Value should still be correct
132+
},
133+
{
134+
Query: "update t set j = 99", // Should still fail for non-DEFAULT values
135+
ExpectedErr: sql.ErrGeneratedColumnValue,
136+
},
137+
},
138+
},
98139
{
99140
Name: "generated column with DEFAULT in VALUES clause (issue #9428)",
100141
SetUpScript: []string{

sql/planbuilder/dml.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,16 +291,25 @@ func (b *Builder) assignmentExprsToExpressions(inScope *scope, e ast.AssignmentE
291291
colIdx := tableSch.IndexOfColName(gf.Name())
292292
// TODO: during trigger parsing the table in the node is unresolved, so we need this additional bounds check
293293
// This means that trigger execution will be able to update generated columns
294-
// Prevent update of generated columns
295-
if colIdx >= 0 && tableSch[colIdx].Generated != nil {
294+
295+
// Check if this is a DEFAULT expression for a generated column
296+
_, isDefaultExpr := updateExpr.Expr.(*ast.Default)
297+
298+
// Prevent update of generated columns, but allow DEFAULT
299+
if colIdx >= 0 && tableSch[colIdx].Generated != nil && !isDefaultExpr {
296300
err := sql.ErrGeneratedColumnValue.New(tableSch[colIdx].Name, inScope.node.(sql.NameableNode).Name())
297301
b.handleErr(err)
298302
}
299303

300304
// Replace default with column default from resolved schema
301-
if _, ok := updateExpr.Expr.(*ast.Default); ok {
305+
if isDefaultExpr {
302306
if colIdx >= 0 {
303-
innerExpr = expression.WrapExpression(tableSch[colIdx].Default)
307+
// For generated columns, use the generated expression as the default
308+
if tableSch[colIdx].Generated != nil {
309+
innerExpr = expression.WrapExpression(tableSch[colIdx].Generated)
310+
} else {
311+
innerExpr = expression.WrapExpression(tableSch[colIdx].Default)
312+
}
304313
}
305314
}
306315
}

0 commit comments

Comments
 (0)