From cce8384672905de774e6ad76b0bc1730bca0b67e Mon Sep 17 00:00:00 2001 From: tangenta Date: Wed, 27 Jul 2022 20:31:11 +0800 Subject: [PATCH 1/3] cherry pick #36613 to release-5.2 Signed-off-by: ti-srebot --- executor/infoschema_reader_test.go | 80 +++++++++++++++++++++++++++++ executor/show.go | 5 ++ planner/core/expression_rewriter.go | 8 ++- planner/core/planbuilder.go | 36 ++++++++++++- 4 files changed, 126 insertions(+), 3 deletions(-) diff --git a/executor/infoschema_reader_test.go b/executor/infoschema_reader_test.go index 400ca848a85c3..0365a6be11edd 100644 --- a/executor/infoschema_reader_test.go +++ b/executor/infoschema_reader_test.go @@ -981,3 +981,83 @@ func (s *testInfoschemaTableSuite) TestTablesPKType(c *C) { tk.MustQuery("SELECT TIDB_PK_TYPE FROM information_schema.tables where table_schema = 'test' and table_name = 't_common'").Check(testkit.Rows("CLUSTERED")) tk.MustQuery("SELECT TIDB_PK_TYPE FROM information_schema.tables where table_schema = 'INFORMATION_SCHEMA' and table_name = 'TABLES'").Check(testkit.Rows("NONCLUSTERED")) } +<<<<<<< HEAD +======= + +// https://github.com/pingcap/tidb/issues/32459. +func TestJoinSystemTableContainsView(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t (a timestamp, b int);") + tk.MustExec("insert into t values (null, 100);") + tk.MustExec("create view v as select * from t;") + // This is used by grafana when TiDB is specified as the data source. + // See https://github.com/grafana/grafana/blob/e86b6662a187c77656f72bef3b0022bf5ced8b98/public/app/plugins/datasource/mysql/meta_query.ts#L31 + for i := 0; i < 10; i++ { + tk.MustQuery(` +SELECT + table_name as table_name, + ( SELECT + column_name as column_name + FROM information_schema.columns c + WHERE + c.table_schema = t.table_schema AND + c.table_name = t.table_name AND + c.data_type IN ('timestamp', 'datetime') + ORDER BY ordinal_position LIMIT 1 + ) AS time_column, + ( SELECT + column_name AS column_name + FROM information_schema.columns c + WHERE + c.table_schema = t.table_schema AND + c.table_name = t.table_name AND + c.data_type IN('float', 'int', 'bigint') + ORDER BY ordinal_position LIMIT 1 + ) AS value_column + FROM information_schema.tables t + WHERE + t.table_schema = database() AND + EXISTS + ( SELECT 1 + FROM information_schema.columns c + WHERE + c.table_schema = t.table_schema AND + c.table_name = t.table_name AND + c.data_type IN ('timestamp', 'datetime') + ) AND + EXISTS + ( SELECT 1 + FROM information_schema.columns c + WHERE + c.table_schema = t.table_schema AND + c.table_name = t.table_name AND + c.data_type IN('float', 'int', 'bigint') + ) + LIMIT 1 +; +`).Check(testkit.Rows("t a b")) + } +} + +// https://github.com/pingcap/tidb/issues/36426. +func TestShowColumnsWithSubQueryView(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + + tk.MustExec("CREATE TABLE added (`id` int(11), `name` text, `some_date` timestamp);") + tk.MustExec("CREATE TABLE incremental (`id` int(11), `name`text, `some_date` timestamp);") + tk.MustExec("create view temp_view as (select * from `added` where id > (select max(id) from `incremental`));") + // Show columns should not send coprocessor request to the storage. + require.NoError(t, failpoint.Enable("tikvclient/tikvStoreSendReqResult", `return("timeout")`)) + tk.MustQuery("show columns from temp_view;").Check(testkit.Rows( + "id int(11) YES ", + "name text YES ", + "some_date timestamp YES ")) + require.NoError(t, failpoint.Disable("tikvclient/tikvStoreSendReqResult")) +} +>>>>>>> e39ef4cae... executor: prevent sending cop request for show columns (#36613) diff --git a/executor/show.go b/executor/show.go index 3269321888222..c23a568324206 100644 --- a/executor/show.go +++ b/executor/show.go @@ -1763,7 +1763,12 @@ func (e *ShowExec) fetchShowBuiltins() error { func tryFillViewColumnType(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, dbName model.CIStr, tbl *model.TableInfo) error { if tbl.IsView() { // Retrieve view columns info. +<<<<<<< HEAD planBuilder, _ := plannercore.NewPlanBuilder().Init(sctx, is, &hint.BlockHintProcessor{}) +======= + planBuilder, _ := plannercore.NewPlanBuilder( + plannercore.PlanBuilderOptNoExecution{}).Init(s, is, &hint.BlockHintProcessor{}) +>>>>>>> e39ef4cae... executor: prevent sending cop request for show columns (#36613) if viewLogicalPlan, err := planBuilder.BuildDataSourceFromView(ctx, dbName, tbl); err == nil { viewSchema := viewLogicalPlan.Schema() viewOutputNames := viewLogicalPlan.OutputNames() diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index e110e4c8e267b..3fd572fb7ba05 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -808,8 +808,14 @@ func (er *expressionRewriter) handleExistSubquery(ctx context.Context, v *ast.Ex return v, true } np = er.popExistsSubPlan(np) +<<<<<<< HEAD if len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 { er.p, er.err = er.b.buildSemiApply(er.p, np, nil, er.asScalar, v.Not) +======= + + if er.b.disableSubQueryPreprocessing || len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 { + er.p, er.err = er.b.buildSemiApply(er.p, np, nil, er.asScalar, v.Not, hasRewriteHint) +>>>>>>> e39ef4cae... executor: prevent sending cop request for show columns (#36613) if er.err != nil || !er.asScalar { return v, true } @@ -981,7 +987,7 @@ func (er *expressionRewriter) handleScalarSubquery(ctx context.Context, v *ast.S return v, true } np = er.b.buildMaxOneRow(np) - if len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 { + if er.b.disableSubQueryPreprocessing || len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 { er.p = er.b.buildApplyWithJoinType(er.p, np, LeftOuterJoin) if np.Schema().Len() > 1 { newCols := make([]expression.Expression, 0, np.Schema().Len()) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 2eed874f10188..f7bf49e67dd2b 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -510,6 +510,21 @@ type PlanBuilder struct { isForUpdateRead bool allocIDForCTEStorage int buildingRecursivePartForCTE bool +<<<<<<< HEAD +======= + buildingCTE bool + + // checkSemiJoinHint checks whether the SEMI_JOIN_REWRITE hint is possible to be applied on the current SELECT stmt. + // We need this variable for the hint since the hint is set in subquery, but we check its availability in its outer scope. + // e.g. select * from t where exists(select /*+ SEMI_JOIN_REWRITE() */ 1 from t1 where t.a=t1.a) + // Whether the hint can be applied or not is checked after the subquery is fully built. + checkSemiJoinHint bool + // hasValidSemijoinHint would tell the outer APPLY/JOIN operator that there's valid hint to be checked later + // if there's SEMI_JOIN_REWRITE hint and we find checkSemiJoinHint is true. + hasValidSemiJoinHint bool + // disableSubQueryPreprocessing indicates whether to pre-process uncorrelated sub-queries in rewriting stage. + disableSubQueryPreprocessing bool +>>>>>>> e39ef4cae... executor: prevent sending cop request for show columns (#36613) } type handleColHelper struct { @@ -611,14 +626,31 @@ func (b *PlanBuilder) popSelectOffset() { b.selectOffset = b.selectOffset[:len(b.selectOffset)-1] } +// PlanBuilderOpt is used to adjust the plan builder. +type PlanBuilderOpt interface { + Apply(builder *PlanBuilder) +} + +// PlanBuilderOptNoExecution means the plan builder should not run any executor during Build(). +type PlanBuilderOptNoExecution struct{} + +// Apply implements the interface PlanBuilderOpt. +func (p PlanBuilderOptNoExecution) Apply(builder *PlanBuilder) { + builder.disableSubQueryPreprocessing = true +} + // NewPlanBuilder creates a new PlanBuilder. -func NewPlanBuilder() *PlanBuilder { - return &PlanBuilder{ +func NewPlanBuilder(opts ...PlanBuilderOpt) *PlanBuilder { + builder := &PlanBuilder{ outerCTEs: make([]*cteInfo, 0), colMapper: make(map[*ast.ColumnNameExpr]int), handleHelper: &handleColHelper{id2HandleMapStack: make([]map[int64][]HandleCols, 0)}, correlatedAggMapper: make(map[*ast.AggregateFuncExpr]*expression.CorrelatedColumn), } + for _, opt := range opts { + opt.Apply(builder) + } + return builder } // Init initialize a PlanBuilder. From 114129535ce0ed2310015da894b3d1a5ab446207 Mon Sep 17 00:00:00 2001 From: xhe Date: Tue, 9 Aug 2022 17:25:54 +0800 Subject: [PATCH 2/3] *: fix CI Signed-off-by: xhe --- executor/infoschema_reader_test.go | 80 ----------------------------- executor/show.go | 4 -- planner/core/expression_rewriter.go | 8 +-- planner/core/planbuilder.go | 13 ----- 4 files changed, 1 insertion(+), 104 deletions(-) diff --git a/executor/infoschema_reader_test.go b/executor/infoschema_reader_test.go index 0365a6be11edd..400ca848a85c3 100644 --- a/executor/infoschema_reader_test.go +++ b/executor/infoschema_reader_test.go @@ -981,83 +981,3 @@ func (s *testInfoschemaTableSuite) TestTablesPKType(c *C) { tk.MustQuery("SELECT TIDB_PK_TYPE FROM information_schema.tables where table_schema = 'test' and table_name = 't_common'").Check(testkit.Rows("CLUSTERED")) tk.MustQuery("SELECT TIDB_PK_TYPE FROM information_schema.tables where table_schema = 'INFORMATION_SCHEMA' and table_name = 'TABLES'").Check(testkit.Rows("NONCLUSTERED")) } -<<<<<<< HEAD -======= - -// https://github.com/pingcap/tidb/issues/32459. -func TestJoinSystemTableContainsView(t *testing.T) { - store, clean := testkit.CreateMockStore(t) - defer clean() - tk := testkit.NewTestKit(t, store) - tk.MustExec("use test") - tk.MustExec("create table t (a timestamp, b int);") - tk.MustExec("insert into t values (null, 100);") - tk.MustExec("create view v as select * from t;") - // This is used by grafana when TiDB is specified as the data source. - // See https://github.com/grafana/grafana/blob/e86b6662a187c77656f72bef3b0022bf5ced8b98/public/app/plugins/datasource/mysql/meta_query.ts#L31 - for i := 0; i < 10; i++ { - tk.MustQuery(` -SELECT - table_name as table_name, - ( SELECT - column_name as column_name - FROM information_schema.columns c - WHERE - c.table_schema = t.table_schema AND - c.table_name = t.table_name AND - c.data_type IN ('timestamp', 'datetime') - ORDER BY ordinal_position LIMIT 1 - ) AS time_column, - ( SELECT - column_name AS column_name - FROM information_schema.columns c - WHERE - c.table_schema = t.table_schema AND - c.table_name = t.table_name AND - c.data_type IN('float', 'int', 'bigint') - ORDER BY ordinal_position LIMIT 1 - ) AS value_column - FROM information_schema.tables t - WHERE - t.table_schema = database() AND - EXISTS - ( SELECT 1 - FROM information_schema.columns c - WHERE - c.table_schema = t.table_schema AND - c.table_name = t.table_name AND - c.data_type IN ('timestamp', 'datetime') - ) AND - EXISTS - ( SELECT 1 - FROM information_schema.columns c - WHERE - c.table_schema = t.table_schema AND - c.table_name = t.table_name AND - c.data_type IN('float', 'int', 'bigint') - ) - LIMIT 1 -; -`).Check(testkit.Rows("t a b")) - } -} - -// https://github.com/pingcap/tidb/issues/36426. -func TestShowColumnsWithSubQueryView(t *testing.T) { - store, clean := testkit.CreateMockStore(t) - defer clean() - tk := testkit.NewTestKit(t, store) - tk.MustExec("use test") - - tk.MustExec("CREATE TABLE added (`id` int(11), `name` text, `some_date` timestamp);") - tk.MustExec("CREATE TABLE incremental (`id` int(11), `name`text, `some_date` timestamp);") - tk.MustExec("create view temp_view as (select * from `added` where id > (select max(id) from `incremental`));") - // Show columns should not send coprocessor request to the storage. - require.NoError(t, failpoint.Enable("tikvclient/tikvStoreSendReqResult", `return("timeout")`)) - tk.MustQuery("show columns from temp_view;").Check(testkit.Rows( - "id int(11) YES ", - "name text YES ", - "some_date timestamp YES ")) - require.NoError(t, failpoint.Disable("tikvclient/tikvStoreSendReqResult")) -} ->>>>>>> e39ef4cae... executor: prevent sending cop request for show columns (#36613) diff --git a/executor/show.go b/executor/show.go index c23a568324206..dda1e1a3146ae 100644 --- a/executor/show.go +++ b/executor/show.go @@ -1763,12 +1763,8 @@ func (e *ShowExec) fetchShowBuiltins() error { func tryFillViewColumnType(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, dbName model.CIStr, tbl *model.TableInfo) error { if tbl.IsView() { // Retrieve view columns info. -<<<<<<< HEAD - planBuilder, _ := plannercore.NewPlanBuilder().Init(sctx, is, &hint.BlockHintProcessor{}) -======= planBuilder, _ := plannercore.NewPlanBuilder( plannercore.PlanBuilderOptNoExecution{}).Init(s, is, &hint.BlockHintProcessor{}) ->>>>>>> e39ef4cae... executor: prevent sending cop request for show columns (#36613) if viewLogicalPlan, err := planBuilder.BuildDataSourceFromView(ctx, dbName, tbl); err == nil { viewSchema := viewLogicalPlan.Schema() viewOutputNames := viewLogicalPlan.OutputNames() diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index 3fd572fb7ba05..440f466c36050 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -808,14 +808,8 @@ func (er *expressionRewriter) handleExistSubquery(ctx context.Context, v *ast.Ex return v, true } np = er.popExistsSubPlan(np) -<<<<<<< HEAD - if len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 { - er.p, er.err = er.b.buildSemiApply(er.p, np, nil, er.asScalar, v.Not) -======= - if er.b.disableSubQueryPreprocessing || len(ExtractCorrelatedCols4LogicalPlan(np)) > 0 { - er.p, er.err = er.b.buildSemiApply(er.p, np, nil, er.asScalar, v.Not, hasRewriteHint) ->>>>>>> e39ef4cae... executor: prevent sending cop request for show columns (#36613) + er.p, er.err = er.b.buildSemiApply(er.p, np, nil, er.asScalar, v.Not) if er.err != nil || !er.asScalar { return v, true } diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index f7bf49e67dd2b..4295ebb461ec3 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -510,21 +510,8 @@ type PlanBuilder struct { isForUpdateRead bool allocIDForCTEStorage int buildingRecursivePartForCTE bool -<<<<<<< HEAD -======= - buildingCTE bool - - // checkSemiJoinHint checks whether the SEMI_JOIN_REWRITE hint is possible to be applied on the current SELECT stmt. - // We need this variable for the hint since the hint is set in subquery, but we check its availability in its outer scope. - // e.g. select * from t where exists(select /*+ SEMI_JOIN_REWRITE() */ 1 from t1 where t.a=t1.a) - // Whether the hint can be applied or not is checked after the subquery is fully built. - checkSemiJoinHint bool - // hasValidSemijoinHint would tell the outer APPLY/JOIN operator that there's valid hint to be checked later - // if there's SEMI_JOIN_REWRITE hint and we find checkSemiJoinHint is true. - hasValidSemiJoinHint bool // disableSubQueryPreprocessing indicates whether to pre-process uncorrelated sub-queries in rewriting stage. disableSubQueryPreprocessing bool ->>>>>>> e39ef4cae... executor: prevent sending cop request for show columns (#36613) } type handleColHelper struct { From 6721fe84734ede68742db223eddcee4c19cd30fa Mon Sep 17 00:00:00 2001 From: xhe Date: Tue, 9 Aug 2022 17:34:14 +0800 Subject: [PATCH 3/3] *: fix CI Signed-off-by: xhe --- executor/show.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executor/show.go b/executor/show.go index dda1e1a3146ae..473b962d1a78f 100644 --- a/executor/show.go +++ b/executor/show.go @@ -1764,7 +1764,7 @@ func tryFillViewColumnType(ctx context.Context, sctx sessionctx.Context, is info if tbl.IsView() { // Retrieve view columns info. planBuilder, _ := plannercore.NewPlanBuilder( - plannercore.PlanBuilderOptNoExecution{}).Init(s, is, &hint.BlockHintProcessor{}) + plannercore.PlanBuilderOptNoExecution{}).Init(sctx, is, &hint.BlockHintProcessor{}) if viewLogicalPlan, err := planBuilder.BuildDataSourceFromView(ctx, dbName, tbl); err == nil { viewSchema := viewLogicalPlan.Schema() viewOutputNames := viewLogicalPlan.OutputNames()