Skip to content

Commit 3f20b33

Browse files
committed
lookup join: add a cast when mapping references in computed columns
Previously, when using a lookup join on an index with a virtual column, we would require the references inside that virtual column to be typed identically on the left and right side. This was a change from our previous behavior, which was to require they be equivalent, but not identical. This tightening of the requirements was done to address issue 124732, which pertains to virtual columns using functions that are senstive to the actual type of the input (e.g. 'pg_typeof'). By tightening the reference requirement, we excluded a set of queries from using lookup joins that had previously been able to do so safely, regressing their performance. In this patch, we add a cast around the left hand side reference to the right hand side's type, so that type sensitive functions return the correct type. This allows us to go back to the old behavior of allowing the types of these references to be equivalent rather than identical. Fixes: #147642 Informs: #124732 Release note (performance improvement): Lookup joins can now be used on tables with virtual columns even if the type of the search argument is not identical to the column type referenced in the virtual column.
1 parent d1856a6 commit 3f20b33

File tree

3 files changed

+25
-15
lines changed

3 files changed

+25
-15
lines changed

pkg/sql/logictest/testdata/logic_test/lookup_join

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1601,8 +1601,10 @@ SELECT col1_6 FROM table_1_124732 INNER HASH JOIN table_3_124732 ON col3_0 = col
16011601
----
16021602
-
16031603

1604-
statement error pgcode XXUUU pq: could not produce a query plan conforming to the LOOKUP JOIN hint
1604+
query T
16051605
SELECT col1_6 FROM table_1_124732 INNER LOOKUP JOIN table_3_124732 ON col3_0 = col1_6;
1606+
----
1607+
-
16061608

16071609
# Regression test for incorrectly remapping columns in a composite-sensitive
16081610
# expression to produce a lookup join (#124732).

pkg/sql/opt/lookupjoin/constraint_builder.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -260,17 +260,6 @@ func (b *ConstraintBuilder) Build(
260260
keyCols = nil
261261
}
262262

263-
// rightEqIdenticalTypeCols is the set of columns in rightEq that have
264-
// identical types to the corresponding columns in leftEq. This is used to
265-
// determine if a computed column can be synthesized for a column in the
266-
// index in order to allow a lookup join.
267-
var rightEqIdenticalTypeCols opt.ColSet
268-
for i := range rightEq {
269-
if b.md.ColumnMeta(rightEq[i]).Type.Identical(b.md.ColumnMeta(leftEq[i]).Type) {
270-
rightEqIdenticalTypeCols.Add(rightEq[i])
271-
}
272-
}
273-
274263
// All the lookup conditions must apply to the prefix of the index and so
275264
// the projected columns created must be created in order.
276265
for j := 0; j < numIndexKeyCols; j++ {
@@ -294,7 +283,7 @@ func (b *ConstraintBuilder) Build(
294283
//
295284
// NOTE: we must only consider equivalent columns with identical types,
296285
// since column remapping is otherwise not valid.
297-
if expr, ok := b.findComputedColJoinEquality(b.table, idxCol, rightEqIdenticalTypeCols); ok {
286+
if expr, ok := b.findComputedColJoinEquality(b.table, idxCol, rightEq.ToSet()); ok {
298287
colMeta := b.md.ColumnMeta(idxCol)
299288
compEqCol := b.md.AddColumn(fmt.Sprintf("%s_eq", colMeta.Alias), colMeta.Type)
300289

@@ -307,7 +296,22 @@ func (b *ConstraintBuilder) Build(
307296

308297
// Project the computed column expression, mapping all columns
309298
// in rightEq to corresponding columns in leftEq.
310-
projection := b.f.ConstructProjectionsItem(b.f.RemapCols(expr, b.eqColMap), compEqCol)
299+
var replace norm.ReplaceFunc
300+
replace = func(e opt.Expr) opt.Expr {
301+
if v, ok := e.(*memo.VariableExpr); ok {
302+
if col, ok := b.eqColMap.Get(int(v.Col)); ok {
303+
// If the column is a computed column, we need to
304+
// cast it to the type of the original column so that
305+
// functions which are type sensitive still return the
306+
// expected results.
307+
return b.f.ConstructCast(b.f.ConstructVariable(opt.ColumnID(col)), b.md.ColumnMeta(v.Col).Type)
308+
} else {
309+
return e
310+
}
311+
}
312+
return b.f.Replace(e, replace)
313+
}
314+
projection := b.f.ConstructProjectionsItem(b.f.Replace(expr, replace).(opt.ScalarExpr), compEqCol)
311315
inputProjections = append(inputProjections, projection)
312316
addEqualityColumns(compEqCol, idxCol)
313317
derivedEquivCols.Add(compEqCol)

pkg/sql/opt/lookupjoin/testdata/computed

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,11 @@ lookup expression:
126126
lookup-constraints left=(a regclass, b int) right=(x oid, v string not null as (x::string) stored) index=(v, x)
127127
x = a
128128
----
129-
lookup join not possible
129+
key cols:
130+
v = v_eq
131+
x = a
132+
input projections:
133+
v_eq = a::OID::STRING [type=STRING]
130134

131135
# Computed columns cannot be remapped if the expression is composite-sensitive.
132136
lookup-constraints left=(a decimal, b int) right=(x decimal, v int not null as (x::int) stored) index=(v, x)

0 commit comments

Comments
 (0)