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

plan, util/admin: fix admin check table error when a column of index is virtual generated #6817

Merged
merged 13 commits into from Aug 28, 2018

Conversation

crazycs520
Copy link
Contributor

@crazycs520 crazycs520 commented Jun 12, 2018

What have you changed? (mandatory)

admin check table will check the Integrity and consistency of index and record.

But how to excute admin check table

  • Before

read value of index key and record key from tikv, decode , compare the value of the Index and the corresponding column.

  • Problem

    when a column of index is virtual generated , decode the record value will get NULL of the virtual generated column , because the virtual generated column have not stored , then compare will be not consistent.

  • How i fix it

    after decode the record value, before compare , we have to calculate the value of virtual generated column.

Test SQL:

create table test ( b json , c int as (JSON_EXTRACT(b,'$.d')) , index idxc(c));
insert into test set b='{"d": 100}';
admin check table test;

What are the type of the changes (mandatory)?

  • Bug fix

How has this PR been tested (mandatory)?

  • Unit tests.

@CLAassistant
Copy link

CLAassistant commented Jun 12, 2018

CLA assistant check
All committers have signed the CLA.

@shenli
Copy link
Member

shenli commented Jun 12, 2018

@crazycs520 Please sign the CLA.

model/model.go Outdated
@@ -17,6 +17,7 @@ import (
"strings"
"time"

"fmt"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the fmt into the upper group.

model/model.go Outdated
@@ -493,3 +494,8 @@ func collationToProto(c string) int32 {
// For the data created when we didn't enforce utf8_bin collation in create table.
return int32(mysql.DefaultCollationID)
}

// GetTableColumnID get a ID of a column with table ID
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/get/gets/

p := &CheckTable{Tables: as.Tables}
p.GenExprs = make(map[string]expression.Expression, 0)

mockTablePlan := LogicalTableDual{}.init(b.ctx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use LogicalTableDual?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mock from buildInsert()
LogicalTableDual is use to b.rewrite(column.GeneratedExpr, mockTablePlan, nil, true)
I wanna directly use CheckTable instead of LogicalTableDual , but it seem not fit

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what's the problem with using CheckTable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CheckTable don't implement LogicalPlan , expr, _, err := b.rewrite need a LogicalPlan

@@ -493,3 +494,8 @@ func collationToProto(c string) int32 {
// For the data created when we didn't enforce utf8_bin collation in create table.
return int32(mysql.DefaultCollationID)
}

// GetTableColumnID gets a ID of a column with table ID
func GetTableColumnID(tableInfo *TableInfo, col *ColumnInfo) string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this function is only used in buildAdminCheckTable, you can put it to planbuilder.go and update its name as getTableColumnID.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function also call on util/admin/admin.go

rowMap[col.ID] = val
}
}
if err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check can be removed.

@@ -490,12 +491,30 @@ func rowWithCols(sessCtx sessionctx.Context, txn kv.Retriever, t table.Table, h
}
continue
}
if col.IsGenerated() && col.GeneratedStored == false {
genFlag = true
break
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why break here? If there are handle column after this column, the check would fail because it did set the handle as line 486 do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some comments here. Why break?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have remove break.

@winkyao
Copy link
Contributor

winkyao commented Jun 14, 2018

@crazycs520 Please address comments.

@@ -244,13 +245,13 @@ func ScanIndexData(sc *stmtctx.StatementContext, txn kv.Transaction, kvIndex tab
// CompareIndexData compares index data one by one.
// It returns nil if the data from the index is equal to the data from the table columns,
// otherwise it returns an error with a different set of records.
func CompareIndexData(sessCtx sessionctx.Context, txn kv.Transaction, t table.Table, idx table.Index) error {
err := checkIndexAndRecord(sessCtx, txn, t, idx)
func CompareIndexData(sessCtx sessionctx.Context, txn kv.Transaction, t table.Table, idx table.Index, genExprs map[string]expression.Expression) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some comment to genExprs param.

schema := expression.TableInfo2SchemaWithDBName(tbl.Schema, tableInfo)
table, ok := b.is.TableByID(tableInfo.ID)
if !ok {
b.err = errors.Errorf("Can't get table %s.", tableInfo.Name.O)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modify to b.err = infoschema.ErrTableNotExists.GenByArgs(....)

@@ -494,6 +493,50 @@ func (b *planBuilder) buildAdmin(as *ast.AdminStmt) Plan {
return ret
}

func (b *planBuilder) buildAdminCheckTable(as *ast.AdminStmt) Plan {
p := &CheckTable{Tables: as.Tables}
p.GenExprs = make(map[string]expression.Expression, 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make(map[string]expression.Expression) is ok.

@@ -539,10 +558,21 @@ func iterRecords(sessCtx sessionctx.Context, retriever kv.Retriever, t table.Tab

log.Debugf("startKey:%q, key:%q, value:%q", startKey, it.Key(), it.Value())

genFlag := false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/genFlag/genColFlag/g

colTps[col.ID] = &col.FieldType
}
row, err := tablecodec.DecodeRow(value, colTps, sessCtx.GetSessionVars().GetTimeZone())
if genFlag {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some comments.

@crazycs520
Copy link
Contributor Author

/run-all-tests

@crazycs520
Copy link
Contributor Author

@winkyao @zimulala @zz-jason PTAL

@@ -349,6 +349,8 @@ type CheckTableExec struct {
tables []*ast.TableName
done bool
is infoschema.InfoSchema

GenExprs map[string]expression.Expression
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need to export this variable.

@@ -495,6 +494,50 @@ func (b *planBuilder) buildAdmin(as *ast.AdminStmt) Plan {
return ret
}

func (b *planBuilder) buildAdminCheckTable(as *ast.AdminStmt) Plan {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the type of return value from Plan to *CheckTable would be better.

zz-jason
zz-jason previously approved these changes Jul 27, 2018
Copy link
Member

@zz-jason zz-jason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@crazycs520
Copy link
Contributor Author

@shenli @winkyao @winkyao PTAL

@@ -56,6 +56,8 @@ type CheckTable struct {
baseSchemaProducer

Tables []*ast.TableName

GenExprs map[string]expression.Expression
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about map[int]expression.Expression where the map key is ColumnInfo.ID.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There maybe have multiple tables, only use ColumnInfo.ID may leads to conflict in same ColumnInfo.ID but in different table.

@crazycs520 crazycs520 added the status/LGT1 Indicates that a PR has LGTM 1. label Aug 27, 2018
Copy link
Member

@winoros winoros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm

winkyao
winkyao previously approved these changes Aug 27, 2018
Copy link
Contributor

@winkyao winkyao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@ciscoxll ciscoxll left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reset LGTM

@@ -462,6 +462,11 @@ func (s *testSuite) TestAdminCheckTable(c *C) {
}
tk.MustExec(`admin check table test;`)

//test index in virtual generated column
tk.MustExec(`drop table if exists test`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s /test/Test

schema := expression.TableInfo2SchemaWithDBName(b.ctx, tbl.Schema, tableInfo)
table, ok := b.is.TableByID(tableInfo.ID)
if !ok {
return nil, infoschema.ErrTableNotExists.GenByArgs(tbl.DBInfo.Name.O, tableInfo.Name.O)
Copy link
Contributor

@ciscoxll ciscoxll Aug 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ tbl.DBInfo.Name.O/ tbl.DBInfo.Name.L

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the original is better. here is for log, not for compare.

@@ -558,12 +562,34 @@ func rowWithCols(sessCtx sessionctx.Context, txn kv.Retriever, t table.Table, h
}
continue
}
// if have virtual generate column , decode all columns.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s / if /If

@crazycs520
Copy link
Contributor Author

/run-all-tests

@crazycs520
Copy link
Contributor Author

/run-unit-test

@crazycs520 crazycs520 merged commit bc97e2d into pingcap:master Aug 28, 2018
@you06 you06 added the sig/sql-infra SIG: SQL Infra label Mar 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
sig/sql-infra SIG: SQL Infra status/LGT1 Indicates that a PR has LGTM 1.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants