Skip to content

Commit 8ef0cae

Browse files
[release-19.0] Implement temporal comparisons (vitessio#17826) (vitessio#17852)
Signed-off-by: Dirkjan Bussink <[email protected]> Co-authored-by: vitess-bot[bot] <108069721+vitess-bot[bot]@users.noreply.github.com>
1 parent 747296f commit 8ef0cae

15 files changed

+891
-348
lines changed

go/vt/vtgate/evalengine/cached_size.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go/vt/vtgate/evalengine/compiler.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ func (c *compiler) compileToDecimal(ct ctype, offset int) ctype {
259259
c.asm.Convert_id(offset)
260260
case sqltypes.Uint64:
261261
c.asm.Convert_ud(offset)
262-
case sqltypes.Datetime, sqltypes.Time:
262+
case sqltypes.Datetime, sqltypes.Time, sqltypes.Timestamp:
263263
scale = ct.Size
264264
size = ct.Size + decimalSizeBase
265265
fallthrough
@@ -269,6 +269,28 @@ func (c *compiler) compileToDecimal(ct ctype, offset int) ctype {
269269
return ctype{Type: sqltypes.Decimal, Flag: ct.Flag, Col: collationNumeric, Scale: scale, Size: size}
270270
}
271271

272+
func (c *compiler) compileToTemporal(doct ctype, typ sqltypes.Type, offset, prec int) ctype {
273+
switch doct.Type {
274+
case typ:
275+
if int(doct.Size) == prec {
276+
return doct
277+
}
278+
fallthrough
279+
default:
280+
switch typ {
281+
case sqltypes.Date:
282+
c.asm.Convert_xD(offset, c.sqlmode.AllowZeroDate())
283+
case sqltypes.Datetime:
284+
c.asm.Convert_xDT(offset, prec, c.sqlmode.AllowZeroDate())
285+
case sqltypes.Timestamp:
286+
c.asm.Convert_xDTs(offset, prec, c.sqlmode.AllowZeroDate())
287+
case sqltypes.Time:
288+
c.asm.Convert_xT(offset, prec)
289+
}
290+
}
291+
return ctype{Type: typ, Col: collationBinary, Flag: flagNullable}
292+
}
293+
272294
func (c *compiler) compileToDate(doct ctype, offset int) ctype {
273295
switch doct.Type {
274296
case sqltypes.Date:
@@ -290,6 +312,17 @@ func (c *compiler) compileToDateTime(doct ctype, offset, prec int) ctype {
290312
return ctype{Type: sqltypes.Datetime, Size: int32(prec), Col: collationBinary, Flag: flagNullable}
291313
}
292314

315+
func (c *compiler) compileToTimestamp(doct ctype, offset, prec int) ctype {
316+
switch doct.Type {
317+
case sqltypes.Timestamp:
318+
c.asm.Convert_tp(offset, prec)
319+
return doct
320+
default:
321+
c.asm.Convert_xDTs(offset, prec, c.sqlmode.AllowZeroDate())
322+
}
323+
return ctype{Type: sqltypes.Timestamp, Size: int32(prec), Col: collationBinary, Flag: flagNullable}
324+
}
325+
293326
func (c *compiler) compileToTime(doct ctype, offset, prec int) ctype {
294327
switch doct.Type {
295328
case sqltypes.Time:

go/vt/vtgate/evalengine/compiler_asm.go

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -767,11 +767,11 @@ func (asm *assembler) CmpDates() {
767767
}, "CMP DATE(SP-2), DATE(SP-1)")
768768
}
769769

770-
func (asm *assembler) Collate(col collations.ID) {
770+
func (asm *assembler) Collate(col collations.TypedCollation) {
771771
asm.emit(func(env *ExpressionEnv) int {
772772
a := env.vm.stack[env.vm.sp-1].(*evalBytes)
773773
a.tt = int16(sqltypes.VarChar)
774-
a.col.Collation = col
774+
a.col = col
775775
return 1
776776
}, "COLLATE VARCHAR(SP-1), %d", col)
777777
}
@@ -1170,6 +1170,21 @@ func (asm *assembler) Convert_xDT(offset, prec int, allowZero bool) {
11701170
}, "CONV (SP-%d), DATETIME", offset)
11711171
}
11721172

1173+
func (asm *assembler) Convert_xDTs(offset, prec int, allowZero bool) {
1174+
asm.emit(func(env *ExpressionEnv) int {
1175+
// Need to explicitly check here or we otherwise
1176+
// store a nil wrapper in an interface vs. a direct
1177+
// nil.
1178+
dt := evalToTimestamp(env.vm.stack[env.vm.sp-offset], prec, env.now, allowZero)
1179+
if dt == nil {
1180+
env.vm.stack[env.vm.sp-offset] = nil
1181+
} else {
1182+
env.vm.stack[env.vm.sp-offset] = dt
1183+
}
1184+
return 1
1185+
}, "CONV (SP-%d), TIMESTAMP", offset)
1186+
}
1187+
11731188
func (asm *assembler) Convert_xT(offset, prec int) {
11741189
asm.emit(func(env *ExpressionEnv) int {
11751190
t := evalToTime(env.vm.stack[env.vm.sp-offset], prec)
@@ -2464,6 +2479,40 @@ func (asm *assembler) Fn_MULTICMP_u(args int, lessThan bool) {
24642479
}, "FN MULTICMP UINT64(SP-%d)...UINT64(SP-1)", args)
24652480
}
24662481

2482+
func (asm *assembler) Fn_MULTICMP_temporal(args int, lessThan bool) {
2483+
asm.adjustStack(-(args - 1))
2484+
2485+
asm.emit(func(env *ExpressionEnv) int {
2486+
var x *evalTemporal
2487+
x, _ = env.vm.stack[env.vm.sp-args].(*evalTemporal)
2488+
for sp := env.vm.sp - args + 1; sp < env.vm.sp; sp++ {
2489+
if env.vm.stack[sp] == nil {
2490+
if lessThan {
2491+
x = nil
2492+
}
2493+
continue
2494+
}
2495+
y := env.vm.stack[sp].(*evalTemporal)
2496+
if lessThan == (y.compare(x) < 0) {
2497+
x = y
2498+
}
2499+
}
2500+
env.vm.stack[env.vm.sp-args] = x
2501+
env.vm.sp -= args - 1
2502+
return 1
2503+
}, "FN MULTICMP TEMPORAL(SP-%d)...TEMPORAL(SP-1)", args)
2504+
}
2505+
2506+
func (asm *assembler) Fn_MULTICMP_temporal_fallback(f multiComparisonFunc, args int, cmp, prec int) {
2507+
asm.adjustStack(-(args - 1))
2508+
2509+
asm.emit(func(env *ExpressionEnv) int {
2510+
env.vm.stack[env.vm.sp-args], env.vm.err = f(env, env.vm.stack[env.vm.sp-args:env.vm.sp], cmp, prec)
2511+
env.vm.sp -= args - 1
2512+
return 1
2513+
}, "FN MULTICMP_FALLBACK TEMPORAL(SP-%d)...TEMPORAL(SP-1)", args)
2514+
}
2515+
24672516
func (asm *assembler) Fn_REPEAT() {
24682517
asm.adjustStack(-1)
24692518

go/vt/vtgate/evalengine/compiler_asm_push.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,23 @@ func (asm *assembler) PushColumn_datetime(offset int) {
296296
}, "PUSH DATETIME(:%d)", offset)
297297
}
298298

299+
func push_timestamp(env *ExpressionEnv, raw []byte) int {
300+
env.vm.stack[env.vm.sp], env.vm.err = parseTimestamp(raw)
301+
env.vm.sp++
302+
return 1
303+
}
304+
305+
func (asm *assembler) PushColumn_timestamp(offset int) {
306+
asm.adjustStack(1)
307+
asm.emit(func(env *ExpressionEnv) int {
308+
col := env.Row[offset]
309+
if col.IsNull() {
310+
return push_null(env)
311+
}
312+
return push_timestamp(env, col.Raw())
313+
}, "PUSH TIMESTAMP(:%d)", offset)
314+
}
315+
299316
func (asm *assembler) PushBVar_datetime(key string) {
300317
asm.adjustStack(1)
301318
asm.emit(func(env *ExpressionEnv) int {
@@ -308,6 +325,18 @@ func (asm *assembler) PushBVar_datetime(key string) {
308325
}, "PUSH DATETIME(:%q)", key)
309326
}
310327

328+
func (asm *assembler) PushBVar_timestamp(key string) {
329+
asm.adjustStack(1)
330+
asm.emit(func(env *ExpressionEnv) int {
331+
var bvar *querypb.BindVariable
332+
bvar, env.vm.err = env.lookupBindVar(key)
333+
if env.vm.err != nil {
334+
return 0
335+
}
336+
return push_timestamp(env, bvar.Value)
337+
}, "PUSH TIMESTAMP(:%q)", key)
338+
}
339+
311340
func push_date(env *ExpressionEnv, raw []byte) int {
312341
env.vm.stack[env.vm.sp], env.vm.err = parseDate(raw)
313342
env.vm.sp++

go/vt/vtgate/evalengine/compiler_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ import (
2424
"testing"
2525
"time"
2626

27-
"github.com/stretchr/testify/assert"
28-
2927
"github.com/olekukonko/tablewriter"
28+
"github.com/stretchr/testify/assert"
3029

3130
"vitess.io/vitess/go/mysql/collations"
31+
"vitess.io/vitess/go/mysql/collations/colldata"
3232
"vitess.io/vitess/go/sqltypes"
3333
querypb "vitess.io/vitess/go/vt/proto/query"
3434
"vitess.io/vitess/go/vt/sqlparser"
@@ -118,7 +118,7 @@ func TestCompilerReference(t *testing.T) {
118118
var supported, total int
119119
env := evalengine.EmptyExpressionEnv(venv)
120120

121-
tc.Run(func(query string, row []sqltypes.Value) {
121+
tc.Run(func(query string, row []sqltypes.Value, _ bool) {
122122
env.Row = row
123123
total++
124124
testCompilerCase(t, query, venv, tc.Schema, env)
@@ -170,6 +170,7 @@ func testCompilerCase(t *testing.T, query string, venv *vtenv.Environment, schem
170170
eval := expected.String()
171171
comp := res.String()
172172
assert.Equalf(t, eval, comp, "bad evaluation from compiler:\nSQL: %s\nEval: %s\nComp: %s", query, eval, comp)
173+
assert.Equalf(t, expected.Collation(), res.Collation(), "bad collation from compiler:\nSQL: %s\nEval: %s\nComp: %s", query, colldata.Lookup(expected.Collation()).Name(), colldata.Lookup(res.Collation()).Name())
173174
case vmErr == nil:
174175
t.Errorf("failed evaluation from evalengine:\nSQL: %s\nError: %s", query, evalErr)
175176
case evalErr == nil:

0 commit comments

Comments
 (0)