Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pkg/sql/opt/optbuilder/insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,8 @@ func (mb *mutationBuilder) addSynthesizedColsForInsert() {
mb.addAssignmentCasts(mb.insertColIDs)

// Now add all computed columns.
mb.addSynthesizedComputedCols(mb.insertColIDs, false /* restrict */)
mb.addSynthesizedComputedCols(mb.insertColIDs,
&mb.targetColList, &mb.targetColSet, false /* restrict */)

// Add assignment casts for computed column values.
mb.addAssignmentCasts(mb.insertColIDs)
Expand Down
15 changes: 12 additions & 3 deletions pkg/sql/opt/optbuilder/mutation_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -732,11 +732,16 @@ func (mb *mutationBuilder) addSynthesizedDefaultCols(
// expression. New columns are synthesized for any missing columns using the
// computed column expression.
//
// The target table columns corresponding to each projected computed column are
// added to targetColList and targetColSet, if they are not nil.
//
// NOTE: colIDs is updated with the column IDs of any synthesized columns which
// are added to mb.outScope. If restrict is true, only columns that depend on
// columns that were already in the list (plus all write-only columns) are
// updated.
func (mb *mutationBuilder) addSynthesizedComputedCols(colIDs opt.OptionalColList, restrict bool) {
func (mb *mutationBuilder) addSynthesizedComputedCols(
colIDs opt.OptionalColList, targetColList *opt.ColList, targetColSet *opt.ColSet, restrict bool,
) {
// We will construct a new Project operator that will contain the newly
// synthesized column(s).
pb := makeProjectionBuilder(mb.b, mb.outScope)
Expand Down Expand Up @@ -803,8 +808,12 @@ func (mb *mutationBuilder) addSynthesizedComputedCols(colIDs opt.OptionalColList
colIDs[i] = newCol

// Add corresponding target column.
mb.targetColList = append(mb.targetColList, tabColID)
mb.targetColSet.Add(tabColID)
if targetColList != nil {
*targetColList = append(*targetColList, tabColID)
}
if targetColSet != nil {
targetColSet.Add(tabColID)
}
}

mb.outScope = pb.Finish()
Expand Down
106 changes: 106 additions & 0 deletions pkg/sql/opt/optbuilder/testdata/trigger
Original file line number Diff line number Diff line change
Expand Up @@ -1233,3 +1233,109 @@ insert t133329
└── filters
├── a = t133329.a
└── k != t133329.k

# Regression test for #154672. Do not set target columns when re-projecting
# computed columns after a BEFORE trigger.
exec-ddl
CREATE TABLE t154672 (
k INT PRIMARY KEY,
a INT,
b INT AS (a + 1) STORED
)
----

exec-ddl
CREATE FUNCTION f154672() RETURNS TRIGGER LANGUAGE PLpgSQL AS $$
BEGIN
RETURN COALESCE(NEW, OLD);
END
$$
----

exec-ddl
CREATE TRIGGER tr154672 BEFORE INSERT OR UPDATE OR DELETE ON t154672 FOR EACH ROW EXECUTE FUNCTION f154672()
----

norm
INSERT INTO t154672 (k, a) VALUES (1, 2) ON CONFLICT (k) DO UPDATE SET a = 3
----
upsert t154672
├── arbiter indexes: t154672_pkey
├── columns: <none>
├── canary column: k:9
├── fetch columns: k:9 a:10 b:11
├── insert-mapping:
│ ├── k_new:29 => k:1
│ ├── a_new:30 => a:2
│ └── b_comp:31 => b:3
├── update-mapping:
│ ├── upsert_k:40 => k:1
│ ├── upsert_a:41 => a:2
│ └── upsert_b:42 => b:3
├── before-triggers
│ └── tr154672
└── project
├── columns: upsert_k:40 upsert_a:41 upsert_b:42 k:9 a:10 b:11 k_new:29 a_new:30 b_comp:31
├── project
│ ├── columns: k_new:37 a_new:38 k:9 a:10 b:11 k_new:29 a_new:30 b_comp:31
│ ├── barrier
│ │ ├── columns: column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13 new:14 f154672:28!null k_new:29 a_new:30 b_comp:31 a_new:32!null b_comp:33!null old:34 new:35 f154672:36!null
│ │ └── select
│ │ ├── columns: column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13 new:14 f154672:28!null k_new:29 a_new:30 b_comp:31 a_new:32!null b_comp:33!null old:34 new:35 f154672:36!null
│ │ ├── project
│ │ │ ├── columns: f154672:36 column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13 new:14 f154672:28!null k_new:29 a_new:30 b_comp:31 a_new:32!null b_comp:33!null old:34 new:35
│ │ │ ├── barrier
│ │ │ │ ├── columns: column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13 new:14 f154672:28!null k_new:29 a_new:30 b_comp:31 a_new:32!null b_comp:33!null old:34 new:35
│ │ │ │ └── project
│ │ │ │ ├── columns: new:35 old:34 b_comp:33!null a_new:32!null b_comp:31 k_new:29 a_new:30 column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13 new:14 f154672:28!null
│ │ │ │ ├── barrier
│ │ │ │ │ ├── columns: column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13 new:14 f154672:28!null
│ │ │ │ │ └── select
│ │ │ │ │ ├── columns: column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13 new:14 f154672:28!null
│ │ │ │ │ ├── project
│ │ │ │ │ │ ├── columns: f154672:28 column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13 new:14
│ │ │ │ │ │ ├── barrier
│ │ │ │ │ │ │ ├── columns: column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13 new:14
│ │ │ │ │ │ │ └── project
│ │ │ │ │ │ │ ├── columns: new:14 column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13
│ │ │ │ │ │ │ ├── left-join (cross)
│ │ │ │ │ │ │ │ ├── columns: column1:6!null column2:7!null b_comp:8!null k:9 a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13
│ │ │ │ │ │ │ │ ├── values
│ │ │ │ │ │ │ │ │ ├── columns: column1:6!null column2:7!null b_comp:8!null
│ │ │ │ │ │ │ │ │ └── (1, 2, 3)
│ │ │ │ │ │ │ │ ├── select
│ │ │ │ │ │ │ │ │ ├── columns: k:9!null a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13
│ │ │ │ │ │ │ │ │ ├── scan t154672
│ │ │ │ │ │ │ │ │ │ ├── columns: k:9!null a:10 b:11 crdb_internal_mvcc_timestamp:12 tableoid:13
│ │ │ │ │ │ │ │ │ │ ├── computed column expressions
│ │ │ │ │ │ │ │ │ │ │ └── b:11
│ │ │ │ │ │ │ │ │ │ │ └── a:10 + 1
│ │ │ │ │ │ │ │ │ │ └── flags: disabled not visible index feature
│ │ │ │ │ │ │ │ │ └── filters
│ │ │ │ │ │ │ │ │ └── k:9 = 1
│ │ │ │ │ │ │ │ └── filters (true)
│ │ │ │ │ │ │ └── projections
│ │ │ │ │ │ │ └── ((column1:6, column2:7, CAST(NULL AS INT8)) AS k, a, b) [as=new:14]
│ │ │ │ │ │ └── projections
│ │ │ │ │ │ └── f154672(new:14, NULL, 'tr154672', 'BEFORE', 'ROW', 'INSERT', 61, 't154672', 't154672', 'public', 0, ARRAY[]) [as=f154672:28]
│ │ │ │ │ └── filters
│ │ │ │ │ └── f154672:28 IS DISTINCT FROM NULL
│ │ │ │ └── projections
│ │ │ │ ├── ((k:9, 3, CAST(NULL AS INT8)) AS k, a, b) [as=new:35]
│ │ │ │ ├── ((k:9, a:10, CAST(NULL AS INT8)) AS k, a, b) [as=old:34]
│ │ │ │ ├── 4 [as=b_comp:33]
│ │ │ │ ├── 3 [as=a_new:32]
│ │ │ │ ├── a:10 + 1 [as=b_comp:31]
│ │ │ │ ├── (f154672:28).k [as=k_new:29]
│ │ │ │ └── (f154672:28).a [as=a_new:30]
│ │ │ └── projections
│ │ │ └── CASE WHEN k:9 IS NOT NULL THEN f154672(new:35, old:34, 'tr154672', 'BEFORE', 'ROW', 'UPDATE', 61, 't154672', 't154672', 'public', 0, ARRAY[]) ELSE new:35 END [as=f154672:36]
│ │ └── filters
│ │ └── f154672:36 IS DISTINCT FROM NULL
│ └── projections
│ ├── (f154672:36).k [as=k_new:37]
│ └── (f154672:36).a [as=a_new:38]
└── projections
├── CASE WHEN k:9 IS NULL THEN k_new:29 ELSE k_new:37 END [as=upsert_k:40]
├── CASE WHEN k:9 IS NULL THEN a_new:30 ELSE a_new:38 END [as=upsert_a:41]
└── CASE WHEN k:9 IS NULL THEN b_comp:31 ELSE a_new:38 + 1 END [as=upsert_b:42]
3 changes: 2 additions & 1 deletion pkg/sql/opt/optbuilder/trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,8 @@ func (mb *mutationBuilder) recomputeComputedColsForTrigger(eventType tree.Trigge
colIDs[i] = 0
}
}
mb.addSynthesizedComputedCols(colIDs, false /* restrict */)
mb.addSynthesizedComputedCols(colIDs,
nil /* targetColList */, nil /* targetColSet */, false /* restrict */)
}

// ============================================================================
Expand Down
3 changes: 2 additions & 1 deletion pkg/sql/opt/optbuilder/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,8 @@ func (mb *mutationBuilder) addSynthesizedColsForUpdate() {
mb.disambiguateColumns()

// Add all computed columns in case their values have changed.
mb.addSynthesizedComputedCols(mb.updateColIDs, true /* restrict */)
mb.addSynthesizedComputedCols(mb.updateColIDs,
&mb.targetColList, &mb.targetColSet, true /* restrict */)

// Add assignment casts for computed column values.
mb.addAssignmentCasts(mb.updateColIDs)
Expand Down