Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release-19.0] Implement temporal comparisons (#17826) #17852

Merged
merged 1 commit into from
Feb 24, 2025
Merged
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
2 changes: 1 addition & 1 deletion go/vt/vtgate/evalengine/cached_size.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 34 additions & 1 deletion go/vt/vtgate/evalengine/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@
c.asm.Convert_id(offset)
case sqltypes.Uint64:
c.asm.Convert_ud(offset)
case sqltypes.Datetime, sqltypes.Time:
case sqltypes.Datetime, sqltypes.Time, sqltypes.Timestamp:

Check warning on line 262 in go/vt/vtgate/evalengine/compiler.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler.go#L262

Added line #L262 was not covered by tests
scale = ct.Size
size = ct.Size + decimalSizeBase
fallthrough
Expand All @@ -269,6 +269,28 @@
return ctype{Type: sqltypes.Decimal, Flag: ct.Flag, Col: collationNumeric, Scale: scale, Size: size}
}

func (c *compiler) compileToTemporal(doct ctype, typ sqltypes.Type, offset, prec int) ctype {
switch doct.Type {
case typ:
if int(doct.Size) == prec {
return doct
}

Check warning on line 277 in go/vt/vtgate/evalengine/compiler.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler.go#L276-L277

Added lines #L276 - L277 were not covered by tests
fallthrough
default:
switch typ {
case sqltypes.Date:
c.asm.Convert_xD(offset, c.sqlmode.AllowZeroDate())

Check warning on line 282 in go/vt/vtgate/evalengine/compiler.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler.go#L281-L282

Added lines #L281 - L282 were not covered by tests
case sqltypes.Datetime:
c.asm.Convert_xDT(offset, prec, c.sqlmode.AllowZeroDate())
case sqltypes.Timestamp:
c.asm.Convert_xDTs(offset, prec, c.sqlmode.AllowZeroDate())

Check warning on line 286 in go/vt/vtgate/evalengine/compiler.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler.go#L285-L286

Added lines #L285 - L286 were not covered by tests
case sqltypes.Time:
c.asm.Convert_xT(offset, prec)
}
}
return ctype{Type: typ, Col: collationBinary, Flag: flagNullable}
}

func (c *compiler) compileToDate(doct ctype, offset int) ctype {
switch doct.Type {
case sqltypes.Date:
Expand All @@ -290,6 +312,17 @@
return ctype{Type: sqltypes.Datetime, Size: int32(prec), Col: collationBinary, Flag: flagNullable}
}

func (c *compiler) compileToTimestamp(doct ctype, offset, prec int) ctype {
switch doct.Type {
case sqltypes.Timestamp:
c.asm.Convert_tp(offset, prec)
return doct
default:
c.asm.Convert_xDTs(offset, prec, c.sqlmode.AllowZeroDate())

Check warning on line 321 in go/vt/vtgate/evalengine/compiler.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler.go#L315-L321

Added lines #L315 - L321 were not covered by tests
}
return ctype{Type: sqltypes.Timestamp, Size: int32(prec), Col: collationBinary, Flag: flagNullable}

Check warning on line 323 in go/vt/vtgate/evalengine/compiler.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler.go#L323

Added line #L323 was not covered by tests
}

func (c *compiler) compileToTime(doct ctype, offset, prec int) ctype {
switch doct.Type {
case sqltypes.Time:
Expand Down
53 changes: 51 additions & 2 deletions go/vt/vtgate/evalengine/compiler_asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -767,11 +767,11 @@
}, "CMP DATE(SP-2), DATE(SP-1)")
}

func (asm *assembler) Collate(col collations.ID) {
func (asm *assembler) Collate(col collations.TypedCollation) {
asm.emit(func(env *ExpressionEnv) int {
a := env.vm.stack[env.vm.sp-1].(*evalBytes)
a.tt = int16(sqltypes.VarChar)
a.col.Collation = col
a.col = col
return 1
}, "COLLATE VARCHAR(SP-1), %d", col)
}
Expand Down Expand Up @@ -1170,6 +1170,21 @@
}, "CONV (SP-%d), DATETIME", offset)
}

func (asm *assembler) Convert_xDTs(offset, prec int, allowZero bool) {
asm.emit(func(env *ExpressionEnv) int {
// Need to explicitly check here or we otherwise
// store a nil wrapper in an interface vs. a direct
// nil.
dt := evalToTimestamp(env.vm.stack[env.vm.sp-offset], prec, env.now, allowZero)
if dt == nil {
env.vm.stack[env.vm.sp-offset] = nil
} else {
env.vm.stack[env.vm.sp-offset] = dt
}
return 1

Check warning on line 1184 in go/vt/vtgate/evalengine/compiler_asm.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler_asm.go#L1173-L1184

Added lines #L1173 - L1184 were not covered by tests
}, "CONV (SP-%d), TIMESTAMP", offset)
}

func (asm *assembler) Convert_xT(offset, prec int) {
asm.emit(func(env *ExpressionEnv) int {
t := evalToTime(env.vm.stack[env.vm.sp-offset], prec)
Expand Down Expand Up @@ -2464,6 +2479,40 @@
}, "FN MULTICMP UINT64(SP-%d)...UINT64(SP-1)", args)
}

func (asm *assembler) Fn_MULTICMP_temporal(args int, lessThan bool) {
asm.adjustStack(-(args - 1))

asm.emit(func(env *ExpressionEnv) int {
var x *evalTemporal
x, _ = env.vm.stack[env.vm.sp-args].(*evalTemporal)
for sp := env.vm.sp - args + 1; sp < env.vm.sp; sp++ {
if env.vm.stack[sp] == nil {
if lessThan {
x = nil
}
continue

Check warning on line 2493 in go/vt/vtgate/evalengine/compiler_asm.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler_asm.go#L2490-L2493

Added lines #L2490 - L2493 were not covered by tests
}
y := env.vm.stack[sp].(*evalTemporal)
if lessThan == (y.compare(x) < 0) {
x = y
}
}
env.vm.stack[env.vm.sp-args] = x
env.vm.sp -= args - 1
return 1
}, "FN MULTICMP TEMPORAL(SP-%d)...TEMPORAL(SP-1)", args)
}

func (asm *assembler) Fn_MULTICMP_temporal_fallback(f multiComparisonFunc, args int, cmp, prec int) {
asm.adjustStack(-(args - 1))

asm.emit(func(env *ExpressionEnv) int {
env.vm.stack[env.vm.sp-args], env.vm.err = f(env, env.vm.stack[env.vm.sp-args:env.vm.sp], cmp, prec)
env.vm.sp -= args - 1
return 1
}, "FN MULTICMP_FALLBACK TEMPORAL(SP-%d)...TEMPORAL(SP-1)", args)
}

func (asm *assembler) Fn_REPEAT() {
asm.adjustStack(-1)

Expand Down
29 changes: 29 additions & 0 deletions go/vt/vtgate/evalengine/compiler_asm_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,23 @@
}, "PUSH DATETIME(:%d)", offset)
}

func push_timestamp(env *ExpressionEnv, raw []byte) int {
env.vm.stack[env.vm.sp], env.vm.err = parseTimestamp(raw)
env.vm.sp++
return 1

Check warning on line 302 in go/vt/vtgate/evalengine/compiler_asm_push.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler_asm_push.go#L299-L302

Added lines #L299 - L302 were not covered by tests
}

func (asm *assembler) PushColumn_timestamp(offset int) {
asm.adjustStack(1)
asm.emit(func(env *ExpressionEnv) int {
col := env.Row[offset]
if col.IsNull() {
return push_null(env)
}
return push_timestamp(env, col.Raw())

Check warning on line 312 in go/vt/vtgate/evalengine/compiler_asm_push.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler_asm_push.go#L305-L312

Added lines #L305 - L312 were not covered by tests
}, "PUSH TIMESTAMP(:%d)", offset)
}

func (asm *assembler) PushBVar_datetime(key string) {
asm.adjustStack(1)
asm.emit(func(env *ExpressionEnv) int {
Expand All @@ -308,6 +325,18 @@
}, "PUSH DATETIME(:%q)", key)
}

func (asm *assembler) PushBVar_timestamp(key string) {
asm.adjustStack(1)
asm.emit(func(env *ExpressionEnv) int {
var bvar *querypb.BindVariable
bvar, env.vm.err = env.lookupBindVar(key)
if env.vm.err != nil {
return 0
}
return push_timestamp(env, bvar.Value)

Check warning on line 336 in go/vt/vtgate/evalengine/compiler_asm_push.go

View check run for this annotation

Codecov / codecov/patch

go/vt/vtgate/evalengine/compiler_asm_push.go#L328-L336

Added lines #L328 - L336 were not covered by tests
}, "PUSH TIMESTAMP(:%q)", key)
}

func push_date(env *ExpressionEnv, raw []byte) int {
env.vm.stack[env.vm.sp], env.vm.err = parseDate(raw)
env.vm.sp++
Expand Down
7 changes: 4 additions & 3 deletions go/vt/vtgate/evalengine/compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import (
"testing"
"time"

"github.com/stretchr/testify/assert"

"github.com/olekukonko/tablewriter"
"github.com/stretchr/testify/assert"

"vitess.io/vitess/go/mysql/collations"
"vitess.io/vitess/go/mysql/collations/colldata"
"vitess.io/vitess/go/sqltypes"
querypb "vitess.io/vitess/go/vt/proto/query"
"vitess.io/vitess/go/vt/sqlparser"
Expand Down Expand Up @@ -118,7 +118,7 @@ func TestCompilerReference(t *testing.T) {
var supported, total int
env := evalengine.EmptyExpressionEnv(venv)

tc.Run(func(query string, row []sqltypes.Value) {
tc.Run(func(query string, row []sqltypes.Value, _ bool) {
env.Row = row
total++
testCompilerCase(t, query, venv, tc.Schema, env)
Expand Down Expand Up @@ -170,6 +170,7 @@ func testCompilerCase(t *testing.T, query string, venv *vtenv.Environment, schem
eval := expected.String()
comp := res.String()
assert.Equalf(t, eval, comp, "bad evaluation from compiler:\nSQL: %s\nEval: %s\nComp: %s", query, eval, comp)
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())
case vmErr == nil:
t.Errorf("failed evaluation from evalengine:\nSQL: %s\nError: %s", query, evalErr)
case evalErr == nil:
Expand Down
Loading
Loading