github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/embedded/cacheable_checker.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 "github.com/whtcorpsinc/BerolinaSQL/ast" 18 "github.com/whtcorpsinc/milevadb/memex" 19 "github.com/whtcorpsinc/milevadb/schemareplicant" 20 "github.com/whtcorpsinc/milevadb/soliton/logutil" 21 "github.com/whtcorpsinc/milevadb/types/BerolinaSQL_driver" 22 "go.uber.org/zap" 23 ) 24 25 // Cacheable checks whether the input ast is cacheable. 26 // Handle "ignore_plan_cache()" hint 27 // If there are multiple hints, only one will take effect 28 func Cacheable(node ast.Node, is schemareplicant.SchemaReplicant) bool { 29 _, isSelect := node.(*ast.SelectStmt) 30 _, isUFIDelate := node.(*ast.UFIDelateStmt) 31 _, isInsert := node.(*ast.InsertStmt) 32 _, isDelete := node.(*ast.DeleteStmt) 33 _, isSetOpr := node.(*ast.SetOprStmt) 34 if !(isSelect || isUFIDelate || isInsert || isDelete || isSetOpr) { 35 return false 36 } 37 checker := cacheableChecker{ 38 cacheable: true, 39 schemaReplicant: is, 40 } 41 node.Accept(&checker) 42 return checker.cacheable 43 } 44 45 // cacheableChecker checks whether a query's plan can be cached, querys that: 46 // 1. have ExistsSubqueryExpr, or 47 // 2. have VariableExpr 48 // will not be cached currently. 49 // NOTE: we can add more rules in the future. 50 type cacheableChecker struct { 51 cacheable bool 52 schemaReplicant schemareplicant.SchemaReplicant 53 } 54 55 // Enter implements Visitor interface. 56 func (checker *cacheableChecker) Enter(in ast.Node) (out ast.Node, skipChildren bool) { 57 switch node := in.(type) { 58 case *ast.SelectStmt: 59 for _, hints := range node.BlockHints { 60 if hints.HintName.L == HintIgnoreCausetCache { 61 checker.cacheable = false 62 return in, true 63 } 64 } 65 case *ast.DeleteStmt: 66 for _, hints := range node.BlockHints { 67 if hints.HintName.L == HintIgnoreCausetCache { 68 checker.cacheable = false 69 return in, true 70 } 71 } 72 case *ast.UFIDelateStmt: 73 for _, hints := range node.BlockHints { 74 if hints.HintName.L == HintIgnoreCausetCache { 75 checker.cacheable = false 76 return in, true 77 } 78 } 79 case *ast.VariableExpr, *ast.ExistsSubqueryExpr, *ast.SubqueryExpr: 80 checker.cacheable = false 81 return in, true 82 case *ast.FuncCallExpr: 83 if _, found := memex.UnCacheableFunctions[node.FnName.L]; found { 84 checker.cacheable = false 85 return in, true 86 } 87 case *ast.OrderByClause: 88 for _, item := range node.Items { 89 if _, isParamMarker := item.Expr.(*driver.ParamMarkerExpr); isParamMarker { 90 checker.cacheable = false 91 return in, true 92 } 93 } 94 case *ast.GroupByClause: 95 for _, item := range node.Items { 96 if _, isParamMarker := item.Expr.(*driver.ParamMarkerExpr); isParamMarker { 97 checker.cacheable = false 98 return in, true 99 } 100 } 101 case *ast.Limit: 102 if node.Count != nil { 103 if _, isParamMarker := node.Count.(*driver.ParamMarkerExpr); isParamMarker { 104 checker.cacheable = false 105 return in, true 106 } 107 } 108 if node.Offset != nil { 109 if _, isParamMarker := node.Offset.(*driver.ParamMarkerExpr); isParamMarker { 110 checker.cacheable = false 111 return in, true 112 } 113 } 114 case *ast.FrameBound: 115 if _, ok := node.Expr.(*driver.ParamMarkerExpr); ok { 116 checker.cacheable = false 117 return in, true 118 } 119 case *ast.BlockName: 120 if checker.schemaReplicant != nil { 121 if checker.isPartitionBlock(node) { 122 checker.cacheable = false 123 return in, true 124 } 125 } 126 } 127 return in, false 128 } 129 130 func (checker *cacheableChecker) isPartitionBlock(tn *ast.BlockName) bool { 131 tb, err := checker.schemaReplicant.BlockByName(tn.Schema, tn.Name) 132 if err != nil { 133 logutil.BgLogger().Error("Error occur in checking cacheable", zap.Error(err)) 134 return false 135 } 136 if tb.Meta().Partition != nil { 137 return true 138 } 139 return false 140 } 141 142 // Leave implements Visitor interface. 143 func (checker *cacheableChecker) Leave(in ast.Node) (out ast.Node, ok bool) { 144 return in, checker.cacheable 145 }