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

*: cut off duration.fsp in chunk #7043

Merged
merged 13 commits into from
Jul 17, 2018
Merged

*: cut off duration.fsp in chunk #7043

merged 13 commits into from
Jul 17, 2018

Conversation

lysu
Copy link
Contributor

@lysu lysu commented Jul 12, 2018

What have you changed? (mandatory)

This PR is "easy way" to #7013 which is more right and more clear in theory, but with big change and be nightmare to both reviewee and reviewer, but I still think it must be done in future.

  • Datum's collation, decimal, length is short-cut for some part coding but wrong for design.
  • Duration's fsp need be remove with Datum 3 field which need big change Decimal
  • Seperate type infer flow with data flow is best.

But this time, we solve chunk in this small PR first.

What is the type of the changes? (mandatory)

  • Improvement (non-breaking change which is an improvement to an existing feature)
  • Bug fix (non-breaking change which fixes an issue)

How has this PR been tested? (mandatory)

  • unit tests
  • integration tests
  • and I will Port duration mysql_test for test so WIP but ready for review

This change is Reviewable

@lysu
Copy link
Contributor Author

lysu commented Jul 12, 2018

/run-all-tests

@lysu lysu changed the title *: cut off Duration.Fsp in chunk *: cut off duration.fsp in chunk Jul 12, 2018
@@ -88,7 +89,8 @@ func (r Row) GetTime(colIdx int) types.Time {
// GetDuration returns the Duration value with the colIdx.
func (r Row) GetDuration(colIdx int) types.Duration {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this change affect the benchmark of GetDuration?

Copy link
Contributor Author

@lysu lysu Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will benchmark later, but it seems will allocate more a types.Duration than before, but this is just as GetTime does...

if err != nil {
return nil, err
}
bf.tp.Decimal = mathutil.Max(arg0Dec, arg1Dec)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a bugfix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this decimal field is no use before this PR, so it got wrong value but not affect the user, but now if the duration comes from chunk.row will need it to compensate missed fsp info.

@@ -1307,13 +1307,13 @@ func (s *testIntegrationSuite) TestTimeBuiltin(c *C) {

// test time
result = tk.MustQuery("select time('2003-12-31 01:02:03')")
result.Check(testkit.Rows("01:02:03"))
result.Check(testkit.Rows("01:02:03.000000"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this result is different from mysql:

MySQL(localhost:3306) > select time('2003-12-31 01:02:03');
+-----------------------------+
| time('2003-12-31 01:02:03') |
+-----------------------------+
| 01:02:03                    |
+-----------------------------+
1 row in set (0.00 sec)

result = tk.MustQuery("select time('2003-12-31 01:02:03.000123')")
result.Check(testkit.Rows("01:02:03.000123"))
result = tk.MustQuery("select time('01:02:03.000123')")
result.Check(testkit.Rows("01:02:03.000123"))
result = tk.MustQuery("select time('01:02:03')")
result.Check(testkit.Rows("01:02:03"))
result.Check(testkit.Rows("01:02:03.000000"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@lysu
Copy link
Contributor Author

lysu commented Jul 13, 2018

There are still some truncate test cases give the different result to MySQL(even in master branch), https://github.com/pingcap/tidb-test/pull/574/commits/21411bae6f795c51b152383dcd2dd06d4e3c94ea

@zz-jason
Copy link
Member

LGTM

But we still need some benchmarks to know the exact performance regression.

@zz-jason zz-jason added type/enhancement The issue or PR belongs to an enhancement. status/LGT1 Indicates that a PR has LGTM 1. sig/execution SIG execution and removed status/WIP labels Jul 13, 2018
types/etc.go Outdated
return true
}
return false
}

// IsStr returns a boolean indicating
// whether the field type is a string type.
func IsStr(ft *FieldType) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ IsStr/ IsString

@@ -20,6 +20,7 @@ import (
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/types/json"
"github.com/pingcap/tidb/util/hack"
"time"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put this line to line17

@@ -5370,3 +5401,19 @@ func (b *builtinLastDaySig) evalTime(row types.Row) (types.Time, bool, error) {
}
return ret, false, nil
}

func timePrecision(ctx sessionctx.Context, expression Expression) (int, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a comment for this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    • name is not very suitable, it was renamed and add comments in new commit.

if isNil || err != nil {
return 0, errors.Trace(err)
}
if n := strings.LastIndexByte(str, '.'); n >= 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check can be replaced by function GetFsp

@@ -2663,7 +2663,7 @@ func (s *testIntegrationSuite) TestCompareBuiltin(c *C) {
tk.MustExec(`insert into t2 values(1, 1.1, "2017-08-01 12:01:01", "12:01:01", "abcdef", 0b10101)`)

result = tk.MustQuery("select coalesce(NULL, a), coalesce(NULL, b, a), coalesce(c, NULL, a, b), coalesce(d, NULL), coalesce(d, c), coalesce(NULL, NULL, e, 1), coalesce(f), coalesce(1, a, b, c, d, e, f) from t2")
result.Check(testkit.Rows(fmt.Sprintf("1 1.1 2017-08-01 12:01:01 12:01:01 %s 12:01:01 abcdef 21 1", time.Now().In(tk.Se.GetSessionVars().GetTimeZone()).Format("2006-01-02"))))
result.Check(testkit.Rows(fmt.Sprintf("1 1.1 2017-08-01 12:01:01 12:01:01.000000 %s 12:01:01 abcdef 21 1", time.Now().In(tk.Se.GetSessionVars().GetTimeZone()).Format("2006-01-02"))))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this compatible with mysql?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh~ that's bug...fixed in new commits

types/fsp.go Outdated
@@ -22,6 +22,8 @@ import (
)

const (
// WaitFillFsp is fsp need fill by caller if they want to use fsp.
WaitFillFsp = -2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When will the caller want to us fsp?

Copy link
Contributor Author

@lysu lysu Jul 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    • the old way needs GetDuration caller to check whether result.fsp == WaitFillFsp than refill Fsp or do nothing...that's buggy.

Now force pass fillFsp paramter in GetDuration(also add some comments) and no longer need this flag. PTAL~thx

@XuHuaiyu
Copy link
Contributor

@lysu DNM label can be removed?

@@ -5370,3 +5401,16 @@ func (b *builtinLastDaySig) evalTime(row types.Row) (types.Time, bool, error) {
}
return ret, false, nil
}

// expressionFsp calculates the fsp from given expression.
func expressionFsp(ctx sessionctx.Context, expression Expression) (int, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ expressionFsp/ getExpressionFsp

@@ -1249,7 +1249,7 @@ func (s *testInferTypeSuite) createTestCase4TimeFuncs() []typeInferTestCase {
{"addtime(c_timestamp, c_time_d)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 26, 4},
{"addtime(c_timestamp_d, c_time_d)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag, 26, 0},
{"addtime(c_time, c_time)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 15, 3},
{"addtime(c_time_d, c_time)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 15, 0},
{"addtime(c_time_d, c_time)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag, 15, 3},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the changes in this file be more reasonable or more compatible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in previous we didn't infer decimal and always be zero, but in MySQL takes that.

mysql> select version();
+---------------------------+
| version()                 |
+---------------------------+
| 5.7.22-0ubuntu18.04.1-log |
+---------------------------+
1 row in set (0.00 sec)

mysql> select addtime(c_time_d, c_time) from t;
Field   1:  `addtime(c_time_d, c_time)`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       TIME
Collation:  binary (63)
Length:     14
Max_length: 0
Decimals:   3
Flags:      BINARY 
0 rows in set (0.00 sec)

types/row.go Outdated
@@ -42,7 +42,9 @@ type Row interface {
GetTime(colIdx int) Time

// GetDuration returns the Duration value with the colIdx.
GetDuration(colIdx int) Duration
// fillFsp is needed for refill fsp info if duration came from chunk.Row which is no longer store fsp info.
// if caller make sure that data from Datum or only use Duration.Duration properties can pass 0 as fillFsp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ is/ If
add . at the end of this comment

types/row.go Outdated
@@ -42,7 +42,9 @@ type Row interface {
GetTime(colIdx int) Time

// GetDuration returns the Duration value with the colIdx.
GetDuration(colIdx int) Duration
// fillFsp is needed for refill fsp info if duration came from chunk.Row which is no longer store fsp info.
// if caller make sure that data from Datum or only use Duration.Duration properties can pass 0 as fillFsp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ is/ If
add . at the end of this comment

types/time.go Outdated
@@ -812,7 +813,7 @@ func (d Duration) String() string {
}

fmt.Fprintf(&buf, "%02d:%02d:%02d", hours, minutes, seconds)
if d.Fsp > 0 {
if d.Fsp > 0 && fraction >= 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a comment for this check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check fraction seems useless....I removed it

types/datum.go Outdated
if err != nil {
return ret, errors.Trace(err)
}
if timeNum > MaxDuration && timeNum < 10000000000 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if timeNum > 10000000000

Copy link
Contributor Author

@lysu lysu Jul 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timeNum > MaxDuration and < 10000000000 must be a wrong value..
but timeNum > 10000000000 will try treat as 'YYYYMMDDHHmmss'

specially timeNum < 0 and timeNum < -10000000000 should NOT treat as 'YYYYMMDDHHmmss'

https://github.com/mysql/mysql-server/blob/e7586bb9c11953a81c816ca10708f612403edc24/sql-common/my_time.c#L846

I add some comments for this if~


arg0Dec, err := expressionFsp(ctx, args[0])
if err != nil {
return nil, err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

errors.Trace(err)

and line 411

@lysu
Copy link
Contributor Author

lysu commented Jul 17, 2018

/run-all-tests tidb-test=pr/574

@coocood
Copy link
Member

coocood commented Jul 17, 2018

LGTM

@lysu
Copy link
Contributor Author

lysu commented Jul 17, 2018

@zz-jason

func BenchmarkGetDurationFromChunk(b *testing.B) {
	chk := chunk.NewChunkWithCapacity([]*types.FieldType{{Tp: mysql.TypeDuration}}, 1)
	chk.AppendDuration(0, types.Duration{Duration: 11233*time.Second, Fsp:1})
	row := chk.GetRow(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		x: = row.GetDuration(0, 1)
                x = x
	}
}

for master:

BenchmarkGetDurationFromChunk-8   	2000000000	         1.06 ns/op	       0 B/op	       0 allocs/op
PASS

for this pr:

BenchmarkGetDurationFromChunk-8   	2000000000	         1.03 ns/op	       0 B/op	       0 allocs/op
PASS

Copy link
Contributor

@XuHuaiyu XuHuaiyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rest LGTM

types/datum.go Outdated
if err != nil {
return ret, errors.Trace(err)
}
// For For huge numbers(>'0001-00-00 00-00-00') try full DATETIME in ParseDuration.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove one For

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

@XuHuaiyu XuHuaiyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@coocood coocood added status/LGT2 Indicates that a PR has LGTM 2. and removed status/LGT1 Indicates that a PR has LGTM 1. labels Jul 17, 2018
@coocood coocood merged commit 9cf670a into pingcap:master Jul 17, 2018
@lysu lysu deleted the dev/duration_cut_off_fsp_with_easy_way branch September 27, 2018 04:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
sig/execution SIG execution status/LGT2 Indicates that a PR has LGTM 2. type/enhancement The issue or PR belongs to an enhancement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

decimals flag in timediff response is incorrect
4 participants