Skip to content

Commit

Permalink
parser,ddl: data type default values support `REPLACE(UPPER(uuid()), …
Browse files Browse the repository at this point in the history
…'-', '')` (pingcap#50963)

close pingcap#50937
  • Loading branch information
zimulala authored Feb 9, 2024
1 parent e7105a0 commit a29bbb5
Show file tree
Hide file tree
Showing 5 changed files with 5,982 additions and 5,851 deletions.
69 changes: 69 additions & 0 deletions pkg/ddl/db_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"sync/atomic"
"testing"
"time"
"unicode"

"github.com/pingcap/errors"
_ "github.com/pingcap/tidb/pkg/autoid_service"
Expand Down Expand Up @@ -1606,6 +1607,74 @@ func TestDefaultColumnWithRand(t *testing.T) {
tk.MustGetErrCode("CREATE TABLE t3 (c int, c1 int default a_function_not_supported_yet());", errno.ErrDefValGeneratedNamedFunctionIsNotAllowed)
}

func TestDefaultColumnWithReplace(t *testing.T) {
store := testkit.CreateMockStoreWithSchemaLease(t, testLease)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t, t1, t2")

// create table
tk.MustExec("create table t (c int(10), c1 varchar(256) default (REPLACE(UPPER(UUID()), '-', '')))")
tk.MustExec("create table t1 (c int(10), c1 int default (REPLACE(UPPER(UUID()), '-', '')))")
tk.MustExec("create table t2 (c int(10), c1 varchar(256) default (REPLACE(CONVERT(UPPER(UUID()) USING UTF8MB4), '-', '')))")
tk.MustGetErrCode("create table t1 (c int(10), c1 varchar(256) default (REPLACE('xdfj-jfj', '-', '')))", errno.ErrDefValGeneratedNamedFunctionIsNotAllowed)
tk.MustGetErrCode("create table t1 (c int(10), c1 varchar(256) default (UPPER(UUID())))", errno.ErrDefValGeneratedNamedFunctionIsNotAllowed)
tk.MustGetErrCode("create table t1 (c int(10), c1 varchar(256) default (REPLACE(UPPER('dfdkj-kjkl-d'), '-', '')))", errno.ErrDefValGeneratedNamedFunctionIsNotAllowed)

// add column with default expression for table t is forbidden in MySQL 8.0
tk.MustGetErrCode("alter table t add column c2 varchar(32) default (REPLACE(UPPER(UUID()), '-', ''))", errno.ErrBinlogUnsafeSystemFunction)
tk.MustGetErrCode("alter table t add column c3 int default (UPPER(UUID()))", errno.ErrDefValGeneratedNamedFunctionIsNotAllowed)
tk.MustGetErrCode("alter table t add column c4 int default (REPLACE(UPPER('dfdkj-kjkl-d'), '-', ''))", errno.ErrBinlogUnsafeSystemFunction)

// insert records
tk.MustExec("insert into t(c) values (1),(2),(3)")
tk.MustGetErrCode("insert into t1(c) values (1)", errno.ErrTruncatedWrongValue)

rows := tk.MustQuery("SELECT c1 from t").Rows()
for _, row := range rows {
d, ok := row[0].(string)
require.True(t, ok)
// It consists of uppercase letters or numbers.
for _, r := range d {
if unicode.IsUpper(r) {
require.True(t, unicode.IsUpper(r), fmt.Sprintf("col val:%v, r:%v", d, r))
} else {
require.True(t, unicode.IsDigit(r), fmt.Sprintf("col val:%v, r:%v", d, r))
}
}
}

// TODO: Implement add the "convert" function when executing "show create table".
// `c1` varchar(16) DEFAULT (replace(convert(upper(uuid()) using utf8mb4),_utf8mb4'-',_utf8mb4''))
tk.MustQuery("show create table t").Check(testkit.Rows(
"t CREATE TABLE `t` (\n" +
" `c` int(10) DEFAULT NULL,\n" +
" `c1` varchar(256) DEFAULT replace(upper(uuid()), _utf8mb4''-'', _utf8mb4'''')\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
tk.MustQuery("show create table t1").Check(testkit.Rows(
"t1 CREATE TABLE `t1` (\n" +
" `c` int(10) DEFAULT NULL,\n" +
" `c1` int(11) DEFAULT replace(upper(uuid()), _utf8mb4''-'', _utf8mb4'''')\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
tk.MustQuery("show create table t2").Check(testkit.Rows(
"t2 CREATE TABLE `t2` (\n" +
" `c` int(10) DEFAULT NULL,\n" +
" `c1` varchar(256) DEFAULT replace(convert(upper(uuid()) using ''utf8mb4''), _utf8mb4''-'', _utf8mb4'''')\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
tk.MustExec("alter table t1 modify column c1 varchar(30) default 'xx';")
tk.MustQuery("show create table t1").Check(testkit.Rows(
"t1 CREATE TABLE `t1` (\n" +
" `c` int(10) DEFAULT NULL,\n" +
" `c1` varchar(30) DEFAULT 'xx'\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
tk.MustExec("alter table t1 modify column c1 varchar(32) default (REPLACE(UPPER(UUID()), '-', ''));")
tk.MustQuery("show create table t1").Check(testkit.Rows(
"t1 CREATE TABLE `t1` (\n" +
" `c` int(10) DEFAULT NULL,\n" +
" `c1` varchar(32) DEFAULT replace(upper(uuid()), _utf8mb4''-'', _utf8mb4'''')\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))
}

func TestChangingDBCharset(t *testing.T) {
store := testkit.CreateMockStore(t, mockstore.WithDDLChecker())

Expand Down
54 changes: 46 additions & 8 deletions pkg/ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,17 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef, o
return col, constraints, nil
}

func restoreFuncCall(expr *ast.FuncCallExpr) (string, error) {
var sb strings.Builder
restoreFlags := format.RestoreStringSingleQuotes | format.RestoreKeyWordLowercase | format.RestoreNameBackQuotes |
format.RestoreSpacesAroundBinaryOperation
restoreCtx := format.NewRestoreCtx(restoreFlags, &sb)
if err := expr.Restore(restoreCtx); err != nil {
return "", err
}
return sb.String(), nil
}

// getFuncCallDefaultValue gets the default column value of function-call expression.
func getFuncCallDefaultValue(col *table.Column, option *ast.ColumnOption, expr *ast.FuncCallExpr) (any, bool, error) {
switch expr.FnName.L {
Expand Down Expand Up @@ -1292,15 +1303,42 @@ func getFuncCallDefaultValue(col *table.Column, option *ast.ColumnOption, expr *
if err := expression.VerifyArgsWrapper(expr.FnName.L, len(expr.Args)); err != nil {
return nil, false, errors.Trace(err)
}
str, err := restoreFuncCall(expr)
if err != nil {
return nil, false, errors.Trace(err)
}
col.DefaultIsExpr = true
var sb strings.Builder
restoreFlags := format.RestoreStringSingleQuotes | format.RestoreKeyWordLowercase | format.RestoreNameBackQuotes |
format.RestoreSpacesAroundBinaryOperation
restoreCtx := format.NewRestoreCtx(restoreFlags, &sb)
if err := expr.Restore(restoreCtx); err != nil {
return "", false, err
return str, false, nil
case ast.Replace:
// Support REPLACE(UPPER(UUID()), '-', '').
if err := expression.VerifyArgsWrapper(expr.FnName.L, len(expr.Args)); err != nil {
return nil, false, errors.Trace(err)
}
return sb.String(), false, nil
funcCall := expr.Args[0]
// Support REPLACE(CONVERT(UPPER(UUID()) USING UTF8MB4), '-', ''))
if convertFunc, ok := funcCall.(*ast.FuncCallExpr); ok && convertFunc.FnName.L == ast.Convert {
if err := expression.VerifyArgsWrapper(convertFunc.FnName.L, len(convertFunc.Args)); err != nil {
return nil, false, errors.Trace(err)
}
funcCall = convertFunc.Args[0]
}
if upperFunc, ok := funcCall.(*ast.FuncCallExpr); ok && upperFunc.FnName.L == ast.Upper {
if err := expression.VerifyArgsWrapper(upperFunc.FnName.L, len(upperFunc.Args)); err != nil {
return nil, false, errors.Trace(err)
}
if uuidFunc, ok := upperFunc.Args[0].(*ast.FuncCallExpr); ok && uuidFunc.FnName.L == ast.UUID {
if err := expression.VerifyArgsWrapper(uuidFunc.FnName.L, len(uuidFunc.Args)); err != nil {
return nil, false, errors.Trace(err)
}
str, err := restoreFuncCall(expr)
if err != nil {
return nil, false, errors.Trace(err)
}
col.DefaultIsExpr = true
return str, false, nil
}
}
return nil, false, dbterror.ErrDefValGeneratedNamedFunctionIsNotAllowed.GenWithStackByArgs(col.Name.String(), expr.FnName.String())
default:
return nil, false, dbterror.ErrDefValGeneratedNamedFunctionIsNotAllowed.GenWithStackByArgs(col.Name.String(), expr.FnName.String())
}
Expand Down Expand Up @@ -4182,7 +4220,7 @@ func CreateNewColumn(ctx sessionctx.Context, schema *model.DBInfo, spec *ast.Alt
return nil, errors.Trace(err)
}
return nil, errors.Trace(dbterror.ErrAddColumnWithSequenceAsDefault.GenWithStackByArgs(specNewColumn.Name.Name.O))
case ast.Rand, ast.UUID, ast.UUIDToBin:
case ast.Rand, ast.UUID, ast.UUIDToBin, ast.Replace:
return nil, errors.Trace(dbterror.ErrBinlogUnsafeSystemFunction.GenWithStackByArgs())
}
}
Expand Down
Loading

0 comments on commit a29bbb5

Please sign in to comment.