@@ -45,6 +45,7 @@ import (
45
45
"github.com/pingcap/tidb/table/tables"
46
46
"github.com/pingcap/tidb/types"
47
47
driver "github.com/pingcap/tidb/types/parser_driver"
48
+ "github.com/pingcap/tidb/util"
48
49
"github.com/pingcap/tidb/util/chunk"
49
50
"github.com/pingcap/tidb/util/logutil"
50
51
"github.com/pingcap/tidb/util/mock"
@@ -3386,16 +3387,12 @@ func (d *ddl) LockTables(ctx sessionctx.Context, stmt *ast.LockTablesStmt) error
3386
3387
SessionID : ctx .GetSessionVars ().ConnectionID ,
3387
3388
}
3388
3389
uniqueTableID := make (map [int64 ]struct {})
3389
- // Check whether the table was already locked by other .
3390
+ // Check whether the table was already locked by another .
3390
3391
for _ , tl := range stmt .TableLocks {
3391
3392
tb := tl .Table
3392
- // TODO: replace const string "performance_schema" with xxx.LowerName.
3393
- // Currently use perfschema.LowerName will have import cycle problem.
3394
- if tb .Schema .L == infoschema .LowerName || tb .Schema .L == "performance_schema" || tb .Schema .L == mysql .SystemDB {
3395
- if ctx .GetSessionVars ().User != nil {
3396
- return infoschema .ErrAccessDenied .GenWithStackByArgs (ctx .GetSessionVars ().User .Username , ctx .GetSessionVars ().User .Hostname )
3397
- }
3398
- return infoschema .ErrAccessDenied
3393
+ err := throwErrIfInMemOrSysDB (ctx , tb .Schema .L )
3394
+ if err != nil {
3395
+ return err
3399
3396
}
3400
3397
schema , t , err := d .getSchemaAndTableByIdent (ctx , ast.Ident {Schema : tb .Schema , Name : tb .Name })
3401
3398
if err != nil {
@@ -3467,10 +3464,75 @@ func (d *ddl) UnlockTables(ctx sessionctx.Context, unlockTables []model.TableLoc
3467
3464
return errors .Trace (err )
3468
3465
}
3469
3466
3467
+ func throwErrIfInMemOrSysDB (ctx sessionctx.Context , dbLowerName string ) error {
3468
+ if util .IsMemOrSysDB (dbLowerName ) {
3469
+ if ctx .GetSessionVars ().User != nil {
3470
+ return infoschema .ErrAccessDenied .GenWithStackByArgs (ctx .GetSessionVars ().User .Username , ctx .GetSessionVars ().User .Hostname )
3471
+ }
3472
+ return infoschema .ErrAccessDenied .GenWithStackByArgs ("" , "" )
3473
+ }
3474
+ return nil
3475
+ }
3476
+
3477
+ func (d * ddl ) CleanupTableLock (ctx sessionctx.Context , tables []* ast.TableName ) error {
3478
+ uniqueTableID := make (map [int64 ]struct {})
3479
+ cleanupTables := make ([]model.TableLockTpInfo , 0 , len (tables ))
3480
+ unlockedTablesNum := 0
3481
+ // Check whether the table was already locked by another.
3482
+ for _ , tb := range tables {
3483
+ err := throwErrIfInMemOrSysDB (ctx , tb .Schema .L )
3484
+ if err != nil {
3485
+ return err
3486
+ }
3487
+ schema , t , err := d .getSchemaAndTableByIdent (ctx , ast.Ident {Schema : tb .Schema , Name : tb .Name })
3488
+ if err != nil {
3489
+ return errors .Trace (err )
3490
+ }
3491
+ if t .Meta ().IsView () {
3492
+ return table .ErrUnsupportedOp
3493
+ }
3494
+ // Maybe the table t was not locked, but still try to unlock this table.
3495
+ // If we skip unlock the table here, the job maybe not consistent with the job.Query.
3496
+ // eg: unlock tables t1,t2; If t2 is not locked and skip here, then the job will only unlock table t1,
3497
+ // and this behaviour is not consistent with the sql query.
3498
+ if ! t .Meta ().IsLocked () {
3499
+ unlockedTablesNum ++
3500
+ }
3501
+ if _ , ok := uniqueTableID [t .Meta ().ID ]; ok {
3502
+ return infoschema .ErrNonuniqTable .GenWithStackByArgs (t .Meta ().Name )
3503
+ }
3504
+ uniqueTableID [t .Meta ().ID ] = struct {}{}
3505
+ cleanupTables = append (cleanupTables , model.TableLockTpInfo {SchemaID : schema .ID , TableID : t .Meta ().ID })
3506
+ }
3507
+ // If the num of cleanupTables is 0, or all cleanupTables is unlocked, just return here.
3508
+ if len (cleanupTables ) == 0 || len (cleanupTables ) == unlockedTablesNum {
3509
+ return nil
3510
+ }
3511
+
3512
+ arg := & lockTablesArg {
3513
+ UnlockTables : cleanupTables ,
3514
+ IsCleanup : true ,
3515
+ }
3516
+ job := & model.Job {
3517
+ SchemaID : cleanupTables [0 ].SchemaID ,
3518
+ TableID : cleanupTables [0 ].TableID ,
3519
+ Type : model .ActionUnlockTable ,
3520
+ BinlogInfo : & model.HistoryInfo {},
3521
+ Args : []interface {}{arg },
3522
+ }
3523
+ err := d .doDDLJob (ctx , job )
3524
+ if err == nil {
3525
+ ctx .ReleaseTableLocks (cleanupTables )
3526
+ }
3527
+ err = d .callHookOnChanged (err )
3528
+ return errors .Trace (err )
3529
+ }
3530
+
3470
3531
type lockTablesArg struct {
3471
3532
LockTables []model.TableLockTpInfo
3472
3533
IndexOfLock int
3473
3534
UnlockTables []model.TableLockTpInfo
3474
3535
IndexOfUnlock int
3475
3536
SessionInfo model.SessionInfo
3537
+ IsCleanup bool
3476
3538
}
0 commit comments