Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*.:support check table stmt #718 #723

Merged
merged 2 commits into from
Jan 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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