github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/alter_user.go (about) 1 // Copyright 2024 Dolthub, 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import ( 18 "fmt" 19 20 "github.com/dolthub/go-mysql-server/sql" 21 "github.com/dolthub/go-mysql-server/sql/types" 22 ) 23 24 // AlterUser represents the statement ALTER USER. 25 type AlterUser struct { 26 IfExists bool 27 User AuthenticatedUser 28 MySQLDb sql.Database 29 } 30 31 var _ sql.Node = (*AlterUser)(nil) 32 var _ sql.Databaser = (*AlterUser)(nil) 33 var _ sql.CollationCoercible = (*AlterUser)(nil) 34 35 // Schema implements the interface sql.Node. 36 func (a *AlterUser) Schema() sql.Schema { 37 return types.OkResultSchema 38 } 39 40 // String implements the interface sql.Node. 41 func (a *AlterUser) String() string { 42 ifExists := "" 43 if a.IfExists { 44 ifExists = "IfExists: " 45 } 46 return fmt.Sprintf("AlterUser(%s%s)", ifExists, a.User.String("")) 47 } 48 49 // Database implements the interface sql.Databaser. 50 func (a *AlterUser) Database() sql.Database { 51 return a.MySQLDb 52 } 53 54 // WithDatabase implements the interface sql.Databaser. 55 func (a *AlterUser) WithDatabase(db sql.Database) (sql.Node, error) { 56 aa := *a 57 aa.MySQLDb = db 58 return &aa, nil 59 } 60 61 // Resolved implements the interface sql.Node. 62 func (a *AlterUser) Resolved() bool { 63 _, ok := a.MySQLDb.(sql.UnresolvedDatabase) 64 return !ok 65 } 66 67 // IsReadOnly implements the interface sql.Node. 68 func (a *AlterUser) IsReadOnly() bool { 69 return false 70 } 71 72 // Children implements the interface sql.Node. 73 func (a *AlterUser) Children() []sql.Node { 74 return nil 75 } 76 77 // WithChildren implements the interface sql.Node. 78 func (a *AlterUser) WithChildren(children ...sql.Node) (sql.Node, error) { 79 if len(children) != 0 { 80 return nil, sql.ErrInvalidChildrenNumber.New(a, len(children), 0) 81 } 82 return a, nil 83 } 84 85 // CheckPrivileges implements the interface sql.Node. 86 func (a *AlterUser) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 87 // From the MySQL reference on ALTER USER: 88 // https://dev.mysql.com/doc/refman/8.0/en/alter-user.html 89 // ALTER USER generally requires either the global `CREATE USER` privilege, or the `UPDATE` privilege 90 // for the `mysql` system schema. 91 if opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation( 92 sql.PrivilegeCheckSubject{Database: "mysql"}, sql.PrivilegeType_Update)) { 93 return true 94 } else if opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation( 95 sql.PrivilegeCheckSubject{}, sql.PrivilegeType_CreateUser)) { 96 return true 97 } 98 99 // There are several exceptions to the general privilege requirements. Currently, the only relevant one is 100 // that any client who connects to the server using a non-anonymous account can change the password for that account. 101 authenticatedUser := ctx.Session.Client() 102 if a.User.Name == authenticatedUser.User { 103 return true 104 } 105 106 return false 107 } 108 109 // CollationCoercibility implements the interface sql.CollationCoercible. 110 func (a *AlterUser) CollationCoercibility(_ *sql.Context) (collation sql.CollationID, coercibility byte) { 111 return sql.Collation_binary, 7 112 }