Skip to content

Commit

Permalink
Merge pull request #723 from hustjieke/feature_support_check_table_stmt
Browse files Browse the repository at this point in the history
*.:support check table stmt #718
  • Loading branch information
BohuTANG authored Jan 20, 2021
2 parents 7c4781a + eaf3d40 commit 9c0186b
Show file tree
Hide file tree
Showing 17 changed files with 4,240 additions and 3,555 deletions.
35 changes: 35 additions & 0 deletions docs/sql_statements/database_administration_statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Table of Contents
* [SHOW PROCESSLIST](#show-processlist)
* [SHOW VARIABLES](#show-variables)
* [Table Maintenance Statements](#table-maintenance-statements)
* [CHECK TABLE Statements](#check-table-statements)
* [CHECKSUM TABLE Statements](#checksum-table-statements)
* [OPTIMIZE TABLE Statements](#optimize-table-statements)
* [Other Administrative Statements](#other-administrative-statements)
Expand Down Expand Up @@ -324,6 +325,40 @@ SHOW VARIABLES

## Table Maintenance Statements

### CHECK TABLE Statements
`Syntax`
```
CHECK {TABLE | TABLES} tbl_name [, tbl_name] ... [option] ...
option: {
FOR UPGRADE
| QUICK
| FAST
| MEDIUM
| EXTENDED
| CHANGED
}
```

`Example: `

```
mysql> check tables t_part for quick;
+------------------+-------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+------------------+-------+----------+----------+
| test.t_part_0000 | check | status | OK |
| test.t_part_0001 | check | status | OK |
| test.t_part_0002 | check | status | OK |
| test.t_part_0003 | check | status | OK |
...
...
| test.t_part_0062 | check | status | OK |
| test.t_part_0063 | check | status | OK |
+------------------+-------+----------+----------+
64 rows in set (0.02 sec)
```

### CHECKSUM TABLE Statements

`Syntax`
Expand Down
106 changes: 106 additions & 0 deletions intergration/radon-test/r/check.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
drop database if exists integrate_test;

create database if not exists integrate_test DEFAULT CHARSET=utf8;

create /*test partition hash, Test of refering to old values*/ table integrate_test.t_part (a int not null key);

create /*test partition list*/ table integrate_test.t_list(c1 int, c2 int) ENGINE=InnoDB DEFAULT CHARSET=utf8 partition by list(c1) (partition backend1 values in (1,3,7), partition backend2 values in (2,5,8));

create /*test partition single, Test of refering to old values*/ table integrate_test.t_single (a int not null key) single;

create /*test global, Test of refering to old values*/ table integrate_test.t_global (a int not null key) global;

check tables integrate_test.t_global for upgrade quick fast medium extended changed;
Table Op Msg_type Msg_text
integrate_test.t_global check status OK
integrate_test.t_global check status OK

check tables integrate_test.t_global, integrate_test.t_single;
Table Op Msg_type Msg_text
integrate_test.t_global check status OK
integrate_test.t_global check status OK
integrate_test.t_single check status OK

check table integrate_test.t_list;
Table Op Msg_type Msg_text
integrate_test.t_list_0000 check status OK
integrate_test.t_list_0001 check status OK
integrate_test.t_list_0002 check status OK
integrate_test.t_list_0003 check status OK
integrate_test.t_list_0004 check status OK
integrate_test.t_list_0005 check status OK

check table integrate_test.t_part;
Table Op Msg_type Msg_text
integrate_test.t_part_0000 check status OK
integrate_test.t_part_0001 check status OK
integrate_test.t_part_0002 check status OK
integrate_test.t_part_0003 check status OK
integrate_test.t_part_0004 check status OK
integrate_test.t_part_0005 check status OK
integrate_test.t_part_0006 check status OK
integrate_test.t_part_0007 check status OK
integrate_test.t_part_0008 check status OK
integrate_test.t_part_0009 check status OK
integrate_test.t_part_0010 check status OK
integrate_test.t_part_0011 check status OK
integrate_test.t_part_0012 check status OK
integrate_test.t_part_0013 check status OK
integrate_test.t_part_0014 check status OK
integrate_test.t_part_0015 check status OK
integrate_test.t_part_0016 check status OK
integrate_test.t_part_0017 check status OK
integrate_test.t_part_0018 check status OK
integrate_test.t_part_0019 check status OK
integrate_test.t_part_0020 check status OK
integrate_test.t_part_0021 check status OK
integrate_test.t_part_0022 check status OK
integrate_test.t_part_0023 check status OK
integrate_test.t_part_0024 check status OK
integrate_test.t_part_0025 check status OK
integrate_test.t_part_0026 check status OK
integrate_test.t_part_0027 check status OK
integrate_test.t_part_0028 check status OK
integrate_test.t_part_0029 check status OK
integrate_test.t_part_0030 check status OK
integrate_test.t_part_0031 check status OK
integrate_test.t_part_0032 check status OK
integrate_test.t_part_0033 check status OK
integrate_test.t_part_0034 check status OK
integrate_test.t_part_0035 check status OK
integrate_test.t_part_0036 check status OK
integrate_test.t_part_0037 check status OK
integrate_test.t_part_0038 check status OK
integrate_test.t_part_0039 check status OK
integrate_test.t_part_0040 check status OK
integrate_test.t_part_0041 check status OK
integrate_test.t_part_0042 check status OK
integrate_test.t_part_0043 check status OK
integrate_test.t_part_0044 check status OK
integrate_test.t_part_0045 check status OK
integrate_test.t_part_0046 check status OK
integrate_test.t_part_0047 check status OK
integrate_test.t_part_0048 check status OK
integrate_test.t_part_0049 check status OK
integrate_test.t_part_0050 check status OK
integrate_test.t_part_0051 check status OK
integrate_test.t_part_0052 check status OK
integrate_test.t_part_0053 check status OK
integrate_test.t_part_0054 check status OK
integrate_test.t_part_0055 check status OK
integrate_test.t_part_0056 check status OK
integrate_test.t_part_0057 check status OK
integrate_test.t_part_0058 check status OK
integrate_test.t_part_0059 check status OK
integrate_test.t_part_0060 check status OK
integrate_test.t_part_0061 check status OK
integrate_test.t_part_0062 check status OK
integrate_test.t_part_0063 check status OK

check /*test error: No Database Selected*/ table t_part;
ERROR 1046 (3D000): No database selected

check /*test error: No such table*/ table integrate_test.t_xxx, integrate_test.t_single;
ERROR 1146 (42S02): Table 't_xxx' doesn't exist

drop database integrate_test;
13 changes: 13 additions & 0 deletions intergration/radon-test/t/check.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
drop database if exists integrate_test;
create database if not exists integrate_test DEFAULT CHARSET=utf8;
create /*test partition hash, Test of refering to old values*/ table integrate_test.t_part (a int not null key);
create /*test partition list*/ table integrate_test.t_list(c1 int, c2 int) ENGINE=InnoDB DEFAULT CHARSET=utf8 partition by list(c1) (partition backend1 values in (1,3,7), partition backend2 values in (2,5,8));
create /*test partition single, Test of refering to old values*/ table integrate_test.t_single (a int not null key) single;
create /*test global, Test of refering to old values*/ table integrate_test.t_global (a int not null key) global;
check tables integrate_test.t_global for upgrade quick fast medium extended changed;
check tables integrate_test.t_global, integrate_test.t_single;
check table integrate_test.t_list;
check table integrate_test.t_part;
check /*test error: No Database Selected*/ table t_part;
check /*test error: No such table*/ table integrate_test.t_xxx, integrate_test.t_single;
drop database integrate_test;
2 changes: 1 addition & 1 deletion src/optimizer/simple_optimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (so *SimpleOptimizer) BuildPlanTree() (*planner.PlanTree, error) {
case *sqlparser.Union:
node := planner.NewUnionPlan(log, database, query, node.(*sqlparser.Union), router)
plans.Add(node)
case *sqlparser.Checksum, *sqlparser.Optimize:
case *sqlparser.Checksum, *sqlparser.Optimize, *sqlparser.Check:
node := planner.NewOthersPlan(log, database, query, node, router)
plans.Add(node)
default:
Expand Down
22 changes: 22 additions & 0 deletions src/planner/others_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,28 @@ func (p *OthersPlan) Build() error {
database := newNode.Tables[0].Qualifier.String()
table := newNode.Tables[0].Name.String()

route, err := p.router.TableConfig(database, table)
if err != nil {
return err
}
for _, segment := range route.Partitions {
newNode.Tables[0].Name = sqlparser.NewTableIdent(segment.Table)
tuple := xcontext.QueryTuple{
Query: sqlparser.String(&newNode),
Backend: segment.Backend,
Range: segment.Segment,
}
p.Querys = append(p.Querys, tuple)
}
case *sqlparser.Check:
newNode := *node
// We`ll rewrite ast on newNode and the table`s format should be like "db.t1", so the "Qualifier" in ast should not be empty.
if newNode.Tables[0].Qualifier.IsEmpty() {
newNode.Tables[0].Qualifier = sqlparser.NewTableIdent(p.database)
}
database := newNode.Tables[0].Qualifier.String()
table := newNode.Tables[0].Name.String()

route, err := p.router.TableConfig(database, table)
if err != nil {
return err
Expand Down
166 changes: 166 additions & 0 deletions src/planner/others_plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,169 @@ func TestOthersPlanOptimizeTableError(t *testing.T) {
}
}
}

func TestOthersPlanCheckTable(t *testing.T) {
results := []string{
`{
"RawQuery": "check table A",
"Partitions": [
{
"Query": "check table sbtest.A1",
"Backend": "backend1",
"Range": "0-32"
},
{
"Query": "check table sbtest.A2",
"Backend": "backend2",
"Range": "32-64"
},
{
"Query": "check table sbtest.A3",
"Backend": "backend3",
"Range": "64-96"
},
{
"Query": "check table sbtest.A4",
"Backend": "backend4",
"Range": "96-256"
},
{
"Query": "check table sbtest.A5",
"Backend": "backend5",
"Range": "256-512"
},
{
"Query": "check table sbtest.A6",
"Backend": "backend6",
"Range": "512-4096"
}
]
}`,
`{
"RawQuery": "check table sbtest.A",
"Partitions": [
{
"Query": "check table sbtest.A1",
"Backend": "backend1",
"Range": "0-32"
},
{
"Query": "check table sbtest.A2",
"Backend": "backend2",
"Range": "32-64"
},
{
"Query": "check table sbtest.A3",
"Backend": "backend3",
"Range": "64-96"
},
{
"Query": "check table sbtest.A4",
"Backend": "backend4",
"Range": "96-256"
},
{
"Query": "check table sbtest.A5",
"Backend": "backend5",
"Range": "256-512"
},
{
"Query": "check table sbtest.A6",
"Backend": "backend6",
"Range": "512-4096"
}
]
}`,
`{
"RawQuery": "check table G",
"Partitions": [
{
"Query": "check table sbtest.G",
"Backend": "backend1",
"Range": ""
},
{
"Query": "check table sbtest.G",
"Backend": "backend2",
"Range": ""
}
]
}`,
`{
"RawQuery": "check table sbtest.S",
"Partitions": [
{
"Query": "check table sbtest.S",
"Backend": "backend1",
"Range": ""
}
]
}`,
}
querys := []string{
"check table A",
"check table sbtest.A",
"check table G",
"check table sbtest.S",
}

log := xlog.NewStdLog(xlog.Level(xlog.PANIC))
database := "sbtest"

route, cleanup := router.MockNewRouter(log)
defer cleanup()

err := route.CreateDatabase(database)
assert.Nil(t, err)
err = route.AddForTest(database, router.MockTableMConfig(), router.MockTableGConfig(), router.MockTableSConfig())
assert.Nil(t, err)
planTree := NewPlanTree()
for i, query := range querys {
node, err := sqlparser.Parse(query)
assert.Nil(t, err)
plan := NewOthersPlan(log, database, query, node, route)

// plan build
{
err := plan.Build()
assert.Nil(t, err)
{
err := planTree.Add(plan)
assert.Nil(t, err)
}
got := plan.JSON()
want := results[i]
assert.Equal(t, want, got)
assert.Equal(t, PlanTypeOthers, plan.Type())
}
}
}

func TestOthersPlanCheckTableError(t *testing.T) {
querys := []string{
"check table A",
"check table xx.A",
}

log := xlog.NewStdLog(xlog.Level(xlog.PANIC))
database := "sbtest"

route, cleanup := router.MockNewRouter(log)
defer cleanup()

err := route.CreateDatabase(database)
assert.Nil(t, err)
err = route.AddForTest(database, router.MockTableMConfig(), router.MockTableGConfig(), router.MockTableSConfig())
assert.Nil(t, err)
for _, query := range querys {
node, err := sqlparser.Parse(query)
assert.Nil(t, err)
plan := NewOthersPlan(log, "", query, node, route)

// plan build
{
err := plan.Build()
assert.NotNil(t, err)
}
}
}
8 changes: 8 additions & 0 deletions src/proxy/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,14 @@ func (spanner *Spanner) ComQuery(session *driver.Session, query string, bindVari
}
spanner.auditLog(session, R, xbase.OPTIMIZE, query, qr, status)
return returnQuery(qr, callback, err)
case *sqlparser.Check:
log.Warning("proxy.query.check.query:%s", query)
if qr, err = spanner.handleCheckTable(session, query, node); err != nil {
log.Error("proxy.check[%s].from.session[%v].error:%+v", query, session.ID(), err)
status = 1
}
spanner.auditLog(session, R, xbase.CHECK, query, qr, status)
return returnQuery(qr, callback, err)
case *sqlparser.Do:
log.Warning("proxy.query.do.query:%s", query)
if qr, err = spanner.handleDo(session, query, node); err != nil {
Expand Down
Loading

0 comments on commit 9c0186b

Please sign in to comment.