github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/embedded/implementation_rules.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 cascades
    15  
    16  import (
    17  	"math"
    18  
    19  	causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded"
    20  	impl "github.com/whtcorpsinc/milevadb/causet/implementation"
    21  	"github.com/whtcorpsinc/milevadb/causet/memo"
    22  	"github.com/whtcorpsinc/milevadb/causet/property"
    23  	"github.com/whtcorpsinc/milevadb/memex"
    24  )
    25  
    26  // ImplementationMemrule defines the interface for implementation rules.
    27  type ImplementationMemrule interface {
    28  	// Match checks if current GroupExpr matches this rule under required physical property.
    29  	Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool)
    30  	// OnImplement generates physical plan using this rule for current GroupExpr. Note that
    31  	// childrenReqProps of generated physical plan should be set correspondingly in this function.
    32  	OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error)
    33  }
    34  
    35  var defaultImplementationMap = map[memo.Operand][]ImplementationMemrule{
    36  	memo.OperandBlockDual: {
    37  		&ImplBlockDual{},
    38  	},
    39  	memo.OperandMemBlockScan: {
    40  		&ImplMemBlockScan{},
    41  	},
    42  	memo.OperandProjection: {
    43  		&ImplProjection{},
    44  	},
    45  	memo.OperandBlockScan: {
    46  		&ImplBlockScan{},
    47  	},
    48  	memo.OperandIndexScan: {
    49  		&ImplIndexScan{},
    50  	},
    51  	memo.OperandEinsteinDBSingleGather: {
    52  		&ImplEinsteinDBSingleReadGather{},
    53  	},
    54  	memo.OperandShow: {
    55  		&ImplShow{},
    56  	},
    57  	memo.OperandSelection: {
    58  		&ImplSelection{},
    59  	},
    60  	memo.OperandSort: {
    61  		&ImplSort{},
    62  	},
    63  	memo.OperanPosetDaggregation: {
    64  		&ImplHashAgg{},
    65  	},
    66  	memo.OperandLimit: {
    67  		&ImplLimit{},
    68  	},
    69  	memo.OperandTopN: {
    70  		&ImplTopN{},
    71  		&ImplTopNAsLimit{},
    72  	},
    73  	memo.OperandJoin: {
    74  		&ImplHashJoinBuildLeft{},
    75  		&ImplHashJoinBuildRight{},
    76  		&ImplMergeJoin{},
    77  	},
    78  	memo.OperandUnionAll: {
    79  		&ImplUnionAll{},
    80  	},
    81  	memo.OperandApply: {
    82  		&ImplApply{},
    83  	},
    84  	memo.OperandMaxOneRow: {
    85  		&ImplMaxOneRow{},
    86  	},
    87  	memo.OperandWindow: {
    88  		&ImplWindow{},
    89  	},
    90  }
    91  
    92  // ImplBlockDual implements LogicalBlockDual as PhysicalBlockDual.
    93  type ImplBlockDual struct {
    94  }
    95  
    96  // Match implements ImplementationMemrule Match interface.
    97  func (r *ImplBlockDual) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
    98  	if !prop.IsEmpty() {
    99  		return false
   100  	}
   101  	return true
   102  }
   103  
   104  // OnImplement implements ImplementationMemrule OnImplement interface.
   105  func (r *ImplBlockDual) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   106  	logicProp := expr.Group.Prop
   107  	logicDual := expr.ExprNode.(*causetembedded.LogicalBlockDual)
   108  	dual := causetembedded.PhysicalBlockDual{RowCount: logicDual.RowCount}.Init(logicDual.SCtx(), logicProp.Stats, logicDual.SelectBlockOffset())
   109  	dual.SetSchema(logicProp.Schema)
   110  	return []memo.Implementation{impl.NewBlockDualImpl(dual)}, nil
   111  }
   112  
   113  // ImplMemBlockScan implements LogicalMemBlock as PhysicalMemBlock.
   114  type ImplMemBlockScan struct {
   115  }
   116  
   117  // Match implements ImplementationMemrule Match interface.
   118  func (r *ImplMemBlockScan) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   119  	if !prop.IsEmpty() {
   120  		return false
   121  	}
   122  	return true
   123  }
   124  
   125  // OnImplement implements ImplementationMemrule OnImplement interface.
   126  func (r *ImplMemBlockScan) OnImplement(
   127  	expr *memo.GroupExpr,
   128  	reqProp *property.PhysicalProperty,
   129  ) ([]memo.Implementation, error) {
   130  	logic := expr.ExprNode.(*causetembedded.LogicalMemBlock)
   131  	logicProp := expr.Group.Prop
   132  	physical := causetembedded.PhysicalMemBlock{
   133  		DBName:          logic.DBName,
   134  		Block:           logic.BlockInfo,
   135  		DeferredCausets: logic.BlockInfo.DeferredCausets,
   136  		Extractor:       logic.Extractor,
   137  	}.Init(logic.SCtx(), logicProp.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt), logic.SelectBlockOffset())
   138  	physical.SetSchema(logicProp.Schema)
   139  	return []memo.Implementation{impl.NewMemBlockScanImpl(physical)}, nil
   140  }
   141  
   142  // ImplProjection implements LogicalProjection as PhysicalProjection.
   143  type ImplProjection struct {
   144  }
   145  
   146  // Match implements ImplementationMemrule Match interface.
   147  func (r *ImplProjection) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   148  	return true
   149  }
   150  
   151  // OnImplement implements ImplementationMemrule OnImplement interface.
   152  func (r *ImplProjection) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   153  	logicProp := expr.Group.Prop
   154  	logicProj := expr.ExprNode.(*causetembedded.LogicalProjection)
   155  	childProp, ok := logicProj.TryToGetChildProp(reqProp)
   156  	if !ok {
   157  		return nil, nil
   158  	}
   159  	proj := causetembedded.PhysicalProjection{
   160  		Exprs:                        logicProj.Exprs,
   161  		CalculateNoDelay:             logicProj.CalculateNoDelay,
   162  		AvoidDeferredCausetEvaluator: logicProj.AvoidDeferredCausetEvaluator,
   163  	}.Init(logicProj.SCtx(), logicProp.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt), logicProj.SelectBlockOffset(), childProp)
   164  	proj.SetSchema(logicProp.Schema)
   165  	return []memo.Implementation{impl.NewProjectionImpl(proj)}, nil
   166  }
   167  
   168  // ImplEinsteinDBSingleReadGather implements EinsteinDBSingleGather
   169  // as PhysicalBlockReader or PhysicalIndexReader.
   170  type ImplEinsteinDBSingleReadGather struct {
   171  }
   172  
   173  // Match implements ImplementationMemrule Match interface.
   174  func (r *ImplEinsteinDBSingleReadGather) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   175  	return true
   176  }
   177  
   178  // OnImplement implements ImplementationMemrule OnImplement interface.
   179  func (r *ImplEinsteinDBSingleReadGather) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   180  	logicProp := expr.Group.Prop
   181  	sg := expr.ExprNode.(*causetembedded.EinsteinDBSingleGather)
   182  	if sg.IsIndexGather {
   183  		reader := sg.GetPhysicalIndexReader(logicProp.Schema, logicProp.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt), reqProp)
   184  		return []memo.Implementation{impl.NewIndexReaderImpl(reader, sg.Source.TblDefCausHists)}, nil
   185  	}
   186  	reader := sg.GetPhysicalBlockReader(logicProp.Schema, logicProp.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt), reqProp)
   187  	return []memo.Implementation{impl.NewBlockReaderImpl(reader, sg.Source.TblDefCausHists)}, nil
   188  }
   189  
   190  // ImplBlockScan implements BlockScan as PhysicalBlockScan.
   191  type ImplBlockScan struct {
   192  }
   193  
   194  // Match implements ImplementationMemrule Match interface.
   195  func (r *ImplBlockScan) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   196  	ts := expr.ExprNode.(*causetembedded.LogicalBlockScan)
   197  	return prop.IsEmpty() || (len(prop.Items) == 1 && ts.HandleDefCauss != nil && prop.Items[0].DefCaus.Equal(nil, ts.HandleDefCauss.GetDefCaus(0)))
   198  }
   199  
   200  // OnImplement implements ImplementationMemrule OnImplement interface.
   201  func (r *ImplBlockScan) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   202  	logicProp := expr.Group.Prop
   203  	logicalScan := expr.ExprNode.(*causetembedded.LogicalBlockScan)
   204  	ts := logicalScan.GetPhysicalScan(logicProp.Schema, logicProp.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt))
   205  	if !reqProp.IsEmpty() {
   206  		ts.KeepOrder = true
   207  		ts.Desc = reqProp.Items[0].Desc
   208  	}
   209  	tblDefCauss, tblDefCausHists := logicalScan.Source.TblDefCauss, logicalScan.Source.TblDefCausHists
   210  	return []memo.Implementation{impl.NewBlockScanImpl(ts, tblDefCauss, tblDefCausHists)}, nil
   211  }
   212  
   213  // ImplIndexScan implements IndexScan as PhysicalIndexScan.
   214  type ImplIndexScan struct {
   215  }
   216  
   217  // Match implements ImplementationMemrule Match interface.
   218  func (r *ImplIndexScan) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   219  	is := expr.ExprNode.(*causetembedded.LogicalIndexScan)
   220  	return is.MatchIndexProp(prop)
   221  }
   222  
   223  // OnImplement implements ImplementationMemrule OnImplement interface.
   224  func (r *ImplIndexScan) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   225  	logicalScan := expr.ExprNode.(*causetembedded.LogicalIndexScan)
   226  	is := logicalScan.GetPhysicalIndexScan(expr.Group.Prop.Schema, expr.Group.Prop.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt))
   227  	if !reqProp.IsEmpty() {
   228  		is.KeepOrder = true
   229  		if reqProp.Items[0].Desc {
   230  			is.Desc = true
   231  		}
   232  	}
   233  	return []memo.Implementation{impl.NewIndexScanImpl(is, logicalScan.Source.TblDefCausHists)}, nil
   234  }
   235  
   236  // ImplShow is the implementation rule which implements LogicalShow to
   237  // PhysicalShow.
   238  type ImplShow struct {
   239  }
   240  
   241  // Match implements ImplementationMemrule Match interface.
   242  func (r *ImplShow) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   243  	return prop.IsEmpty()
   244  }
   245  
   246  // OnImplement implements ImplementationMemrule OnImplement interface.
   247  func (r *ImplShow) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   248  	logicProp := expr.Group.Prop
   249  	show := expr.ExprNode.(*causetembedded.LogicalShow)
   250  
   251  	// TODO(zz-jason): unifying LogicalShow and PhysicalShow to a single
   252  	// struct. So that we don't need to create a new PhysicalShow object, which
   253  	// can help us to reduce the gc pressure of golang runtime and improve the
   254  	// overall performance.
   255  	showPhys := causetembedded.PhysicalShow{ShowContents: show.ShowContents}.Init(show.SCtx())
   256  	showPhys.SetSchema(logicProp.Schema)
   257  	return []memo.Implementation{impl.NewShowImpl(showPhys)}, nil
   258  }
   259  
   260  // ImplSelection is the implementation rule which implements LogicalSelection
   261  // to PhysicalSelection.
   262  type ImplSelection struct {
   263  }
   264  
   265  // Match implements ImplementationMemrule Match interface.
   266  func (r *ImplSelection) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   267  	return true
   268  }
   269  
   270  // OnImplement implements ImplementationMemrule OnImplement interface.
   271  func (r *ImplSelection) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   272  	logicalSel := expr.ExprNode.(*causetembedded.LogicalSelection)
   273  	physicalSel := causetembedded.PhysicalSelection{
   274  		Conditions: logicalSel.Conditions,
   275  	}.Init(logicalSel.SCtx(), expr.Group.Prop.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt), logicalSel.SelectBlockOffset(), reqProp.Clone())
   276  	switch expr.Group.EngineType {
   277  	case memo.EngineMilevaDB:
   278  		return []memo.Implementation{impl.NewMilevaDBSelectionImpl(physicalSel)}, nil
   279  	case memo.EngineEinsteinDB:
   280  		return []memo.Implementation{impl.NewEinsteinDBSelectionImpl(physicalSel)}, nil
   281  	default:
   282  		return nil, causetembedded.ErrInternal.GenWithStack("Unsupported EngineType '%s' for Selection.", expr.Group.EngineType.String())
   283  	}
   284  }
   285  
   286  // ImplSort is the implementation rule which implements LogicalSort
   287  // to PhysicalSort or NominalSort.
   288  type ImplSort struct {
   289  }
   290  
   291  // Match implements ImplementationMemrule match interface.
   292  func (r *ImplSort) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   293  	ls := expr.ExprNode.(*causetembedded.LogicalSort)
   294  	return causetembedded.MatchItems(prop, ls.ByItems)
   295  }
   296  
   297  // OnImplement implements ImplementationMemrule OnImplement interface.
   298  // If all of the sort items are defCausumns, generate a NominalSort, otherwise
   299  // generate a PhysicalSort.
   300  func (r *ImplSort) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   301  	ls := expr.ExprNode.(*causetembedded.LogicalSort)
   302  	if newProp, canUseNominal := causetembedded.GetPropByOrderByItems(ls.ByItems); canUseNominal {
   303  		newProp.ExpectedCnt = reqProp.ExpectedCnt
   304  		ns := causetembedded.NominalSort{}.Init(
   305  			ls.SCtx(), expr.Group.Prop.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt), ls.SelectBlockOffset(), newProp)
   306  		return []memo.Implementation{impl.NewNominalSortImpl(ns)}, nil
   307  	}
   308  	ps := causetembedded.PhysicalSort{ByItems: ls.ByItems}.Init(
   309  		ls.SCtx(),
   310  		expr.Group.Prop.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt),
   311  		ls.SelectBlockOffset(),
   312  		&property.PhysicalProperty{ExpectedCnt: math.MaxFloat64},
   313  	)
   314  	return []memo.Implementation{impl.NewSortImpl(ps)}, nil
   315  }
   316  
   317  // ImplHashAgg is the implementation rule which implements LogicalAggregation
   318  // to PhysicalHashAgg.
   319  type ImplHashAgg struct {
   320  }
   321  
   322  // Match implements ImplementationMemrule Match interface.
   323  func (r *ImplHashAgg) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   324  	// TODO: deal with the hints when we have implemented StreamAgg.
   325  	return prop.IsEmpty()
   326  }
   327  
   328  // OnImplement implements ImplementationMemrule OnImplement interface.
   329  func (r *ImplHashAgg) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   330  	la := expr.ExprNode.(*causetembedded.LogicalAggregation)
   331  	hashAgg := causetembedded.NewPhysicalHashAgg(
   332  		la,
   333  		expr.Group.Prop.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt),
   334  		&property.PhysicalProperty{ExpectedCnt: math.MaxFloat64},
   335  	)
   336  	hashAgg.SetSchema(expr.Group.Prop.Schema.Clone())
   337  	switch expr.Group.EngineType {
   338  	case memo.EngineMilevaDB:
   339  		return []memo.Implementation{impl.NewMilevaDBHashAggImpl(hashAgg)}, nil
   340  	case memo.EngineEinsteinDB:
   341  		return []memo.Implementation{impl.NewEinsteinDBHashAggImpl(hashAgg)}, nil
   342  	default:
   343  		return nil, causetembedded.ErrInternal.GenWithStack("Unsupported EngineType '%s' for HashAggregation.", expr.Group.EngineType.String())
   344  	}
   345  }
   346  
   347  // ImplLimit is the implementation rule which implements LogicalLimit
   348  // to PhysicalLimit.
   349  type ImplLimit struct {
   350  }
   351  
   352  // Match implements ImplementationMemrule Match interface.
   353  func (r *ImplLimit) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   354  	return prop.IsEmpty()
   355  }
   356  
   357  // OnImplement implements ImplementationMemrule OnImplement interface.
   358  func (r *ImplLimit) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   359  	logicalLimit := expr.ExprNode.(*causetembedded.LogicalLimit)
   360  	newProp := &property.PhysicalProperty{ExpectedCnt: float64(logicalLimit.Count + logicalLimit.Offset)}
   361  	physicalLimit := causetembedded.PhysicalLimit{
   362  		Offset: logicalLimit.Offset,
   363  		Count:  logicalLimit.Count,
   364  	}.Init(logicalLimit.SCtx(), expr.Group.Prop.Stats, logicalLimit.SelectBlockOffset(), newProp)
   365  	return []memo.Implementation{impl.NewLimitImpl(physicalLimit)}, nil
   366  }
   367  
   368  // ImplTopN is the implementation rule which implements LogicalTopN
   369  // to PhysicalTopN.
   370  type ImplTopN struct {
   371  }
   372  
   373  // Match implements ImplementationMemrule Match interface.
   374  func (r *ImplTopN) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   375  	topN := expr.ExprNode.(*causetembedded.LogicalTopN)
   376  	if expr.Group.EngineType != memo.EngineMilevaDB {
   377  		return prop.IsEmpty()
   378  	}
   379  	return causetembedded.MatchItems(prop, topN.ByItems)
   380  }
   381  
   382  // OnImplement implements ImplementationMemrule OnImplement interface.
   383  func (r *ImplTopN) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   384  	lt := expr.ExprNode.(*causetembedded.LogicalTopN)
   385  	resultProp := &property.PhysicalProperty{ExpectedCnt: math.MaxFloat64}
   386  	topN := causetembedded.PhysicalTopN{
   387  		ByItems: lt.ByItems,
   388  		Count:   lt.Count,
   389  		Offset:  lt.Offset,
   390  	}.Init(lt.SCtx(), expr.Group.Prop.Stats, lt.SelectBlockOffset(), resultProp)
   391  	switch expr.Group.EngineType {
   392  	case memo.EngineMilevaDB:
   393  		return []memo.Implementation{impl.NewMilevaDBTopNImpl(topN)}, nil
   394  	case memo.EngineEinsteinDB:
   395  		return []memo.Implementation{impl.NewEinsteinDBTopNImpl(topN)}, nil
   396  	default:
   397  		return nil, causetembedded.ErrInternal.GenWithStack("Unsupported EngineType '%s' for TopN.", expr.Group.EngineType.String())
   398  	}
   399  }
   400  
   401  // ImplTopNAsLimit is the implementation rule which implements LogicalTopN
   402  // as PhysicalLimit with required order property.
   403  type ImplTopNAsLimit struct {
   404  }
   405  
   406  // Match implements ImplementationMemrule Match interface.
   407  func (r *ImplTopNAsLimit) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   408  	topN := expr.ExprNode.(*causetembedded.LogicalTopN)
   409  	_, canUseLimit := causetembedded.GetPropByOrderByItems(topN.ByItems)
   410  	return canUseLimit && causetembedded.MatchItems(prop, topN.ByItems)
   411  }
   412  
   413  // OnImplement implements ImplementationMemrule OnImplement interface.
   414  func (r *ImplTopNAsLimit) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   415  	lt := expr.ExprNode.(*causetembedded.LogicalTopN)
   416  	newProp := &property.PhysicalProperty{ExpectedCnt: float64(lt.Count + lt.Offset)}
   417  	newProp.Items = make([]property.Item, len(lt.ByItems))
   418  	for i, item := range lt.ByItems {
   419  		newProp.Items[i].DefCaus = item.Expr.(*memex.DeferredCauset)
   420  		newProp.Items[i].Desc = item.Desc
   421  	}
   422  	physicalLimit := causetembedded.PhysicalLimit{
   423  		Offset: lt.Offset,
   424  		Count:  lt.Count,
   425  	}.Init(lt.SCtx(), expr.Group.Prop.Stats, lt.SelectBlockOffset(), newProp)
   426  	return []memo.Implementation{impl.NewLimitImpl(physicalLimit)}, nil
   427  }
   428  
   429  func getImplForHashJoin(expr *memo.GroupExpr, prop *property.PhysicalProperty, innerIdx int, useOuterToBuild bool) memo.Implementation {
   430  	join := expr.ExprNode.(*causetembedded.LogicalJoin)
   431  	chReqProps := make([]*property.PhysicalProperty, 2)
   432  	chReqProps[0] = &property.PhysicalProperty{ExpectedCnt: math.MaxFloat64}
   433  	chReqProps[1] = &property.PhysicalProperty{ExpectedCnt: math.MaxFloat64}
   434  	stats := expr.Group.Prop.Stats
   435  	if prop.ExpectedCnt < stats.RowCount {
   436  		expCntScale := prop.ExpectedCnt / stats.RowCount
   437  		chReqProps[1-innerIdx].ExpectedCnt = expr.Children[1-innerIdx].Prop.Stats.RowCount * expCntScale
   438  	}
   439  	hashJoin := causetembedded.NewPhysicalHashJoin(join, innerIdx, useOuterToBuild, stats.ScaleByExpectCnt(prop.ExpectedCnt), chReqProps...)
   440  	hashJoin.SetSchema(expr.Group.Prop.Schema)
   441  	return impl.NewHashJoinImpl(hashJoin)
   442  }
   443  
   444  // ImplHashJoinBuildLeft implements LogicalJoin to PhysicalHashJoin which uses the left child to build hash causet.
   445  type ImplHashJoinBuildLeft struct {
   446  }
   447  
   448  // Match implements ImplementationMemrule Match interface.
   449  func (r *ImplHashJoinBuildLeft) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   450  	switch expr.ExprNode.(*causetembedded.LogicalJoin).JoinType {
   451  	case causetembedded.InnerJoin, causetembedded.LeftOuterJoin, causetembedded.RightOuterJoin:
   452  		return prop.IsEmpty()
   453  	default:
   454  		return false
   455  	}
   456  }
   457  
   458  // OnImplement implements ImplementationMemrule OnImplement interface.
   459  func (r *ImplHashJoinBuildLeft) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   460  	join := expr.ExprNode.(*causetembedded.LogicalJoin)
   461  	switch join.JoinType {
   462  	case causetembedded.InnerJoin:
   463  		return []memo.Implementation{getImplForHashJoin(expr, reqProp, 0, false)}, nil
   464  	case causetembedded.LeftOuterJoin:
   465  		return []memo.Implementation{getImplForHashJoin(expr, reqProp, 1, true)}, nil
   466  	case causetembedded.RightOuterJoin:
   467  		return []memo.Implementation{getImplForHashJoin(expr, reqProp, 0, false)}, nil
   468  	default:
   469  		return nil, nil
   470  	}
   471  }
   472  
   473  // ImplHashJoinBuildRight implements LogicalJoin to PhysicalHashJoin which uses the right child to build hash causet.
   474  type ImplHashJoinBuildRight struct {
   475  }
   476  
   477  // Match implements ImplementationMemrule Match interface.
   478  func (r *ImplHashJoinBuildRight) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   479  	return prop.IsEmpty()
   480  }
   481  
   482  // OnImplement implements ImplementationMemrule OnImplement interface.
   483  func (r *ImplHashJoinBuildRight) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   484  	join := expr.ExprNode.(*causetembedded.LogicalJoin)
   485  	switch join.JoinType {
   486  	case causetembedded.SemiJoin, causetembedded.AntiSemiJoin,
   487  		causetembedded.LeftOuterSemiJoin, causetembedded.AntiLeftOuterSemiJoin:
   488  		return []memo.Implementation{getImplForHashJoin(expr, reqProp, 1, false)}, nil
   489  	case causetembedded.InnerJoin:
   490  		return []memo.Implementation{getImplForHashJoin(expr, reqProp, 1, false)}, nil
   491  	case causetembedded.LeftOuterJoin:
   492  		return []memo.Implementation{getImplForHashJoin(expr, reqProp, 1, false)}, nil
   493  	case causetembedded.RightOuterJoin:
   494  		return []memo.Implementation{getImplForHashJoin(expr, reqProp, 0, true)}, nil
   495  	}
   496  	return nil, nil
   497  }
   498  
   499  // ImplMergeJoin implements LogicalMergeJoin to PhysicalMergeJoin.
   500  type ImplMergeJoin struct {
   501  }
   502  
   503  // Match implements ImplementationMemrule Match interface.
   504  func (r *ImplMergeJoin) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   505  	return true
   506  }
   507  
   508  // OnImplement implements ImplementationMemrule OnImplement interface.
   509  func (r *ImplMergeJoin) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   510  	join := expr.ExprNode.(*causetembedded.LogicalJoin)
   511  	physicalMergeJoins := join.GetMergeJoin(reqProp, expr.Schema(), expr.Group.Prop.Stats, expr.Children[0].Prop.Stats, expr.Children[1].Prop.Stats)
   512  	mergeJoinImpls := make([]memo.Implementation, 0, len(physicalMergeJoins))
   513  	for _, physicalCauset := range physicalMergeJoins {
   514  		physicalMergeJoin := physicalCauset.(*causetembedded.PhysicalMergeJoin)
   515  		mergeJoinImpls = append(mergeJoinImpls, impl.NewMergeJoinImpl(physicalMergeJoin))
   516  	}
   517  	return mergeJoinImpls, nil
   518  }
   519  
   520  // ImplUnionAll implements LogicalUnionAll to PhysicalUnionAll.
   521  type ImplUnionAll struct {
   522  }
   523  
   524  // Match implements ImplementationMemrule Match interface.
   525  func (r *ImplUnionAll) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   526  	return prop.IsEmpty()
   527  }
   528  
   529  // OnImplement implements ImplementationMemrule OnImplement interface.
   530  func (r *ImplUnionAll) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   531  	logicalUnion := expr.ExprNode.(*causetembedded.LogicalUnionAll)
   532  	chReqProps := make([]*property.PhysicalProperty, len(expr.Children))
   533  	for i := range expr.Children {
   534  		chReqProps[i] = &property.PhysicalProperty{ExpectedCnt: reqProp.ExpectedCnt}
   535  	}
   536  	physicalUnion := causetembedded.PhysicalUnionAll{}.Init(
   537  		logicalUnion.SCtx(),
   538  		expr.Group.Prop.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt),
   539  		logicalUnion.SelectBlockOffset(),
   540  		chReqProps...,
   541  	)
   542  	physicalUnion.SetSchema(expr.Group.Prop.Schema)
   543  	return []memo.Implementation{impl.NewUnionAllImpl(physicalUnion)}, nil
   544  }
   545  
   546  // ImplApply implements LogicalApply to PhysicalApply
   547  type ImplApply struct {
   548  }
   549  
   550  // Match implements ImplementationMemrule Match interface.
   551  func (r *ImplApply) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   552  	return prop.AllDefCaussFromSchema(expr.Children[0].Prop.Schema)
   553  }
   554  
   555  // OnImplement implements ImplementationMemrule OnImplement interface
   556  func (r *ImplApply) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   557  	la := expr.ExprNode.(*causetembedded.LogicalApply)
   558  	join := la.GetHashJoin(reqProp)
   559  	physicalApply := causetembedded.PhysicalApply{
   560  		PhysicalHashJoin: *join,
   561  		OuterSchema:      la.CorDefCauss,
   562  	}.Init(
   563  		la.SCtx(),
   564  		expr.Group.Prop.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt),
   565  		la.SelectBlockOffset(),
   566  		&property.PhysicalProperty{ExpectedCnt: math.MaxFloat64, Items: reqProp.Items},
   567  		&property.PhysicalProperty{ExpectedCnt: math.MaxFloat64})
   568  	physicalApply.SetSchema(expr.Group.Prop.Schema)
   569  	return []memo.Implementation{impl.NewApplyImpl(physicalApply)}, nil
   570  }
   571  
   572  // ImplMaxOneRow implements LogicalMaxOneRow to PhysicalMaxOneRow.
   573  type ImplMaxOneRow struct {
   574  }
   575  
   576  // Match implements ImplementationMemrule Match interface.
   577  func (r *ImplMaxOneRow) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   578  	return prop.IsEmpty()
   579  }
   580  
   581  // OnImplement implements ImplementationMemrule OnImplement interface
   582  func (r *ImplMaxOneRow) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   583  	mor := expr.ExprNode.(*causetembedded.LogicalMaxOneRow)
   584  	physicalMaxOneRow := causetembedded.PhysicalMaxOneRow{}.Init(
   585  		mor.SCtx(),
   586  		expr.Group.Prop.Stats,
   587  		mor.SelectBlockOffset(),
   588  		&property.PhysicalProperty{ExpectedCnt: 2})
   589  	return []memo.Implementation{impl.NewMaxOneRowImpl(physicalMaxOneRow)}, nil
   590  }
   591  
   592  // ImplWindow implements LogicalWindow to PhysicalWindow.
   593  type ImplWindow struct {
   594  }
   595  
   596  // Match implements ImplementationMemrule Match interface.
   597  func (w *ImplWindow) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
   598  	lw := expr.ExprNode.(*causetembedded.LogicalWindow)
   599  	var byItems []property.Item
   600  	byItems = append(byItems, lw.PartitionBy...)
   601  	byItems = append(byItems, lw.OrderBy...)
   602  	childProperty := &property.PhysicalProperty{ExpectedCnt: math.MaxFloat64, Items: byItems}
   603  	return prop.IsPrefix(childProperty)
   604  }
   605  
   606  // OnImplement implements ImplementationMemrule OnImplement interface.
   607  func (w *ImplWindow) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) ([]memo.Implementation, error) {
   608  	lw := expr.ExprNode.(*causetembedded.LogicalWindow)
   609  	var byItems []property.Item
   610  	byItems = append(byItems, lw.PartitionBy...)
   611  	byItems = append(byItems, lw.OrderBy...)
   612  	physicalWindow := causetembedded.PhysicalWindow{
   613  		WindowFuncDescs: lw.WindowFuncDescs,
   614  		PartitionBy:     lw.PartitionBy,
   615  		OrderBy:         lw.OrderBy,
   616  		Frame:           lw.Frame,
   617  	}.Init(
   618  		lw.SCtx(),
   619  		expr.Group.Prop.Stats.ScaleByExpectCnt(reqProp.ExpectedCnt),
   620  		lw.SelectBlockOffset(),
   621  		&property.PhysicalProperty{ExpectedCnt: math.MaxFloat64, Items: byItems},
   622  	)
   623  	physicalWindow.SetSchema(expr.Group.Prop.Schema)
   624  	return []memo.Implementation{impl.NewWindowImpl(physicalWindow)}, nil
   625  }