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 }