github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/embedded/logical_plans.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package embedded
    15  
    16  import (
    17  	"math"
    18  
    19  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    20  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    21  	"github.com/whtcorpsinc/BerolinaSQL/auth"
    22  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    23  	"github.com/whtcorpsinc/milevadb/causet"
    24  	"github.com/whtcorpsinc/milevadb/causet/property"
    25  	"github.com/whtcorpsinc/milevadb/causet/soliton"
    26  	"github.com/whtcorpsinc/milevadb/memex"
    27  	"github.com/whtcorpsinc/milevadb/memex/aggregation"
    28  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    29  	"github.com/whtcorpsinc/milevadb/soliton/ranger"
    30  	"github.com/whtcorpsinc/milevadb/statistics"
    31  	"github.com/whtcorpsinc/milevadb/types"
    32  	"go.uber.org/zap"
    33  )
    34  
    35  var (
    36  	_ LogicalCauset = &LogicalJoin{}
    37  	_ LogicalCauset = &LogicalAggregation{}
    38  	_ LogicalCauset = &LogicalProjection{}
    39  	_ LogicalCauset = &LogicalSelection{}
    40  	_ LogicalCauset = &LogicalApply{}
    41  	_ LogicalCauset = &LogicalMaxOneRow{}
    42  	_ LogicalCauset = &LogicalBlockDual{}
    43  	_ LogicalCauset = &DataSource{}
    44  	_ LogicalCauset = &EinsteinDBSingleGather{}
    45  	_ LogicalCauset = &LogicalBlockScan{}
    46  	_ LogicalCauset = &LogicalIndexScan{}
    47  	_ LogicalCauset = &LogicalUnionAll{}
    48  	_ LogicalCauset = &LogicalSort{}
    49  	_ LogicalCauset = &LogicalLock{}
    50  	_ LogicalCauset = &LogicalLimit{}
    51  	_ LogicalCauset = &LogicalWindow{}
    52  )
    53  
    54  // JoinType contains CrossJoin, InnerJoin, LeftOuterJoin, RightOuterJoin, FullOuterJoin, SemiJoin.
    55  type JoinType int
    56  
    57  const (
    58  	// InnerJoin means inner join.
    59  	InnerJoin JoinType = iota
    60  	// LeftOuterJoin means left join.
    61  	LeftOuterJoin
    62  	// RightOuterJoin means right join.
    63  	RightOuterJoin
    64  	// SemiJoin means if event a in causet A matches some rows in B, just output a.
    65  	SemiJoin
    66  	// AntiSemiJoin means if event a in causet A does not match any event in B, then output a.
    67  	AntiSemiJoin
    68  	// LeftOuterSemiJoin means if event a in causet A matches some rows in B, output (a, true), otherwise, output (a, false).
    69  	LeftOuterSemiJoin
    70  	// AntiLeftOuterSemiJoin means if event a in causet A matches some rows in B, output (a, false), otherwise, output (a, true).
    71  	AntiLeftOuterSemiJoin
    72  )
    73  
    74  // IsOuterJoin returns if this joiner is a outer joiner
    75  func (tp JoinType) IsOuterJoin() bool {
    76  	return tp == LeftOuterJoin || tp == RightOuterJoin ||
    77  		tp == LeftOuterSemiJoin || tp == AntiLeftOuterSemiJoin
    78  }
    79  
    80  func (tp JoinType) String() string {
    81  	switch tp {
    82  	case InnerJoin:
    83  		return "inner join"
    84  	case LeftOuterJoin:
    85  		return "left outer join"
    86  	case RightOuterJoin:
    87  		return "right outer join"
    88  	case SemiJoin:
    89  		return "semi join"
    90  	case AntiSemiJoin:
    91  		return "anti semi join"
    92  	case LeftOuterSemiJoin:
    93  		return "left outer semi join"
    94  	case AntiLeftOuterSemiJoin:
    95  		return "anti left outer semi join"
    96  	}
    97  	return "unsupported join type"
    98  }
    99  
   100  const (
   101  	preferLeftAsINLJInner uint = 1 << iota
   102  	preferRightAsINLJInner
   103  	preferLeftAsINLHJInner
   104  	preferRightAsINLHJInner
   105  	preferLeftAsINLMJInner
   106  	preferRightAsINLMJInner
   107  	preferHashJoin
   108  	preferMergeJoin
   109  	preferBCJoin
   110  	preferHashAgg
   111  	preferStreamAgg
   112  )
   113  
   114  const (
   115  	preferEinsteinDB = 1 << iota
   116  	preferTiFlash
   117  )
   118  
   119  // LogicalJoin is the logical join plan.
   120  type LogicalJoin struct {
   121  	logicalSchemaProducer
   122  
   123  	JoinType      JoinType
   124  	reordered     bool
   125  	cartesianJoin bool
   126  	StraightJoin  bool
   127  
   128  	// hintInfo stores the join algorithm hint information specified by client.
   129  	hintInfo       *blockHintInfo
   130  	preferJoinType uint
   131  
   132  	EqualConditions []*memex.ScalarFunction
   133  	LeftConditions  memex.CNFExprs
   134  	RightConditions memex.CNFExprs
   135  	OtherConditions memex.CNFExprs
   136  
   137  	leftProperties  [][]*memex.DeferredCauset
   138  	rightProperties [][]*memex.DeferredCauset
   139  
   140  	// DefaultValues is only used for left/right outer join, which is values the inner event's should be when the outer causet
   141  	// doesn't match any inner causet's event.
   142  	// That it's nil just means the default values is a slice of NULL.
   143  	// Currently, only `aggregation push down` phase will set this.
   144  	DefaultValues []types.Causet
   145  
   146  	// redundantSchema contains columns which are eliminated in join.
   147  	// For select * from a join b using (c); a.c will in output schemaReplicant, and b.c will in redundantSchema.
   148  	redundantSchema *memex.Schema
   149  	redundantNames  types.NameSlice
   150  
   151  	// equalCondOutCnt indicates the estimated count of joined rows after evaluating `EqualConditions`.
   152  	equalCondOutCnt float64
   153  }
   154  
   155  // Shallow shallow copies a LogicalJoin struct.
   156  func (p *LogicalJoin) Shallow() *LogicalJoin {
   157  	join := *p
   158  	return join.Init(p.ctx, p.blockOffset)
   159  }
   160  
   161  // GetJoinKeys extracts join keys(columns) from EqualConditions. It returns left join keys, right
   162  // join keys and an `isNullEQ` array which means the `joinKey[i]` is a `NullEQ` function. The `hasNullEQ`
   163  // means whether there is a `NullEQ` of a join key.
   164  func (p *LogicalJoin) GetJoinKeys() (leftKeys, rightKeys []*memex.DeferredCauset, isNullEQ []bool, hasNullEQ bool) {
   165  	for _, expr := range p.EqualConditions {
   166  		leftKeys = append(leftKeys, expr.GetArgs()[0].(*memex.DeferredCauset))
   167  		rightKeys = append(rightKeys, expr.GetArgs()[1].(*memex.DeferredCauset))
   168  		isNullEQ = append(isNullEQ, expr.FuncName.L == ast.NullEQ)
   169  		hasNullEQ = hasNullEQ || expr.FuncName.L == ast.NullEQ
   170  	}
   171  	return
   172  }
   173  
   174  func (p *LogicalJoin) columnSubstitute(schemaReplicant *memex.Schema, exprs []memex.Expression) {
   175  	for i, cond := range p.LeftConditions {
   176  		p.LeftConditions[i] = memex.DeferredCausetSubstitute(cond, schemaReplicant, exprs)
   177  	}
   178  
   179  	for i, cond := range p.RightConditions {
   180  		p.RightConditions[i] = memex.DeferredCausetSubstitute(cond, schemaReplicant, exprs)
   181  	}
   182  
   183  	for i, cond := range p.OtherConditions {
   184  		p.OtherConditions[i] = memex.DeferredCausetSubstitute(cond, schemaReplicant, exprs)
   185  	}
   186  
   187  	for i := len(p.EqualConditions) - 1; i >= 0; i-- {
   188  		newCond := memex.DeferredCausetSubstitute(p.EqualConditions[i], schemaReplicant, exprs).(*memex.ScalarFunction)
   189  
   190  		// If the columns used in the new filter all come from the left child,
   191  		// we can push this filter to it.
   192  		if memex.ExprFromSchema(newCond, p.children[0].Schema()) {
   193  			p.LeftConditions = append(p.LeftConditions, newCond)
   194  			p.EqualConditions = append(p.EqualConditions[:i], p.EqualConditions[i+1:]...)
   195  			continue
   196  		}
   197  
   198  		// If the columns used in the new filter all come from the right
   199  		// child, we can push this filter to it.
   200  		if memex.ExprFromSchema(newCond, p.children[1].Schema()) {
   201  			p.RightConditions = append(p.RightConditions, newCond)
   202  			p.EqualConditions = append(p.EqualConditions[:i], p.EqualConditions[i+1:]...)
   203  			continue
   204  		}
   205  
   206  		_, lhsIsDefCaus := newCond.GetArgs()[0].(*memex.DeferredCauset)
   207  		_, rhsIsDefCaus := newCond.GetArgs()[1].(*memex.DeferredCauset)
   208  
   209  		// If the columns used in the new filter are not all memex.DeferredCauset,
   210  		// we can not use it as join's equal condition.
   211  		if !(lhsIsDefCaus && rhsIsDefCaus) {
   212  			p.OtherConditions = append(p.OtherConditions, newCond)
   213  			p.EqualConditions = append(p.EqualConditions[:i], p.EqualConditions[i+1:]...)
   214  			continue
   215  		}
   216  
   217  		p.EqualConditions[i] = newCond
   218  	}
   219  }
   220  
   221  // AttachOnConds extracts on conditions for join and set the `EqualConditions`, `LeftConditions`, `RightConditions` and
   222  // `OtherConditions` by the result of extract.
   223  func (p *LogicalJoin) AttachOnConds(onConds []memex.Expression) {
   224  	eq, left, right, other := p.extractOnCondition(onConds, false, false)
   225  	p.AppendJoinConds(eq, left, right, other)
   226  }
   227  
   228  // AppendJoinConds appends new join conditions.
   229  func (p *LogicalJoin) AppendJoinConds(eq []*memex.ScalarFunction, left, right, other []memex.Expression) {
   230  	p.EqualConditions = append(eq, p.EqualConditions...)
   231  	p.LeftConditions = append(left, p.LeftConditions...)
   232  	p.RightConditions = append(right, p.RightConditions...)
   233  	p.OtherConditions = append(other, p.OtherConditions...)
   234  }
   235  
   236  // ExtractCorrelatedDefCauss implements LogicalCauset interface.
   237  func (p *LogicalJoin) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset {
   238  	corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(p.EqualConditions)+len(p.LeftConditions)+len(p.RightConditions)+len(p.OtherConditions))
   239  	for _, fun := range p.EqualConditions {
   240  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(fun)...)
   241  	}
   242  	for _, fun := range p.LeftConditions {
   243  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(fun)...)
   244  	}
   245  	for _, fun := range p.RightConditions {
   246  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(fun)...)
   247  	}
   248  	for _, fun := range p.OtherConditions {
   249  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(fun)...)
   250  	}
   251  	return corDefCauss
   252  }
   253  
   254  // ExtractJoinKeys extract join keys as a schemaReplicant for child with childIdx.
   255  func (p *LogicalJoin) ExtractJoinKeys(childIdx int) *memex.Schema {
   256  	joinKeys := make([]*memex.DeferredCauset, 0, len(p.EqualConditions))
   257  	for _, eqCond := range p.EqualConditions {
   258  		joinKeys = append(joinKeys, eqCond.GetArgs()[childIdx].(*memex.DeferredCauset))
   259  	}
   260  	return memex.NewSchema(joinKeys...)
   261  }
   262  
   263  // LogicalProjection represents a select fields plan.
   264  type LogicalProjection struct {
   265  	logicalSchemaProducer
   266  
   267  	Exprs []memex.Expression
   268  
   269  	// calculateGenDefCauss indicates the projection is for calculating generated columns.
   270  	// In *UFIDelATE*, we should know this to tell different projections.
   271  	calculateGenDefCauss bool
   272  
   273  	// CalculateNoDelay indicates this Projection is the root Causet and should be
   274  	// calculated without delay and will not return any result to client.
   275  	// Currently it is "true" only when the current allegrosql query is a "DO" memex.
   276  	// See "https://dev.allegrosql.com/doc/refman/5.7/en/do.html" for more detail.
   277  	CalculateNoDelay bool
   278  
   279  	// AvoidDeferredCausetEvaluator is a temporary variable which is ONLY used to avoid
   280  	// building columnEvaluator for the memexs of Projection which is
   281  	// built by buildProjection4Union.
   282  	// This can be removed after column pool being supported.
   283  	// Related issue: MilevaDB#8141(https://github.com/whtcorpsinc/milevadb/issues/8141)
   284  	AvoidDeferredCausetEvaluator bool
   285  }
   286  
   287  // ExtractCorrelatedDefCauss implements LogicalCauset interface.
   288  func (p *LogicalProjection) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset {
   289  	corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(p.Exprs))
   290  	for _, expr := range p.Exprs {
   291  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...)
   292  	}
   293  	return corDefCauss
   294  }
   295  
   296  // GetUsedDefCauss extracts all of the DeferredCausets used by proj.
   297  func (p *LogicalProjection) GetUsedDefCauss() (usedDefCauss []*memex.DeferredCauset) {
   298  	for _, expr := range p.Exprs {
   299  		usedDefCauss = append(usedDefCauss, memex.ExtractDeferredCausets(expr)...)
   300  	}
   301  	return usedDefCauss
   302  }
   303  
   304  // LogicalAggregation represents an aggregate plan.
   305  type LogicalAggregation struct {
   306  	logicalSchemaProducer
   307  
   308  	AggFuncs     []*aggregation.AggFuncDesc
   309  	GroupByItems []memex.Expression
   310  	// groupByDefCauss stores the columns that are group-by items.
   311  	groupByDefCauss []*memex.DeferredCauset
   312  
   313  	// aggHints stores aggregation hint information.
   314  	aggHints aggHintInfo
   315  
   316  	possibleProperties [][]*memex.DeferredCauset
   317  	inputCount         float64 // inputCount is the input count of this plan.
   318  }
   319  
   320  // HasDistinct shows whether LogicalAggregation has functions with distinct.
   321  func (la *LogicalAggregation) HasDistinct() bool {
   322  	for _, aggFunc := range la.AggFuncs {
   323  		if aggFunc.HasDistinct {
   324  			return true
   325  		}
   326  	}
   327  	return false
   328  }
   329  
   330  // CopyAggHints copies the aggHints from another LogicalAggregation.
   331  func (la *LogicalAggregation) CopyAggHints(agg *LogicalAggregation) {
   332  	// TODO: Copy the hint may make the un-applicable hint throw the
   333  	// same warning message more than once. We'd better add a flag for
   334  	// `HaveThrownWarningMessage` to avoid this. Besides, finalAgg and
   335  	// partialAgg (in cascades causet) should share the same hint, instead
   336  	// of a copy.
   337  	la.aggHints = agg.aggHints
   338  }
   339  
   340  // IsPartialModeAgg returns if all of the AggFuncs are partialMode.
   341  func (la *LogicalAggregation) IsPartialModeAgg() bool {
   342  	// Since all of the AggFunc share the same AggMode, we only need to check the first one.
   343  	return la.AggFuncs[0].Mode == aggregation.Partial1Mode
   344  }
   345  
   346  // IsCompleteModeAgg returns if all of the AggFuncs are CompleteMode.
   347  func (la *LogicalAggregation) IsCompleteModeAgg() bool {
   348  	// Since all of the AggFunc share the same AggMode, we only need to check the first one.
   349  	return la.AggFuncs[0].Mode == aggregation.CompleteMode
   350  }
   351  
   352  // GetGroupByDefCauss returns the groupByDefCauss. If the groupByDefCauss haven't be collected,
   353  // this method would collect them at first. If the GroupByItems have been changed,
   354  // we should explicitly collect GroupByDeferredCausets before this method.
   355  func (la *LogicalAggregation) GetGroupByDefCauss() []*memex.DeferredCauset {
   356  	if la.groupByDefCauss == nil {
   357  		la.collectGroupByDeferredCausets()
   358  	}
   359  	return la.groupByDefCauss
   360  }
   361  
   362  // ExtractCorrelatedDefCauss implements LogicalCauset interface.
   363  func (la *LogicalAggregation) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset {
   364  	corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(la.GroupByItems)+len(la.AggFuncs))
   365  	for _, expr := range la.GroupByItems {
   366  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...)
   367  	}
   368  	for _, fun := range la.AggFuncs {
   369  		for _, arg := range fun.Args {
   370  			corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(arg)...)
   371  		}
   372  	}
   373  	return corDefCauss
   374  }
   375  
   376  // GetUsedDefCauss extracts all of the DeferredCausets used by agg including GroupByItems and AggFuncs.
   377  func (la *LogicalAggregation) GetUsedDefCauss() (usedDefCauss []*memex.DeferredCauset) {
   378  	for _, groupByItem := range la.GroupByItems {
   379  		usedDefCauss = append(usedDefCauss, memex.ExtractDeferredCausets(groupByItem)...)
   380  	}
   381  	for _, aggDesc := range la.AggFuncs {
   382  		for _, expr := range aggDesc.Args {
   383  			usedDefCauss = append(usedDefCauss, memex.ExtractDeferredCausets(expr)...)
   384  		}
   385  	}
   386  	return usedDefCauss
   387  }
   388  
   389  // LogicalSelection represents a where or having predicate.
   390  type LogicalSelection struct {
   391  	baseLogicalCauset
   392  
   393  	// Originally the WHERE or ON condition is parsed into a single memex,
   394  	// but after we converted to CNF(Conjunctive normal form), it can be
   395  	// split into a list of AND conditions.
   396  	Conditions []memex.Expression
   397  }
   398  
   399  // ExtractCorrelatedDefCauss implements LogicalCauset interface.
   400  func (p *LogicalSelection) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset {
   401  	corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(p.Conditions))
   402  	for _, cond := range p.Conditions {
   403  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(cond)...)
   404  	}
   405  	return corDefCauss
   406  }
   407  
   408  // LogicalApply gets one event from outer interlock and gets one event from inner interlock according to outer event.
   409  type LogicalApply struct {
   410  	LogicalJoin
   411  
   412  	CorDefCauss []*memex.CorrelatedDeferredCauset
   413  }
   414  
   415  // ExtractCorrelatedDefCauss implements LogicalCauset interface.
   416  func (la *LogicalApply) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset {
   417  	corDefCauss := la.LogicalJoin.ExtractCorrelatedDefCauss()
   418  	for i := len(corDefCauss) - 1; i >= 0; i-- {
   419  		if la.children[0].Schema().Contains(&corDefCauss[i].DeferredCauset) {
   420  			corDefCauss = append(corDefCauss[:i], corDefCauss[i+1:]...)
   421  		}
   422  	}
   423  	return corDefCauss
   424  }
   425  
   426  // LogicalMaxOneRow checks if a query returns no more than one event.
   427  type LogicalMaxOneRow struct {
   428  	baseLogicalCauset
   429  }
   430  
   431  // LogicalBlockDual represents a dual causet plan.
   432  type LogicalBlockDual struct {
   433  	logicalSchemaProducer
   434  
   435  	RowCount int
   436  }
   437  
   438  // LogicalMemBlock represents a memory causet or virtual causet
   439  // Some memory blocks wants to take the tenantship of some predications
   440  // e.g
   441  // SELECT * FROM cluster_log WHERE type='einsteindb' AND address='192.16.5.32'
   442  // Assume that the causet `cluster_log` is a memory causet, which is used
   443  // to retrieve logs from remote components. In the above situation we should
   444  // send log search request to the target EinsteinDB (192.16.5.32) directly instead of
   445  // requesting all cluster components log search gRPC interface to retrieve
   446  // log message and filtering them in MilevaDB node.
   447  type LogicalMemBlock struct {
   448  	logicalSchemaProducer
   449  
   450  	Extractor MemBlockPredicateExtractor
   451  	DBName    perceptron.CIStr
   452  	BlockInfo *perceptron.BlockInfo
   453  	// QueryTimeRange is used to specify the time range for metrics summary blocks and inspection blocks
   454  	// e.g: select /*+ time_range('2020-02-02 12:10:00', '2020-02-02 13:00:00') */ from metrics_summary;
   455  	//      select /*+ time_range('2020-02-02 12:10:00', '2020-02-02 13:00:00') */ from metrics_summary_by_label;
   456  	//      select /*+ time_range('2020-02-02 12:10:00', '2020-02-02 13:00:00') */ from inspection_summary;
   457  	//      select /*+ time_range('2020-02-02 12:10:00', '2020-02-02 13:00:00') */ from inspection_result;
   458  	QueryTimeRange QueryTimeRange
   459  }
   460  
   461  // LogicalUnionScan is only used in non read-only txn.
   462  type LogicalUnionScan struct {
   463  	baseLogicalCauset
   464  
   465  	conditions []memex.Expression
   466  
   467  	handleDefCauss HandleDefCauss
   468  }
   469  
   470  // DataSource represents a blockScan without condition push down.
   471  type DataSource struct {
   472  	logicalSchemaProducer
   473  
   474  	astIndexHints   []*ast.IndexHint
   475  	IndexHints      []indexHintInfo
   476  	causet          causet.Block
   477  	blockInfo       *perceptron.BlockInfo
   478  	DeferredCausets []*perceptron.DeferredCausetInfo
   479  	DBName          perceptron.CIStr
   480  
   481  	BlockAsName *perceptron.CIStr
   482  	// indexMergeHints are the hint for indexmerge.
   483  	indexMergeHints []indexHintInfo
   484  	// pushedDownConds are the conditions that will be pushed down to interlock.
   485  	pushedDownConds []memex.Expression
   486  	// allConds contains all the filters on this causet. For now it's maintained
   487  	// in predicate push down and used only in partition pruning.
   488  	allConds []memex.Expression
   489  
   490  	statisticBlock *statistics.Block
   491  	blockStats     *property.StatsInfo
   492  
   493  	// possibleAccessPaths stores all the possible access path for physical plan, including causet scan.
   494  	possibleAccessPaths []*soliton.AccessPath
   495  
   496  	// The data source may be a partition, rather than a real causet.
   497  	isPartition     bool
   498  	physicalBlockID int64
   499  	partitionNames  []perceptron.CIStr
   500  
   501  	// handleDefCaus represents the handle column for the datasource, either the
   502  	// int primary key column or extra handle column.
   503  	//handleDefCaus *memex.DeferredCauset
   504  	handleDefCauss HandleDefCauss
   505  	// TblDefCauss contains the original columns of causet before being pruned, and it
   506  	// is used for estimating causet scan cost.
   507  	TblDefCauss []*memex.DeferredCauset
   508  	// commonHandleDefCauss and commonHandleLens save the info of primary key which is the clustered index.
   509  	commonHandleDefCauss []*memex.DeferredCauset
   510  	commonHandleLens     []int
   511  	// TblDefCausHists contains the Histogram of all original causet columns,
   512  	// it is converted from statisticBlock, and used for IO/network cost estimating.
   513  	TblDefCausHists *statistics.HistDefCausl
   514  	// preferStoreType means the DataSource is enforced to which storage.
   515  	preferStoreType int
   516  	// preferPartitions causetstore the map, the key represents causetstore type, the value represents the partition name list.
   517  	preferPartitions map[int][]perceptron.CIStr
   518  }
   519  
   520  // ExtractCorrelatedDefCauss implements LogicalCauset interface.
   521  func (ds *DataSource) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset {
   522  	corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(ds.pushedDownConds))
   523  	for _, expr := range ds.pushedDownConds {
   524  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...)
   525  	}
   526  	return corDefCauss
   527  }
   528  
   529  // EinsteinDBSingleGather is a leaf logical operator of MilevaDB layer to gather
   530  // tuples from EinsteinDB regions.
   531  type EinsteinDBSingleGather struct {
   532  	logicalSchemaProducer
   533  	Source *DataSource
   534  	// IsIndexGather marks if this EinsteinDBSingleGather gathers tuples from an IndexScan.
   535  	// in implementation phase, we need this flag to determine whether to generate
   536  	// PhysicalBlockReader or PhysicalIndexReader.
   537  	IsIndexGather bool
   538  	Index         *perceptron.IndexInfo
   539  }
   540  
   541  // LogicalBlockScan is the logical causet scan operator for EinsteinDB.
   542  type LogicalBlockScan struct {
   543  	logicalSchemaProducer
   544  	Source         *DataSource
   545  	HandleDefCauss HandleDefCauss
   546  	AccessConds    memex.CNFExprs
   547  	Ranges         []*ranger.Range
   548  }
   549  
   550  // LogicalIndexScan is the logical index scan operator for EinsteinDB.
   551  type LogicalIndexScan struct {
   552  	logicalSchemaProducer
   553  	// DataSource should be read-only here.
   554  	Source       *DataSource
   555  	IsDoubleRead bool
   556  
   557  	EqCondCount int
   558  	AccessConds memex.CNFExprs
   559  	Ranges      []*ranger.Range
   560  
   561  	Index              *perceptron.IndexInfo
   562  	DeferredCausets    []*perceptron.DeferredCausetInfo
   563  	FullIdxDefCauss    []*memex.DeferredCauset
   564  	FullIdxDefCausLens []int
   565  	IdxDefCauss        []*memex.DeferredCauset
   566  	IdxDefCausLens     []int
   567  }
   568  
   569  // MatchIndexProp checks if the indexScan can match the required property.
   570  func (p *LogicalIndexScan) MatchIndexProp(prop *property.PhysicalProperty) (match bool) {
   571  	if prop.IsEmpty() {
   572  		return true
   573  	}
   574  	if all, _ := prop.AllSameOrder(); !all {
   575  		return false
   576  	}
   577  	for i, col := range p.IdxDefCauss {
   578  		if col.Equal(nil, prop.Items[0].DefCaus) {
   579  			return matchIndicesProp(p.IdxDefCauss[i:], p.IdxDefCausLens[i:], prop.Items)
   580  		} else if i >= p.EqCondCount {
   581  			break
   582  		}
   583  	}
   584  	return false
   585  }
   586  
   587  // getBlockPath finds the BlockPath from a group of accessPaths.
   588  func getBlockPath(paths []*soliton.AccessPath) *soliton.AccessPath {
   589  	for _, path := range paths {
   590  		if path.IsBlockPath() {
   591  			return path
   592  		}
   593  	}
   594  	return nil
   595  }
   596  
   597  func (ds *DataSource) buildBlockGather() LogicalCauset {
   598  	ts := LogicalBlockScan{Source: ds, HandleDefCauss: ds.handleDefCauss}.Init(ds.ctx, ds.blockOffset)
   599  	ts.SetSchema(ds.Schema())
   600  	sg := EinsteinDBSingleGather{Source: ds, IsIndexGather: false}.Init(ds.ctx, ds.blockOffset)
   601  	sg.SetSchema(ds.Schema())
   602  	sg.SetChildren(ts)
   603  	return sg
   604  }
   605  
   606  func (ds *DataSource) buildIndexGather(path *soliton.AccessPath) LogicalCauset {
   607  	is := LogicalIndexScan{
   608  		Source:             ds,
   609  		IsDoubleRead:       false,
   610  		Index:              path.Index,
   611  		FullIdxDefCauss:    path.FullIdxDefCauss,
   612  		FullIdxDefCausLens: path.FullIdxDefCausLens,
   613  		IdxDefCauss:        path.IdxDefCauss,
   614  		IdxDefCausLens:     path.IdxDefCausLens,
   615  	}.Init(ds.ctx, ds.blockOffset)
   616  
   617  	is.DeferredCausets = make([]*perceptron.DeferredCausetInfo, len(ds.DeferredCausets))
   618  	copy(is.DeferredCausets, ds.DeferredCausets)
   619  	is.SetSchema(ds.Schema())
   620  	is.IdxDefCauss, is.IdxDefCausLens = memex.IndexInfo2PrefixDefCauss(is.DeferredCausets, is.schemaReplicant.DeferredCausets, is.Index)
   621  
   622  	sg := EinsteinDBSingleGather{
   623  		Source:        ds,
   624  		IsIndexGather: true,
   625  		Index:         path.Index,
   626  	}.Init(ds.ctx, ds.blockOffset)
   627  	sg.SetSchema(ds.Schema())
   628  	sg.SetChildren(is)
   629  	return sg
   630  }
   631  
   632  // Convert2Gathers builds logical EinsteinDBSingleGathers from DataSource.
   633  func (ds *DataSource) Convert2Gathers() (gathers []LogicalCauset) {
   634  	tg := ds.buildBlockGather()
   635  	gathers = append(gathers, tg)
   636  	for _, path := range ds.possibleAccessPaths {
   637  		if !path.IsIntHandlePath {
   638  			path.FullIdxDefCauss, path.FullIdxDefCausLens = memex.IndexInfo2DefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index)
   639  			path.IdxDefCauss, path.IdxDefCausLens = memex.IndexInfo2PrefixDefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index)
   640  			// If index columns can cover all of the needed columns, we can use a IndexGather + IndexScan.
   641  			if ds.isCoveringIndex(ds.schemaReplicant.DeferredCausets, path.FullIdxDefCauss, path.FullIdxDefCausLens, ds.blockInfo) {
   642  				gathers = append(gathers, ds.buildIndexGather(path))
   643  			}
   644  			// TODO: If index columns can not cover the schemaReplicant, use IndexLookUpGather.
   645  		}
   646  	}
   647  	return gathers
   648  }
   649  
   650  func (ds *DataSource) deriveCommonHandleBlockPathStats(path *soliton.AccessPath, conds []memex.Expression, isIm bool) (bool, error) {
   651  	path.CountAfterAccess = float64(ds.statisticBlock.Count)
   652  	path.Ranges = ranger.FullNotNullRange()
   653  	path.IdxDefCauss, path.IdxDefCausLens = memex.IndexInfo2PrefixDefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index)
   654  	path.FullIdxDefCauss, path.FullIdxDefCausLens = memex.IndexInfo2DefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index)
   655  	if len(conds) == 0 {
   656  		return false, nil
   657  	}
   658  	sc := ds.ctx.GetStochastikVars().StmtCtx
   659  	if len(path.IdxDefCauss) != 0 {
   660  		res, err := ranger.DetachCondAndBuildRangeForIndex(ds.ctx, conds, path.IdxDefCauss, path.IdxDefCausLens)
   661  		if err != nil {
   662  			return false, err
   663  		}
   664  		path.Ranges = res.Ranges
   665  		path.AccessConds = res.AccessConds
   666  		path.BlockFilters = res.RemainedConds
   667  		path.EqCondCount = res.EqCondCount
   668  		path.EqOrInCondCount = res.EqOrInCount
   669  		path.IsDNFCond = res.IsDNFCond
   670  		path.CountAfterAccess, err = ds.blockStats.HistDefCausl.GetRowCountByIndexRanges(sc, path.Index.ID, path.Ranges)
   671  		if err != nil {
   672  			return false, err
   673  		}
   674  	} else {
   675  		path.BlockFilters = conds
   676  	}
   677  	if path.EqOrInCondCount == len(path.AccessConds) {
   678  		accesses, remained := path.SplitCorDefCausAccessCondFromFilters(ds.ctx, path.EqOrInCondCount)
   679  		path.AccessConds = append(path.AccessConds, accesses...)
   680  		path.BlockFilters = remained
   681  		if len(accesses) > 0 && ds.statisticBlock.Pseudo {
   682  			path.CountAfterAccess = ds.statisticBlock.PseudoAvgCountPerValue()
   683  		} else {
   684  			selectivity := path.CountAfterAccess / float64(ds.statisticBlock.Count)
   685  			for i := range accesses {
   686  				col := path.IdxDefCauss[path.EqOrInCondCount+i]
   687  				ndv := ds.getDeferredCausetNDV(col.ID)
   688  				ndv *= selectivity
   689  				if ndv < 1 {
   690  					ndv = 1.0
   691  				}
   692  				path.CountAfterAccess = path.CountAfterAccess / ndv
   693  			}
   694  		}
   695  	}
   696  	// If the `CountAfterAccess` is less than `stats.RowCount`, there must be some inconsistent stats info.
   697  	// We prefer the `stats.RowCount` because it could use more stats info to calculate the selectivity.
   698  	if path.CountAfterAccess < ds.stats.RowCount && !isIm {
   699  		path.CountAfterAccess = math.Min(ds.stats.RowCount/SelectionFactor, float64(ds.statisticBlock.Count))
   700  	}
   701  	// Check whether there's only point query.
   702  	noIntervalRanges := true
   703  	haveNullVal := false
   704  	for _, ran := range path.Ranges {
   705  		// Not point or the not full matched.
   706  		if !ran.IsPoint(sc) || len(ran.HighVal) != len(path.Index.DeferredCausets) {
   707  			noIntervalRanges = false
   708  			break
   709  		}
   710  		// Check whether there's null value.
   711  		for i := 0; i < len(path.Index.DeferredCausets); i++ {
   712  			if ran.HighVal[i].IsNull() {
   713  				haveNullVal = true
   714  				break
   715  			}
   716  		}
   717  		if haveNullVal {
   718  			break
   719  		}
   720  	}
   721  	return noIntervalRanges && !haveNullVal, nil
   722  }
   723  
   724  // deriveBlockPathStats will fulfill the information that the AccessPath need.
   725  // And it will check whether the primary key is covered only by point query.
   726  // isIm indicates whether this function is called to generate the partial path for IndexMerge.
   727  func (ds *DataSource) deriveBlockPathStats(path *soliton.AccessPath, conds []memex.Expression, isIm bool) (bool, error) {
   728  	if path.IsCommonHandlePath {
   729  		return ds.deriveCommonHandleBlockPathStats(path, conds, isIm)
   730  	}
   731  	var err error
   732  	sc := ds.ctx.GetStochastikVars().StmtCtx
   733  	path.CountAfterAccess = float64(ds.statisticBlock.Count)
   734  	path.BlockFilters = conds
   735  	var pkDefCaus *memex.DeferredCauset
   736  	columnLen := len(ds.schemaReplicant.DeferredCausets)
   737  	isUnsigned := false
   738  	if ds.blockInfo.PKIsHandle {
   739  		if pkDefCausInfo := ds.blockInfo.GetPkDefCausInfo(); pkDefCausInfo != nil {
   740  			isUnsigned = allegrosql.HasUnsignedFlag(pkDefCausInfo.Flag)
   741  			pkDefCaus = memex.DefCausInfo2DefCaus(ds.schemaReplicant.DeferredCausets, pkDefCausInfo)
   742  		}
   743  	} else if columnLen > 0 && ds.schemaReplicant.DeferredCausets[columnLen-1].ID == perceptron.ExtraHandleID {
   744  		pkDefCaus = ds.schemaReplicant.DeferredCausets[columnLen-1]
   745  	}
   746  	if pkDefCaus == nil {
   747  		path.Ranges = ranger.FullIntRange(isUnsigned)
   748  		return false, nil
   749  	}
   750  
   751  	path.Ranges = ranger.FullIntRange(isUnsigned)
   752  	if len(conds) == 0 {
   753  		return false, nil
   754  	}
   755  	path.AccessConds, path.BlockFilters = ranger.DetachCondsForDeferredCauset(ds.ctx, conds, pkDefCaus)
   756  	// If there's no access cond, we try to find that whether there's memex containing correlated column that
   757  	// can be used to access data.
   758  	corDefCausInAccessConds := false
   759  	if len(path.AccessConds) == 0 {
   760  		for i, filter := range path.BlockFilters {
   761  			eqFunc, ok := filter.(*memex.ScalarFunction)
   762  			if !ok || eqFunc.FuncName.L != ast.EQ {
   763  				continue
   764  			}
   765  			lDefCaus, lOk := eqFunc.GetArgs()[0].(*memex.DeferredCauset)
   766  			if lOk && lDefCaus.Equal(ds.ctx, pkDefCaus) {
   767  				_, rOk := eqFunc.GetArgs()[1].(*memex.CorrelatedDeferredCauset)
   768  				if rOk {
   769  					path.AccessConds = append(path.AccessConds, filter)
   770  					path.BlockFilters = append(path.BlockFilters[:i], path.BlockFilters[i+1:]...)
   771  					corDefCausInAccessConds = true
   772  					break
   773  				}
   774  			}
   775  			rDefCaus, rOk := eqFunc.GetArgs()[1].(*memex.DeferredCauset)
   776  			if rOk && rDefCaus.Equal(ds.ctx, pkDefCaus) {
   777  				_, lOk := eqFunc.GetArgs()[0].(*memex.CorrelatedDeferredCauset)
   778  				if lOk {
   779  					path.AccessConds = append(path.AccessConds, filter)
   780  					path.BlockFilters = append(path.BlockFilters[:i], path.BlockFilters[i+1:]...)
   781  					corDefCausInAccessConds = true
   782  					break
   783  				}
   784  			}
   785  		}
   786  	}
   787  	if corDefCausInAccessConds {
   788  		path.CountAfterAccess = 1
   789  		return true, nil
   790  	}
   791  	path.Ranges, err = ranger.BuildBlockRange(path.AccessConds, sc, pkDefCaus.RetType)
   792  	if err != nil {
   793  		return false, err
   794  	}
   795  	path.CountAfterAccess, err = ds.statisticBlock.GetRowCountByIntDeferredCausetRanges(sc, pkDefCaus.ID, path.Ranges)
   796  	// If the `CountAfterAccess` is less than `stats.RowCount`, there must be some inconsistent stats info.
   797  	// We prefer the `stats.RowCount` because it could use more stats info to calculate the selectivity.
   798  	if path.CountAfterAccess < ds.stats.RowCount && !isIm {
   799  		path.CountAfterAccess = math.Min(ds.stats.RowCount/SelectionFactor, float64(ds.statisticBlock.Count))
   800  	}
   801  	// Check whether the primary key is covered by point query.
   802  	noIntervalRange := true
   803  	for _, ran := range path.Ranges {
   804  		if !ran.IsPoint(sc) {
   805  			noIntervalRange = false
   806  			break
   807  		}
   808  	}
   809  	return noIntervalRange, err
   810  }
   811  
   812  func (ds *DataSource) fillIndexPath(path *soliton.AccessPath, conds []memex.Expression) error {
   813  	sc := ds.ctx.GetStochastikVars().StmtCtx
   814  	path.Ranges = ranger.FullRange()
   815  	path.CountAfterAccess = float64(ds.statisticBlock.Count)
   816  	path.IdxDefCauss, path.IdxDefCausLens = memex.IndexInfo2PrefixDefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index)
   817  	path.FullIdxDefCauss, path.FullIdxDefCausLens = memex.IndexInfo2DefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index)
   818  	if !path.Index.Unique && !path.Index.Primary && len(path.Index.DeferredCausets) == len(path.IdxDefCauss) {
   819  		handleDefCaus := ds.getPKIsHandleDefCaus()
   820  		if handleDefCaus != nil && !allegrosql.HasUnsignedFlag(handleDefCaus.RetType.Flag) {
   821  			alreadyHandle := false
   822  			for _, col := range path.IdxDefCauss {
   823  				if col.ID == perceptron.ExtraHandleID || col.Equal(nil, handleDefCaus) {
   824  					alreadyHandle = true
   825  				}
   826  			}
   827  			// Don't add one column twice to the index. May cause unexpected errors.
   828  			if !alreadyHandle {
   829  				path.IdxDefCauss = append(path.IdxDefCauss, handleDefCaus)
   830  				path.IdxDefCausLens = append(path.IdxDefCausLens, types.UnspecifiedLength)
   831  			}
   832  		}
   833  	}
   834  	if len(path.IdxDefCauss) != 0 {
   835  		res, err := ranger.DetachCondAndBuildRangeForIndex(ds.ctx, conds, path.IdxDefCauss, path.IdxDefCausLens)
   836  		if err != nil {
   837  			return err
   838  		}
   839  		path.Ranges = res.Ranges
   840  		path.AccessConds = res.AccessConds
   841  		path.BlockFilters = res.RemainedConds
   842  		path.EqCondCount = res.EqCondCount
   843  		path.EqOrInCondCount = res.EqOrInCount
   844  		path.IsDNFCond = res.IsDNFCond
   845  		path.CountAfterAccess, err = ds.blockStats.HistDefCausl.GetRowCountByIndexRanges(sc, path.Index.ID, path.Ranges)
   846  		if err != nil {
   847  			return err
   848  		}
   849  	} else {
   850  		path.BlockFilters = conds
   851  	}
   852  	return nil
   853  }
   854  
   855  // deriveIndexPathStats will fulfill the information that the AccessPath need.
   856  // And it will check whether this index is full matched by point query. We will use this check to
   857  // determine whether we remove other paths or not.
   858  // conds is the conditions used to generate the DetachRangeResult for path.
   859  // isIm indicates whether this function is called to generate the partial path for IndexMerge.
   860  func (ds *DataSource) deriveIndexPathStats(path *soliton.AccessPath, conds []memex.Expression, isIm bool) bool {
   861  	sc := ds.ctx.GetStochastikVars().StmtCtx
   862  	if path.EqOrInCondCount == len(path.AccessConds) {
   863  		accesses, remained := path.SplitCorDefCausAccessCondFromFilters(ds.ctx, path.EqOrInCondCount)
   864  		path.AccessConds = append(path.AccessConds, accesses...)
   865  		path.BlockFilters = remained
   866  		if len(accesses) > 0 && ds.statisticBlock.Pseudo {
   867  			path.CountAfterAccess = ds.statisticBlock.PseudoAvgCountPerValue()
   868  		} else {
   869  			selectivity := path.CountAfterAccess / float64(ds.statisticBlock.Count)
   870  			for i := range accesses {
   871  				col := path.IdxDefCauss[path.EqOrInCondCount+i]
   872  				ndv := ds.getDeferredCausetNDV(col.ID)
   873  				ndv *= selectivity
   874  				if ndv < 1 {
   875  					ndv = 1.0
   876  				}
   877  				path.CountAfterAccess = path.CountAfterAccess / ndv
   878  			}
   879  		}
   880  	}
   881  	var indexFilters []memex.Expression
   882  	indexFilters, path.BlockFilters = ds.splitIndexFilterConditions(path.BlockFilters, path.FullIdxDefCauss, path.FullIdxDefCausLens, ds.blockInfo)
   883  	path.IndexFilters = append(path.IndexFilters, indexFilters...)
   884  	// If the `CountAfterAccess` is less than `stats.RowCount`, there must be some inconsistent stats info.
   885  	// We prefer the `stats.RowCount` because it could use more stats info to calculate the selectivity.
   886  	if path.CountAfterAccess < ds.stats.RowCount && !isIm {
   887  		path.CountAfterAccess = math.Min(ds.stats.RowCount/SelectionFactor, float64(ds.statisticBlock.Count))
   888  	}
   889  	if path.IndexFilters != nil {
   890  		selectivity, _, err := ds.blockStats.HistDefCausl.Selectivity(ds.ctx, path.IndexFilters, nil)
   891  		if err != nil {
   892  			logutil.BgLogger().Debug("calculate selectivity failed, use selection factor", zap.Error(err))
   893  			selectivity = SelectionFactor
   894  		}
   895  		if isIm {
   896  			path.CountAfterIndex = path.CountAfterAccess * selectivity
   897  		} else {
   898  			path.CountAfterIndex = math.Max(path.CountAfterAccess*selectivity, ds.stats.RowCount)
   899  		}
   900  	}
   901  	// Check whether there's only point query.
   902  	noIntervalRanges := true
   903  	haveNullVal := false
   904  	for _, ran := range path.Ranges {
   905  		// Not point or the not full matched.
   906  		if !ran.IsPoint(sc) || len(ran.HighVal) != len(path.Index.DeferredCausets) {
   907  			noIntervalRanges = false
   908  			break
   909  		}
   910  		// Check whether there's null value.
   911  		for i := 0; i < len(path.Index.DeferredCausets); i++ {
   912  			if ran.HighVal[i].IsNull() {
   913  				haveNullVal = true
   914  				break
   915  			}
   916  		}
   917  		if haveNullVal {
   918  			break
   919  		}
   920  	}
   921  	return noIntervalRanges && !haveNullVal
   922  }
   923  
   924  func getPKIsHandleDefCausFromSchema(defcaus []*perceptron.DeferredCausetInfo, schemaReplicant *memex.Schema, pkIsHandle bool) *memex.DeferredCauset {
   925  	if !pkIsHandle {
   926  		// If the PKIsHandle is false, return the ExtraHandleDeferredCauset.
   927  		for i, col := range defcaus {
   928  			if col.ID == perceptron.ExtraHandleID {
   929  				return schemaReplicant.DeferredCausets[i]
   930  			}
   931  		}
   932  		return nil
   933  	}
   934  	for i, col := range defcaus {
   935  		if allegrosql.HasPriKeyFlag(col.Flag) {
   936  			return schemaReplicant.DeferredCausets[i]
   937  		}
   938  	}
   939  	return nil
   940  }
   941  
   942  func (ds *DataSource) getPKIsHandleDefCaus() *memex.DeferredCauset {
   943  	return getPKIsHandleDefCausFromSchema(ds.DeferredCausets, ds.schemaReplicant, ds.blockInfo.PKIsHandle)
   944  }
   945  
   946  func (p *LogicalIndexScan) getPKIsHandleDefCaus(schemaReplicant *memex.Schema) *memex.DeferredCauset {
   947  	// We cannot use p.Source.getPKIsHandleDefCaus() here,
   948  	// Because we may re-prune p.DeferredCausets and p.schemaReplicant during the transformation.
   949  	// That will make p.DeferredCausets different from p.Source.DeferredCausets.
   950  	return getPKIsHandleDefCausFromSchema(p.DeferredCausets, schemaReplicant, p.Source.blockInfo.PKIsHandle)
   951  }
   952  
   953  // BlockInfo returns the *BlockInfo of data source.
   954  func (ds *DataSource) BlockInfo() *perceptron.BlockInfo {
   955  	return ds.blockInfo
   956  }
   957  
   958  // LogicalUnionAll represents LogicalUnionAll plan.
   959  type LogicalUnionAll struct {
   960  	logicalSchemaProducer
   961  }
   962  
   963  // LogicalPartitionUnionAll represents the LogicalUnionAll plan is for partition causet.
   964  type LogicalPartitionUnionAll struct {
   965  	LogicalUnionAll
   966  }
   967  
   968  // LogicalSort stands for the order by plan.
   969  type LogicalSort struct {
   970  	baseLogicalCauset
   971  
   972  	ByItems []*soliton.ByItems
   973  }
   974  
   975  // ExtractCorrelatedDefCauss implements LogicalCauset interface.
   976  func (ls *LogicalSort) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset {
   977  	corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(ls.ByItems))
   978  	for _, item := range ls.ByItems {
   979  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(item.Expr)...)
   980  	}
   981  	return corDefCauss
   982  }
   983  
   984  // LogicalTopN represents a top-n plan.
   985  type LogicalTopN struct {
   986  	baseLogicalCauset
   987  
   988  	ByItems    []*soliton.ByItems
   989  	Offset     uint64
   990  	Count      uint64
   991  	limitHints limitHintInfo
   992  }
   993  
   994  // ExtractCorrelatedDefCauss implements LogicalCauset interface.
   995  func (lt *LogicalTopN) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset {
   996  	corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(lt.ByItems))
   997  	for _, item := range lt.ByItems {
   998  		corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(item.Expr)...)
   999  	}
  1000  	return corDefCauss
  1001  }
  1002  
  1003  // isLimit checks if TopN is a limit plan.
  1004  func (lt *LogicalTopN) isLimit() bool {
  1005  	return len(lt.ByItems) == 0
  1006  }
  1007  
  1008  // LogicalLimit represents offset and limit plan.
  1009  type LogicalLimit struct {
  1010  	baseLogicalCauset
  1011  
  1012  	Offset     uint64
  1013  	Count      uint64
  1014  	limitHints limitHintInfo
  1015  }
  1016  
  1017  // LogicalLock represents a select dagger plan.
  1018  type LogicalLock struct {
  1019  	baseLogicalCauset
  1020  
  1021  	Lock             *ast.SelectLockInfo
  1022  	tblID2Handle     map[int64][]HandleDefCauss
  1023  	partitionedBlock []causet.PartitionedBlock
  1024  }
  1025  
  1026  // WindowFrame represents a window function frame.
  1027  type WindowFrame struct {
  1028  	Type  ast.FrameType
  1029  	Start *FrameBound
  1030  	End   *FrameBound
  1031  }
  1032  
  1033  // FrameBound is the boundary of a frame.
  1034  type FrameBound struct {
  1035  	Type      ast.BoundType
  1036  	UnBounded bool
  1037  	Num       uint64
  1038  	// CalcFuncs is used for range framed windows.
  1039  	// We will build the date_add or date_sub functions for frames like `INTERVAL '2:30' MINUTE_SECOND FOLLOWING`,
  1040  	// and plus or minus for frames like `1 preceding`.
  1041  	CalcFuncs []memex.Expression
  1042  	// CmpFuncs is used to decide whether one event is included in the current frame.
  1043  	CmpFuncs []memex.CompareFunc
  1044  }
  1045  
  1046  // LogicalWindow represents a logical window function plan.
  1047  type LogicalWindow struct {
  1048  	logicalSchemaProducer
  1049  
  1050  	WindowFuncDescs []*aggregation.WindowFuncDesc
  1051  	PartitionBy     []property.Item
  1052  	OrderBy         []property.Item
  1053  	Frame           *WindowFrame
  1054  }
  1055  
  1056  // ExtractCorrelatedDefCauss implements LogicalCauset interface.
  1057  func (p *LogicalWindow) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset {
  1058  	corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(p.WindowFuncDescs))
  1059  	for _, windowFunc := range p.WindowFuncDescs {
  1060  		for _, arg := range windowFunc.Args {
  1061  			corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(arg)...)
  1062  		}
  1063  	}
  1064  	if p.Frame != nil {
  1065  		if p.Frame.Start != nil {
  1066  			for _, expr := range p.Frame.Start.CalcFuncs {
  1067  				corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...)
  1068  			}
  1069  		}
  1070  		if p.Frame.End != nil {
  1071  			for _, expr := range p.Frame.End.CalcFuncs {
  1072  				corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...)
  1073  			}
  1074  		}
  1075  	}
  1076  	return corDefCauss
  1077  }
  1078  
  1079  // GetWindowResultDeferredCausets returns the columns storing the result of the window function.
  1080  func (p *LogicalWindow) GetWindowResultDeferredCausets() []*memex.DeferredCauset {
  1081  	return p.schemaReplicant.DeferredCausets[p.schemaReplicant.Len()-len(p.WindowFuncDescs):]
  1082  }
  1083  
  1084  // ExtractCorDeferredCausetsBySchema only extracts the correlated columns that match the specified schemaReplicant.
  1085  // e.g. If the correlated columns from plan are [t1.a, t2.a, t3.a] and specified schemaReplicant is [t2.a, t2.b, t2.c],
  1086  // only [t2.a] is returned.
  1087  func ExtractCorDeferredCausetsBySchema(corDefCauss []*memex.CorrelatedDeferredCauset, schemaReplicant *memex.Schema, resolveIndex bool) []*memex.CorrelatedDeferredCauset {
  1088  	resultCorDefCauss := make([]*memex.CorrelatedDeferredCauset, schemaReplicant.Len())
  1089  	for _, corDefCaus := range corDefCauss {
  1090  		idx := schemaReplicant.DeferredCausetIndex(&corDefCaus.DeferredCauset)
  1091  		if idx != -1 {
  1092  			if resultCorDefCauss[idx] == nil {
  1093  				resultCorDefCauss[idx] = &memex.CorrelatedDeferredCauset{
  1094  					DeferredCauset: *schemaReplicant.DeferredCausets[idx],
  1095  					Data:           new(types.Causet),
  1096  				}
  1097  			}
  1098  			corDefCaus.Data = resultCorDefCauss[idx].Data
  1099  		}
  1100  	}
  1101  	// Shrink slice. e.g. [col1, nil, col2, nil] will be changed to [col1, col2].
  1102  	length := 0
  1103  	for _, col := range resultCorDefCauss {
  1104  		if col != nil {
  1105  			resultCorDefCauss[length] = col
  1106  			length++
  1107  		}
  1108  	}
  1109  	resultCorDefCauss = resultCorDefCauss[:length]
  1110  
  1111  	if resolveIndex {
  1112  		for _, corDefCaus := range resultCorDefCauss {
  1113  			corDefCaus.Index = schemaReplicant.DeferredCausetIndex(&corDefCaus.DeferredCauset)
  1114  		}
  1115  	}
  1116  
  1117  	return resultCorDefCauss
  1118  }
  1119  
  1120  // extractCorDeferredCausetsBySchema4LogicalCauset only extracts the correlated columns that match the specified schemaReplicant.
  1121  // e.g. If the correlated columns from plan are [t1.a, t2.a, t3.a] and specified schemaReplicant is [t2.a, t2.b, t2.c],
  1122  // only [t2.a] is returned.
  1123  func extractCorDeferredCausetsBySchema4LogicalCauset(p LogicalCauset, schemaReplicant *memex.Schema) []*memex.CorrelatedDeferredCauset {
  1124  	corDefCauss := ExtractCorrelatedDefCauss4LogicalCauset(p)
  1125  	return ExtractCorDeferredCausetsBySchema(corDefCauss, schemaReplicant, false)
  1126  }
  1127  
  1128  // ExtractCorDeferredCausetsBySchema4PhysicalCauset only extracts the correlated columns that match the specified schemaReplicant.
  1129  // e.g. If the correlated columns from plan are [t1.a, t2.a, t3.a] and specified schemaReplicant is [t2.a, t2.b, t2.c],
  1130  // only [t2.a] is returned.
  1131  func ExtractCorDeferredCausetsBySchema4PhysicalCauset(p PhysicalCauset, schemaReplicant *memex.Schema) []*memex.CorrelatedDeferredCauset {
  1132  	corDefCauss := ExtractCorrelatedDefCauss4PhysicalCauset(p)
  1133  	return ExtractCorDeferredCausetsBySchema(corDefCauss, schemaReplicant, true)
  1134  }
  1135  
  1136  // ShowContents stores the contents for the `SHOW` memex.
  1137  type ShowContents struct {
  1138  	Tp             ast.ShowStmtType // Databases/Blocks/DeferredCausets/....
  1139  	DBName         string
  1140  	Block          *ast.BlockName          // Used for showing columns.
  1141  	DeferredCauset *ast.DeferredCausetName // Used for `desc causet column`.
  1142  	IndexName      perceptron.CIStr
  1143  	Flag           int                  // Some flag parsed from allegrosql, such as FULL.
  1144  	User           *auth.UserIdentity   // Used for show grants.
  1145  	Roles          []*auth.RoleIdentity // Used for show grants.
  1146  
  1147  	Full        bool
  1148  	IfNotExists bool // Used for `show create database if not exists`.
  1149  	GlobalScope bool // Used by show variables.
  1150  	Extended    bool // Used for `show extended columns from ...`
  1151  }
  1152  
  1153  // LogicalShow represents a show plan.
  1154  type LogicalShow struct {
  1155  	logicalSchemaProducer
  1156  	ShowContents
  1157  }
  1158  
  1159  // LogicalShowDBSJobs is for showing DBS job list.
  1160  type LogicalShowDBSJobs struct {
  1161  	logicalSchemaProducer
  1162  
  1163  	JobNumber int64
  1164  }