Skip to content

Commit

Permalink
cherry pick pingcap#36613 to release-5.3
Browse files Browse the repository at this point in the history
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>
  • Loading branch information
tangenta authored and ti-srebot committed Aug 2, 2022
1 parent d674b64 commit e5d47f0
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 3 deletions.
80 changes: 80 additions & 0 deletions executor/infoschema_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -986,3 +986,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 <nil> ",
"name text YES <nil> ",
"some_date timestamp YES <nil> "))
require.NoError(t, failpoint.Disable("tikvclient/tikvStoreSendReqResult"))
}
>>>>>>> e39ef4cae... executor: prevent sending cop request for show columns (#36613)
5 changes: 5 additions & 0 deletions executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -1844,7 +1844,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()
Expand Down
8 changes: 7 additions & 1 deletion planner/core/expression_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,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
}
Expand Down Expand Up @@ -984,7 +990,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())
Expand Down
36 changes: 34 additions & 2 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,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 {
Expand Down Expand Up @@ -614,14 +629,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.
Expand Down

0 comments on commit e5d47f0

Please sign in to comment.