github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/alter_tenant.go (about) 1 // Copyright 2022 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 // ReplicationCutoverTime represent the user-specified cutover time 14 type ReplicationCutoverTime struct { 15 Timestamp Expr 16 Latest bool 17 } 18 19 // AlterTenantReplication represents an ALTER VIRTUAL CLUSTER REPLICATION statement. 20 type AlterTenantReplication struct { 21 TenantSpec *TenantSpec 22 Command JobCommand 23 Cutover *ReplicationCutoverTime 24 Options TenantReplicationOptions 25 } 26 27 var _ Statement = &AlterTenantReplication{} 28 29 // Format implements the NodeFormatter interface. 30 func (n *AlterTenantReplication) Format(ctx *FmtCtx) { 31 ctx.WriteString("ALTER VIRTUAL CLUSTER ") 32 ctx.FormatNode(n.TenantSpec) 33 ctx.WriteByte(' ') 34 if n.Cutover != nil { 35 ctx.WriteString("COMPLETE REPLICATION TO ") 36 if n.Cutover.Latest { 37 ctx.WriteString("LATEST") 38 } else { 39 ctx.WriteString("SYSTEM TIME ") 40 ctx.FormatNode(n.Cutover.Timestamp) 41 } 42 } else if !n.Options.IsDefault() { 43 ctx.WriteString("SET REPLICATION ") 44 ctx.FormatNode(&n.Options) 45 } else if n.Command == PauseJob || n.Command == ResumeJob { 46 ctx.WriteString(JobCommandToStatement[n.Command]) 47 ctx.WriteString(" REPLICATION") 48 } 49 } 50 51 // TenantCapability is a key-value parameter representing a tenant capability. 52 type TenantCapability struct { 53 Name string 54 Value Expr 55 } 56 57 // AlterTenantCapability represents an ALTER VIRTUAL CLUSTER CAPABILITY statement. 58 type AlterTenantCapability struct { 59 TenantSpec *TenantSpec 60 Capabilities []TenantCapability 61 IsRevoke bool 62 63 AllCapabilities bool 64 } 65 66 var _ Statement = &AlterTenantCapability{} 67 68 // Format implements the NodeFormatter interface. 69 func (n *AlterTenantCapability) Format(ctx *FmtCtx) { 70 ctx.WriteString("ALTER VIRTUAL CLUSTER ") 71 ctx.FormatNode(n.TenantSpec) 72 if n.IsRevoke { 73 ctx.WriteString(" REVOKE ") 74 } else { 75 ctx.WriteString(" GRANT ") 76 } 77 if n.AllCapabilities { 78 ctx.WriteString("ALL CAPABILITIES") 79 } else { 80 ctx.WriteString("CAPABILITY ") 81 for i, capability := range n.Capabilities { 82 if i > 0 { 83 ctx.WriteString(", ") 84 } 85 ctx.WriteString(capability.Name) 86 value := capability.Value 87 if value != nil { 88 ctx.WriteString(" = ") 89 ctx.FormatNode(value) 90 } 91 } 92 } 93 } 94 95 // TenantSpec designates a tenant for the ALTER VIRTUAL CLUSTER statements. 96 type TenantSpec struct { 97 Expr Expr 98 IsName bool 99 All bool 100 } 101 102 // alreadyDelimitedAsSyntacticDExpr is an interface that marks 103 // Expr types for which there is never an ambiguity when 104 // the expression syntax is followed by a non-reserved 105 // keyword. When this property is true, that expression 106 // can be pretty-printed without enclosing parentheses in 107 // a context followed by more non-reserved keywords, and 108 // result in syntax that is still unambiguous. 109 // That is, given an expression E and an arbitrary following 110 // word X, the syntax "E X" is always unambiguously parsed 111 // as "(E) X". 112 // 113 // This property is obviously true of "atomic" expressions such as 114 // string and number literals, and also obviously true of 115 // well-enclosed expressions "(...)" / "[...]". However, it is not 116 // always true of other composite expression types. For example, 117 // "A::B" (CastExpr) is not well-delimited because there are 118 // identifiers/keywords such that "A::B C" can be parsed as "A::(B 119 // C)". Consider "'a'::INTERVAL" and the non-reserved keyword 120 // "MINUTE". 121 // 122 // This property is closely related to the d_expr syntactic rule in 123 // the grammar, hence its name. *Approximately* the expression types 124 // produced by the d_expr rule tend to exhibit the "well-delimited" 125 // property. However, this is not a proper equivalence: certain Expr 126 // types are _also_ produced by other parsing rules than d_expr, so 127 // inspection of the contents of the Expr object is necessary to 128 // determine whether it is well-delimited or not (for example, some 129 // FuncExpr objects are well-delimited, and others are not). 130 // Therefore, it is not generally correct to assign the property to 131 // all the d_expr expression *types*. We can only do so for a few 132 // types for which we know that *all possible objects* of that type 133 // are well-delimited, such as Subquery, NumVal or Placeholder. 134 type alreadyDelimitedAsSyntacticDExpr interface { 135 Expr 136 alreadyDelimitedAsSyntacticDExpr() 137 } 138 139 func (*UnresolvedName) alreadyDelimitedAsSyntacticDExpr() {} 140 func (*ParenExpr) alreadyDelimitedAsSyntacticDExpr() {} 141 func (*Subquery) alreadyDelimitedAsSyntacticDExpr() {} 142 func (*Placeholder) alreadyDelimitedAsSyntacticDExpr() {} 143 func (*NumVal) alreadyDelimitedAsSyntacticDExpr() {} 144 func (*StrVal) alreadyDelimitedAsSyntacticDExpr() {} 145 func (dNull) alreadyDelimitedAsSyntacticDExpr() {} 146 147 // Format implements the NodeFormatter interface. 148 func (n *TenantSpec) Format(ctx *FmtCtx) { 149 if n.All { 150 ctx.WriteString("ALL") 151 } else if n.IsName { 152 // Beware to enclose the expression within parentheses if it is 153 // not a simple identifier and is not already enclosed in 154 // parentheses. 155 _, canOmitParentheses := n.Expr.(alreadyDelimitedAsSyntacticDExpr) 156 if !canOmitParentheses { 157 ctx.WriteByte('(') 158 } 159 ctx.FormatNode(n.Expr) 160 if !canOmitParentheses { 161 ctx.WriteByte(')') 162 } 163 } else { 164 ctx.WriteByte('[') 165 ctx.FormatNode(n.Expr) 166 ctx.WriteByte(']') 167 } 168 } 169 170 // AlterTenantRename represents an ALTER VIRTUAL CLUSTER RENAME statement. 171 type AlterTenantRename struct { 172 TenantSpec *TenantSpec 173 174 // For NewName we only support the name syntax, not the numeric 175 // syntax. So we could make-do with just an Expr here. However, we 176 // like to use TenantSpec as a container for that name because it 177 // takes care of pretty-printing with all the special rules. See the 178 // doc of (*TenantSpec).Format() for details. 179 NewName *TenantSpec 180 } 181 182 var _ Statement = &AlterTenantRename{} 183 184 // Format implements the NodeFormatter interface. 185 func (n *AlterTenantRename) Format(ctx *FmtCtx) { 186 ctx.WriteString("ALTER VIRTUAL CLUSTER ") 187 ctx.FormatNode(n.TenantSpec) 188 ctx.WriteString(" RENAME TO ") 189 ctx.FormatNode(n.NewName) 190 } 191 192 // AlterTenantService represents an ALTER VIRTUAL CLUSTER START/STOP SERVICE statement. 193 type AlterTenantService struct { 194 TenantSpec *TenantSpec 195 Command TenantServiceCmd 196 } 197 198 // TenantServiceCmd represents a parameter to ALTER VIRTUAL CLUSTER. 199 type TenantServiceCmd int8 200 201 const ( 202 // TenantStartServiceExternal encodes START SERVICE EXTERNAL. 203 TenantStartServiceExternal TenantServiceCmd = 0 204 // TenantStartServiceExternal encodes START SERVICE SHARED. 205 TenantStartServiceShared TenantServiceCmd = 1 206 // TenantStartServiceExternal encodes STOP SERVICE. 207 TenantStopService TenantServiceCmd = 2 208 ) 209 210 var _ Statement = &AlterTenantService{} 211 212 // Format implements the NodeFormatter interface. 213 func (n *AlterTenantService) Format(ctx *FmtCtx) { 214 ctx.WriteString("ALTER VIRTUAL CLUSTER ") 215 ctx.FormatNode(n.TenantSpec) 216 switch n.Command { 217 case TenantStartServiceExternal: 218 ctx.WriteString(" START SERVICE EXTERNAL") 219 case TenantStartServiceShared: 220 ctx.WriteString(" START SERVICE SHARED") 221 case TenantStopService: 222 ctx.WriteString(" STOP SERVICE") 223 } 224 }