Skip to content

Commit

Permalink
DDL: add two limits for JSON column: used as key and not null default…
Browse files Browse the repository at this point in the history
… value. (pingcap#3401)
  • Loading branch information
hicqu authored Jun 8, 2017
1 parent eb2b32e commit 72981fd
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 2 deletions.
8 changes: 8 additions & 0 deletions ddl/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ var (
errBadField = terror.ClassDDL.New(codeBadField, "Unknown column '%s' in '%s'")
errInvalidDefault = terror.ClassDDL.New(codeInvalidDefault, "Invalid default value for '%s'")
errInvalidUseOfNull = terror.ClassDDL.New(codeInvalidUseOfNull, "Invalid use of NULL value")
// errJSONUsedAsKey forbiddens to use JSON as key or index.
errJSONUsedAsKey = terror.ClassDDL.New(codeJSONUsedAsKey, mysql.MySQLErrName[mysql.ErrJSONUsedAsKey])
// errBlobCantHaveDefault forbiddens to give not null default value to TEXT/BLOB/JSON.
errBlobCantHaveDefault = terror.ClassDDL.New(codeBlobCantHaveDefault, mysql.MySQLErrName[mysql.ErrBlobCantHaveDefault])

// ErrInvalidDBState returns for invalid database state.
ErrInvalidDBState = terror.ClassDDL.New(codeInvalidDBState, "invalid database state")
Expand Down Expand Up @@ -520,6 +524,8 @@ const (
codeInvalidUseOfNull = 1138
codeBlobKeyWithoutLength = 1170
codeInvalidOnUpdate = 1294
codeJSONUsedAsKey = 3152
codeBlobCantHaveDefault = 1101
)

func init() {
Expand All @@ -541,6 +547,8 @@ func init() {
codeBadField: mysql.ErrBadField,
codeInvalidDefault: mysql.ErrInvalidDefault,
codeInvalidUseOfNull: mysql.ErrInvalidUseOfNull,
codeJSONUsedAsKey: mysql.ErrJSONUsedAsKey,
codeBlobCantHaveDefault: mysql.ErrBlobCantHaveDefault,
}
terror.ErrClassToMySQLCodes[terror.ClassDDL] = ddlMySQLErrCodes
}
19 changes: 18 additions & 1 deletion ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ func buildColumnAndConstraint(ctx context.Context, offset int,
return col, cts, nil
}

// checkColumnCantHaveDefaultValue checks the column can have value as default or not.
// Now, TEXT/BLOB/JSON can't have not null value as default.
func checkColumnCantHaveDefaultValue(col *table.Column, value interface{}) (err error) {
if value != nil && (col.Tp == mysql.TypeJSON ||
col.Tp == mysql.TypeTinyBlob || col.Tp == mysql.TypeMediumBlob ||
col.Tp == mysql.TypeLongBlob || col.Tp == mysql.TypeBlob) {
// TEXT/BLOB/JSON can't have not null default values.
return errBlobCantHaveDefault.GenByArgs(col.Name.O)
}
return nil
}

// columnDefToCol converts ColumnDef to Col and TableConstraints.
func columnDefToCol(ctx context.Context, offset int, colDef *ast.ColumnDef) (*table.Column, []*ast.Constraint, error) {
constraints := []*ast.Constraint{}
Expand Down Expand Up @@ -292,6 +304,9 @@ func columnDefToCol(ctx context.Context, offset int, colDef *ast.ColumnDef) (*ta
if err != nil {
return nil, nil, ErrColumnBadNull.Gen("invalid default value - %s", err)
}
if err = checkColumnCantHaveDefaultValue(col, value); err != nil {
return nil, nil, errors.Trace(err)
}
col.DefaultValue = value
hasDefaultValue = true
removeOnUpdateNowFlag(col)
Expand Down Expand Up @@ -988,6 +1003,9 @@ func setDefaultAndComment(ctx context.Context, col *table.Column, options []*ast
if err != nil {
return ErrColumnBadNull.Gen("invalid default value - %s", err)
}
if err = checkColumnCantHaveDefaultValue(col, value); err != nil {
return errors.Trace(err)
}
col.DefaultValue = value
hasDefaultValue = true
case ast.ColumnOptionComment:
Expand All @@ -1004,7 +1022,6 @@ func setDefaultAndComment(ctx context.Context, col *table.Column, options []*ast
if !expression.IsCurrentTimeExpr(opt.Expr) {
return ErrInvalidOnUpdate.Gen("invalid ON UPDATE for - %s", col.Name)
}

col.Flag |= mysql.OnUpdateNowFlag
setOnUpdateNow = true
default:
Expand Down
5 changes: 5 additions & 0 deletions ddl/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ func buildIndexColumns(columns []*model.ColumnInfo, idxColNames []*ast.IndexColN
return nil, errKeyColumnDoesNotExits.Gen("column does not exist: %s", ic.Column.Name)
}

// JSON column cannot index.
if col.FieldType.Tp == mysql.TypeJSON {
return nil, errors.Trace(errJSONUsedAsKey.GenByArgs(col.Name.O))
}

// Length must be specified for BLOB and TEXT column indexes.
if types.IsTypeBlob(col.FieldType.Tp) && ic.Length == types.UnspecifiedLength {
return nil, errors.Trace(errBlobKeyWithoutLength)
Expand Down
27 changes: 27 additions & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"testing"
"time"

"github.com/juju/errors"
"github.com/ngaut/log"
. "github.com/pingcap/check"
"github.com/pingcap/tidb"
Expand All @@ -28,6 +29,7 @@ import (
"github.com/pingcap/tidb/inspectkv"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/mysql"
"github.com/pingcap/tidb/parser"
"github.com/pingcap/tidb/plan"
"github.com/pingcap/tidb/sessionctx"
Expand Down Expand Up @@ -989,6 +991,31 @@ func (s *testSuite) TestJSON(c *C) {
result = tk.MustQuery(`select a from test_json tj where a = "string"`)
result.Check(testkit.Rows(`"string"`))

// check some DDL limits for TEXT/BLOB/JSON column.
var err error
var terr *terror.Error

_, err = tk.Exec(`create table test_bad_json(a json default '{}')`)
c.Assert(err, NotNil)
terr = errors.Trace(err).(*errors.Err).Cause().(*terror.Error)
c.Assert(terr.Code(), Equals, terror.ErrCode(mysql.ErrBlobCantHaveDefault))

_, err = tk.Exec(`create table test_bad_json(a blob default 'hello')`)
c.Assert(err, NotNil)
terr = errors.Trace(err).(*errors.Err).Cause().(*terror.Error)
c.Assert(terr.Code(), Equals, terror.ErrCode(mysql.ErrBlobCantHaveDefault))

_, err = tk.Exec(`create table test_bad_json(a text default 'world')`)
c.Assert(err, NotNil)
terr = errors.Trace(err).(*errors.Err).Cause().(*terror.Error)
c.Assert(terr.Code(), Equals, terror.ErrCode(mysql.ErrBlobCantHaveDefault))

// check json fields cannot be used as key.
_, err = tk.Exec(`create table test_bad_json(id int, a json, key (a))`)
c.Assert(err, NotNil)
terr = errors.Trace(err).(*errors.Err).Cause().(*terror.Error)
c.Assert(terr.Code(), Equals, terror.ErrCode(mysql.ErrJSONUsedAsKey))

// check CAST AS JSON.
result = tk.MustQuery(`select CAST('3' AS JSON), CAST('{}' AS JSON), CAST(null AS JSON)`)
result.Check(testkit.Rows(`3 {} <nil>`))
Expand Down
1 change: 1 addition & 0 deletions mysql/errcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -885,4 +885,5 @@ const (
ErrInvalidJSONText = 3140
ErrInvalidJSONPath = 3143
ErrInvalidJSONData = 3146
ErrJSONUsedAsKey = 3152
)
3 changes: 2 additions & 1 deletion mysql/errname.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ var MySQLErrName = map[uint16]string{
ErrNoUniqueLogFile: "Can't generate a unique log-filename %-.200s.(1-999)\n",
ErrTableNotLockedForWrite: "Table '%-.192s' was locked with a READ lock and can't be updated",
ErrTableNotLocked: "Table '%-.192s' was not locked with LOCK TABLES",
ErrBlobCantHaveDefault: "BLOB/TEXT column '%-.192s' can't have a default value",
ErrBlobCantHaveDefault: "BLOB/TEXT/JSON column '%-.192s' can't have a default value",
ErrWrongDBName: "Incorrect database name '%-.100s'",
ErrWrongTableName: "Incorrect table name '%-.100s'",
ErrTooBigSelect: "The SELECT would examine more than MAXJOINSIZE rows; check your WHERE and use SET SQLBIGSELECTS=1 or SET MAXJOINSIZE=# if the SELECT is okay",
Expand Down Expand Up @@ -882,4 +882,5 @@ var MySQLErrName = map[uint16]string{
ErrInvalidJSONText: "Invalid JSON text: %-.192s",
ErrInvalidJSONPath: "Invalid JSON path expression %s.",
ErrInvalidJSONData: "Invalid data type for JSON data",
ErrJSONUsedAsKey: "JSON column '%-.192s' cannot be used in key specification.",
}
1 change: 1 addition & 0 deletions mysql/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,5 @@ var MySQLState = map[uint16]string{
ErrInvalidJSONText: "22032",
ErrInvalidJSONPath: "42000",
ErrInvalidJSONData: "22032",
ErrJSONUsedAsKey: "42000",
}

0 comments on commit 72981fd

Please sign in to comment.