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

parser,executor: make load data support user_var in column list and set clause #7707

Closed
wants to merge 4 commits into from
Closed

parser,executor: make load data support user_var in column list and set clause #7707

wants to merge 4 commits into from

Conversation

lysu
Copy link
Contributor

@lysu lysu commented Sep 14, 2018

What problem does this PR solve?

fixes #7404

from: https://dev.mysql.com/doc/refman/5.7/en/load-data.html

LOAD DATA support

    [(col_name_or_user_var
        [, col_name_or_user_var] ...)]
    [SET col_name={expr | DEFAULT},
        [, col_name={expr | DEFAULT}] ...]

this PR, make TiDB support SET clause and user_var(we are alreay support col_name) which make user have ability to change data during loading data(like exchange column order or call some function to transform), also some type like binary 's import require this feature(just as mysql-doc said).

What is changed and how it works?

  • make parser support set and @xx in load data
  • change executor

Check List

Tests

  • Integration test

Code changes

  • logic change

Side effects

  • no

Related changes

  • Need to update the documentation
  • Need to be included in the release note

This change is Reviewable

Remain question

  • unsupport correlated subquery
  • it seem ignore/replace is unsupport
  • enclosed by still unsupport

@lysu lysu changed the title parser,executor: make load data support set clause and user_var in column list parser,executor: make load data support user_var in column list and set clause Sep 14, 2018
@lysu
Copy link
Contributor Author

lysu commented Sep 14, 2018

/run-all-tests

@lysu lysu removed the status/WIP label Sep 17, 2018
@lysu
Copy link
Contributor Author

lysu commented Sep 21, 2018

/run-all-tests tidb-test=pr/627

@lysu
Copy link
Contributor Author

lysu commented Sep 21, 2018

@coocood @jackysp PTAL if free thx~

@lysu
Copy link
Contributor Author

lysu commented Sep 25, 2018

PTAL @coocood @jackysp

parser/parser.y Outdated
@@ -593,7 +593,10 @@ import (
ColumnNameList "column name list"
ColumnList "column list"
ColumnNameListOpt "column name list opt"
ColumnNameListOptWithBrackets "column name list opt with brackets"
ColumnOrVarListOptWithBrackets "column or variable list opt with brackets"
ColumnOrVarList "column or variable list"
Copy link
Member

Choose a reason for hiding this comment

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

Keep aligning.

@@ -1267,27 +1267,62 @@ func (b *planBuilder) buildSelectPlanOfInsert(insert *ast.InsertStmt, insertPlan
return nil
}

func (b *planBuilder) buildSetValuesOfLoadData(ld *ast.LoadDataStmt, ldPlan *LoadData, mockTablePlan *LogicalTableDual) error {
colNames := make([]string, 0, len(ld.SetList))
Copy link
Member

Choose a reason for hiding this comment

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

where to use it?

exprCols = append(exprCols, exprCol)
}

for i, assign := range ld.SetList {
Copy link
Member

Choose a reason for hiding this comment

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

could we merge this loop with the above one?

LinesInfo *ast.LinesClause
IgnoreLines uint64
SetList []*expression.Assignment
tableSchema *expression.Schema

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 could remove this empty line now.

parser/parser.y Outdated
ColumnOrVar:
UserVariable
{
$$ = &ast.ColNameOrVar{VariableExpr: $1.(*ast.VariableExpr)}
Copy link
Member

Choose a reason for hiding this comment

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

keep aligning.

parser/parser.y Outdated
}
| ColumnName
{
$$ = &ast.ColNameOrVar{ColumnName: $1.(*ast.ColumnName)}
Copy link
Member

Choose a reason for hiding this comment

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

keep aligning.

parser/parser.y Outdated
}

LoadDataSetOpt:
/* EMPTY */
Copy link
Member

Choose a reason for hiding this comment

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

keep aligning

@lysu
Copy link
Contributor Author

lysu commented Sep 27, 2018

/run-all-tests tidb-test=pr/627

Columns []*ast.ColumnName
Lists [][]expression.Expression
SetList []*expression.Assignment
ColNameOrVars []*ast.ColNameOrVar
Copy link
Member

Choose a reason for hiding this comment

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

emmm... I think this element is used only for load data. Could we move it out?

server/server_test.go Outdated Show resolved Hide resolved
dbt.Check(err, IsNil)
dbt.Check(*aa, DeepEquals, 0)
dbt.Check(*bb, DeepEquals, 0)
//dbt.Check(cc, DeepEquals, ([]uint8)(nil)) FIXME: stranger
Copy link
Member

Choose a reason for hiding this comment

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

should it be fixed?

@lysu
Copy link
Contributor Author

lysu commented Sep 27, 2018

@coocood ColNameOrVar has be removed, PTAL thx~

}
colsBind, err := table.FindCols(tableCols, columns, e.Table.Meta().PKIsHandle)
if err != nil {
return nil, 0, errors.Errorf("LOAD DATA SET %s: %s", e.Table.Meta().Name.O, err)
Copy link
Member

Choose a reason for hiding this comment

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

what kind of error will MySQL returned?

return errors.Trace(err)
}
if exprCol == nil {
return errors.Errorf("Can't find column %s", assign.Column)
Copy link
Member

Choose a reason for hiding this comment

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

It's better to return the same error as MySQL does.

Copy link
Member

@jackysp jackysp left a comment

Choose a reason for hiding this comment

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

rest LGTM

@lysu
Copy link
Contributor Author

lysu commented Oct 10, 2018

PTAL @jackysp

}
}

mRow := chunk.MutRowFromDatums(row).ToRow()
Copy link
Member

Choose a reason for hiding this comment

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

Could we skip this if the SetList is nil?

@lysu
Copy link
Contributor Author

lysu commented Oct 12, 2018

PTAL @jackysp @tiancaiamao

@lysu lysu requested a review from tiancaiamao October 12, 2018 11:15
Copy link
Member

@jackysp jackysp left a comment

Choose a reason for hiding this comment

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

LGTM

ast/dml.go Outdated
@@ -685,11 +686,20 @@ func (n *LoadDataStmt) Accept(v Visitor) (Node, bool) {
n.Table = node.(*TableName)
}
for i, val := range n.Columns {
node, ok := val.Accept(v)
if colExpr, isCol := val.(*ColumnNameExpr); isCol {
Copy link
Contributor

Choose a reason for hiding this comment

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

How about this

switch val.(type) {
    case *ColumnNameExpr:
    case *VariableExpr:
}

ast/dml.go Outdated
@@ -664,10 +664,11 @@ type LoadDataStmt struct {
IsLocal bool
Path string
Table *TableName
Columns []*ColumnName
Columns []ExprNode
Copy link
Contributor

Choose a reason for hiding this comment

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

Rename it to ColumnOrVars ?

if colName, isCol := colOrVar.(*ast.ColumnNameExpr); isCol {
columns = append(columns, colName.Name.Name.O)
} else {
columns = append(columns, "")
Copy link
Contributor

Choose a reason for hiding this comment

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

table.FindCols(tableCols, "", ...) 

What's the purpose of this line ?

Copy link
Contributor Author

@lysu lysu Oct 16, 2018

Choose a reason for hiding this comment

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

had added some comments to this line in code :)

@@ -559,6 +559,55 @@ func (b *executorBuilder) buildInsert(v *plannercore.Insert) Executor {
return insert
}

func getColumnInfo4LoadData(e *InsertValues, tableCols []*table.Column, colOrVars []ast.ExprNode) ([]*table.Column, int, 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 comment for the returned int value

t.Assert(outB, Equals, "23:59:59")
})
}

func runTestLoadDataWithSet(c *C, server *Server) {
path := "/tmp/load_data_test2.csv"
Copy link
Contributor

Choose a reason for hiding this comment

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

bb *int
cc []uint8
)
rows := dbt.mustQuery("select a, b, c from t")
Copy link
Contributor

Choose a reason for hiding this comment

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

This kind of code could be simplified with the util/testkit utilities.

Copy link
Contributor Author

@lysu lysu Oct 16, 2018

Choose a reason for hiding this comment

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

it seems server_test.go never use testkit? 😹 because testkit is kv.Storage based, and integration test need sql.DB?

@lysu lysu added the status/LGT1 Indicates that a PR has LGTM 1. label Oct 16, 2018
mRow := chunk.MutRowFromDatums(row).ToRow()
for _, setExpr := range e.SetList {
colInfo := e.colInfo[i]
v, err := setExpr.Expr.Eval(mRow)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

here need wait #7935 , can reuse one buffer instead renew row by row.

@zz-jason
Copy link
Member

any update?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

LOAD DATA need support column/variable list and SET clause
4 participants