github.com/dolthub/go-mysql-server@v0.18.0/sql/mysql_db/procs_priv.go (about) 1 // Copyright 2023 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 mysql_db 16 17 import ( 18 "strings" 19 "sync" 20 "time" 21 22 "github.com/dolthub/vitess/go/sqltypes" 23 24 "github.com/dolthub/go-mysql-server/sql" 25 "github.com/dolthub/go-mysql-server/sql/expression" 26 "github.com/dolthub/go-mysql-server/sql/in_mem_table" 27 "github.com/dolthub/go-mysql-server/sql/types" 28 ) 29 30 const procsPrivTblName = "procs_priv" 31 32 var procsPrivTblSchema = buildProcsPrivSchema() 33 34 func NewUserProcsIndexedSetTable(set in_mem_table.IndexedSet[*User], lock, rlock sync.Locker) *in_mem_table.MultiIndexedSetTable[*User] { 35 table := in_mem_table.NewMultiIndexedSetTable[*User]( 36 procsPrivTblName, 37 procsPrivTblSchema, 38 sql.Collation_utf8mb3_bin, 39 set, 40 in_mem_table.MultiValueOps[*User]{ 41 ToRows: UserToProcsPrivRows, 42 FromRow: UserFromProcsPrivRow, 43 AddRow: UserAddProcsPrivRow, 44 DeleteRow: UserRemoveProcsPrivRow, 45 }, 46 lock, 47 rlock, 48 ) 49 return table 50 } 51 52 func newEmptyRow(ctx *sql.Context) sql.Row { 53 row := make(sql.Row, len(procsPrivTblSchema)) 54 var err error 55 for i, col := range procsPrivTblSchema { 56 row[i], err = col.Default.Eval(ctx, nil) 57 if err != nil { 58 panic(err) // Schema is static. New rows should never fail. 59 } 60 } 61 return row 62 } 63 64 func UserToProcsPrivRows(ctx *sql.Context, user *User) ([]sql.Row, error) { 65 66 var ans []sql.Row 67 for _, dbSet := range user.PrivilegeSet.GetDatabases() { 68 for _, routineSet := range dbSet.GetRoutines() { 69 if routineSet.Count() == 0 { 70 continue 71 } 72 row := newEmptyRow(ctx) 73 74 row[procsPrivTblColIndex_Host] = user.Host 75 row[procsPrivTblColIndex_Db] = dbSet.Name() 76 row[procsPrivTblColIndex_User] = user.User 77 row[procsPrivTblColIndex_RoutineName] = routineSet.RoutineName() 78 row[procsPrivTblColIndex_RoutineType] = routineSet.RoutineType() 79 80 var privs []string 81 for _, priv := range routineSet.ToSlice() { 82 switch priv { 83 case sql.PrivilegeType_Execute: 84 privs = append(privs, "Execute") 85 case sql.PrivilegeType_GrantOption: 86 privs = append(privs, "Grant") // MySQL prints just "Grant", and not "Grant Option" 87 case sql.PrivilegeType_AlterRoutine: 88 privs = append(privs, "Alter Routine") 89 } 90 } 91 privsStr := strings.Join(privs, ",") 92 row[procsPrivTblColIndex_ProcPriv] = privsStr 93 94 ans = append(ans, row) 95 } 96 } 97 98 return ans, nil 99 } 100 101 func UserFromProcsPrivRow(ctx *sql.Context, row sql.Row) (*User, error) { 102 panic("implement me") // Currently inaccessible code path. 103 } 104 105 func UserAddProcsPrivRow(ctx *sql.Context, row sql.Row, user *User) (*User, error) { 106 panic("implement me") // Currently inaccessible code path. 107 } 108 109 func UserRemoveProcsPrivRow(ctx *sql.Context, row sql.Row, user *User) (*User, error) { 110 panic("implement me") // Currently inaccessible code path. 111 } 112 113 // buildProcsPrivSchema builds the schema for the "procs_priv" Grant Table. 114 // MySQL Table for reference: 115 // 116 // mysql> show create table mysql.procs_priv: 117 // 118 // CREATE TABLE `procs_priv` ( 119 // 120 // `Host` char(255) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT '', 121 // `Db` char(64) COLLATE utf8mb3_bin NOT NULL DEFAULT '', 122 // `User` char(32) COLLATE utf8mb3_bin NOT NULL DEFAULT '', 123 // `Routine_name` char(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '', 124 // `Routine_type` enum('FUNCTION','PROCEDURE') COLLATE utf8mb3_bin NOT NULL, 125 // `Grantor` varchar(288) COLLATE utf8mb3_bin NOT NULL DEFAULT '', 126 // `Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '', 127 // `Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 128 // PRIMARY KEY (`Host`,`User`,`Db`,`Routine_name`,`Routine_type`), 129 // KEY `Grantor` (`Grantor` 130 // ) 131 func buildProcsPrivSchema() sql.Schema { 132 len255_asciii := types.MustCreateString(sqltypes.Char, 255, sql.Collation_ascii_general_ci) 133 len64_utf8_bin := types.MustCreateString(sqltypes.Char, 64, sql.Collation_utf8_bin) 134 len64_utf8_gen := types.MustCreateString(sqltypes.Char, 64, sql.Collation_utf8_general_ci) 135 len32_utf8 := types.MustCreateString(sqltypes.Char, 32, sql.Collation_utf8_bin) 136 routine_types_enum := types.MustCreateEnumType([]string{"FUNCTION", "PROCEDURE"}, sql.Collation_utf8_bin) 137 varchar288_utf8 := types.MustCreateString(sqltypes.VarChar, 288, sql.Collation_utf8_bin) 138 set_privs := types.MustCreateSetType([]string{"Execute", "Alter Routine", "Grant"}, sql.Collation_utf8_general_ci) 139 140 return sql.Schema{ 141 columnTemplate("Host", procsPrivTblName, true, &sql.Column{ 142 Type: len255_asciii, 143 Default: mustDefault(expression.NewLiteral("", len255_asciii), len255_asciii, true, false), 144 Nullable: false}), 145 columnTemplate("Db", procsPrivTblName, true, &sql.Column{ 146 Type: len64_utf8_bin, 147 Default: mustDefault(expression.NewLiteral("", len64_utf8_bin), len64_utf8_bin, true, false), 148 Nullable: false}), 149 columnTemplate("User", procsPrivTblName, true, &sql.Column{ 150 Type: len32_utf8, 151 Default: mustDefault(expression.NewLiteral("", len32_utf8), len32_utf8, true, false), 152 Nullable: false}), 153 columnTemplate("Routine_name", procsPrivTblName, true, &sql.Column{ 154 Type: len64_utf8_gen, 155 Default: mustDefault(expression.NewLiteral("", len64_utf8_gen), len64_utf8_gen, true, false), 156 Nullable: false}), 157 columnTemplate("Routine_type", procsPrivTblName, true, &sql.Column{ 158 Type: routine_types_enum, 159 Default: mustDefault(expression.NewLiteral("PROCEDURE", routine_types_enum), routine_types_enum, true, false), 160 Nullable: false}), 161 columnTemplate("Grantor", procsPrivTblName, false, &sql.Column{ 162 Type: varchar288_utf8, 163 Default: mustDefault(expression.NewLiteral("", varchar288_utf8), varchar288_utf8, true, false), 164 Nullable: false}), 165 columnTemplate("Proc_priv", procsPrivTblName, false, &sql.Column{ 166 Type: set_privs, 167 Default: mustDefault(expression.NewLiteral("", set_privs), set_privs, true, false), 168 Nullable: false}), 169 columnTemplate("Timestamp", tablesPrivTblName, false, &sql.Column{ 170 Type: types.Timestamp, 171 Default: mustDefault(expression.NewLiteral(time.Unix(1, 0).UTC(), types.Timestamp), types.Timestamp, true, false), 172 Nullable: false}), 173 } 174 } 175 176 // The column indexes of the "procs_priv" Grant Table. 177 // https://dev.mysql.com/doc/refman/8.0/en/grant-tables.html#grant-tables-procs-priv 178 // https://mariadb.com/kb/en/mysqlprocs_priv-table/ 179 const ( 180 procsPrivTblColIndex_Host int = iota 181 procsPrivTblColIndex_Db 182 procsPrivTblColIndex_User 183 procsPrivTblColIndex_RoutineName 184 procsPrivTblColIndex_RoutineType 185 procsPrivTblColIndex_Grantor 186 procsPrivTblColIndex_ProcPriv 187 procsPrivTblColIndex_Timestamp 188 )