github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/alter_pk.go (about) 1 // Copyright 2021 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 "gopkg.in/src-d/go-errors.v1" 21 22 "github.com/dolthub/go-mysql-server/sql" 23 "github.com/dolthub/go-mysql-server/sql/transform" 24 "github.com/dolthub/go-mysql-server/sql/types" 25 ) 26 27 type PKAction byte 28 29 const ( 30 PrimaryKeyAction_Create PKAction = iota 31 PrimaryKeyAction_Drop 32 ) 33 34 // ErrNotPrimaryKeyAlterable is return when a table cannot be determined to be primary key alterable 35 var ErrNotPrimaryKeyAlterable = errors.NewKind("error: table is not primary key alterable") 36 37 type AlterPK struct { 38 ddlNode 39 40 Action PKAction 41 Table sql.Node 42 Columns []sql.IndexColumn 43 Catalog sql.Catalog 44 targetSchema sql.Schema 45 } 46 47 var _ sql.Node = (*AlterPK)(nil) 48 var _ sql.Databaser = (*AlterPK)(nil) 49 var _ sql.SchemaTarget = (*AlterPK)(nil) 50 var _ sql.CollationCoercible = (*AlterPK)(nil) 51 52 func NewAlterCreatePk(db sql.Database, table sql.Node, columns []sql.IndexColumn) *AlterPK { 53 return &AlterPK{ 54 Action: PrimaryKeyAction_Create, 55 ddlNode: ddlNode{Db: db}, 56 Table: table, 57 Columns: columns, 58 } 59 } 60 61 func NewAlterDropPk(db sql.Database, table sql.Node) *AlterPK { 62 return &AlterPK{ 63 Action: PrimaryKeyAction_Drop, 64 Table: table, 65 ddlNode: ddlNode{Db: db}, 66 } 67 } 68 69 func (a *AlterPK) Resolved() bool { 70 return a.Table.Resolved() && a.ddlNode.Resolved() && a.targetSchema.Resolved() 71 } 72 73 func (a *AlterPK) IsReadOnly() bool { 74 return false 75 } 76 77 func (a *AlterPK) String() string { 78 action := "add" 79 if a.Action == PrimaryKeyAction_Drop { 80 action = "drop" 81 } 82 83 return fmt.Sprintf("alter table %s %s primary key", a.Table.String(), action) 84 } 85 86 func (a *AlterPK) Schema() sql.Schema { 87 return types.OkResultSchema 88 } 89 90 func (a AlterPK) WithTargetSchema(schema sql.Schema) (sql.Node, error) { 91 a.targetSchema = schema 92 return &a, nil 93 } 94 95 func (a *AlterPK) TargetSchema() sql.Schema { 96 return a.targetSchema 97 } 98 99 func (a *AlterPK) Expressions() []sql.Expression { 100 return transform.WrappedColumnDefaults(a.targetSchema) 101 } 102 103 func (a AlterPK) WithExpressions(exprs ...sql.Expression) (sql.Node, error) { 104 if len(exprs) != len(a.targetSchema) { 105 return nil, sql.ErrInvalidChildrenNumber.New(a, len(exprs), len(a.targetSchema)) 106 } 107 108 sch, err := transform.SchemaWithDefaults(a.targetSchema, exprs[:len(a.targetSchema)]) 109 if err != nil { 110 return nil, err 111 } 112 a.targetSchema = sch 113 114 return &a, nil 115 } 116 117 func HasPrimaryKeys(table sql.Table) bool { 118 for _, c := range table.Schema() { 119 if c.PrimaryKey { 120 return true 121 } 122 } 123 124 return false 125 } 126 127 func (a AlterPK) WithChildren(children ...sql.Node) (sql.Node, error) { 128 if len(children) != 1 { 129 return nil, sql.ErrInvalidChildrenNumber.New(a, len(children), 1) 130 } 131 132 a.Table = children[0] 133 return &a, nil 134 } 135 136 // Children implements the sql.Node interface. 137 func (a *AlterPK) Children() []sql.Node { 138 return []sql.Node{a.Table} 139 } 140 141 // WithDatabase implements the sql.Databaser interface. 142 func (a AlterPK) WithDatabase(database sql.Database) (sql.Node, error) { 143 a.Db = database 144 return &a, nil 145 } 146 147 // CheckPrivileges implements the interface sql.Node. 148 func (a *AlterPK) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 149 subject := sql.PrivilegeCheckSubject{ 150 Database: a.Database().Name(), 151 Table: getTableName(a.Table), 152 } 153 154 return opChecker.UserHasPrivileges(ctx, 155 sql.NewPrivilegedOperation(subject, sql.PrivilegeType_Alter)) 156 } 157 158 // CollationCoercibility implements the interface sql.CollationCoercible. 159 func (*AlterPK) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 160 return sql.Collation_binary, 7 161 }