github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/txn.go (about)

     1  // Copyright 2015 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package tree
    12  
    13  import (
    14  	"fmt"
    15  	"strings"
    16  
    17  	"github.com/cockroachdb/cockroachdb-parser/pkg/kv/kvserver/concurrency/isolation"
    18  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgcode"
    19  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgerror"
    20  	"github.com/cockroachdb/redact"
    21  )
    22  
    23  // IsolationLevel holds the isolation level for a transaction.
    24  type IsolationLevel int
    25  
    26  var _ redact.SafeValue = IsolationLevel(0)
    27  
    28  // SafeValue makes Kind a redact.SafeValue.
    29  func (k IsolationLevel) SafeValue() {}
    30  
    31  // IsolationLevel values
    32  const (
    33  	UnspecifiedIsolation IsolationLevel = iota
    34  	ReadUncommittedIsolation
    35  	ReadCommittedIsolation
    36  	RepeatableReadIsolation
    37  	SnapshotIsolation
    38  	SerializableIsolation
    39  )
    40  
    41  var isolationLevelNames = [...]string{
    42  	UnspecifiedIsolation:     "UNSPECIFIED",
    43  	ReadUncommittedIsolation: "READ UNCOMMITTED",
    44  	ReadCommittedIsolation:   "READ COMMITTED",
    45  	RepeatableReadIsolation:  "REPEATABLE READ",
    46  	SnapshotIsolation:        "SNAPSHOT",
    47  	SerializableIsolation:    "SERIALIZABLE",
    48  }
    49  
    50  // IsolationLevelMap is a map from string isolation level name to isolation
    51  // level, in the lowercase format that set isolation_level supports.
    52  var IsolationLevelMap = map[string]IsolationLevel{
    53  	"read uncommitted": ReadUncommittedIsolation,
    54  	"read committed":   ReadCommittedIsolation,
    55  	"repeatable read":  RepeatableReadIsolation,
    56  	"snapshot":         SnapshotIsolation,
    57  	"serializable":     SerializableIsolation,
    58  }
    59  
    60  func (i IsolationLevel) String() string {
    61  	if i < 0 || i > IsolationLevel(len(isolationLevelNames)-1) {
    62  		return fmt.Sprintf("IsolationLevel(%d)", i)
    63  	}
    64  	return isolationLevelNames[i]
    65  }
    66  
    67  // IsolationLevelFromKVTxnIsolationLevel converts a kv level isolation.Level to
    68  // its SQL semantic equivalent.
    69  func IsolationLevelFromKVTxnIsolationLevel(level isolation.Level) IsolationLevel {
    70  	var ret IsolationLevel
    71  	switch level {
    72  	case isolation.Serializable:
    73  		ret = SerializableIsolation
    74  	case isolation.ReadCommitted:
    75  		ret = ReadCommittedIsolation
    76  	case isolation.Snapshot:
    77  		ret = SnapshotIsolation
    78  	default:
    79  		panic("What to do here? Log is a banned import")
    80  		// log.Fatalf(context.Background(), "unknown isolation level: %s", level)
    81  	}
    82  	return ret
    83  }
    84  
    85  // UserPriority holds the user priority for a transaction.
    86  type UserPriority int
    87  
    88  // UserPriority values
    89  const (
    90  	UnspecifiedUserPriority UserPriority = iota
    91  	Low
    92  	Normal
    93  	High
    94  )
    95  
    96  var userPriorityNames = [...]string{
    97  	UnspecifiedUserPriority: "UNSPECIFIED",
    98  	Low:                     "LOW",
    99  	Normal:                  "NORMAL",
   100  	High:                    "HIGH",
   101  }
   102  
   103  func (up UserPriority) String() string {
   104  	if up < 0 || up > UserPriority(len(userPriorityNames)-1) {
   105  		return fmt.Sprintf("UserPriority(%d)", up)
   106  	}
   107  	return userPriorityNames[up]
   108  }
   109  
   110  // UserPriorityFromString converts a string into a UserPriority.
   111  func UserPriorityFromString(val string) (_ UserPriority, ok bool) {
   112  	switch strings.ToUpper(val) {
   113  	case "LOW":
   114  		return Low, true
   115  	case "NORMAL":
   116  		return Normal, true
   117  	case "HIGH":
   118  		return High, true
   119  	default:
   120  		return 0, false
   121  	}
   122  }
   123  
   124  // ReadWriteMode holds the read write mode for a transaction.
   125  type ReadWriteMode int
   126  
   127  // ReadWriteMode values
   128  const (
   129  	UnspecifiedReadWriteMode ReadWriteMode = iota
   130  	ReadOnly
   131  	ReadWrite
   132  )
   133  
   134  var readWriteModeNames = [...]string{
   135  	UnspecifiedReadWriteMode: "UNSPECIFIED",
   136  	ReadOnly:                 "ONLY",
   137  	ReadWrite:                "WRITE",
   138  }
   139  
   140  func (ro ReadWriteMode) String() string {
   141  	if ro < 0 || ro > ReadWriteMode(len(readWriteModeNames)-1) {
   142  		return fmt.Sprintf("ReadWriteMode(%d)", ro)
   143  	}
   144  	return readWriteModeNames[ro]
   145  }
   146  
   147  // DeferrableMode holds the deferrable mode for a transaction.
   148  type DeferrableMode int
   149  
   150  // DeferrableMode values.
   151  const (
   152  	UnspecifiedDeferrableMode DeferrableMode = iota
   153  	Deferrable
   154  	NotDeferrable
   155  )
   156  
   157  var deferrableModeNames = [...]string{
   158  	UnspecifiedDeferrableMode: "UNSPECIFIED",
   159  	Deferrable:                "DEFERRABLE",
   160  	NotDeferrable:             "NOT DEFERRABLE",
   161  }
   162  
   163  func (d DeferrableMode) String() string {
   164  	if d < 0 || d > DeferrableMode(len(deferrableModeNames)-1) {
   165  		return fmt.Sprintf("DeferrableMode(%d)", d)
   166  	}
   167  	return deferrableModeNames[d]
   168  }
   169  
   170  // TransactionModes holds the transaction modes for a transaction.
   171  type TransactionModes struct {
   172  	Isolation     IsolationLevel
   173  	UserPriority  UserPriority
   174  	ReadWriteMode ReadWriteMode
   175  	AsOf          AsOfClause
   176  	Deferrable    DeferrableMode
   177  }
   178  
   179  // Format implements the NodeFormatter interface.
   180  func (node *TransactionModes) Format(ctx *FmtCtx) {
   181  	var sep string
   182  	if node.Isolation != UnspecifiedIsolation {
   183  		ctx.Printf(" ISOLATION LEVEL %s", node.Isolation)
   184  		sep = ","
   185  	}
   186  	if node.UserPriority != UnspecifiedUserPriority {
   187  		ctx.Printf("%s PRIORITY %s", sep, node.UserPriority)
   188  		sep = ","
   189  	}
   190  	if node.ReadWriteMode != UnspecifiedReadWriteMode {
   191  		ctx.Printf("%s READ %s", sep, node.ReadWriteMode)
   192  		sep = ","
   193  	}
   194  	if node.AsOf.Expr != nil {
   195  		ctx.WriteString(sep)
   196  		ctx.WriteString(" ")
   197  		ctx.FormatNode(&node.AsOf)
   198  		sep = ","
   199  	}
   200  	if node.Deferrable != UnspecifiedDeferrableMode {
   201  		ctx.Printf("%s %s", sep, node.Deferrable)
   202  	}
   203  }
   204  
   205  var (
   206  	errIsolationLevelSpecifiedMultipleTimes = pgerror.New(pgcode.Syntax, "isolation level specified multiple times")
   207  	errUserPrioritySpecifiedMultipleTimes   = pgerror.New(pgcode.Syntax, "user priority specified multiple times")
   208  	errReadModeSpecifiedMultipleTimes       = pgerror.New(pgcode.Syntax, "read mode specified multiple times")
   209  	errAsOfSpecifiedMultipleTimes           = pgerror.New(pgcode.Syntax, "AS OF SYSTEM TIME specified multiple times")
   210  	errDeferrableSpecifiedMultipleTimes     = pgerror.New(pgcode.Syntax, "deferrable mode specified multiple times")
   211  
   212  	// ErrAsOfSpecifiedWithReadWrite is returned when a statement attempts to set
   213  	// a historical query to READ WRITE which conflicts with its implied READ ONLY
   214  	// mode.
   215  	ErrAsOfSpecifiedWithReadWrite = pgerror.New(pgcode.Syntax, "AS OF SYSTEM TIME specified with READ WRITE mode")
   216  )
   217  
   218  // Merge groups two sets of transaction modes together.
   219  // Used in the parser.
   220  func (node *TransactionModes) Merge(other TransactionModes) error {
   221  	if other.Isolation != UnspecifiedIsolation {
   222  		if node.Isolation != UnspecifiedIsolation {
   223  			return errIsolationLevelSpecifiedMultipleTimes
   224  		}
   225  		node.Isolation = other.Isolation
   226  	}
   227  	if other.UserPriority != UnspecifiedUserPriority {
   228  		if node.UserPriority != UnspecifiedUserPriority {
   229  			return errUserPrioritySpecifiedMultipleTimes
   230  		}
   231  		node.UserPriority = other.UserPriority
   232  	}
   233  	if other.AsOf.Expr != nil {
   234  		if node.AsOf.Expr != nil {
   235  			return errAsOfSpecifiedMultipleTimes
   236  		}
   237  		node.AsOf.Expr = other.AsOf.Expr
   238  	}
   239  	if other.ReadWriteMode != UnspecifiedReadWriteMode {
   240  		if node.ReadWriteMode != UnspecifiedReadWriteMode {
   241  			return errReadModeSpecifiedMultipleTimes
   242  		}
   243  		node.ReadWriteMode = other.ReadWriteMode
   244  	}
   245  	if node.ReadWriteMode != UnspecifiedReadWriteMode &&
   246  		node.ReadWriteMode != ReadOnly &&
   247  		node.AsOf.Expr != nil {
   248  		return ErrAsOfSpecifiedWithReadWrite
   249  	}
   250  	if other.Deferrable != UnspecifiedDeferrableMode {
   251  		if node.Deferrable != UnspecifiedDeferrableMode {
   252  			return errDeferrableSpecifiedMultipleTimes
   253  		}
   254  		node.Deferrable = other.Deferrable
   255  	}
   256  	return nil
   257  }
   258  
   259  // BeginTransaction represents a BEGIN statement
   260  type BeginTransaction struct {
   261  	// FormatWithStart says whether this statement must be formatted with
   262  	// "START" rather than "BEGIN". This is needed if this statement is in a
   263  	// BEGIN ATOMIC block of a procedure or function.
   264  	FormatWithStart bool
   265  	Modes           TransactionModes
   266  }
   267  
   268  // Format implements the NodeFormatter interface.
   269  func (node *BeginTransaction) Format(ctx *FmtCtx) {
   270  	if node.FormatWithStart {
   271  		ctx.WriteString("START TRANSACTION")
   272  	} else {
   273  		ctx.WriteString("BEGIN TRANSACTION")
   274  	}
   275  	ctx.FormatNode(&node.Modes)
   276  }
   277  
   278  // CommitTransaction represents a COMMIT statement.
   279  type CommitTransaction struct{}
   280  
   281  // Format implements the NodeFormatter interface.
   282  func (node *CommitTransaction) Format(ctx *FmtCtx) {
   283  	ctx.WriteString("COMMIT TRANSACTION")
   284  }
   285  
   286  // RollbackTransaction represents a ROLLBACK statement.
   287  type RollbackTransaction struct{}
   288  
   289  // Format implements the NodeFormatter interface.
   290  func (node *RollbackTransaction) Format(ctx *FmtCtx) {
   291  	ctx.WriteString("ROLLBACK TRANSACTION")
   292  }
   293  
   294  // Savepoint represents a SAVEPOINT <name> statement.
   295  type Savepoint struct {
   296  	Name Name
   297  }
   298  
   299  // Format implements the NodeFormatter interface.
   300  func (node *Savepoint) Format(ctx *FmtCtx) {
   301  	ctx.WriteString("SAVEPOINT ")
   302  	ctx.FormatNode(&node.Name)
   303  }
   304  
   305  // ReleaseSavepoint represents a RELEASE SAVEPOINT <name> statement.
   306  type ReleaseSavepoint struct {
   307  	Savepoint Name
   308  }
   309  
   310  // Format implements the NodeFormatter interface.
   311  func (node *ReleaseSavepoint) Format(ctx *FmtCtx) {
   312  	ctx.WriteString("RELEASE SAVEPOINT ")
   313  	ctx.FormatNode(&node.Savepoint)
   314  }
   315  
   316  // RollbackToSavepoint represents a ROLLBACK TO SAVEPOINT <name> statement.
   317  type RollbackToSavepoint struct {
   318  	Savepoint Name
   319  }
   320  
   321  // Format implements the NodeFormatter interface.
   322  func (node *RollbackToSavepoint) Format(ctx *FmtCtx) {
   323  	ctx.WriteString("ROLLBACK TRANSACTION TO SAVEPOINT ")
   324  	ctx.FormatNode(&node.Savepoint)
   325  }