从这篇开始,以后会在一篇文章里面写比较多的PR后再发布,不然文章数量太多了。
tables tests: replace cnt + 1 to cnt++ #106
使用cnt++替换cnt += 1
driver: check argument types #105
在checkArgs()增加对类型的转换,转换到mysql类型。
expressions: update subquery #110
对 subquery增加返回row()的处理以及支持plan。
parser/parser.y: S/R conflicts 10->9. #104
修复了一个S/R冲突。
check subquery column #111
对columnCount()支持subquery的计算,需要调用plan,所以传值增加了 ctx。
并且多select.go支持了checkOneColumn()检查是否只有一列数据。并在select的plan中的Fields,GroupBy,OrderBy,Having表达式增加这个检查(他们只允许返回一列的值)。
expressions,parser: IN expression uses subquery #113
对in表达式支持subquery子查询。然后每次检查表达式左右列数相等。
parser/parser.y: S/R conflicts 9->4. #116
解决一个S/R 冲突。
Shenli/show variables #114
支持类似SHOW VARIABLES LIKE ‘character_set_results’;的语法。
parser/parser.y: S/R conflicts 4->3. #118
解决一个S/R冲突。
parser/parser.y: S/R conflicts 3->2. #119
解决一个S/R冲突。
parser/parser.y: S/R conflicts 2->1. #121
解决一个S/R冲突。
add pre-requirement #115
README.md增加了go版本要求说明。
parser/parser.y: S/R conflicts 1->0. #122
解决了所有S/R冲突。
parser: Charset name can be string literal #117
对SET CHARACTER SET ‘utf8mb4’支持字符串。
kv,tidb: fix issue #67 #126
修复issue#67不同索引前缀可能被包含的问题。
以前索引key是使用indexPrefix_indexName来编码的,当两个索引名为c和c1时,由于indexPrefix都是相同的,参考indexprefix生成:
indexPrefix: fmt.Sprintf("%d_i", tableID),
(同一个表的indexprefix都是相同的)
再根据索引前缀生成规则:
fmt.Sprintf("%s_%s", indexPrefix, indexName)
那么c和c1两个索引的key会变成1_i_c1和1_i_c,这样查询c索引的时候会把c1索引全部查询出来。
解决:改变编码规则,在最后加上0x00, 0x01这样前缀就区分开了。
Makefile: Make check by default. #127
makefile all中增加check。
types: Fix convert TypeBit error #131
修复bit类型转换时出错。
makefile, session: tiny clean up and fix a golint check. #132
清理和修复代码格式检查。
expressions: use integer for time in arithmetic op if FSP = 0 #133
当mysql.Time和mysql.Duration的FSP(精度)为0时则转换为整数。
kv: Remove unused fields #134
删除没有用到的字段。
column: Remove unused indexKey #135
删除未使用的indexKey。
Support any/some/all subquery. #125
新增支持any/some/all的子查询。
以select 1 < (select 1)为例,首先根据整个语句plan出来,然后在newdriverRows()中运行Do后会到达:
p, err := cs.R.Plan(ctx) if err != nil { return nil, errors.Trace(err) }
这里会对子查询(select 1)进行plan:
// Plan implements plan.Planner interface. func (sq *SubQuery) Plan(ctx context.Context) (plan.Plan, error) { if sq.p != nil { return sq.p, nil } var err error sq.p, err = sq.Stmt.Plan(ctx) return sq.p, errors.Trace(err) }
然后返回后会在checkResult得到最终比较结果。
expression, parser: Tiny clean up #136
清理一些无效代码。
store, parser: Remove unused variables #137
删除没有使用的变量。
parser: Remove imaginary and runeType #138
清理代码。
check arithmetic operation overflow #140
对算术计算检查是否溢出。
use absolute path for sed on mac #142
makefie:在Mac上使用绝对路径.
Tiny clean up #141
清理代码。
Shenli/cleanup function #139
整理了各个函数。
parser: Fix bug in parse database() #147
修复类似select DATABASE()这样的语句错误。
parser: simplify compare operation #148
简化比较操作的parser代码。
arithmetic overflow #143
支持更多的计算溢出检查。
add make command shell #130
添加make.cmd的windows命令
parser: cleanup parser/scanner error. #145
修改parser和scanner中的错误输出提示。
plans: Support information_schema.collations #150
给mysql内置数据库information_schema增加表collations的数据。
parser: Support cast char with charset #151
支持类似SELECT *, CAST(data AS CHAR CHARACTER SET utf8) FROM t;这样的字符集转换 语法。
*: Support binary operator #153
支持mysql的BINARY表达式:https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#operator_binary
合并在了FunctionCast,加了表示变量,其实SELECT ‘a’ = ‘A’;这样的sql在mysql返回的是1(忽略大小写的),而SELECT BINARY ‘a’ = ‘A’;才返回0。
plan: Next skeleton #123
这个PR比较大,包含很多commit,对Plan支持Next()。
一个一个commit来分析:
:先对需要用到next的plan添加空的plan()函数。
:使用plan.Row{}替换Next的data []interface{}, rowKeys []*plan.RowKeyEntr (其实就是放到了一个结构体)
:增加Close()来关闭Next(),都还未实现。
:给Plan接口新增了ImplementedNext(),会不断调用有ImplementedNext方法的Plan,用于检测是否要有下一个Next()。接着在Recordset的Do()中添加了对Next()的调用。
:对之前的ImplementedNext改名成ImplementedNext ,实现了部分Plan的Next(),其实就是用Next()重构了原来的Do()。
:把where的Do也写到了Next()。增加了一些测试数据。
:实现了limit和offset的Next()。
:实现了order by的Next()。
:实现了TableNil的Next()。
:实现了DistinctDefaultPlan的Next()。
:实现了index的Next()。
:实现了InfoSchemaPlan的Next()。
:实现了ShowPlan的Next()。
:修改变量名通过golint检查。
:在colose()清理一些变量,使其回到初始值,以支持close后的plan可以重复使用,执行Next()等。
:实现了GroupByDefault的Next()。
:实现了Having的Next()。
:实现了Union的Next()。
:实现了Join的Next()。
:删除了之前添加的UseNext().
:修改注释。
:修改 cross join左右儿子遍历顺序。
:修改了注释。
:增加注释,清理了一些语法。
:补上没有添加到Next中的fetchCollations。
types: Allow []byte as orderby type #154
增加[]byte类型到Isorderby(),标记可以作为排序类型。
plans: Fix build error #156
在fetchAll也修改IsOrderedType()的调用方式。
support hexadecimal literal type #157
支持16进制https://dev.mysql.com/doc/refman/5.7/en/hexadecimal-literals.html 运算。(这里还未支持select 的打印输出)
*: Clean up unused code #152
清理无效代码。
types: remove unnecessary code #160
删除没有用到的代码。
expressions,tidb: unary handes bool type #161
修复select + (1 > 0), – (1 > 0)的错误。
fix issue 108 #146
修复类似UPDATE user T0 LEFT OUTER JOIN user_profile T1 ON T1.id = T0.profile_id SET T0.profile_id = ? WHERE T0.profile_id IN (?);的错误。
也就是支持了带有join的修改语句。
Add exists subquery support. #144
支持exists的子查询语句。
driver: add Next method for Recordset and use it in driver#162
把plan中的Do()全部删掉,替换成新的Next()。
tables: Allow multiple null entries for unique index column#163
解决unique索引不能插入多个NULL值的问题。
drop table if exists t; CREATE TABLE test.t (a int primary key auto_increment, b varchar(255) unique); insert into t values (1, NULL), (2,NULL);
原因:
在Creat()中发现了已经存在的KEY:
// unique index _, err = txn.Get(keyBuf) if IsErrNotFound(err) { err = txn.Set(keyBuf, encodeHandle(h)) return errors.Trace(err) } return errors.Trace(ErrKeyExists) }
解决:
需要让unique时如果为NULL,那么可以无限插入,则需要保证keyBuf不同。那么keyBuf是在这里获得的:
// Create creates a new entry in the kvIndex data. // If the index is unique and there already exists an entry with the same key, Create will return ErrKeyExists func (c *kvIndex) Create(txn Transaction, indexedValues []interface{}, h int64) error { keyBuf, err := c.genIndexKey(indexedValues, h) if err != nil { return err }
所以进入genIndexKey,保证key不重复即可。
修改后的genIndexKey:
func (c *kvIndex) genIndexKey(indexedValues []interface{}, h int64) ([]byte, error) { var ( encVal []byte err error ) // only support single value index if !c.unique { encVal, err = EncodeValue(append(indexedValues, h)...) } else { /* See: https://dev.mysql.com/doc/refman/5.7/en/create-index.html A UNIQUE index creates a constraint such that all values in the index must be distinct. An error occurs if you try to add a new row with a key value that matches an existing row. For all engines, a UNIQUE index permits multiple NULL values for columns that can contain NULL. */ containsNull := false for _, cv := range indexedValues { if cv == nil { containsNull = true } } if containsNull { encVal, err = EncodeValue(append(indexedValues, h)...) } else { encVal, err = EncodeValue(indexedValues...) } } if err != nil { return nil, err } buf := append([]byte(nil), []byte(c.prefix)...) buf = append(buf, encVal...) return buf, nil }
tidb: Clean up tidb test #167
清理测试数据。
Set ServerStatusInTrans flag #159
把以前的IsAutocommit()的修改为ShouldAutocommit(),并且增加SetStatusInTrans()设置标志位。
stmts: Fix bug in update single-table syntax but with multiple tables #168
修复下列SQL执行错误:
drop table if exists items; drop table if exists month; CREATE TABLE items (id int, price TEXT); insert into items values (11, "items_price_11"), (12, "items_price_12"), (13, "items_price_13"); CREATE TABLE month (mid int, mprice TEXT); insert into month values (11, "month_price_11"), (22, "month_price_22"), (13, "month_price_13"); UPDATE items join month on items.id=month.mid SET items.price=month.mid;
原因:
tcols, err2 := getUpdateColumns(tbl, s.List, s.MultipleTable) if err2 != nil { return nil, errors.Trace(err2) } if len(tcols) == 0 { // Nothing to update for this table. continue } // Get data in the table err2 = updateRecord(ctx, handle, data, tbl, tcols, s.List, nil, m) if err2 != nil { return nil, errors.Trace(err2) } updatedRowKeys[k] = true } } return nil, nil }
进入这里时s.MultipleTable还是false,那么在getUpdateColumns()找不到另外一张表的字段,所以抛出了错误。
解决:
给JoinRset加上了判断是否有join,有就表示存在多张表:
// MultipleTable checks if the JoinRset contains multiple tables. func (r *JoinRset) MultipleTable() bool { if _, ok := r.Left.(*TableSource); ok { if r.Right == nil { return false } } return true }
stmts: Rename id to handle #171
修改变量名。
*: Replace h with handle #172
把行号变量h改名为handle。
codec: fix ARM build fail #169
修复在arm等32位机器上编译错误。把超出uint32的值加上强制转换uint64即可(int同理)