github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/insert.go (about) 1 // Copyright 2020-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 "strings" 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 ) 25 26 // ErrInsertIntoNotSupported is thrown when a table doesn't support inserts 27 var ErrInsertIntoNotSupported = errors.NewKind("table doesn't support INSERT INTO") 28 var ErrReplaceIntoNotSupported = errors.NewKind("table doesn't support REPLACE INTO") 29 var ErrOnDuplicateKeyUpdateNotSupported = errors.NewKind("table doesn't support ON DUPLICATE KEY UPDATE") 30 var ErrAutoIncrementNotSupported = errors.NewKind("table doesn't support AUTO_INCREMENT") 31 var ErrInsertIntoUnsupportedValues = errors.NewKind("%T is unsupported for inserts") 32 var ErrInsertIntoIncompatibleTypes = errors.NewKind("cannot convert type %s to %s") 33 34 // cc: https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sql-mode-strict 35 // The INSERT IGNORE syntax applies to these ignorable errors 36 // ER_BAD_NULL_ERROR - yes 37 // ER_DUP_ENTRY - yes 38 // ER_DUP_ENTRY_WITH_KEY_NAME - Yes 39 // ER_DUP_KEY - kinda 40 // ER_NO_PARTITION_FOR_GIVEN_VALUE - yes 41 // ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT - No 42 // ER_NO_REFERENCED_ROW_2 - Yes 43 // ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET - No 44 // ER_ROW_IS_REFERENCED_2 - Yes 45 // ER_SUBQUERY_NO_1_ROW - yes 46 // ER_VIEW_CHECK_FAILED - No 47 var IgnorableErrors = []*errors.Kind{sql.ErrInsertIntoNonNullableProvidedNull, 48 sql.ErrPrimaryKeyViolation, 49 sql.ErrPartitionNotFound, 50 sql.ErrExpectedSingleRow, 51 sql.ErrForeignKeyChildViolation, 52 sql.ErrForeignKeyParentViolation, 53 sql.ErrDuplicateEntry, 54 sql.ErrUniqueKeyViolation, 55 sql.ErrCheckConstraintViolated, 56 } 57 58 // InsertInto is the top level node for INSERT INTO statements. It has a source for rows and a destination to insert 59 // them into. 60 type InsertInto struct { 61 db sql.Database 62 Destination sql.Node 63 Source sql.Node 64 ColumnNames []string 65 IsReplace bool 66 HasUnspecifiedAutoInc bool 67 OnDupExprs []sql.Expression 68 checks sql.CheckConstraints 69 Ignore bool 70 } 71 72 var _ sql.Databaser = (*InsertInto)(nil) 73 var _ sql.Node = (*InsertInto)(nil) 74 var _ sql.Expressioner = (*InsertInto)(nil) 75 var _ sql.CollationCoercible = (*InsertInto)(nil) 76 var _ DisjointedChildrenNode = (*InsertInto)(nil) 77 78 // NewInsertInto creates an InsertInto node. 79 func NewInsertInto(db sql.Database, dst, src sql.Node, isReplace bool, cols []string, onDupExprs []sql.Expression, ignore bool) *InsertInto { 80 return &InsertInto{ 81 db: db, 82 Destination: dst, 83 Source: src, 84 ColumnNames: cols, 85 IsReplace: isReplace, 86 OnDupExprs: onDupExprs, 87 Ignore: ignore, 88 } 89 } 90 91 var _ sql.CheckConstraintNode = (*RenameColumn)(nil) 92 93 func (ii *InsertInto) Checks() sql.CheckConstraints { 94 return ii.checks 95 } 96 97 func (ii *InsertInto) WithChecks(checks sql.CheckConstraints) sql.Node { 98 ret := *ii 99 ret.checks = checks 100 return &ret 101 } 102 103 func (ii *InsertInto) Dispose() { 104 disposeNode(ii.Source) 105 } 106 107 // Schema implements the sql.Node interface. 108 // Insert nodes return rows that are inserted. Replaces return a concatenation of the deleted row and the inserted row. 109 // If no row was deleted, the value of those columns is nil. 110 func (ii *InsertInto) Schema() sql.Schema { 111 if ii.IsReplace { 112 return append(ii.Destination.Schema(), ii.Destination.Schema()...) 113 } 114 return ii.Destination.Schema() 115 } 116 117 func (ii *InsertInto) Children() []sql.Node { 118 // The source node is analyzed completely independently, so we don't include it in children 119 return []sql.Node{ii.Destination} 120 } 121 122 func (ii *InsertInto) Database() sql.Database { 123 return ii.db 124 } 125 126 func (ii *InsertInto) IsReadOnly() bool { 127 return false 128 } 129 130 func (ii *InsertInto) WithDatabase(database sql.Database) (sql.Node, error) { 131 nc := *ii 132 nc.db = database 133 return &nc, nil 134 } 135 136 func (ii InsertInto) WithColumnNames(cols []string) *InsertInto { 137 ii.ColumnNames = cols 138 return &ii 139 } 140 141 // InsertDestination is a wrapper for a table to be used with InsertInto.Destination that allows the schema to be 142 // overridden. This is useful when the table in question has late-resolving column defaults. 143 type InsertDestination struct { 144 UnaryNode 145 DestinationName string 146 Sch sql.Schema 147 } 148 149 var _ sql.Node = (*InsertDestination)(nil) 150 var _ sql.Nameable = (*InsertDestination)(nil) 151 var _ sql.Expressioner = (*InsertDestination)(nil) 152 var _ sql.CollationCoercible = (*InsertDestination)(nil) 153 154 func NewInsertDestination(schema sql.Schema, node sql.Node) *InsertDestination { 155 nameable := node.(sql.Nameable) 156 return &InsertDestination{ 157 UnaryNode: UnaryNode{Child: node}, 158 Sch: schema, 159 DestinationName: nameable.Name(), 160 } 161 } 162 163 func (id *InsertDestination) Expressions() []sql.Expression { 164 return transform.WrappedColumnDefaults(id.Sch) 165 } 166 167 func (id InsertDestination) WithExpressions(exprs ...sql.Expression) (sql.Node, error) { 168 if len(exprs) != len(id.Sch) { 169 return nil, sql.ErrInvalidChildrenNumber.New(id, len(exprs), len(id.Sch)) 170 } 171 172 sch, err := transform.SchemaWithDefaults(id.Sch, exprs) 173 if err != nil { 174 return nil, err 175 } 176 177 id.Sch = sch 178 return &id, nil 179 } 180 181 func (id *InsertDestination) Name() string { 182 return id.DestinationName 183 } 184 185 func (id *InsertDestination) IsReadOnly() bool { 186 return true 187 } 188 189 func (id *InsertDestination) String() string { 190 return id.UnaryNode.Child.String() 191 } 192 193 func (id *InsertDestination) DebugString() string { 194 pr := sql.NewTreePrinter() 195 pr.WriteNode("InsertDestination") 196 var children []string 197 for _, col := range id.Sch { 198 children = append(children, sql.DebugString(col.Default)) 199 } 200 children = append(children, sql.DebugString(id.Child)) 201 202 pr.WriteChildren(children...) 203 204 return pr.String() 205 } 206 207 func (id *InsertDestination) Schema() sql.Schema { 208 return id.Sch 209 } 210 211 func (id *InsertDestination) Resolved() bool { 212 if !id.UnaryNode.Resolved() { 213 return false 214 } 215 216 for _, col := range id.Sch { 217 if !col.Default.Resolved() { 218 return false 219 } 220 } 221 222 return true 223 } 224 225 func (id InsertDestination) WithChildren(children ...sql.Node) (sql.Node, error) { 226 if len(children) != 1 { 227 return nil, sql.ErrInvalidChildrenNumber.New(id, len(children), 1) 228 } 229 230 id.UnaryNode.Child = children[0] 231 return &id, nil 232 } 233 234 // CheckPrivileges implements the interface sql.Node. 235 func (id *InsertDestination) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 236 return id.Child.CheckPrivileges(ctx, opChecker) 237 } 238 239 // CollationCoercibility implements the interface sql.CollationCoercible. 240 func (id *InsertDestination) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 241 return sql.GetCoercibility(ctx, id.Child) 242 } 243 244 // WithChildren implements the Node interface. 245 func (ii *InsertInto) WithChildren(children ...sql.Node) (sql.Node, error) { 246 if len(children) != 1 { 247 return nil, sql.ErrInvalidChildrenNumber.New(ii, len(children), 1) 248 } 249 250 np := *ii 251 np.Destination = children[0] 252 return &np, nil 253 } 254 255 // CheckPrivileges implements the interface sql.Node. 256 func (ii *InsertInto) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 257 subject := sql.PrivilegeCheckSubject{ 258 Database: CheckPrivilegeNameForDatabase(ii.db), 259 Table: getTableName(ii.Destination), 260 } 261 262 if ii.IsReplace { 263 return opChecker.UserHasPrivileges(ctx, 264 sql.NewPrivilegedOperation(subject, sql.PrivilegeType_Insert, sql.PrivilegeType_Delete)) 265 } else { 266 return opChecker.UserHasPrivileges(ctx, 267 sql.NewPrivilegedOperation(subject, sql.PrivilegeType_Insert)) 268 } 269 } 270 271 // CollationCoercibility implements the interface sql.CollationCoercible. 272 func (*InsertInto) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 273 return sql.Collation_binary, 7 274 } 275 276 // DisjointedChildren implements the interface DisjointedChildrenNode. 277 func (ii *InsertInto) DisjointedChildren() [][]sql.Node { 278 return [][]sql.Node{ 279 {ii.Destination}, 280 {ii.Source}, 281 } 282 } 283 284 // WithDisjointedChildren implements the interface DisjointedChildrenNode. 285 func (ii *InsertInto) WithDisjointedChildren(children [][]sql.Node) (sql.Node, error) { 286 if len(children) != 2 || len(children[0]) != 1 || len(children[1]) != 1 { 287 return nil, sql.ErrInvalidChildrenNumber.New(ii, len(children), 2) 288 } 289 np := *ii 290 np.Destination = children[0][0] 291 np.Source = children[1][0] 292 return &np, nil 293 } 294 295 // WithSource sets the source node for this insert, which is analyzed separately 296 func (ii *InsertInto) WithSource(src sql.Node) *InsertInto { 297 np := *ii 298 np.Source = src 299 return &np 300 } 301 302 // WithUnspecifiedAutoIncrement sets the unspecified auto increment flag for this insert operation. Inserts with this 303 // property set the LAST_INSERT_ID session variable, whereas inserts that manually specify values for an auto-insert 304 // column do not. 305 func (ii *InsertInto) WithUnspecifiedAutoIncrement(unspecifiedAutoIncrement bool) *InsertInto { 306 np := *ii 307 np.HasUnspecifiedAutoInc = unspecifiedAutoIncrement 308 return &np 309 } 310 311 func (ii InsertInto) String() string { 312 pr := sql.NewTreePrinter() 313 if ii.IsReplace { 314 _ = pr.WriteNode("Replace(%s)", strings.Join(ii.ColumnNames, ", ")) 315 } else { 316 _ = pr.WriteNode("Insert(%s)", strings.Join(ii.ColumnNames, ", ")) 317 } 318 _ = pr.WriteChildren(ii.Destination.String(), ii.Source.String()) 319 return pr.String() 320 } 321 322 func (ii InsertInto) DebugString() string { 323 pr := sql.NewTreePrinter() 324 if ii.IsReplace { 325 _ = pr.WriteNode("Replace(%s)", strings.Join(ii.ColumnNames, ", ")) 326 } else { 327 _ = pr.WriteNode("Insert(%s)", strings.Join(ii.ColumnNames, ", ")) 328 } 329 _ = pr.WriteChildren(sql.DebugString(ii.Destination), sql.DebugString(ii.Source)) 330 return pr.String() 331 } 332 333 func (ii *InsertInto) Expressions() []sql.Expression { 334 return append(ii.OnDupExprs, ii.checks.ToExpressions()...) 335 } 336 337 func (ii InsertInto) WithExpressions(newExprs ...sql.Expression) (sql.Node, error) { 338 if len(newExprs) != len(ii.OnDupExprs)+len(ii.checks) { 339 return nil, sql.ErrInvalidChildrenNumber.New(ii, len(newExprs), len(ii.OnDupExprs)+len(ii.checks)) 340 } 341 342 ii.OnDupExprs = newExprs[:len(ii.OnDupExprs)] 343 344 var err error 345 ii.checks, err = ii.checks.FromExpressions(newExprs[len(ii.OnDupExprs):]) 346 if err != nil { 347 return nil, err 348 } 349 350 return &ii, nil 351 } 352 353 // Resolved implements the Resolvable interface. 354 func (ii *InsertInto) Resolved() bool { 355 if !ii.Destination.Resolved() || !ii.Source.Resolved() { 356 return false 357 } 358 for _, updateExpr := range ii.OnDupExprs { 359 if !updateExpr.Resolved() { 360 return false 361 } 362 } 363 for _, checkExpr := range ii.checks { 364 if !checkExpr.Expr.Resolved() { 365 return false 366 } 367 } 368 return true 369 } 370 371 func GetInsertable(node sql.Node) (sql.InsertableTable, error) { 372 switch node := node.(type) { 373 case *Exchange: 374 return GetInsertable(node.Child) 375 case sql.InsertableTable: 376 return node, nil 377 case *ResolvedTable: 378 return getInsertableTable(node.Table) 379 case sql.TableWrapper: 380 return getInsertableTable(node.Underlying()) 381 case *InsertDestination: 382 return GetInsertable(node.Child) 383 case *PrependNode: 384 return GetInsertable(node.Child) 385 default: 386 return nil, ErrInsertIntoNotSupported.New() 387 } 388 } 389 390 func getInsertableTable(t sql.Table) (sql.InsertableTable, error) { 391 switch t := t.(type) { 392 case sql.InsertableTable: 393 return t, nil 394 case sql.TableWrapper: 395 return getInsertableTable(t.Underlying()) 396 default: 397 return nil, ErrInsertIntoNotSupported.New() 398 } 399 }