vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/filter.go (about) 1 /* 2 Copyright 2021 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package engine 18 19 import ( 20 "context" 21 22 "vitess.io/vitess/go/vt/sqlparser" 23 "vitess.io/vitess/go/vt/vtgate/evalengine" 24 25 "vitess.io/vitess/go/sqltypes" 26 27 querypb "vitess.io/vitess/go/vt/proto/query" 28 ) 29 30 var _ Primitive = (*Filter)(nil) 31 32 // Filter is a primitive that performs the FILTER operation. 33 type Filter struct { 34 Predicate evalengine.Expr 35 ASTPredicate sqlparser.Expr 36 Input Primitive 37 38 noTxNeeded 39 } 40 41 // RouteType returns a description of the query routing type used by the primitive 42 func (f *Filter) RouteType() string { 43 return f.Input.RouteType() 44 } 45 46 // GetKeyspaceName specifies the Keyspace that this primitive routes to. 47 func (f *Filter) GetKeyspaceName() string { 48 return f.Input.GetKeyspaceName() 49 } 50 51 // GetTableName specifies the table that this primitive routes to. 52 func (f *Filter) GetTableName() string { 53 return f.Input.GetTableName() 54 } 55 56 // TryExecute satisfies the Primitive interface. 57 func (f *Filter) TryExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { 58 result, err := vcursor.ExecutePrimitive(ctx, f.Input, bindVars, wantfields) 59 if err != nil { 60 return nil, err 61 } 62 env := evalengine.EnvWithBindVars(bindVars, vcursor.ConnCollation()) 63 var rows [][]sqltypes.Value 64 env.Fields = result.Fields 65 for _, row := range result.Rows { 66 env.Row = row 67 evalResult, err := env.Evaluate(f.Predicate) 68 if err != nil { 69 return nil, err 70 } 71 intEvalResult, err := evalResult.Value().ToInt64() 72 if err != nil { 73 return nil, err 74 } 75 if intEvalResult == 1 { 76 rows = append(rows, row) 77 } 78 } 79 result.Rows = rows 80 return result, nil 81 } 82 83 // TryStreamExecute satisfies the Primitive interface. 84 func (f *Filter) TryStreamExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error { 85 env := evalengine.EnvWithBindVars(bindVars, vcursor.ConnCollation()) 86 filter := func(results *sqltypes.Result) error { 87 var rows [][]sqltypes.Value 88 env.Fields = results.Fields 89 for _, row := range results.Rows { 90 env.Row = row 91 evalResult, err := env.Evaluate(f.Predicate) 92 if err != nil { 93 return err 94 } 95 intEvalResult, err := evalResult.Value().ToInt64() 96 if err != nil { 97 return err 98 } 99 if intEvalResult == 1 { 100 rows = append(rows, row) 101 } 102 } 103 results.Rows = rows 104 return callback(results) 105 } 106 107 return vcursor.StreamExecutePrimitive(ctx, f.Input, bindVars, wantfields, filter) 108 } 109 110 // GetFields implements the Primitive interface. 111 func (f *Filter) GetFields(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) { 112 return f.Input.GetFields(ctx, vcursor, bindVars) 113 } 114 115 // Inputs returns the input to limit 116 func (f *Filter) Inputs() []Primitive { 117 return []Primitive{f.Input} 118 } 119 120 func (f *Filter) description() PrimitiveDescription { 121 other := map[string]any{ 122 "Predicate": sqlparser.String(f.ASTPredicate), 123 } 124 125 return PrimitiveDescription{ 126 OperatorType: "Filter", 127 Other: other, 128 } 129 }