github.com/pingcap/tidb/parser@v0.0.0-20231013125129-93a834a6bf8d/ast/util.go (about)

     1  // Copyright 2018 PingCAP, 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 ast
    15  
    16  import "math"
    17  
    18  // UnspecifiedSize is unspecified size.
    19  const (
    20  	UnspecifiedSize = math.MaxUint64
    21  )
    22  
    23  // IsReadOnly checks whether the input ast is readOnly.
    24  func IsReadOnly(node Node) bool {
    25  	switch st := node.(type) {
    26  	case *SelectStmt:
    27  		if st.LockInfo != nil {
    28  			switch st.LockInfo.LockType {
    29  			case SelectLockForUpdate, SelectLockForUpdateNoWait, SelectLockForUpdateWaitN:
    30  				return false
    31  			}
    32  		}
    33  
    34  		checker := readOnlyChecker{
    35  			readOnly: true,
    36  		}
    37  
    38  		node.Accept(&checker)
    39  		return checker.readOnly
    40  	case *ExplainStmt:
    41  		return !st.Analyze || IsReadOnly(st.Stmt)
    42  	case *DoStmt, *ShowStmt:
    43  		return true
    44  	case *SetOprStmt:
    45  		for _, sel := range node.(*SetOprStmt).SelectList.Selects {
    46  			if !IsReadOnly(sel) {
    47  				return false
    48  			}
    49  		}
    50  		return true
    51  	case *SetOprSelectList:
    52  		for _, sel := range node.(*SetOprSelectList).Selects {
    53  			if !IsReadOnly(sel) {
    54  				return false
    55  			}
    56  		}
    57  		return true
    58  	case *AdminStmt:
    59  		switch node.(*AdminStmt).Tp {
    60  		case AdminShowTelemetry, AdminShowDDL, AdminShowDDLJobs, AdminShowSlow,
    61  			AdminCaptureBindings, AdminShowNextRowID, AdminShowDDLJobQueries,
    62  			AdminShowDDLJobQueriesWithRange:
    63  			return true
    64  		default:
    65  			return false
    66  		}
    67  	default:
    68  		return false
    69  	}
    70  }
    71  
    72  // readOnlyChecker checks whether a query's ast is readonly, if it satisfied
    73  // 1. selectstmt;
    74  // 2. need not to set var;
    75  // it is readonly statement.
    76  type readOnlyChecker struct {
    77  	readOnly bool
    78  }
    79  
    80  // Enter implements Visitor interface.
    81  func (checker *readOnlyChecker) Enter(in Node) (out Node, skipChildren bool) {
    82  	if node, ok := in.(*VariableExpr); ok {
    83  		// like func rewriteVariable(), this stands for SetVar.
    84  		if !node.IsSystem && node.Value != nil {
    85  			checker.readOnly = false
    86  			return in, true
    87  		}
    88  	}
    89  	return in, false
    90  }
    91  
    92  // Leave implements Visitor interface.
    93  func (checker *readOnlyChecker) Leave(in Node) (out Node, ok bool) {
    94  	return in, checker.readOnly
    95  }