diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3e23f56c60f38..eed7fbd2b1279 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,7 +15,7 @@ A Contributor refers to the person who contributes to the following projects: ## How to become a TiDB Contributor? -If a PR (Pull Request) submitted to the TiDB / TiKV / TiSpark / PD / Docs/Docs-cn projects by you is approved and merged, then you become a TiDB Contributor. +If a PR (Pull Request) submitted to the TiDB/TiKV/TiSpark/PD/Docs/Docs-cn projects by you is approved and merged, then you become a TiDB Contributor. You are also encouraged to participate in the projects in the following ways: - Actively answer technical questions asked by community users. diff --git a/Makefile b/Makefile index 7220dda9dc99d..be1c07d0cccdd 100644 --- a/Makefile +++ b/Makefile @@ -24,8 +24,8 @@ PACKAGES := $$($(PACKAGE_LIST)) PACKAGE_DIRECTORIES := $(PACKAGE_LIST) | sed 's|github.com/pingcap/$(PROJECT)/||' FILES := $$(find $$($(PACKAGE_DIRECTORIES)) -name "*.go") -GOFAIL_ENABLE := $$(find $$PWD/ -type d | grep -vE "(\.git|tools)" | xargs gofail enable) -GOFAIL_DISABLE := $$(find $$PWD/ -type d | grep -vE "(\.git|tools)" | xargs gofail disable) +GOFAIL_ENABLE := $$(find $$PWD/ -type d | grep -vE "(\.git|tools)" | xargs tools/bin/gofail enable) +GOFAIL_DISABLE := $$(find $$PWD/ -type d | grep -vE "(\.git|tools)" | xargs tools/bin/gofail disable) LDFLAGS += -X "github.com/pingcap/parser/mysql.TiDBReleaseVersion=$(shell git describe --tags --dirty)" LDFLAGS += -X "github.com/pingcap/tidb/util/printer.TiDBBuildTS=$(shell date -u '+%Y-%m-%d %I:%M:%S')" @@ -123,11 +123,7 @@ ifeq ("$(TRAVIS_COVERAGE)", "1") bash <(curl -s https://codecov.io/bash) endif -gotest: - @rm -rf $GOPATH/bin/gofail - $(GO) get github.com/pingcap/gofail - @which gofail - @$(GOFAIL_ENABLE) +gotest: gofail-enable ifeq ("$(TRAVIS_COVERAGE)", "1") @echo "Running in TRAVIS_COVERAGE mode." @export log_level=error; \ @@ -140,23 +136,17 @@ else endif @$(GOFAIL_DISABLE) -race: - $(GO) get github.com/pingcap/gofail - @$(GOFAIL_ENABLE) +race: gofail-enable @export log_level=debug; \ $(GOTEST) -timeout 20m -race $(PACKAGES) || { $(GOFAIL_DISABLE); exit 1; } @$(GOFAIL_DISABLE) -leak: - $(GO) get github.com/pingcap/gofail - @$(GOFAIL_ENABLE) +leak: gofail-enable @export log_level=debug; \ $(GOTEST) -tags leak $(PACKAGES) || { $(GOFAIL_DISABLE); exit 1; } @$(GOFAIL_DISABLE) -tikv_integration_test: - $(GO) get github.com/pingcap/gofail - @$(GOFAIL_ENABLE) +tikv_integration_test: gofail-enable $(GOTEST) ./store/tikv/. -with-tikv=true || { $(GOFAIL_DISABLE); exit 1; } @$(GOFAIL_DISABLE) @@ -200,37 +190,40 @@ importer: checklist: cat checklist.md -gofail-enable: +gofail-enable: tools/bin/gofail # Converting gofail failpoints... @$(GOFAIL_ENABLE) -gofail-disable: +gofail-disable: tools/bin/gofail # Restoring gofail failpoints... @$(GOFAIL_DISABLE) checkdep: $(GO) list -f '{{ join .Imports "\n" }}' github.com/pingcap/tidb/store/tikv | grep ^github.com/pingcap/parser$$ || exit 0; exit 1 -tools/bin/megacheck: +tools/bin/megacheck: tools/check/go.mod cd tools/check; \ - $go build -o ../bin/megacheck honnef.co/go/tools/cmd/megacheck + $(GO) build -o ../bin/megacheck honnef.co/go/tools/cmd/megacheck -tools/bin/revive: +tools/bin/revive: tools/check/go.mod cd tools/check; \ $(GO) build -o ../bin/revive github.com/mgechev/revive -tools/bin/goword: +tools/bin/goword: tools/check/go.mod cd tools/check; \ $(GO) build -o ../bin/goword github.com/chzchzchz/goword -tools/bin/gometalinter: +tools/bin/gometalinter: tools/check/go.mod cd tools/check; \ $(GO) build -o ../bin/gometalinter gopkg.in/alecthomas/gometalinter.v2 -tools/bin/gosec: +tools/bin/gosec: tools/check/go.mod cd tools/check; \ $(GO) build -o ../bin/gosec github.com/securego/gosec/cmd/gosec -tools/bin/errcheck: +tools/bin/errcheck: tools/check/go.mod cd tools/check; \ $(GO) build -o ../bin/errcheck github.com/kisielk/errcheck + +tools/bin/gofail: go.mod + $(GO) build -o $@ github.com/pingcap/gofail diff --git a/ddl/db_test.go b/ddl/db_test.go index 377b0061aa372..abe615c0f5d9f 100644 --- a/ddl/db_test.go +++ b/ddl/db_test.go @@ -1619,14 +1619,49 @@ func (s *testDBSuite) testRenameTable(c *C, sql string, isAlterTable bool) { // for failure case failSQL := fmt.Sprintf(sql, "test_not_exist.t", "test_not_exist.t") - s.testErrorCode(c, failSQL, tmysql.ErrFileNotFound) + if isAlterTable { + s.testErrorCode(c, failSQL, tmysql.ErrNoSuchTable) + } else { + s.testErrorCode(c, failSQL, tmysql.ErrFileNotFound) + } failSQL = fmt.Sprintf(sql, "test.test_not_exist", "test.test_not_exist") - s.testErrorCode(c, failSQL, tmysql.ErrFileNotFound) + if isAlterTable { + s.testErrorCode(c, failSQL, tmysql.ErrNoSuchTable) + } else { + s.testErrorCode(c, failSQL, tmysql.ErrFileNotFound) + } failSQL = fmt.Sprintf(sql, "test.t_not_exist", "test_not_exist.t") - s.testErrorCode(c, failSQL, tmysql.ErrFileNotFound) + if isAlterTable { + s.testErrorCode(c, failSQL, tmysql.ErrNoSuchTable) + } else { + s.testErrorCode(c, failSQL, tmysql.ErrFileNotFound) + } failSQL = fmt.Sprintf(sql, "test1.t2", "test_not_exist.t") s.testErrorCode(c, failSQL, tmysql.ErrErrorOnRename) + s.tk.MustExec("use test1") + s.tk.MustExec("create table if not exists t_exist (c1 int, c2 int)") + failSQL = fmt.Sprintf(sql, "test1.t2", "test1.t_exist") + s.testErrorCode(c, failSQL, tmysql.ErrTableExists) + failSQL = fmt.Sprintf(sql, "test.t_not_exist", "test1.t_exist") + if isAlterTable { + s.testErrorCode(c, failSQL, tmysql.ErrNoSuchTable) + } else { + s.testErrorCode(c, failSQL, tmysql.ErrTableExists) + } + failSQL = fmt.Sprintf(sql, "test_not_exist.t", "test1.t_exist") + if isAlterTable { + s.testErrorCode(c, failSQL, tmysql.ErrNoSuchTable) + } else { + s.testErrorCode(c, failSQL, tmysql.ErrTableExists) + } + failSQL = fmt.Sprintf(sql, "test_not_exist.t", "test1.t_not_exist") + if isAlterTable { + s.testErrorCode(c, failSQL, tmysql.ErrNoSuchTable) + } else { + s.testErrorCode(c, failSQL, tmysql.ErrFileNotFound) + } + // for the same table name s.tk.MustExec("use test1") s.tk.MustExec("create table if not exists t (c1 int, c2 int)") diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 7f6f2a45d1e1d..ed699dca0dc93 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -2283,10 +2283,22 @@ func (d *ddl) RenameTable(ctx sessionctx.Context, oldIdent, newIdent ast.Ident, is := d.GetInformationSchema(ctx) oldSchema, ok := is.SchemaByName(oldIdent.Schema) if !ok { + if isAlterTable { + return infoschema.ErrTableNotExists.GenWithStackByArgs(oldIdent.Schema, oldIdent.Name) + } + if is.TableExists(newIdent.Schema, newIdent.Name) { + return infoschema.ErrTableExists.GenWithStackByArgs(newIdent) + } return errFileNotFound.GenWithStackByArgs(oldIdent.Schema, oldIdent.Name) } oldTbl, err := is.TableByName(oldIdent.Schema, oldIdent.Name) if err != nil { + if isAlterTable { + return infoschema.ErrTableNotExists.GenWithStackByArgs(oldIdent.Schema, oldIdent.Name) + } + if is.TableExists(newIdent.Schema, newIdent.Name) { + return infoschema.ErrTableExists.GenWithStackByArgs(newIdent) + } return errFileNotFound.GenWithStackByArgs(oldIdent.Schema, oldIdent.Name) } if isAlterTable && newIdent.Schema.L == oldIdent.Schema.L && newIdent.Name.L == oldIdent.Name.L { diff --git a/executor/ddl_test.go b/executor/ddl_test.go index 3778bec4a535d..9cada7e004648 100644 --- a/executor/ddl_test.go +++ b/executor/ddl_test.go @@ -27,6 +27,7 @@ import ( "github.com/pingcap/tidb/ddl" ddlutil "github.com/pingcap/tidb/ddl/util" "github.com/pingcap/tidb/domain" + "github.com/pingcap/tidb/meta/autoid" plannercore "github.com/pingcap/tidb/planner/core" "github.com/pingcap/tidb/sessionctx/variable" "github.com/pingcap/tidb/table" @@ -470,6 +471,24 @@ func (s *testSuite3) TestShardRowIDBits(c *C) { _, err = tk.Exec("alter table auto shard_row_id_bits = 4") c.Assert(err, NotNil) tk.MustExec("alter table auto shard_row_id_bits = 0") + + // Test overflow + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t1 (a int) shard_row_id_bits = 15") + defer tk.MustExec("drop table if exists t1") + + tbl, err = domain.GetDomain(tk.Se).InfoSchema().TableByName(model.NewCIStr("test"), model.NewCIStr("t1")) + c.Assert(err, IsNil) + maxID := 1<<(64-15-1) - 1 + err = tbl.RebaseAutoID(tk.Se, int64(maxID)-1, false) + c.Assert(err, IsNil) + tk.MustExec("insert into t1 values(1)") + + // continue inserting will fail. + _, err = tk.Exec("insert into t1 values(2)") + c.Assert(autoid.ErrAutoincReadFailed.Equal(err), IsTrue, Commentf("err:%v", err)) + _, err = tk.Exec("insert into t1 values(3)") + c.Assert(autoid.ErrAutoincReadFailed.Equal(err), IsTrue, Commentf("err:%v", err)) } func (s *testSuite3) TestMaxHandleAddIndex(c *C) { diff --git a/executor/seqtest/prepared_test.go b/executor/seqtest/prepared_test.go index 505ee50f9ffb3..e83bba66e5c01 100644 --- a/executor/seqtest/prepared_test.go +++ b/executor/seqtest/prepared_test.go @@ -218,7 +218,7 @@ func (s *seqTestSuite) TestPrepared(c *C) { tk.MustExec("create table prepare1 (a decimal(1))") tk.MustExec("insert into prepare1 values(1);") _, err = tk.Exec("prepare stmt FROM @sql1") - c.Assert(err.Error(), Equals, "line 1 column 4 near \"\" (total length 4)") + c.Assert(err.Error(), Equals, "line 1 column 4 near \"NULL\" (total length 4)") tk.MustExec("SET @sql = 'update prepare1 set a=5 where a=?';") _, err = tk.Exec("prepare stmt FROM @sql") c.Assert(err, IsNil) diff --git a/expression/integration_test.go b/expression/integration_test.go index e399aebfe9a6f..aed28975c7227 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -3702,7 +3702,7 @@ func (s *testIntegrationSuite) TestUnknowHintIgnore(c *C) { tk.MustExec("USE test") tk.MustExec("create table t(a int)") tk.MustQuery("select /*+ unknown_hint(c1)*/ 1").Check(testkit.Rows("1")) - tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 line 1 column 29 near \" 1\" (total length 31)")) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 line 1 column 29 near \"select /*+ unknown_hint(c1)*/ 1\" (total length 31)")) _, err := tk.Exec("select 1 from /*+ test1() */ t") c.Assert(err, NotNil) } diff --git a/go.mod b/go.mod index 8c87769f48057..fcf325a9541d3 100644 --- a/go.mod +++ b/go.mod @@ -48,7 +48,7 @@ require ( github.com/pingcap/gofail v0.0.0-20181217135706-6a951c1e42c3 github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e github.com/pingcap/kvproto v0.0.0-20181203065228-c14302da291c - github.com/pingcap/parser v0.0.0-20190103131433-5d5a6dd34655 + github.com/pingcap/parser v0.0.0-20190106063416-3483d83d44bd github.com/pingcap/pd v2.1.0-rc.4+incompatible github.com/pingcap/tidb-tools v2.1.1-0.20181218072513-b2235d442b06+incompatible github.com/pingcap/tipb v0.0.0-20181012112600-11e33c750323 diff --git a/go.sum b/go.sum index 49785cec81608..708d32b715daa 100644 --- a/go.sum +++ b/go.sum @@ -110,8 +110,8 @@ github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rG github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= github.com/pingcap/kvproto v0.0.0-20181203065228-c14302da291c h1:Qf5St5XGwKgKQLar9lEXoeO0hJMVaFBj3JqvFguWtVg= github.com/pingcap/kvproto v0.0.0-20181203065228-c14302da291c/go.mod h1:Ja9XPjot9q4/3JyCZodnWDGNXt4pKemhIYCvVJM7P24= -github.com/pingcap/parser v0.0.0-20190103131433-5d5a6dd34655 h1:nAGxJRuzO6T7mL/uAaOOZSVl9x+Vmy6cTYuzQjFDRw4= -github.com/pingcap/parser v0.0.0-20190103131433-5d5a6dd34655/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= +github.com/pingcap/parser v0.0.0-20190106063416-3483d83d44bd h1:FWAAGBZWj5oL4XwYF3p2rfhMSH5JeApOyW2c7ggCsUY= +github.com/pingcap/parser v0.0.0-20190106063416-3483d83d44bd/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= github.com/pingcap/pd v2.1.0-rc.4+incompatible h1:/buwGk04aHO5odk/+O8ZOXGs4qkUjYTJ2UpCJXna8NE= github.com/pingcap/pd v2.1.0-rc.4+incompatible/go.mod h1:nD3+EoYes4+aNNODO99ES59V83MZSI+dFbhyr667a0E= github.com/pingcap/tidb-tools v2.1.1-0.20181218072513-b2235d442b06+incompatible h1:Bsd+NHosPVowEGB3BCx+2d8wUQGDTXSSC5ljeNS6cXo= diff --git a/planner/core/errors.go b/planner/core/errors.go index 6cf557cb24db6..562657db2b97b 100644 --- a/planner/core/errors.go +++ b/planner/core/errors.go @@ -54,6 +54,12 @@ const ( codePrivilegeCheckFail = mysql.ErrUnknown codeWindowInvalidWindowFuncUse = mysql.ErrWindowInvalidWindowFuncUse codeWindowInvalidWindowFuncAliasUse = mysql.ErrWindowInvalidWindowFuncAliasUse + codeWindowNoSuchWindow = mysql.ErrWindowNoSuchWindow + codeWindowCircularityInWindowGraph = mysql.ErrWindowCircularityInWindowGraph + codeWindowNoChildPartitioning = mysql.ErrWindowNoChildPartitioning + codeWindowNoInherentFrame = mysql.ErrWindowNoInherentFrame + codeWindowNoRedefineOrderBy = mysql.ErrWindowNoRedefineOrderBy + codeWindowDuplicateName = mysql.ErrWindowDuplicateName ) // error definitions. @@ -94,6 +100,12 @@ var ( ErrPrivilegeCheckFail = terror.ClassOptimizer.New(codePrivilegeCheckFail, "privilege check fail") ErrWindowInvalidWindowFuncUse = terror.ClassOptimizer.New(codeWindowInvalidWindowFuncUse, mysql.MySQLErrName[mysql.ErrWindowInvalidWindowFuncUse]) ErrWindowInvalidWindowFuncAliasUse = terror.ClassOptimizer.New(codeWindowInvalidWindowFuncAliasUse, mysql.MySQLErrName[mysql.ErrWindowInvalidWindowFuncAliasUse]) + ErrWindowNoSuchWindow = terror.ClassOptimizer.New(codeWindowNoSuchWindow, mysql.MySQLErrName[mysql.ErrWindowNoSuchWindow]) + ErrWindowCircularityInWindowGraph = terror.ClassOptimizer.New(codeWindowCircularityInWindowGraph, mysql.MySQLErrName[mysql.ErrWindowCircularityInWindowGraph]) + ErrWindowNoChildPartitioning = terror.ClassOptimizer.New(codeWindowNoChildPartitioning, mysql.MySQLErrName[mysql.ErrWindowNoChildPartitioning]) + ErrWindowNoInherentFrame = terror.ClassOptimizer.New(codeWindowNoInherentFrame, mysql.MySQLErrName[mysql.ErrWindowNoInherentFrame]) + ErrWindowNoRedefineOrderBy = terror.ClassOptimizer.New(codeWindowNoRedefineOrderBy, mysql.MySQLErrName[mysql.ErrWindowNoRedefineOrderBy]) + ErrWindowDuplicateName = terror.ClassOptimizer.New(codeWindowDuplicateName, mysql.MySQLErrName[mysql.ErrWindowDuplicateName]) ) func init() { @@ -124,6 +136,12 @@ func init() { codeWindowInvalidWindowFuncUse: mysql.ErrWindowInvalidWindowFuncUse, codeWindowInvalidWindowFuncAliasUse: mysql.ErrWindowInvalidWindowFuncAliasUse, + codeWindowNoSuchWindow: mysql.ErrWindowNoSuchWindow, + codeWindowCircularityInWindowGraph: mysql.ErrWindowCircularityInWindowGraph, + codeWindowNoChildPartitioning: mysql.ErrWindowNoChildPartitioning, + codeWindowNoInherentFrame: mysql.ErrWindowNoInherentFrame, + codeWindowNoRedefineOrderBy: mysql.ErrWindowNoRedefineOrderBy, + codeWindowDuplicateName: mysql.ErrWindowDuplicateName, } terror.ErrClassToMySQLCodes[terror.ClassOptimizer] = mysqlErrCodeMap } diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 1199dc80fec3c..a65812350e96b 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -1878,6 +1878,11 @@ func (b *PlanBuilder) buildSelect(sel *ast.SelectStmt) (p LogicalPlan, err error } } + b.windowSpecs, err = buildWindowSpecs(sel.WindowSpecs) + if err != nil { + return nil, err + } + if hasWindowFuncField { // Now we build the window function fields. p, oldLen, err = b.buildProjection(p, sel.Fields.Fields, windowMap, true) @@ -2592,6 +2597,16 @@ func (b *PlanBuilder) buildProjectionForWindow(p LogicalPlan, expr *ast.WindowFu var items []*ast.ByItem spec := expr.Spec + if spec.Ref.L != "" { + ref, ok := b.windowSpecs[spec.Ref.L] + if !ok { + return nil, nil, nil, ErrWindowNoSuchWindow.GenWithStackByArgs(spec.Ref.O) + } + err := mergeWindowSpec(&spec, &ref) + if err != nil { + return nil, nil, nil, err + } + } if spec.PartitionBy != nil { items = append(items, spec.PartitionBy.Items...) } @@ -2679,6 +2694,68 @@ func (b *PlanBuilder) buildWindowFunction(p LogicalPlan, expr *ast.WindowFuncExp return window, nil } +// resolveWindowSpec resolve window specifications for sql like `select ... from t window w1 as (w2), w2 as (partition by a)`. +// We need to resolve the referenced window to get the definition of current window spec. +func resolveWindowSpec(spec *ast.WindowSpec, specs map[string]ast.WindowSpec, inStack map[string]bool) error { + if inStack[spec.Name.L] { + return errors.Trace(ErrWindowCircularityInWindowGraph) + } + if spec.Ref.L == "" { + return nil + } + ref, ok := specs[spec.Ref.L] + if !ok { + return ErrWindowNoSuchWindow.GenWithStackByArgs(spec.Ref.O) + } + inStack[spec.Name.L] = true + err := resolveWindowSpec(&ref, specs, inStack) + if err != nil { + return err + } + inStack[spec.Name.L] = false + return mergeWindowSpec(spec, &ref) +} + +func mergeWindowSpec(spec, ref *ast.WindowSpec) error { + if ref.Frame != nil { + return ErrWindowNoInherentFrame.GenWithStackByArgs(ref.Name.O) + } + if ref.OrderBy != nil { + if spec.OrderBy != nil { + name := spec.Name.O + if name == "" { + name = "" + } + return ErrWindowNoRedefineOrderBy.GenWithStackByArgs(name, ref.Name.O) + } + spec.OrderBy = ref.OrderBy + } + if spec.PartitionBy != nil { + return errors.Trace(ErrWindowNoChildPartitioning) + } + spec.PartitionBy = ref.PartitionBy + spec.Ref = model.NewCIStr("") + return nil +} + +func buildWindowSpecs(specs []ast.WindowSpec) (map[string]ast.WindowSpec, error) { + specsMap := make(map[string]ast.WindowSpec, len(specs)) + for _, spec := range specs { + if _, ok := specsMap[spec.Name.L]; ok { + return nil, ErrWindowDuplicateName.GenWithStackByArgs(spec.Name.O) + } + specsMap[spec.Name.L] = spec + } + inStack := make(map[string]bool, len(specs)) + for _, spec := range specs { + err := resolveWindowSpec(&spec, specsMap, inStack) + if err != nil { + return nil, err + } + } + return specsMap, nil +} + // extractTableList extracts all the TableNames from node. func extractTableList(node ast.ResultSetNode, input []*ast.TableName) []*ast.TableName { switch x := node.(type) { diff --git a/planner/core/logical_plan_test.go b/planner/core/logical_plan_test.go index 58c55b2b0a73f..677b4ad2a74ce 100644 --- a/planner/core/logical_plan_test.go +++ b/planner/core/logical_plan_test.go @@ -1960,6 +1960,42 @@ func (s *testPlanSuite) TestWindowFunction(c *C) { sql: "select sum(a) over() as sum_a from t group by sum_a", result: "[planner:1247]Reference 'sum_a' not supported (reference to window function)", }, + { + sql: "select sum(a) over() from t window w1 as (w2)", + result: "[planner:3579]Window name 'w2' is not defined.", + }, + { + sql: "select sum(a) over(w) from t", + result: "[planner:3579]Window name 'w' is not defined.", + }, + { + sql: "select sum(a) over() from t window w1 as (w2), w2 as (w1)", + result: "[planner:3580]There is a circularity in the window dependency graph.", + }, + { + sql: "select sum(a) over(w partition by a) from t window w as ()", + result: "[planner:3581]A window which depends on another cannot define partitioning.", + }, + { + sql: "select sum(a) over(w) from t window w as (rows between 1 preceding AND 1 following)", + result: "[planner:3582]Window 'w' has a frame definition, so cannot be referenced by another window.", + }, + { + sql: "select sum(a) over(w order by b) from t window w as (order by a)", + result: "[planner:3583]Window '' cannot inherit 'w' since both contain an ORDER BY clause.", + }, + { + sql: "select sum(a) over() from t window w1 as (), w1 as ()", + result: "[planner:3591]Window 'w1' is defined twice.", + }, + { + sql: "select sum(a) over(w1), avg(a) over(w2) from t window w1 as (partition by a), w2 as (w1)", + result: "TableReader(Table(t))->Window(sum(test.t.a))->Window(avg(test.t.a))->Projection", + }, + { + sql: "select a from t window w1 as (partition by a) order by (sum(a) over(w1))", + result: "TableReader(Table(t))->Window(sum(test.t.a))->Sort->Projection", + }, } s.Parser.EnableWindowFunc(true) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index ee723274ff50d..ccd0f72e2f156 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -137,6 +137,8 @@ type PlanBuilder struct { // inStraightJoin represents whether the current "SELECT" statement has // "STRAIGHT_JOIN" option. inStraightJoin bool + + windowSpecs map[string]ast.WindowSpec } // GetVisitInfo gets the visitInfo of the PlanBuilder. diff --git a/table/tables/tables.go b/table/tables/tables.go index 50ef94a4500d0..82d7e4aad2949 100644 --- a/table/tables/tables.go +++ b/table/tables/tables.go @@ -919,6 +919,16 @@ func (t *tableCommon) AllocAutoID(ctx sessionctx.Context) (int64, error) { return 0, errors.Trace(err) } if t.meta.ShardRowIDBits > 0 { + if t.overflowShardBits(rowID) { + // If overflow, the rowID may be duplicated. For examples, + // t.meta.ShardRowIDBits = 4 + // rowID = 0010111111111111111111111111111111111111111111111111111111111111 + // shard = 01000000000000000000000000000000000000000000000000000000000000000 + // will be duplicated with: + // rowID = 0100111111111111111111111111111111111111111111111111111111111111 + // shard = 0010000000000000000000000000000000000000000000000000000000000000 + return 0, autoid.ErrAutoincReadFailed + } txnCtx := ctx.GetSessionVars().TxnCtx if txnCtx.Shard == nil { shard := t.calcShard(txnCtx.StartTS) @@ -929,6 +939,12 @@ func (t *tableCommon) AllocAutoID(ctx sessionctx.Context) (int64, error) { return rowID, nil } +// overflowShardBits check whether the rowID overflow `1<<(64-t.meta.ShardRowIDBits-1) -1`. +func (t *tableCommon) overflowShardBits(rowID int64) bool { + mask := (1< 0 +} + func (t *tableCommon) calcShard(startTS uint64) int64 { var buf [8]byte binary.LittleEndian.PutUint64(buf[:], startTS)