github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/rule/constant_fold.go (about)

     1  // Copyright 2021 - 2022 Matrix Origin
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package rule
    16  
    17  import (
    18  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    19  	"github.com/matrixorigin/matrixone/pkg/container/nulls"
    20  	"github.com/matrixorigin/matrixone/pkg/container/types"
    21  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    22  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    23  	"github.com/matrixorigin/matrixone/pkg/sql/colexec"
    24  	"github.com/matrixorigin/matrixone/pkg/sql/plan/function"
    25  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    26  )
    27  
    28  type ConstantFold struct {
    29  	bat        *batch.Batch
    30  	isPrepared bool
    31  }
    32  
    33  func NewConstantFold(isPrepared bool) *ConstantFold {
    34  	bat := batch.NewWithSize(0)
    35  	bat.Zs = []int64{1}
    36  	return &ConstantFold{
    37  		bat:        bat,
    38  		isPrepared: isPrepared,
    39  	}
    40  }
    41  
    42  func (r *ConstantFold) GetBatch() *batch.Batch {
    43  	return r.bat
    44  }
    45  
    46  // Match always true
    47  func (r *ConstantFold) Match(n *plan.Node) bool {
    48  	return true
    49  }
    50  
    51  func (r *ConstantFold) Apply(n *plan.Node, _ *plan.Query, proc *process.Process) {
    52  	if n.Limit != nil {
    53  		n.Limit = r.constantFold(n.Limit, proc)
    54  	}
    55  	if n.Offset != nil {
    56  		n.Offset = r.constantFold(n.Offset, proc)
    57  	}
    58  	if len(n.OnList) > 0 {
    59  		for i := range n.OnList {
    60  			n.OnList[i] = r.constantFold(n.OnList[i], proc)
    61  		}
    62  	}
    63  	if len(n.FilterList) > 0 {
    64  		for i := range n.FilterList {
    65  			n.FilterList[i] = r.constantFold(n.FilterList[i], proc)
    66  		}
    67  	}
    68  	if len(n.ProjectList) > 0 {
    69  		for i := range n.ProjectList {
    70  			n.ProjectList[i] = r.constantFold(n.ProjectList[i], proc)
    71  		}
    72  	}
    73  }
    74  
    75  func (r *ConstantFold) constantFold(e *plan.Expr, proc *process.Process) *plan.Expr {
    76  	ef, ok := e.Expr.(*plan.Expr_F)
    77  	if !ok {
    78  		if el, ok := e.Expr.(*plan.Expr_List); ok {
    79  			lenList := len(el.List.List)
    80  			for i := 0; i < lenList; i++ {
    81  				el.List.List[i] = r.constantFold(el.List.List[i], proc)
    82  			}
    83  		}
    84  		return e
    85  	}
    86  	overloadID := ef.F.Func.GetObj()
    87  	f, exists := function.GetFunctionByIDWithoutError(overloadID)
    88  	if !exists {
    89  		return e
    90  	}
    91  	if f.Volatile { // function cannot be fold
    92  		return e
    93  	}
    94  	if f.RealTimeRelated && r.isPrepared {
    95  		return e
    96  	}
    97  	for i := range ef.F.Args {
    98  		ef.F.Args[i] = r.constantFold(ef.F.Args[i], proc)
    99  	}
   100  	if !IsConstant(e) {
   101  		return e
   102  	}
   103  	vec, err := colexec.EvalExpr(r.bat, proc, e)
   104  	if err != nil {
   105  		return e
   106  	}
   107  	c := GetConstantValue(vec, false)
   108  	if c == nil {
   109  		return e
   110  	}
   111  
   112  	if f.RealTimeRelated {
   113  		c.Src = &plan.Expr{
   114  			Typ: &plan.Type{
   115  				Id:          e.Typ.Id,
   116  				NotNullable: e.Typ.NotNullable,
   117  				Width:       e.Typ.Width,
   118  				Precision:   e.Typ.Precision,
   119  				Size:        e.Typ.Size,
   120  				Scale:       e.Typ.Scale,
   121  				AutoIncr:    e.Typ.AutoIncr,
   122  				Table:       e.Typ.Table,
   123  			},
   124  			Expr: &plan.Expr_F{
   125  				F: &plan.Function{
   126  					Func: &plan.ObjectRef{
   127  						Server:     ef.F.Func.GetServer(),
   128  						Db:         ef.F.Func.GetDb(),
   129  						Schema:     ef.F.Func.GetSchema(),
   130  						Obj:        ef.F.Func.GetObj(),
   131  						ServerName: ef.F.Func.GetServerName(),
   132  						DbName:     ef.F.Func.GetDbName(),
   133  						SchemaName: ef.F.Func.GetSchemaName(),
   134  						ObjName:    ef.F.Func.GetObjName(),
   135  					},
   136  					Args: make([]*plan.Expr, 0),
   137  				},
   138  			},
   139  		}
   140  	} else {
   141  		existRealTimeFunc := false
   142  		for i, expr := range ef.F.Args {
   143  			if ac, cok := expr.Expr.(*plan.Expr_C); cok && ac.C.Src != nil {
   144  				if _, pok := ac.C.Src.Expr.(*plan.Expr_V); !pok {
   145  					ef.F.Args[i] = ac.C.Src
   146  					existRealTimeFunc = true
   147  				}
   148  			}
   149  		}
   150  		if existRealTimeFunc {
   151  			c.Src = &plan.Expr{
   152  				Typ: &plan.Type{
   153  					Id:          e.Typ.Id,
   154  					NotNullable: e.Typ.NotNullable,
   155  					Width:       e.Typ.Width,
   156  					Precision:   e.Typ.Precision,
   157  					Size:        e.Typ.Size,
   158  					Scale:       e.Typ.Scale,
   159  					AutoIncr:    e.Typ.AutoIncr,
   160  					Table:       e.Typ.Table,
   161  				},
   162  				Expr: ef,
   163  			}
   164  		}
   165  	}
   166  
   167  	ec := &plan.Expr_C{
   168  		C: c,
   169  	}
   170  	e.Typ = &plan.Type{Id: int32(vec.Typ.Oid), Precision: vec.Typ.Precision, Scale: vec.Typ.Scale, Width: vec.Typ.Width, Size: vec.Typ.Size}
   171  	e.Expr = ec
   172  	return e
   173  }
   174  
   175  func GetConstantValue(vec *vector.Vector, transAll bool) *plan.Const {
   176  	if nulls.Any(vec.Nsp) {
   177  		return &plan.Const{Isnull: true}
   178  	}
   179  	switch vec.Typ.Oid {
   180  	case types.T_bool:
   181  		return &plan.Const{
   182  			Value: &plan.Const_Bval{
   183  				Bval: vec.Col.([]bool)[0],
   184  			},
   185  		}
   186  	case types.T_int8:
   187  		return &plan.Const{
   188  			Value: &plan.Const_I8Val{
   189  				I8Val: int32(vec.Col.([]int8)[0]),
   190  			},
   191  		}
   192  	case types.T_int16:
   193  		return &plan.Const{
   194  			Value: &plan.Const_I16Val{
   195  				I16Val: int32(vec.Col.([]int16)[0]),
   196  			},
   197  		}
   198  	case types.T_int32:
   199  		return &plan.Const{
   200  			Value: &plan.Const_I32Val{
   201  				I32Val: vec.Col.([]int32)[0],
   202  			},
   203  		}
   204  	case types.T_int64:
   205  		return &plan.Const{
   206  			Value: &plan.Const_I64Val{
   207  				I64Val: vec.Col.([]int64)[0],
   208  			},
   209  		}
   210  	case types.T_uint8:
   211  		return &plan.Const{
   212  			Value: &plan.Const_U8Val{
   213  				U8Val: uint32(vec.Col.([]uint8)[0]),
   214  			},
   215  		}
   216  	case types.T_uint16:
   217  		return &plan.Const{
   218  			Value: &plan.Const_U16Val{
   219  				U16Val: uint32(vec.Col.([]uint16)[0]),
   220  			},
   221  		}
   222  	case types.T_uint32:
   223  		return &plan.Const{
   224  			Value: &plan.Const_U32Val{
   225  				U32Val: vec.Col.([]uint32)[0],
   226  			},
   227  		}
   228  	case types.T_uint64:
   229  		return &plan.Const{
   230  			Value: &plan.Const_U64Val{
   231  				U64Val: vec.Col.([]uint64)[0],
   232  			},
   233  		}
   234  	case types.T_float32:
   235  		return &plan.Const{
   236  			Value: &plan.Const_Fval{
   237  				Fval: vec.Col.([]float32)[0],
   238  			},
   239  		}
   240  	case types.T_float64:
   241  		return &plan.Const{
   242  			Value: &plan.Const_Dval{
   243  				Dval: vec.Col.([]float64)[0],
   244  			},
   245  		}
   246  	case types.T_varchar, types.T_char, types.T_text, types.T_blob:
   247  		return &plan.Const{
   248  			Value: &plan.Const_Sval{
   249  				Sval: vec.GetString(0),
   250  			},
   251  		}
   252  	case types.T_json:
   253  		if !transAll {
   254  			return nil
   255  		}
   256  		return &plan.Const{
   257  			Value: &plan.Const_Sval{
   258  				Sval: vec.GetString(0),
   259  			},
   260  		}
   261  	case types.T_timestamp:
   262  		return &plan.Const{
   263  			Value: &plan.Const_Timestampval{
   264  				Timestampval: int64(vector.MustTCols[types.Timestamp](vec)[0]),
   265  			},
   266  		}
   267  	case types.T_date:
   268  		return &plan.Const{
   269  			Value: &plan.Const_Dateval{
   270  				Dateval: int32(vector.MustTCols[types.Date](vec)[0]),
   271  			},
   272  		}
   273  	case types.T_time:
   274  		if !transAll {
   275  			return nil
   276  		}
   277  		return &plan.Const{
   278  			Value: &plan.Const_Timeval{
   279  				Timeval: int64(vector.MustTCols[types.Time](vec)[0]),
   280  			},
   281  		}
   282  	case types.T_datetime:
   283  		if !transAll {
   284  			return nil
   285  		}
   286  		return &plan.Const{
   287  			Value: &plan.Const_Datetimeval{
   288  				Datetimeval: int64(vector.MustTCols[types.Datetime](vec)[0]),
   289  			},
   290  		}
   291  	case types.T_decimal64:
   292  		if !transAll {
   293  			return nil
   294  		}
   295  		return &plan.Const{
   296  			Value: &plan.Const_Decimal64Val{
   297  				Decimal64Val: &plan.Decimal64{A: types.Decimal64ToInt64Raw(vector.MustTCols[types.Decimal64](vec)[0])},
   298  			},
   299  		}
   300  	case types.T_decimal128:
   301  		if !transAll {
   302  			return nil
   303  		}
   304  		decimalValue := &plan.Decimal128{}
   305  		decimalValue.A, decimalValue.B = types.Decimal128ToInt64Raw(vector.MustTCols[types.Decimal128](vec)[0])
   306  		return &plan.Const{Value: &plan.Const_Decimal128Val{Decimal128Val: decimalValue}}
   307  	default:
   308  		return nil
   309  	}
   310  }
   311  
   312  func IsConstant(e *plan.Expr) bool {
   313  	switch ef := e.Expr.(type) {
   314  	case *plan.Expr_C, *plan.Expr_T:
   315  		return true
   316  	case *plan.Expr_F:
   317  		overloadID := ef.F.Func.GetObj()
   318  		f, exists := function.GetFunctionByIDWithoutError(overloadID)
   319  		if !exists {
   320  			return false
   321  		}
   322  		if f.Volatile { // function cannot be fold
   323  			return false
   324  		}
   325  		for i := range ef.F.Args {
   326  			if !IsConstant(ef.F.Args[i]) {
   327  				return false
   328  			}
   329  		}
   330  		return true
   331  	default:
   332  		return false
   333  	}
   334  }