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  }