@@ -18,7 +18,6 @@ import (
1818 "fmt"
1919 "strings"
2020 "sync"
21- "sync/atomic"
2221
2322 regex "github.com/dolthub/go-icu-regex"
2423 "gopkg.in/src-d/go-errors.v1"
@@ -35,15 +34,16 @@ type RegexpLike struct {
3534 Pattern sql.Expression
3635 Flags sql.Expression
3736
38- cachedVal atomic.Value
37+ cachedVal any
38+ cacheable bool
3939 re regex.Regex
4040 compileOnce sync.Once
4141 compileErr error
4242}
4343
4444var _ sql.FunctionExpression = (* RegexpLike )(nil )
4545var _ sql.CollationCoercible = (* RegexpLike )(nil )
46- var _ sql.Closer = (* RegexpLike )(nil )
46+ var _ sql.Disposable = (* RegexpLike )(nil )
4747
4848// NewRegexpLike creates a new RegexpLike expression.
4949func NewRegexpLike (args ... sql.Expression ) (sql.Expression , error ) {
@@ -115,6 +115,7 @@ func (r *RegexpLike) WithChildren(children ...sql.Expression) (sql.Expression, e
115115 return NewRegexpLike (children ... )
116116}
117117
118+ // String implements the sql.Expression interface.
118119func (r * RegexpLike ) String () string {
119120 var args []string
120121 for _ , e := range r .Children () {
@@ -123,23 +124,34 @@ func (r *RegexpLike) String() string {
123124 return fmt .Sprintf ("%s(%s)" , r .FunctionName (), strings .Join (args , "," ))
124125}
125126
126- func (r * RegexpLike ) compile (ctx * sql.Context ) {
127+ // compile handles compilation of the regex.
128+ func (r * RegexpLike ) compile (ctx * sql.Context , row sql.Row ) {
127129 r .compileOnce .Do (func () {
128- r .re , r .compileErr = compileRegex (ctx , r .Pattern , r .Text , r .Flags , r .FunctionName (), nil )
130+ r .cacheable = canBeCached (r .Text , r .Pattern , r .Flags )
131+ if r .cacheable {
132+ r .re , r .compileErr = compileRegex (ctx , r .Pattern , r .Text , r .Flags , r .FunctionName (), row )
133+ }
129134 })
135+ if ! r .cacheable {
136+ if r .re != nil {
137+ if r .compileErr = r .re .Close (); r .compileErr != nil {
138+ return
139+ }
140+ }
141+ r .re , r .compileErr = compileRegex (ctx , r .Pattern , r .Text , r .Flags , r .FunctionName (), row )
142+ }
130143}
131144
132145// Eval implements the sql.Expression interface.
133146func (r * RegexpLike ) Eval (ctx * sql.Context , row sql.Row ) (interface {}, error ) {
134147 span , ctx := ctx .Span ("function.RegexpLike" )
135148 defer span .End ()
136149
137- cached := r .cachedVal .Load ()
138- if cached != nil {
139- return cached , nil
150+ if r .cachedVal != nil {
151+ return r .cachedVal , nil
140152 }
141153
142- r .compile (ctx )
154+ r .compile (ctx , row )
143155 if r .compileErr != nil {
144156 return nil , r .compileErr
145157 }
@@ -174,18 +186,17 @@ func (r *RegexpLike) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
174186 outVal = int8 (0 )
175187 }
176188
177- if canBeCached ( r . Text ) {
178- r .cachedVal . Store ( outVal )
189+ if r . cacheable {
190+ r .cachedVal = outVal
179191 }
180192 return outVal , nil
181193}
182194
183- // Close implements the sql.Closer interface.
184- func (r * RegexpLike ) Close ( ctx * sql. Context ) error {
195+ // Dispose implements the sql.Disposable interface.
196+ func (r * RegexpLike ) Dispose () {
185197 if r .re != nil {
186- return r .re .Close ()
198+ _ = r .re .Close ()
187199 }
188- return nil
189200}
190201
191202func compileRegex (ctx * sql.Context , pattern , text , flags sql.Expression , funcName string , row sql.Row ) (regex.Regex , error ) {
@@ -293,14 +304,24 @@ func consolidateRegexpFlags(flags, funcName string) (string, error) {
293304 return flags , nil
294305}
295306
296- func canBeCached (e sql.Expression ) bool {
307+ // canBeCached returns whether the expression(s) can be cached
308+ func canBeCached (exprs ... sql.Expression ) bool {
297309 hasCols := false
298- sql .Inspect (e , func (e sql.Expression ) bool {
299- switch e .(type ) {
300- case * expression.GetField , * expression.UserVar , * expression.SystemVar , * expression.ProcedureParam :
301- hasCols = true
310+ for _ , expr := range exprs {
311+ if expr == nil {
312+ continue
302313 }
303- return true
304- })
314+ sql .Inspect (expr , func (e sql.Expression ) bool {
315+ switch e .(type ) {
316+ case * expression.GetField , * expression.UserVar , * expression.SystemVar , * expression.ProcedureParam :
317+ hasCols = true
318+ default :
319+ if nonDet , ok := expr .(sql.NonDeterministicExpression ); ok {
320+ hasCols = hasCols || nonDet .IsNonDeterministic ()
321+ }
322+ }
323+ return true
324+ })
325+ }
305326 return ! hasCols
306327}
0 commit comments