├── .gitignore ├── .travis.yml ├── Godeps ├── Godeps.json └── Readme ├── LICENSE ├── Makefile ├── README.md ├── bootstrap.sh ├── cmd ├── agent │ └── main.go ├── config │ └── main.go └── proxy │ └── main.go ├── doc ├── .DS_Store ├── architecture.png └── zookeeper_cn.md ├── go ├── Godeps │ ├── Godeps.json │ └── Readme ├── model │ ├── action.go │ ├── doc.go │ ├── group.go │ ├── proxy.go │ ├── route.go │ └── schema.go ├── proxy │ ├── handler.go │ ├── proxy.go │ └── stats.go ├── sqlparser │ ├── Makefile │ ├── analyzer.go │ ├── ast.go │ ├── ast_test.go │ ├── parse_test.go │ ├── parsed_query.go │ ├── parsed_query_test.go │ ├── sql.go │ ├── sql.y │ ├── sql_test.go │ ├── token.go │ └── tracked_buffer.go ├── sqltypes │ └── sqltypes.go └── topo │ ├── agent.go │ ├── group.go │ ├── proxy.go │ ├── schema.go │ ├── topo.go │ └── topo_test.go └── vitess_license /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | _workspace 3 | y.output -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.3 5 | - tip 6 | 7 | before_install: 8 | - go get github.com/tools/godep 9 | - go install -race std 10 | - mysql -e "CREATE DATABASE IF NOT EXISTS test;" -uroot 11 | script: 12 | - godep go test -race ./go/... 13 | -------------------------------------------------------------------------------- /Godeps/Godeps.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportPath": "github.com/go-cloud/myshard", 3 | "GoVersion": "go1.3.3", 4 | "Packages": [ 5 | "./..." 6 | ], 7 | "Deps": [ 8 | { 9 | "ImportPath": "github.com/go-cloud/go-zookeeper/zk", 10 | "Rev": "4ba0637c18318c5127d9eb27fb83a090b36c1f17" 11 | }, 12 | { 13 | "ImportPath": "github.com/go-cloud/zkhelper", 14 | "Rev": "4f44ffeb00758a5ec16f43b3c2ad807a58554343" 15 | }, 16 | { 17 | "ImportPath": "github.com/golang/glog", 18 | "Rev": "d1c4472bf2efd3826f2b5bdcc02d8416798d678c" 19 | }, 20 | { 21 | "ImportPath": "github.com/siddontang/go-mysql/mysql", 22 | "Rev": "7a9586a84dafada6865ace32e7f87f5b7c05434f" 23 | }, 24 | { 25 | "ImportPath": "github.com/siddontang/go-mysql/packet", 26 | "Rev": "7a9586a84dafada6865ace32e7f87f5b7c05434f" 27 | }, 28 | { 29 | "ImportPath": "github.com/siddontang/go-mysql/server", 30 | "Rev": "7a9586a84dafada6865ace32e7f87f5b7c05434f" 31 | }, 32 | { 33 | "ImportPath": "github.com/siddontang/go/hack", 34 | "Rev": "8f64946c30746240c2f3bdb606eed9a4aca34478" 35 | }, 36 | { 37 | "ImportPath": "github.com/siddontang/go/sync2", 38 | "Rev": "8f64946c30746240c2f3bdb606eed9a4aca34478" 39 | }, 40 | { 41 | "ImportPath": "gopkg.in/check.v1", 42 | "Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 go-cloud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: build 2 | 3 | build: build-proxy build-config build-agent 4 | 5 | build-proxy: 6 | go build -o bin/my-proxy ./cmd/proxy 7 | 8 | build-config: 9 | go build -o bin/my-config ./cmd/config 10 | 11 | build-agent: 12 | go build -o bin/my-agent ./cmd/agent 13 | 14 | clean: 15 | @rm -rf bin 16 | 17 | test: 18 | go test ./go/... -race 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Myshard [![Build Status](https://travis-ci.org/go-cloud/myshard.svg?branch=master)](https://travis-ci.org/go-cloud/myshard) 2 | 3 | Yet another MySQL proxy with Go. 4 | 5 | ![Architecture](./doc/architecture.png) 6 | 7 | ## Install 8 | 9 | cd $WORKSPACE 10 | git clone git@github.com:go-cloud/myshard.git src/github.com/go-cloud/myshard 11 | 12 | cd src/github.com/go-cloud/myshard 13 | 14 | ./bootstrap.sh 15 | 16 | make 17 | make test 18 | 19 | ## Feature 20 | 21 | ## Feedback 22 | 23 | + siddontang@gmail.com -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Test godep install 4 | # godep path > /dev/null 2>&1 5 | # if [ "$?" = 0 ]; then 6 | # GOPATH=`godep path` 7 | # # https://github.com/tools/godep/issues/60 8 | # # have to rm Godeps/_workspace first, then restore 9 | # rm -rf $GOPATH 10 | # godep restore 11 | # exit 0 12 | # fi 13 | -------------------------------------------------------------------------------- /cmd/agent/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | log "github.com/golang/glog" 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | ) 10 | 11 | /* 12 | Agent monitors a MySQL server. 13 | 14 | Agent first create an ephemeral node in zookeeper(zk), and then pings MySQL every second. If the MySQL crashed, 15 | agent will close the connection with zk to let other services do something, like failover. 16 | 17 | If agent crashed but MySQL not, other services will think MySQL down too, but can not do failover. So we must also 18 | have a way to monitor agent, like using supervisor or crontab, the agent must be restarted quickly after down. 19 | 20 | You should put agent and MySQL in the same machine, if not, some network error may cause agent think MySQL was crashed. 21 | 22 | A MySQL server can only be monitored by an agent. 23 | */ 24 | 25 | var zkAddr = flag.String("zk", "127.0.0.1:2181", `zookeeper addres, you can use multi zk addresses seperated by ",", like 127.0.0.1:2181,127.0.0.1:2182`) 26 | var myAddr = flag.String("mysql_addr", "127.0.0.1:3306", "local MySQL address") 27 | var myUser = flag.String("mysql_user", "root", "local MySQL user") 28 | var myPassword = flag.String("mysql_pass", "", "local MySQL password") 29 | 30 | func main() { 31 | flag.Parse() 32 | 33 | c := make(chan os.Signal, 1) 34 | signal.Notify(c, os.Interrupt) 35 | signal.Notify(c, syscall.SIGTERM) 36 | <-c 37 | log.Info("ctrl-c or SIGTERM found, exit") 38 | } 39 | -------------------------------------------------------------------------------- /cmd/config/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /cmd/proxy/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/go-cloud/myshard/go/proxy" 7 | "net/http" 8 | _ "net/http/pprof" 9 | "os" 10 | "os/signal" 11 | "runtime" 12 | "syscall" 13 | ) 14 | 15 | var addr = flag.String("addr", "127.0.0.1:4000", "Proxy listen address") 16 | var user = flag.String("user", "root", "Username") 17 | var password = flag.String("password", "", "Password") 18 | var usePprof = flag.Bool("pprof", false, "Enable pprof") 19 | var pprofPort = flag.Int("pprof_port", 6060, "Pprof http port") 20 | 21 | func main() { 22 | runtime.GOMAXPROCS(runtime.NumCPU()) 23 | 24 | flag.Parse() 25 | 26 | s, err := proxy.NewServer(*addr, *user, *password) 27 | if err != nil { 28 | println(err.Error()) 29 | return 30 | } 31 | 32 | sc := make(chan os.Signal, 1) 33 | signal.Notify(sc, 34 | os.Kill, 35 | os.Interrupt, 36 | syscall.SIGHUP, 37 | syscall.SIGINT, 38 | syscall.SIGTERM, 39 | syscall.SIGQUIT) 40 | 41 | if *usePprof { 42 | go func() { 43 | err := http.ListenAndServe(fmt.Sprintf(":%d", *pprofPort), nil) 44 | if err != nil { 45 | println(err.Error()) 46 | } 47 | }() 48 | } 49 | 50 | <-sc 51 | 52 | s.Close() 53 | 54 | } 55 | -------------------------------------------------------------------------------- /doc/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-cloud/myshard/17b9906df802e3c8d4912210f66ad3f1591fda13/doc/.DS_Store -------------------------------------------------------------------------------- /doc/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-cloud/myshard/17b9906df802e3c8d4912210f66ad3f1591fda13/doc/architecture.png -------------------------------------------------------------------------------- /doc/zookeeper_cn.md: -------------------------------------------------------------------------------- 1 | 在myshard里面,我们使用zookeeper(后续以zk代替)来进行全局配置管理,以及协调多个服务。 2 | 3 | 这里只是一个草稿,后续代码实现可能变动较大,仅仅作为临时记录实现的地方 4 | 5 | 后续会有完整的英文文档 6 | 7 | ## MySQL 8 | 9 | 我们使用group来表明一组MySQL,一组MySQL至少需要有一个master,可以有0个或者多个slave。也就是最常用的master/slave模式,我们不建议使用master/master架构模式,因为这样可能引入更多的复制问题,如果真要支持,myshard也可能只会选择一个进行写入操作,而将另一个当做slave。另外,还需要考虑gelera的架构模式,应该可以退化到单master情况,(gelera虽然有三台MySQL,但外部通过一个入口访问。) 10 | 11 | group是全局唯一的,使用数字1,2,3来表示,不同group不允许出现相同的MySQL实例。 12 | 13 | 14 | group: 15 | 16 | ``` 17 | /zk/myshard/groups/group_1 18 | /zk/myshard/groups/group_2 19 | /zk/myshard/groups/group_3 20 | ``` 21 | 22 | group node 23 | 24 | ``` 25 | type GroupNode struct { 26 | ID int 27 | Status string 28 | } 29 | ``` 30 | 31 | group MySQL 32 | 33 | ``` 34 | /zk/myshard/groups/group_1/10.20.151.151:3306 35 | /zk/myshard/groups/group_1/10.20.151.152:3306 36 | ``` 37 | 38 | MySQL 39 | 40 | ``` 41 | /zk/myshard/mysqls/10.20.151.151:3306 42 | /zk/myshard/mysqls/10.20.151.152:3306 43 | ``` 44 | 45 | MySQL node 46 | 47 | ``` 48 | type MySQLNode struct { 49 | Addr string 50 | Type string //master or slave 51 | Status string 52 | GroupID int 53 | } 54 | ``` 55 | 56 | ## Agent 57 | 58 | agent用来监控MySQL是否存活,通常跟MySQL在一台机器上面,agent在zk上面注册一个ephemeral节点,当MySQL当掉,或者所在机器当掉,agent与zk的连接断开,zk就能通知其他监控程序后续处理,譬如邮件通知,或者自动failover处理。 59 | 60 | 但我们还可能面临一种情况就是agent挂掉了,但MySQL仍然存活,所以我们外部的程序仍然需要额外判断MySQL是不是真正当掉了。 61 | 62 | agent 63 | 64 | ``` 65 | /zk/myshard/agents/10.20.151.151:3306 66 | ``` 67 | 68 | ## Proxy 69 | 70 | proxy是一个无状态的服务,所以我们使用sequence flag来在zk上面创建相应的node 71 | 72 | ``` 73 | /zk/myshard/proxys/proxy_seq 74 | ``` 75 | 76 | proxy node 77 | 78 | ``` 79 | type ProxyNode struct { 80 | ID int 81 | Addr string 82 | HttpAddr string 83 | Status string 84 | } 85 | ``` 86 | 87 | ## Route 88 | 89 | route用来存放路由表信息,myshard会根据首先解析sql,然后根据响应的路由规则将sql发到不同的group里面的一台MySQL去执行。 90 | 91 | 对于客户端来说,它只知道sql的db和table,但是在myshard内部,我们可能将该数据拆分到不同的子table上面,也就是说,对外可能是user表,但在 92 | myshard内部,我们使用的是user_1, user_2, ... user_1024。 93 | 94 | 而对于一个db,它可能存放到不同的group上面 95 | 96 | ``` 97 | /zk/myshard/dbs/db_1 98 | /zk/myshard/dbs/db_2 99 | ``` 100 | 101 | db node 102 | 103 | ``` 104 | type DBNode struct { 105 | Name string 106 | GroupIDs []int //group ids 107 | Status string 108 | 109 | //如果table没有指定group,则默认在该group上面 110 | DefaultGroupID int 111 | } 112 | ``` 113 | 114 | table 115 | 116 | ``` 117 | /zk/myshard/dbs/db_1/user 118 | ``` 119 | 120 | table node 121 | 122 | ``` 123 | type TableNode struct { 124 | //如果改table没有切分,则使用groupid,否则,各个子表需要使用各自对应的groupid 125 | GroupID int 126 | 127 | //因为可能会有多个子表,为了简单,key的格式可能如下 128 | // 1 表示table_1 129 | // 1,2,3 表示table_1, table_2, table_3 130 | // 1-3 表示table_1, table_2, table_3 131 | SubTables map[string]int 132 | } 133 | ``` 134 | 135 | ``` 136 | /zk/myshard/routes/db_1/user_route 137 | ``` 138 | 139 | route node 140 | 141 | ``` 142 | type RouteNode struct { 143 | DB string 144 | Table string 145 | 146 | Type string //hash or range 147 | Column string //table column for route 148 | 149 | RangeMap map[string]int // key like "1-100" -> table id 150 | } 151 | ``` 152 | 153 | ## Action 154 | 155 | sequence flag 156 | 157 | ``` 158 | /zk/myshard/actions/action_seq 159 | ``` 160 | 161 | action node 162 | 163 | ``` 164 | type ActionNode struct { 165 | ID int 166 | CreateTime int 167 | Command string 168 | Args []interface{} 169 | } 170 | ``` 171 | 172 | ## Lock 173 | 174 | 任何对全局配置的更改都必须获取lock 175 | 176 | ``` 177 | /zk/myshard/lock 178 | ``` 179 | 180 | ## Migrate 181 | 182 | 如果预估到一个表数据量会很大,我们需要在开始的时候就对其进行分表处理,譬如1024张表 183 | 184 | myshard对于数据迁移是以子表为单位的,假设现在结构如下 185 | 186 | group1 -> user_1, user_2, user_3 187 | group2 -> user_4 188 | 189 | 因为group1的压力,我们需要将user_2移动到group2 190 | 191 | + 我们先将当前user_2表数据拷贝到group2上面 192 | + 因为这时候可能会有新的写入操作发生,我们只需要进行binlog同步就可以 193 | + 当binlog同步完成或者两个group之间的相差不大,我们通过config像zk发起迁移action 194 | + proxy收到改action之后,会拒绝所有对user表的写操作,但读仍然可行,同时等待先前所有对user表的写操作完成 195 | + proxy通过zk告知config可以迁移 196 | + config等待binlog同步完成,然后更新路由表 197 | + proxy收到路由表更新事件,在本地更新路由表,同时告知config更新完成 198 | + config发起迁移完成action,proxy收到之后开始新的处理。因为这时候仍然有老的连接在使用就得数据查询,所以我们会在一段时间之后才从group1删除user_2 199 | 200 | 迁移过程中的错误处理,后续完善 201 | 202 | ## Up and Down MySQL 203 | 204 | 通过config对某个group内的MySQL集群进行操作,大概流程类似migrate,只是proxy需要处理的是group,而不是特定的表 205 | 206 | config在操作的时候一定要首先获取lock,也就是同一个时间只允许一个全局更新操作 -------------------------------------------------------------------------------- /go/Godeps/Godeps.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportPath": "github.com/go-cloud/myshard/go", 3 | "GoVersion": "go1.3.3", 4 | "Packages": [ 5 | "./..." 6 | ], 7 | "Deps": [ 8 | { 9 | "ImportPath": "github.com/go-cloud/go-zookeeper/zk", 10 | "Rev": "4ba0637c18318c5127d9eb27fb83a090b36c1f17" 11 | }, 12 | { 13 | "ImportPath": "github.com/go-cloud/zkhelper", 14 | "Rev": "4f44ffeb00758a5ec16f43b3c2ad807a58554343" 15 | }, 16 | { 17 | "ImportPath": "github.com/golang/glog", 18 | "Rev": "44145f04b68cf362d9c4df2182967c2275eaefed" 19 | }, 20 | { 21 | "ImportPath": "github.com/siddontang/go-mysql/mysql", 22 | "Rev": "7a9586a84dafada6865ace32e7f87f5b7c05434f" 23 | }, 24 | { 25 | "ImportPath": "github.com/siddontang/go-mysql/packet", 26 | "Rev": "7a9586a84dafada6865ace32e7f87f5b7c05434f" 27 | }, 28 | { 29 | "ImportPath": "github.com/siddontang/go-mysql/server", 30 | "Rev": "7a9586a84dafada6865ace32e7f87f5b7c05434f" 31 | }, 32 | { 33 | "ImportPath": "github.com/siddontang/go/hack", 34 | "Rev": "8f64946c30746240c2f3bdb606eed9a4aca34478" 35 | }, 36 | { 37 | "ImportPath": "github.com/siddontang/go/sync2", 38 | "Rev": "8f64946c30746240c2f3bdb606eed9a4aca34478" 39 | }, 40 | { 41 | "ImportPath": "gopkg.in/check.v1", 42 | "Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /go/Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /go/model/action.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Action struct { 4 | } 5 | -------------------------------------------------------------------------------- /go/model/doc.go: -------------------------------------------------------------------------------- 1 | package model 2 | -------------------------------------------------------------------------------- /go/model/group.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | const ( 4 | NodeUpStatus = "up" 5 | NodeDownStatus = "down" 6 | ) 7 | 8 | const ( 9 | NodeMasterType = "master" 10 | NodeSlaveType = "slave" 11 | ) 12 | 13 | // Node is a MySQL instance 14 | type Node struct { 15 | GroupID int `json:"group_id"` 16 | Addr string `json:"addr"` 17 | Type string `json:"type"` 18 | Status string `json:"status"` 19 | Weight int `json:"weight"` 20 | } 21 | 22 | const ( 23 | GroupUpStatus = "up" 24 | GroupDownStatus = "down" 25 | ) 26 | 27 | // Group includes one or more MySQL instances 28 | // A group must have a master, none or more slaves 29 | type Group struct { 30 | ID int `json:"id"` 31 | Status string `json:"status"` 32 | Nodes []Node `json:"-"` 33 | } 34 | 35 | type NodeSlice []Node 36 | 37 | func (ns NodeSlice) Len() int { 38 | return len(ns) 39 | } 40 | 41 | // master node is at the beginning 42 | // for same type, higher weight is in front 43 | func (ns NodeSlice) Less(i, j int) bool { 44 | if ns[i].Type != ns[j].Type { 45 | if ns[i].Type == NodeMasterType { 46 | return true 47 | } else { 48 | return false 49 | } 50 | } else { 51 | return ns[i].Weight >= ns[j].Weight 52 | } 53 | } 54 | 55 | func (ns NodeSlice) Swap(i, j int) { 56 | ns[i] = ns[j] 57 | } 58 | -------------------------------------------------------------------------------- /go/model/proxy.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | const ( 4 | ProxyStatusUp = "up" 5 | ProxyStatusDown = "down" 6 | ) 7 | 8 | // Proxy is proxy server 9 | type Proxy struct { 10 | // For MySQL protocol communication 11 | Addr string `json:"addr"` 12 | 13 | // Proxy HTTP communication 14 | HttpAddr string `json:"http_addr"` 15 | 16 | Status string `json:"status"` 17 | } 18 | -------------------------------------------------------------------------------- /go/model/route.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "hash/adler32" 5 | "hash/crc32" 6 | ) 7 | 8 | const ( 9 | RouteTypeHash = "hash" 10 | RouteTypeRange = "range" 11 | ) 12 | 13 | // We will route to let a SQL exexuted in the exact group 14 | type Route struct { 15 | DB string `json:"db"` 16 | Table string `json:"table"` 17 | Column string `json:"column"` 18 | Type string `json:"type"` 19 | 20 | // For hash type 21 | // crc32, adler32, or you can use your own hash function if registered 22 | // default is crc32 23 | Hash string `json:"hash"` 24 | 25 | // For range type 26 | // key format 1-10000, left close and right open 27 | // value is sub table id 28 | // e.g, if the ranges is {"0-100" : 0, "100-200" : 1} 29 | // if a key is 50, we may know that the data will be saved in table_0 30 | Ranges map[string]int `json:"ranges"` 31 | } 32 | 33 | type HashFunc func([]byte) uint32 34 | 35 | var hashFuncs map[string]HashFunc 36 | 37 | func RegisterHashFunc(name string, fn HashFunc) { 38 | hashFuncs[name] = fn 39 | } 40 | 41 | func Hash(name string, data []byte) uint32 { 42 | fn, ok := hashFuncs[name] 43 | if !ok { 44 | return crc32.ChecksumIEEE(data) 45 | } 46 | 47 | return fn(data) 48 | } 49 | 50 | func init() { 51 | hashFuncs = make(map[string]HashFunc) 52 | 53 | hashFuncs["crc32"] = crc32.ChecksumIEEE 54 | hashFuncs["adler32"] = adler32.Checksum 55 | } 56 | -------------------------------------------------------------------------------- /go/model/schema.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // Schema is MySQL database, and can be stored in one or more groups. 4 | type Schema struct { 5 | Name string `json:"name"` 6 | 7 | GroupIDs []int `json:"group_ids"` 8 | 9 | // The default group for the table stored 10 | DefaultGroupID int `json:"default_group_id"` 11 | 12 | // Later use, todo, maybe for migrate 13 | Status string `json:"status"` 14 | } 15 | 16 | type Table struct { 17 | DB string `json:"db"` 18 | 19 | Name string `json:"name"` 20 | 21 | // If the table is not splitted, it will be stored in this group 22 | GroupID int `json:"group_id"` 23 | 24 | // If the table is splitted, e.g. a user table, may be splitted into 1024, 25 | // so the real table may be stored in different groups 26 | // like user_0 stored in group_0, user_1 stored in group_1 27 | // the sub table id must start from 0, so we can use a slice to map 28 | // the table id -> group id 29 | SubTables []int `json:"sub_tables"` 30 | 31 | // Later use, todo, maybe for migrate 32 | Status string `json:"status"` 33 | } 34 | -------------------------------------------------------------------------------- /go/proxy/handler.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | "fmt" 5 | . "github.com/siddontang/go-mysql/mysql" 6 | "github.com/siddontang/go-mysql/server" 7 | ) 8 | 9 | type Handler struct { 10 | s *Server 11 | 12 | conn *server.Conn 13 | } 14 | 15 | func newHandler(s *Server) *Handler { 16 | h := new(Handler) 17 | 18 | h.s = s 19 | 20 | return h 21 | } 22 | 23 | func (h *Handler) UseDB(dbName string) error { 24 | return nil 25 | } 26 | 27 | func (h *Handler) HandleQuery(query string) (*Result, error) { 28 | return nil, fmt.Errorf("not supported now") 29 | } 30 | 31 | func (h *Handler) HandleFieldList(table string, fieldWildcard string) ([]*Field, error) { 32 | return nil, fmt.Errorf("not supported now") 33 | } 34 | 35 | func (h *Handler) HandleStmtPreprare(query string) (params int, columns int, context interface{}, err error) { 36 | err = fmt.Errorf("not supported now") 37 | return 38 | } 39 | 40 | func (h *Handler) HandleStmtExecute(context interface{}, query string, args []interface{}) (*Result, error) { 41 | return nil, fmt.Errorf("not supported now") 42 | } 43 | -------------------------------------------------------------------------------- /go/proxy/proxy.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | import ( 4 | log "github.com/golang/glog" 5 | . "github.com/siddontang/go-mysql/mysql" 6 | "github.com/siddontang/go-mysql/server" 7 | "net" 8 | "sync" 9 | ) 10 | 11 | // Server acts as a MySQL server, it listens and accepts MySQL client connections, 12 | // parses the commands then sends them to the specified MySQL server. 13 | type Server struct { 14 | l net.Listener 15 | 16 | quit chan struct{} 17 | addr string 18 | user string 19 | password string 20 | 21 | wg sync.WaitGroup 22 | } 23 | 24 | func NewServer(addr string, user string, password string) (*Server, error) { 25 | s := new(Server) 26 | 27 | s.addr = addr 28 | s.user = user 29 | s.password = password 30 | 31 | s.quit = make(chan struct{}) 32 | 33 | var err error 34 | proto := GetNetProto(addr) 35 | if s.l, err = net.Listen(proto, addr); err != nil { 36 | return nil, err 37 | } 38 | 39 | go s.run() 40 | 41 | return s, nil 42 | } 43 | 44 | func (s *Server) run() { 45 | for { 46 | c, err := s.l.Accept() 47 | if err != nil { 48 | return 49 | } 50 | 51 | s.wg.Add(1) 52 | go s.onConn(c) 53 | } 54 | } 55 | 56 | func (s *Server) onConn(c net.Conn) { 57 | defer s.wg.Done() 58 | 59 | h := newHandler(s) 60 | conn, err := server.NewConn(c, s.user, s.password, h) 61 | if err != nil { 62 | log.Errorf("new connection error %s", err.Error()) 63 | c.Close() 64 | return 65 | } 66 | 67 | h.conn = conn 68 | 69 | for { 70 | select { 71 | case <-s.quit: 72 | // Proxy quited, close conection 73 | conn.Close() 74 | return 75 | default: 76 | break 77 | } 78 | 79 | err = conn.HandleCommand() 80 | if err != nil { 81 | log.Errorf("handle command error %s", err.Error()) 82 | return 83 | } 84 | } 85 | } 86 | 87 | func (s *Server) Close() { 88 | close(s.quit) 89 | 90 | if s.l != nil { 91 | s.l.Close() 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /go/proxy/stats.go: -------------------------------------------------------------------------------- 1 | package proxy 2 | 3 | type Stats struct { 4 | } 5 | -------------------------------------------------------------------------------- /go/sqlparser/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2012, Google Inc. All rights reserved. 2 | # Use of this source code is governed by a BSD-style license that can 3 | # be found in the LICENSE file. 4 | 5 | MAKEFLAGS = -s 6 | 7 | sql.go: sql.y 8 | go tool yacc -o sql.go sql.y 9 | gofmt -w sql.go 10 | 11 | clean: 12 | rm -f y.output sql.go 13 | -------------------------------------------------------------------------------- /go/sqlparser/analyzer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlparser 6 | 7 | // analyzer.go contains utility analysis functions. 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/go-cloud/myshard/go/sqltypes" 13 | ) 14 | 15 | // GetTableName returns the table name from the SimpleTableExpr 16 | // only if it's a simple expression. Otherwise, it returns "". 17 | func GetTableName(node SimpleTableExpr) string { 18 | if n, ok := node.(*TableName); ok && n.Qualifier == nil { 19 | return string(n.Name) 20 | } 21 | // sub-select or '.' expression 22 | return "" 23 | } 24 | 25 | // GetColName returns the column name, only if 26 | // it's a simple expression. Otherwise, it returns "". 27 | func GetColName(node Expr) string { 28 | if n, ok := node.(*ColName); ok { 29 | return string(n.Name) 30 | } 31 | return "" 32 | } 33 | 34 | // IsColName returns true if the ValExpr is a *ColName. 35 | func IsColName(node ValExpr) bool { 36 | _, ok := node.(*ColName) 37 | return ok 38 | } 39 | 40 | // IsValue returns true if the ValExpr is a string, number or value arg. 41 | // NULL is not considered to be a value. 42 | func IsValue(node ValExpr) bool { 43 | switch node.(type) { 44 | case StrVal, NumVal, ValArg: 45 | return true 46 | } 47 | return false 48 | } 49 | 50 | // HasINCaluse returns true if any of the conditions has an IN clause. 51 | func HasINClause(conditions []BoolExpr) bool { 52 | for _, node := range conditions { 53 | if c, ok := node.(*ComparisonExpr); ok && c.Operator == AST_IN { 54 | return true 55 | } 56 | } 57 | return false 58 | } 59 | 60 | // IsSimpleTuple returns true if the ValExpr is a ValTuple that 61 | // contains simple values or if it's a list arg. 62 | func IsSimpleTuple(node ValExpr) bool { 63 | switch vals := node.(type) { 64 | case ValTuple: 65 | for _, n := range vals { 66 | if !IsValue(n) { 67 | return false 68 | } 69 | } 70 | return true 71 | case ListArg: 72 | return true 73 | } 74 | // It's a subquery 75 | return false 76 | } 77 | 78 | // AsInterface converts the ValExpr to an interface. It converts 79 | // ValTuple to []interface{}, ValArg to string, StrVal to sqltypes.String, 80 | // NumVal to sqltypes.Numeric, NullVal to nil. 81 | // Otherwise, it returns an error. 82 | func AsInterface(node ValExpr) (interface{}, error) { 83 | switch node := node.(type) { 84 | case ValTuple: 85 | vals := make([]interface{}, 0, len(node)) 86 | for _, val := range node { 87 | v, err := AsInterface(val) 88 | if err != nil { 89 | return nil, err 90 | } 91 | vals = append(vals, v) 92 | } 93 | return vals, nil 94 | case ValArg: 95 | return string(node), nil 96 | case ListArg: 97 | return string(node), nil 98 | case StrVal: 99 | return sqltypes.MakeString(node), nil 100 | case NumVal: 101 | n, err := sqltypes.BuildNumeric(string(node)) 102 | if err != nil { 103 | return nil, fmt.Errorf("type mismatch: %s", err) 104 | } 105 | return n, nil 106 | case *NullVal: 107 | return nil, nil 108 | } 109 | return nil, fmt.Errorf("unexpected node %v", node) 110 | } 111 | 112 | // StringIn is a convenience function that returns 113 | // true if str matches any of the values. 114 | func StringIn(str string, values ...string) bool { 115 | for _, val := range values { 116 | if str == val { 117 | return true 118 | } 119 | } 120 | return false 121 | } 122 | -------------------------------------------------------------------------------- /go/sqlparser/ast.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlparser 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "strconv" 11 | 12 | "github.com/go-cloud/myshard/go/sqltypes" 13 | ) 14 | 15 | // Instructions for creating new types: If a type 16 | // needs to satisfy an interface, declare that function 17 | // along with that interface. This will help users 18 | // identify the list of types to which they can assert 19 | // those interfaces. 20 | // If the member of a type has a string with a predefined 21 | // list of values, declare those values as const following 22 | // the type. 23 | // For interfaces that define dummy functions to consolidate 24 | // a set of types, define the function as ITypeName. 25 | // This will help avoid name collisions. 26 | 27 | // Parse parses the sql and returns a Statement, which 28 | // is the AST representation of the query. 29 | func Parse(sql string) (Statement, error) { 30 | tokenizer := NewStringTokenizer(sql) 31 | if yyParse(tokenizer) != 0 { 32 | return nil, errors.New(tokenizer.LastError) 33 | } 34 | return tokenizer.ParseTree, nil 35 | } 36 | 37 | // SQLNode defines the interface for all nodes 38 | // generated by the parser. 39 | type SQLNode interface { 40 | Format(buf *TrackedBuffer) 41 | } 42 | 43 | // String returns a string representation of an SQLNode. 44 | func String(node SQLNode) string { 45 | buf := NewTrackedBuffer(nil) 46 | buf.Myprintf("%v", node) 47 | return buf.String() 48 | } 49 | 50 | // Statement represents a statement. 51 | type Statement interface { 52 | IStatement() 53 | SQLNode 54 | } 55 | 56 | func (*Union) IStatement() {} 57 | func (*Select) IStatement() {} 58 | func (*Insert) IStatement() {} 59 | func (*Update) IStatement() {} 60 | func (*Delete) IStatement() {} 61 | func (*Set) IStatement() {} 62 | func (*DDL) IStatement() {} 63 | func (*Other) IStatement() {} 64 | 65 | // SelectStatement any SELECT statement. 66 | type SelectStatement interface { 67 | ISelectStatement() 68 | IStatement() 69 | IInsertRows() 70 | SQLNode 71 | } 72 | 73 | func (*Select) ISelectStatement() {} 74 | func (*Union) ISelectStatement() {} 75 | 76 | // Select represents a SELECT statement. 77 | type Select struct { 78 | Comments Comments 79 | Distinct string 80 | SelectExprs SelectExprs 81 | From TableExprs 82 | Where *Where 83 | GroupBy GroupBy 84 | Having *Where 85 | OrderBy OrderBy 86 | Limit *Limit 87 | Lock string 88 | } 89 | 90 | // Select.Distinct 91 | const ( 92 | AST_DISTINCT = "distinct " 93 | ) 94 | 95 | // Select.Lock 96 | const ( 97 | AST_FOR_UPDATE = " for update" 98 | AST_SHARE_MODE = " lock in share mode" 99 | ) 100 | 101 | func (node *Select) Format(buf *TrackedBuffer) { 102 | buf.Myprintf("select %v%s%v from %v%v%v%v%v%v%s", 103 | node.Comments, node.Distinct, node.SelectExprs, 104 | node.From, node.Where, 105 | node.GroupBy, node.Having, node.OrderBy, 106 | node.Limit, node.Lock) 107 | } 108 | 109 | // Union represents a UNION statement. 110 | type Union struct { 111 | Type string 112 | Left, Right SelectStatement 113 | } 114 | 115 | // Union.Type 116 | const ( 117 | AST_UNION = "union" 118 | AST_UNION_ALL = "union all" 119 | AST_SET_MINUS = "minus" 120 | AST_EXCEPT = "except" 121 | AST_INTERSECT = "intersect" 122 | ) 123 | 124 | func (node *Union) Format(buf *TrackedBuffer) { 125 | buf.Myprintf("%v %s %v", node.Left, node.Type, node.Right) 126 | } 127 | 128 | // Insert represents an INSERT statement. 129 | type Insert struct { 130 | Comments Comments 131 | Table *TableName 132 | Columns Columns 133 | Rows InsertRows 134 | OnDup OnDup 135 | } 136 | 137 | func (node *Insert) Format(buf *TrackedBuffer) { 138 | buf.Myprintf("insert %vinto %v%v %v%v", 139 | node.Comments, 140 | node.Table, node.Columns, node.Rows, node.OnDup) 141 | } 142 | 143 | // InsertRows represents the rows for an INSERT statement. 144 | type InsertRows interface { 145 | IInsertRows() 146 | SQLNode 147 | } 148 | 149 | func (*Select) IInsertRows() {} 150 | func (*Union) IInsertRows() {} 151 | func (Values) IInsertRows() {} 152 | 153 | // Update represents an UPDATE statement. 154 | type Update struct { 155 | Comments Comments 156 | Table *TableName 157 | Exprs UpdateExprs 158 | Where *Where 159 | OrderBy OrderBy 160 | Limit *Limit 161 | } 162 | 163 | func (node *Update) Format(buf *TrackedBuffer) { 164 | buf.Myprintf("update %v%v set %v%v%v%v", 165 | node.Comments, node.Table, 166 | node.Exprs, node.Where, node.OrderBy, node.Limit) 167 | } 168 | 169 | // Delete represents a DELETE statement. 170 | type Delete struct { 171 | Comments Comments 172 | Table *TableName 173 | Where *Where 174 | OrderBy OrderBy 175 | Limit *Limit 176 | } 177 | 178 | func (node *Delete) Format(buf *TrackedBuffer) { 179 | buf.Myprintf("delete %vfrom %v%v%v%v", 180 | node.Comments, 181 | node.Table, node.Where, node.OrderBy, node.Limit) 182 | } 183 | 184 | // Set represents a SET statement. 185 | type Set struct { 186 | Comments Comments 187 | Exprs UpdateExprs 188 | } 189 | 190 | func (node *Set) Format(buf *TrackedBuffer) { 191 | buf.Myprintf("set %v%v", node.Comments, node.Exprs) 192 | } 193 | 194 | // DDL represents a CREATE, ALTER, DROP or RENAME statement. 195 | // Table is set for AST_ALTER, AST_DROP, AST_RENAME. 196 | // NewName is set for AST_ALTER, AST_CREATE, AST_RENAME. 197 | type DDL struct { 198 | Action string 199 | Table []byte 200 | NewName []byte 201 | } 202 | 203 | const ( 204 | AST_CREATE = "create" 205 | AST_ALTER = "alter" 206 | AST_DROP = "drop" 207 | AST_RENAME = "rename" 208 | ) 209 | 210 | func (node *DDL) Format(buf *TrackedBuffer) { 211 | switch node.Action { 212 | case AST_CREATE: 213 | buf.Myprintf("%s table %s", node.Action, node.NewName) 214 | case AST_RENAME: 215 | buf.Myprintf("%s table %s %s", node.Action, node.Table, node.NewName) 216 | default: 217 | buf.Myprintf("%s table %s", node.Action, node.Table) 218 | } 219 | } 220 | 221 | // Other represents a SHOW, DESCRIBE, or EXPLAIN statement. 222 | // It should be used only as an indicator. It does not contain 223 | // the full AST for the statement. 224 | type Other struct{} 225 | 226 | func (node *Other) Format(buf *TrackedBuffer) { 227 | buf.WriteString("other") 228 | } 229 | 230 | // Comments represents a list of comments. 231 | type Comments [][]byte 232 | 233 | func (node Comments) Format(buf *TrackedBuffer) { 234 | for _, c := range node { 235 | buf.Myprintf("%s ", c) 236 | } 237 | } 238 | 239 | // SelectExprs represents SELECT expressions. 240 | type SelectExprs []SelectExpr 241 | 242 | func (node SelectExprs) Format(buf *TrackedBuffer) { 243 | var prefix string 244 | for _, n := range node { 245 | buf.Myprintf("%s%v", prefix, n) 246 | prefix = ", " 247 | } 248 | } 249 | 250 | // SelectExpr represents a SELECT expression. 251 | type SelectExpr interface { 252 | ISelectExpr() 253 | SQLNode 254 | } 255 | 256 | func (*StarExpr) ISelectExpr() {} 257 | func (*NonStarExpr) ISelectExpr() {} 258 | 259 | // StarExpr defines a '*' or 'table.*' expression. 260 | type StarExpr struct { 261 | TableName []byte 262 | } 263 | 264 | func (node *StarExpr) Format(buf *TrackedBuffer) { 265 | if node.TableName != nil { 266 | buf.Myprintf("%s.", node.TableName) 267 | } 268 | buf.Myprintf("*") 269 | } 270 | 271 | // NonStarExpr defines a non-'*' select expr. 272 | type NonStarExpr struct { 273 | Expr Expr 274 | As []byte 275 | } 276 | 277 | func (node *NonStarExpr) Format(buf *TrackedBuffer) { 278 | buf.Myprintf("%v", node.Expr) 279 | if node.As != nil { 280 | buf.Myprintf(" as %s", node.As) 281 | } 282 | } 283 | 284 | // Columns represents an insert column list. 285 | // The syntax for Columns is a subset of SelectExprs. 286 | // So, it's castable to a SelectExprs and can be analyzed 287 | // as such. 288 | type Columns []SelectExpr 289 | 290 | func (node Columns) Format(buf *TrackedBuffer) { 291 | if node == nil { 292 | return 293 | } 294 | buf.Myprintf("(%v)", SelectExprs(node)) 295 | } 296 | 297 | // TableExprs represents a list of table expressions. 298 | type TableExprs []TableExpr 299 | 300 | func (node TableExprs) Format(buf *TrackedBuffer) { 301 | var prefix string 302 | for _, n := range node { 303 | buf.Myprintf("%s%v", prefix, n) 304 | prefix = ", " 305 | } 306 | } 307 | 308 | // TableExpr represents a table expression. 309 | type TableExpr interface { 310 | ITableExpr() 311 | SQLNode 312 | } 313 | 314 | func (*AliasedTableExpr) ITableExpr() {} 315 | func (*ParenTableExpr) ITableExpr() {} 316 | func (*JoinTableExpr) ITableExpr() {} 317 | 318 | // AliasedTableExpr represents a table expression 319 | // coupled with an optional alias or index hint. 320 | type AliasedTableExpr struct { 321 | Expr SimpleTableExpr 322 | As []byte 323 | Hints *IndexHints 324 | } 325 | 326 | func (node *AliasedTableExpr) Format(buf *TrackedBuffer) { 327 | buf.Myprintf("%v", node.Expr) 328 | if node.As != nil { 329 | buf.Myprintf(" as %s", node.As) 330 | } 331 | if node.Hints != nil { 332 | // Hint node provides the space padding. 333 | buf.Myprintf("%v", node.Hints) 334 | } 335 | } 336 | 337 | // SimpleTableExpr represents a simple table expression. 338 | type SimpleTableExpr interface { 339 | ISimpleTableExpr() 340 | SQLNode 341 | } 342 | 343 | func (*TableName) ISimpleTableExpr() {} 344 | func (*Subquery) ISimpleTableExpr() {} 345 | 346 | // TableName represents a table name. 347 | type TableName struct { 348 | Name, Qualifier []byte 349 | } 350 | 351 | func (node *TableName) Format(buf *TrackedBuffer) { 352 | if node.Qualifier != nil { 353 | escape(buf, node.Qualifier) 354 | buf.Myprintf(".") 355 | } 356 | escape(buf, node.Name) 357 | } 358 | 359 | // ParenTableExpr represents a parenthesized TableExpr. 360 | type ParenTableExpr struct { 361 | Expr TableExpr 362 | } 363 | 364 | func (node *ParenTableExpr) Format(buf *TrackedBuffer) { 365 | buf.Myprintf("(%v)", node.Expr) 366 | } 367 | 368 | // JoinTableExpr represents a TableExpr that's a JOIN operation. 369 | type JoinTableExpr struct { 370 | LeftExpr TableExpr 371 | Join string 372 | RightExpr TableExpr 373 | On BoolExpr 374 | } 375 | 376 | // JoinTableExpr.Join 377 | const ( 378 | AST_JOIN = "join" 379 | AST_STRAIGHT_JOIN = "straight_join" 380 | AST_LEFT_JOIN = "left join" 381 | AST_RIGHT_JOIN = "right join" 382 | AST_CROSS_JOIN = "cross join" 383 | AST_NATURAL_JOIN = "natural join" 384 | ) 385 | 386 | func (node *JoinTableExpr) Format(buf *TrackedBuffer) { 387 | buf.Myprintf("%v %s %v", node.LeftExpr, node.Join, node.RightExpr) 388 | if node.On != nil { 389 | buf.Myprintf(" on %v", node.On) 390 | } 391 | } 392 | 393 | // IndexHints represents a list of index hints. 394 | type IndexHints struct { 395 | Type string 396 | Indexes [][]byte 397 | } 398 | 399 | const ( 400 | AST_USE = "use" 401 | AST_IGNORE = "ignore" 402 | AST_FORCE = "force" 403 | ) 404 | 405 | func (node *IndexHints) Format(buf *TrackedBuffer) { 406 | buf.Myprintf(" %s index ", node.Type) 407 | prefix := "(" 408 | for _, n := range node.Indexes { 409 | buf.Myprintf("%s%s", prefix, n) 410 | prefix = ", " 411 | } 412 | buf.Myprintf(")") 413 | } 414 | 415 | // Where represents a WHERE or HAVING clause. 416 | type Where struct { 417 | Type string 418 | Expr BoolExpr 419 | } 420 | 421 | // Where.Type 422 | const ( 423 | AST_WHERE = "where" 424 | AST_HAVING = "having" 425 | ) 426 | 427 | // NewWhere creates a WHERE or HAVING clause out 428 | // of a BoolExpr. If the expression is nil, it returns nil. 429 | func NewWhere(typ string, expr BoolExpr) *Where { 430 | if expr == nil { 431 | return nil 432 | } 433 | return &Where{Type: typ, Expr: expr} 434 | } 435 | 436 | func (node *Where) Format(buf *TrackedBuffer) { 437 | if node == nil || node.Expr == nil { 438 | return 439 | } 440 | buf.Myprintf(" %s %v", node.Type, node.Expr) 441 | } 442 | 443 | // Expr represents an expression. 444 | type Expr interface { 445 | IExpr() 446 | SQLNode 447 | } 448 | 449 | func (*AndExpr) IExpr() {} 450 | func (*OrExpr) IExpr() {} 451 | func (*NotExpr) IExpr() {} 452 | func (*ParenBoolExpr) IExpr() {} 453 | func (*ComparisonExpr) IExpr() {} 454 | func (*RangeCond) IExpr() {} 455 | func (*NullCheck) IExpr() {} 456 | func (*ExistsExpr) IExpr() {} 457 | func (*KeyrangeExpr) IExpr() {} 458 | func (StrVal) IExpr() {} 459 | func (NumVal) IExpr() {} 460 | func (ValArg) IExpr() {} 461 | func (*NullVal) IExpr() {} 462 | func (*ColName) IExpr() {} 463 | func (ValTuple) IExpr() {} 464 | func (*Subquery) IExpr() {} 465 | func (ListArg) IExpr() {} 466 | func (*BinaryExpr) IExpr() {} 467 | func (*UnaryExpr) IExpr() {} 468 | func (*FuncExpr) IExpr() {} 469 | func (*CaseExpr) IExpr() {} 470 | 471 | // BoolExpr represents a boolean expression. 472 | type BoolExpr interface { 473 | IBoolExpr() 474 | Expr 475 | } 476 | 477 | func (*AndExpr) IBoolExpr() {} 478 | func (*OrExpr) IBoolExpr() {} 479 | func (*NotExpr) IBoolExpr() {} 480 | func (*ParenBoolExpr) IBoolExpr() {} 481 | func (*ComparisonExpr) IBoolExpr() {} 482 | func (*RangeCond) IBoolExpr() {} 483 | func (*NullCheck) IBoolExpr() {} 484 | func (*ExistsExpr) IBoolExpr() {} 485 | func (*KeyrangeExpr) IBoolExpr() {} 486 | 487 | // AndExpr represents an AND expression. 488 | type AndExpr struct { 489 | Left, Right BoolExpr 490 | } 491 | 492 | func (node *AndExpr) Format(buf *TrackedBuffer) { 493 | buf.Myprintf("%v and %v", node.Left, node.Right) 494 | } 495 | 496 | // OrExpr represents an OR expression. 497 | type OrExpr struct { 498 | Left, Right BoolExpr 499 | } 500 | 501 | func (node *OrExpr) Format(buf *TrackedBuffer) { 502 | buf.Myprintf("%v or %v", node.Left, node.Right) 503 | } 504 | 505 | // NotExpr represents a NOT expression. 506 | type NotExpr struct { 507 | Expr BoolExpr 508 | } 509 | 510 | func (node *NotExpr) Format(buf *TrackedBuffer) { 511 | buf.Myprintf("not %v", node.Expr) 512 | } 513 | 514 | // ParenBoolExpr represents a parenthesized boolean expression. 515 | type ParenBoolExpr struct { 516 | Expr BoolExpr 517 | } 518 | 519 | func (node *ParenBoolExpr) Format(buf *TrackedBuffer) { 520 | buf.Myprintf("(%v)", node.Expr) 521 | } 522 | 523 | // ComparisonExpr represents a two-value comparison expression. 524 | type ComparisonExpr struct { 525 | Operator string 526 | Left, Right ValExpr 527 | } 528 | 529 | // ComparisonExpr.Operator 530 | const ( 531 | AST_EQ = "=" 532 | AST_LT = "<" 533 | AST_GT = ">" 534 | AST_LE = "<=" 535 | AST_GE = ">=" 536 | AST_NE = "!=" 537 | AST_NSE = "<=>" 538 | AST_IN = "in" 539 | AST_NOT_IN = "not in" 540 | AST_LIKE = "like" 541 | AST_NOT_LIKE = "not like" 542 | ) 543 | 544 | func (node *ComparisonExpr) Format(buf *TrackedBuffer) { 545 | buf.Myprintf("%v %s %v", node.Left, node.Operator, node.Right) 546 | } 547 | 548 | // RangeCond represents a BETWEEN or a NOT BETWEEN expression. 549 | type RangeCond struct { 550 | Operator string 551 | Left ValExpr 552 | From, To ValExpr 553 | } 554 | 555 | // RangeCond.Operator 556 | const ( 557 | AST_BETWEEN = "between" 558 | AST_NOT_BETWEEN = "not between" 559 | ) 560 | 561 | func (node *RangeCond) Format(buf *TrackedBuffer) { 562 | buf.Myprintf("%v %s %v and %v", node.Left, node.Operator, node.From, node.To) 563 | } 564 | 565 | // NullCheck represents an IS NULL or an IS NOT NULL expression. 566 | type NullCheck struct { 567 | Operator string 568 | Expr ValExpr 569 | } 570 | 571 | // NullCheck.Operator 572 | const ( 573 | AST_IS_NULL = "is null" 574 | AST_IS_NOT_NULL = "is not null" 575 | ) 576 | 577 | func (node *NullCheck) Format(buf *TrackedBuffer) { 578 | buf.Myprintf("%v %s", node.Expr, node.Operator) 579 | } 580 | 581 | // ExistsExpr represents an EXISTS expression. 582 | type ExistsExpr struct { 583 | Subquery *Subquery 584 | } 585 | 586 | func (node *ExistsExpr) Format(buf *TrackedBuffer) { 587 | buf.Myprintf("exists %v", node.Subquery) 588 | } 589 | 590 | // KeyrangeExpr represents a KEYRANGE expression. 591 | type KeyrangeExpr struct { 592 | Start, End ValExpr 593 | } 594 | 595 | func (node *KeyrangeExpr) Format(buf *TrackedBuffer) { 596 | buf.Myprintf("keyrange(%v, %v)", node.Start, node.End) 597 | } 598 | 599 | // ValExpr represents a value expression. 600 | type ValExpr interface { 601 | IValExpr() 602 | Expr 603 | } 604 | 605 | func (StrVal) IValExpr() {} 606 | func (NumVal) IValExpr() {} 607 | func (ValArg) IValExpr() {} 608 | func (*NullVal) IValExpr() {} 609 | func (*ColName) IValExpr() {} 610 | func (ValTuple) IValExpr() {} 611 | func (*Subquery) IValExpr() {} 612 | func (ListArg) IValExpr() {} 613 | func (*BinaryExpr) IValExpr() {} 614 | func (*UnaryExpr) IValExpr() {} 615 | func (*FuncExpr) IValExpr() {} 616 | func (*CaseExpr) IValExpr() {} 617 | 618 | // StrVal represents a string value. 619 | type StrVal []byte 620 | 621 | func (node StrVal) Format(buf *TrackedBuffer) { 622 | s := sqltypes.MakeString([]byte(node)) 623 | s.EncodeSql(buf) 624 | } 625 | 626 | // NumVal represents a number. 627 | type NumVal []byte 628 | 629 | func (node NumVal) Format(buf *TrackedBuffer) { 630 | buf.Myprintf("%s", []byte(node)) 631 | } 632 | 633 | // ValArg represents a named bind var argument. 634 | type ValArg []byte 635 | 636 | func (node ValArg) Format(buf *TrackedBuffer) { 637 | buf.WriteArg(string(node)) 638 | } 639 | 640 | // NullVal represents a NULL value. 641 | type NullVal struct{} 642 | 643 | func (node *NullVal) Format(buf *TrackedBuffer) { 644 | buf.Myprintf("null") 645 | } 646 | 647 | // ColName represents a column name. 648 | type ColName struct { 649 | Name, Qualifier []byte 650 | } 651 | 652 | func (node *ColName) Format(buf *TrackedBuffer) { 653 | if node.Qualifier != nil { 654 | escape(buf, node.Qualifier) 655 | buf.Myprintf(".") 656 | } 657 | escape(buf, node.Name) 658 | } 659 | 660 | func escape(buf *TrackedBuffer, name []byte) { 661 | if _, ok := keywords[string(name)]; ok { 662 | buf.Myprintf("`%s`", name) 663 | } else { 664 | buf.Myprintf("%s", name) 665 | } 666 | } 667 | 668 | // ColTuple represents a list of column values. 669 | // It can be ValTuple, Subquery, ListArg. 670 | type ColTuple interface { 671 | IColTuple() 672 | ValExpr 673 | } 674 | 675 | func (ValTuple) IColTuple() {} 676 | func (*Subquery) IColTuple() {} 677 | func (ListArg) IColTuple() {} 678 | 679 | // ValTuple represents a tuple of actual values. 680 | type ValTuple ValExprs 681 | 682 | func (node ValTuple) Format(buf *TrackedBuffer) { 683 | buf.Myprintf("(%v)", ValExprs(node)) 684 | } 685 | 686 | // ValExprs represents a list of value expressions. 687 | // It's not a valid expression because it's not parenthesized. 688 | type ValExprs []ValExpr 689 | 690 | func (node ValExprs) Format(buf *TrackedBuffer) { 691 | var prefix string 692 | for _, n := range node { 693 | buf.Myprintf("%s%v", prefix, n) 694 | prefix = ", " 695 | } 696 | } 697 | 698 | // Subquery represents a subquery. 699 | type Subquery struct { 700 | Select SelectStatement 701 | } 702 | 703 | func (node *Subquery) Format(buf *TrackedBuffer) { 704 | buf.Myprintf("(%v)", node.Select) 705 | } 706 | 707 | // ListArg represents a named list argument. 708 | type ListArg []byte 709 | 710 | func (node ListArg) Format(buf *TrackedBuffer) { 711 | buf.WriteArg(string(node)) 712 | } 713 | 714 | // BinaryExpr represents a binary value expression. 715 | type BinaryExpr struct { 716 | Operator byte 717 | Left, Right Expr 718 | } 719 | 720 | // BinaryExpr.Operator 721 | const ( 722 | AST_BITAND = '&' 723 | AST_BITOR = '|' 724 | AST_BITXOR = '^' 725 | AST_PLUS = '+' 726 | AST_MINUS = '-' 727 | AST_MULT = '*' 728 | AST_DIV = '/' 729 | AST_MOD = '%' 730 | ) 731 | 732 | func (node *BinaryExpr) Format(buf *TrackedBuffer) { 733 | buf.Myprintf("%v%c%v", node.Left, node.Operator, node.Right) 734 | } 735 | 736 | // UnaryExpr represents a unary value expression. 737 | type UnaryExpr struct { 738 | Operator byte 739 | Expr Expr 740 | } 741 | 742 | // UnaryExpr.Operator 743 | const ( 744 | AST_UPLUS = '+' 745 | AST_UMINUS = '-' 746 | AST_TILDA = '~' 747 | ) 748 | 749 | func (node *UnaryExpr) Format(buf *TrackedBuffer) { 750 | buf.Myprintf("%c%v", node.Operator, node.Expr) 751 | } 752 | 753 | // FuncExpr represents a function call. 754 | type FuncExpr struct { 755 | Name []byte 756 | Distinct bool 757 | Exprs SelectExprs 758 | } 759 | 760 | func (node *FuncExpr) Format(buf *TrackedBuffer) { 761 | var distinct string 762 | if node.Distinct { 763 | distinct = "distinct " 764 | } 765 | buf.Myprintf("%s(%s%v)", node.Name, distinct, node.Exprs) 766 | } 767 | 768 | // Aggregates is a map of all aggregate functions. 769 | var Aggregates = map[string]bool{ 770 | "avg": true, 771 | "bit_and": true, 772 | "bit_or": true, 773 | "bit_xor": true, 774 | "count": true, 775 | "group_concat": true, 776 | "max": true, 777 | "min": true, 778 | "std": true, 779 | "stddev_pop": true, 780 | "stddev_samp": true, 781 | "stddev": true, 782 | "sum": true, 783 | "var_pop": true, 784 | "var_samp": true, 785 | "variance": true, 786 | } 787 | 788 | func (node *FuncExpr) IsAggregate() bool { 789 | return Aggregates[string(node.Name)] 790 | } 791 | 792 | // CaseExpr represents a CASE expression. 793 | type CaseExpr struct { 794 | Expr ValExpr 795 | Whens []*When 796 | Else ValExpr 797 | } 798 | 799 | func (node *CaseExpr) Format(buf *TrackedBuffer) { 800 | buf.Myprintf("case ") 801 | if node.Expr != nil { 802 | buf.Myprintf("%v ", node.Expr) 803 | } 804 | for _, when := range node.Whens { 805 | buf.Myprintf("%v ", when) 806 | } 807 | if node.Else != nil { 808 | buf.Myprintf("else %v ", node.Else) 809 | } 810 | buf.Myprintf("end") 811 | } 812 | 813 | // When represents a WHEN sub-expression. 814 | type When struct { 815 | Cond BoolExpr 816 | Val ValExpr 817 | } 818 | 819 | func (node *When) Format(buf *TrackedBuffer) { 820 | buf.Myprintf("when %v then %v", node.Cond, node.Val) 821 | } 822 | 823 | // GroupBy represents a GROUP BY clause. 824 | type GroupBy []ValExpr 825 | 826 | func (node GroupBy) Format(buf *TrackedBuffer) { 827 | prefix := " group by " 828 | for _, n := range node { 829 | buf.Myprintf("%s%v", prefix, n) 830 | prefix = ", " 831 | } 832 | } 833 | 834 | // OrderBy represents an ORDER By clause. 835 | type OrderBy []*Order 836 | 837 | func (node OrderBy) Format(buf *TrackedBuffer) { 838 | prefix := " order by " 839 | for _, n := range node { 840 | buf.Myprintf("%s%v", prefix, n) 841 | prefix = ", " 842 | } 843 | } 844 | 845 | // Order represents an ordering expression. 846 | type Order struct { 847 | Expr ValExpr 848 | Direction string 849 | } 850 | 851 | // Order.Direction 852 | const ( 853 | AST_ASC = "asc" 854 | AST_DESC = "desc" 855 | ) 856 | 857 | func (node *Order) Format(buf *TrackedBuffer) { 858 | buf.Myprintf("%v %s", node.Expr, node.Direction) 859 | } 860 | 861 | // Limit represents a LIMIT clause. 862 | type Limit struct { 863 | Offset, Rowcount ValExpr 864 | } 865 | 866 | func (node *Limit) Format(buf *TrackedBuffer) { 867 | if node == nil { 868 | return 869 | } 870 | buf.Myprintf(" limit ") 871 | if node.Offset != nil { 872 | buf.Myprintf("%v, ", node.Offset) 873 | } 874 | buf.Myprintf("%v", node.Rowcount) 875 | } 876 | 877 | // Limits returns the values of the LIMIT clause as interfaces. 878 | // The returned values can be nil for absent field, string for 879 | // bind variable names, or int64 for an actual number. 880 | // Otherwise, it's an error. 881 | func (node *Limit) Limits() (offset, rowcount interface{}, err error) { 882 | if node == nil { 883 | return nil, nil, nil 884 | } 885 | switch v := node.Offset.(type) { 886 | case NumVal: 887 | o, err := strconv.ParseInt(string(v), 0, 64) 888 | if err != nil { 889 | return nil, nil, err 890 | } 891 | if o < 0 { 892 | return nil, nil, fmt.Errorf("negative offset: %d", o) 893 | } 894 | offset = o 895 | case ValArg: 896 | offset = string(v) 897 | case nil: 898 | // pass 899 | default: 900 | return nil, nil, fmt.Errorf("unexpected node for offset: %+v", v) 901 | } 902 | switch v := node.Rowcount.(type) { 903 | case NumVal: 904 | rc, err := strconv.ParseInt(string(v), 0, 64) 905 | if err != nil { 906 | return nil, nil, err 907 | } 908 | if rc < 0 { 909 | return nil, nil, fmt.Errorf("negative limit: %d", rc) 910 | } 911 | rowcount = rc 912 | case ValArg: 913 | rowcount = string(v) 914 | default: 915 | return nil, nil, fmt.Errorf("unexpected node for rowcount: %+v", v) 916 | } 917 | return offset, rowcount, nil 918 | } 919 | 920 | // Values represents a VALUES clause. 921 | type Values []RowTuple 922 | 923 | func (node Values) Format(buf *TrackedBuffer) { 924 | prefix := "values " 925 | for _, n := range node { 926 | buf.Myprintf("%s%v", prefix, n) 927 | prefix = ", " 928 | } 929 | } 930 | 931 | // RowTuple represents a row of values. It can be ValTuple, Subquery. 932 | type RowTuple interface { 933 | IRowTuple() 934 | ValExpr 935 | } 936 | 937 | func (ValTuple) IRowTuple() {} 938 | func (*Subquery) IRowTuple() {} 939 | 940 | // UpdateExprs represents a list of update expressions. 941 | type UpdateExprs []*UpdateExpr 942 | 943 | func (node UpdateExprs) Format(buf *TrackedBuffer) { 944 | var prefix string 945 | for _, n := range node { 946 | buf.Myprintf("%s%v", prefix, n) 947 | prefix = ", " 948 | } 949 | } 950 | 951 | // UpdateExpr represents an update expression. 952 | type UpdateExpr struct { 953 | Name *ColName 954 | Expr ValExpr 955 | } 956 | 957 | func (node *UpdateExpr) Format(buf *TrackedBuffer) { 958 | buf.Myprintf("%v = %v", node.Name, node.Expr) 959 | } 960 | 961 | // OnDup represents an ON DUPLICATE KEY clause. 962 | type OnDup UpdateExprs 963 | 964 | func (node OnDup) Format(buf *TrackedBuffer) { 965 | if node == nil { 966 | return 967 | } 968 | buf.Myprintf(" on duplicate key update %v", UpdateExprs(node)) 969 | } 970 | 971 | func (*Begin) IStatement() {} 972 | func (*Commit) IStatement() {} 973 | func (*Rollback) IStatement() {} 974 | 975 | type Begin struct { 976 | } 977 | 978 | func (node *Begin) Format(buf *TrackedBuffer) { 979 | buf.Myprintf("begin") 980 | } 981 | 982 | type Commit struct { 983 | } 984 | 985 | func (node *Commit) Format(buf *TrackedBuffer) { 986 | buf.Myprintf("commit") 987 | } 988 | 989 | type Rollback struct { 990 | } 991 | 992 | func (node *Rollback) Format(buf *TrackedBuffer) { 993 | buf.Myprintf("rollback") 994 | } 995 | 996 | // Replace represents an REPLACE statement. 997 | type Replace struct { 998 | Comments Comments 999 | Table *TableName 1000 | Columns Columns 1001 | Rows InsertRows 1002 | } 1003 | 1004 | func (node *Replace) Format(buf *TrackedBuffer) { 1005 | buf.Myprintf("replace %vinto %v%v %v%v", 1006 | node.Comments, 1007 | node.Table, node.Columns, node.Rows) 1008 | } 1009 | 1010 | func (*Replace) IStatement() {} 1011 | 1012 | type SimpleSelect struct { 1013 | Comments Comments 1014 | Distinct string 1015 | SelectExprs SelectExprs 1016 | } 1017 | 1018 | func (node *SimpleSelect) Format(buf *TrackedBuffer) { 1019 | buf.Myprintf("select %v%s%v", node.Comments, node.Distinct, node.SelectExprs) 1020 | } 1021 | 1022 | func (*SimpleSelect) IStatement() {} 1023 | func (*SimpleSelect) ISelectStatement() {} 1024 | func (*SimpleSelect) IInsertRows() {} 1025 | -------------------------------------------------------------------------------- /go/sqlparser/ast_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlparser 6 | 7 | import "testing" 8 | 9 | func TestWhere(t *testing.T) { 10 | var w *Where 11 | buf := NewTrackedBuffer(nil) 12 | w.Format(buf) 13 | if buf.String() != "" { 14 | t.Errorf("w.Format(nil): %q, want \"\"", buf.String) 15 | } 16 | w = NewWhere(AST_WHERE, nil) 17 | buf = NewTrackedBuffer(nil) 18 | w.Format(buf) 19 | if buf.String() != "" { 20 | t.Errorf("w.Format(&Where{nil}: %q, want \"\"", buf.String) 21 | } 22 | } 23 | 24 | func TestLimits(t *testing.T) { 25 | var l *Limit 26 | o, r, err := l.Limits() 27 | if o != nil || r != nil || err != nil { 28 | t.Errorf("got %v, %v, %v, want nils", o, r, err) 29 | } 30 | 31 | l = &Limit{Offset: NumVal([]byte("aa"))} 32 | _, _, err = l.Limits() 33 | wantErr := "strconv.ParseInt: parsing \"aa\": invalid syntax" 34 | if err == nil || err.Error() != wantErr { 35 | t.Errorf("got %v, want %s", err, wantErr) 36 | } 37 | 38 | l = &Limit{Offset: NumVal([]byte("2"))} 39 | _, _, err = l.Limits() 40 | wantErr = "unexpected node for rowcount: " 41 | if err == nil || err.Error() != wantErr { 42 | t.Errorf("got %v, want %s", err, wantErr) 43 | } 44 | 45 | l = &Limit{Offset: StrVal([]byte("2"))} 46 | _, _, err = l.Limits() 47 | wantErr = "unexpected node for offset: [50]" 48 | if err == nil || err.Error() != wantErr { 49 | t.Errorf("got %v, want %s", err, wantErr) 50 | } 51 | 52 | l = &Limit{Offset: NumVal([]byte("2")), Rowcount: NumVal([]byte("aa"))} 53 | _, _, err = l.Limits() 54 | wantErr = "strconv.ParseInt: parsing \"aa\": invalid syntax" 55 | if err == nil || err.Error() != wantErr { 56 | t.Errorf("got %v, want %s", err, wantErr) 57 | } 58 | 59 | l = &Limit{Offset: NumVal([]byte("2")), Rowcount: NumVal([]byte("3"))} 60 | o, r, err = l.Limits() 61 | if o.(int64) != 2 || r.(int64) != 3 || err != nil { 62 | t.Errorf("got %v %v %v, want 2, 3, nil", o, r, err) 63 | } 64 | 65 | l = &Limit{Offset: ValArg([]byte(":a")), Rowcount: NumVal([]byte("3"))} 66 | o, r, err = l.Limits() 67 | if o.(string) != ":a" || r.(int64) != 3 || err != nil { 68 | t.Errorf("got %v %v %v, want :a, 3, nil", o, r, err) 69 | } 70 | 71 | l = &Limit{Offset: nil, Rowcount: NumVal([]byte("3"))} 72 | o, r, err = l.Limits() 73 | if o != nil || r.(int64) != 3 || err != nil { 74 | t.Errorf("got %v %v %v, want nil, 3, nil", o, r, err) 75 | } 76 | 77 | l = &Limit{Offset: nil, Rowcount: ValArg([]byte(":a"))} 78 | o, r, err = l.Limits() 79 | if o != nil || r.(string) != ":a" || err != nil { 80 | t.Errorf("got %v %v %v, want nil, :a, nil", o, r, err) 81 | } 82 | 83 | l = &Limit{Offset: NumVal([]byte("-2")), Rowcount: NumVal([]byte("0"))} 84 | _, _, err = l.Limits() 85 | wantErr = "negative offset: -2" 86 | if err == nil || err.Error() != wantErr { 87 | t.Errorf("got %v, want %s", err, wantErr) 88 | } 89 | 90 | l = &Limit{Offset: NumVal([]byte("2")), Rowcount: NumVal([]byte("-2"))} 91 | _, _, err = l.Limits() 92 | wantErr = "negative limit: -2" 93 | if err == nil || err.Error() != wantErr { 94 | t.Errorf("got %v, want %s", err, wantErr) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /go/sqlparser/parse_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlparser 6 | 7 | import ( 8 | // "bufio" 9 | // "fmt" 10 | // "io" 11 | // "os" 12 | // "strings" 13 | "testing" 14 | 15 | // "github.com/youtube/vitess/go/testfiles" 16 | ) 17 | 18 | func TestGen(t *testing.T) { 19 | _, err := Parse("select :a from a where a in (:b)") 20 | if err != nil { 21 | t.Error(err) 22 | } 23 | } 24 | 25 | // func TestParse(t *testing.T) { 26 | // for tcase := range iterateFiles("sqlparser_test/*.sql") { 27 | // if tcase.output == "" { 28 | // tcase.output = tcase.input 29 | // } 30 | // tree, err := Parse(tcase.input) 31 | // var out string 32 | // if err != nil { 33 | // out = err.Error() 34 | // } else { 35 | // out = String(tree) 36 | // } 37 | // if out != tcase.output { 38 | // t.Error(fmt.Sprintf("File:%s Line:%v\n%q\n%q", tcase.file, tcase.lineno, tcase.output, out)) 39 | // } 40 | // } 41 | // } 42 | 43 | func BenchmarkParse1(b *testing.B) { 44 | sql := "select 'abcd', 20, 30.0, eid from a where 1=eid and name='3'" 45 | for i := 0; i < b.N; i++ { 46 | _, err := Parse(sql) 47 | if err != nil { 48 | b.Fatal(err) 49 | } 50 | } 51 | } 52 | 53 | func BenchmarkParse2(b *testing.B) { 54 | sql := "select aaaa, bbb, ccc, ddd, eeee, ffff, gggg, hhhh, iiii from tttt, ttt1, ttt3 where aaaa = bbbb and bbbb = cccc and dddd+1 = eeee group by fff, gggg having hhhh = iiii and iiii = jjjj order by kkkk, llll limit 3, 4" 55 | for i := 0; i < b.N; i++ { 56 | _, err := Parse(sql) 57 | if err != nil { 58 | b.Fatal(err) 59 | } 60 | } 61 | } 62 | 63 | // type testCase struct { 64 | // file string 65 | // lineno int 66 | // input string 67 | // output string 68 | // } 69 | 70 | // func iterateFiles(pattern string) (testCaseIterator chan testCase) { 71 | // names := testfiles.Glob(pattern) 72 | // testCaseIterator = make(chan testCase) 73 | // go func() { 74 | // defer close(testCaseIterator) 75 | // for _, name := range names { 76 | // fd, err := os.OpenFile(name, os.O_RDONLY, 0) 77 | // if err != nil { 78 | // panic(fmt.Sprintf("Could not open file %s", name)) 79 | // } 80 | 81 | // r := bufio.NewReader(fd) 82 | // lineno := 0 83 | // for { 84 | // line, err := r.ReadString('\n') 85 | // lines := strings.Split(strings.TrimRight(line, "\n"), "#") 86 | // lineno++ 87 | // if err != nil { 88 | // if err != io.EOF { 89 | // panic(fmt.Sprintf("Error reading file %s: %s", name, err.Error())) 90 | // } 91 | // break 92 | // } 93 | // input := lines[0] 94 | // output := "" 95 | // if len(lines) > 1 { 96 | // output = lines[1] 97 | // } 98 | // if input == "" { 99 | // continue 100 | // } 101 | // testCaseIterator <- testCase{name, lineno, input, output} 102 | // } 103 | // } 104 | // }() 105 | // return testCaseIterator 106 | // } 107 | -------------------------------------------------------------------------------- /go/sqlparser/parsed_query.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlparser 6 | 7 | import ( 8 | "bytes" 9 | "encoding/json" 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/go-cloud/myshard/go/sqltypes" 14 | ) 15 | 16 | type bindLocation struct { 17 | offset, length int 18 | } 19 | 20 | type ParsedQuery struct { 21 | Query string 22 | bindLocations []bindLocation 23 | } 24 | 25 | type EncoderFunc func(value interface{}) ([]byte, error) 26 | 27 | func (pq *ParsedQuery) GenerateQuery(bindVariables map[string]interface{}) ([]byte, error) { 28 | if len(pq.bindLocations) == 0 { 29 | return []byte(pq.Query), nil 30 | } 31 | buf := bytes.NewBuffer(make([]byte, 0, len(pq.Query))) 32 | current := 0 33 | for _, loc := range pq.bindLocations { 34 | buf.WriteString(pq.Query[current:loc.offset]) 35 | name := pq.Query[loc.offset : loc.offset+loc.length] 36 | supplied, _, err := FetchBindVar(name, bindVariables) 37 | if err != nil { 38 | return nil, err 39 | } 40 | if err := EncodeValue(buf, supplied); err != nil { 41 | return nil, err 42 | } 43 | current = loc.offset + loc.length 44 | } 45 | buf.WriteString(pq.Query[current:]) 46 | return buf.Bytes(), nil 47 | } 48 | 49 | func (pq *ParsedQuery) MarshalJSON() ([]byte, error) { 50 | return json.Marshal(pq.Query) 51 | } 52 | 53 | func EncodeValue(buf *bytes.Buffer, value interface{}) error { 54 | switch bindVal := value.(type) { 55 | case nil: 56 | buf.WriteString("null") 57 | case []sqltypes.Value: 58 | for i := 0; i < len(bindVal); i++ { 59 | if i != 0 { 60 | buf.WriteString(", ") 61 | } 62 | if err := EncodeValue(buf, bindVal[i]); err != nil { 63 | return err 64 | } 65 | } 66 | case [][]sqltypes.Value: 67 | for i := 0; i < len(bindVal); i++ { 68 | if i != 0 { 69 | buf.WriteString(", ") 70 | } 71 | buf.WriteByte('(') 72 | if err := EncodeValue(buf, bindVal[i]); err != nil { 73 | return err 74 | } 75 | buf.WriteByte(')') 76 | } 77 | case []interface{}: 78 | buf.WriteByte('(') 79 | for i, v := range bindVal { 80 | if i != 0 { 81 | buf.WriteString(", ") 82 | } 83 | if err := EncodeValue(buf, v); err != nil { 84 | return err 85 | } 86 | } 87 | buf.WriteByte(')') 88 | case TupleEqualityList: 89 | if err := bindVal.Encode(buf); err != nil { 90 | return err 91 | } 92 | default: 93 | v, err := sqltypes.BuildValue(bindVal) 94 | if err != nil { 95 | return err 96 | } 97 | v.EncodeSql(buf) 98 | } 99 | return nil 100 | } 101 | 102 | type TupleEqualityList struct { 103 | Columns []string 104 | Rows [][]sqltypes.Value 105 | } 106 | 107 | func (tpl *TupleEqualityList) Encode(buf *bytes.Buffer) error { 108 | if len(tpl.Rows) == 0 { 109 | return errors.New("cannot encode with 0 rows") 110 | } 111 | if len(tpl.Columns) == 1 { 112 | return tpl.encodeAsIN(buf) 113 | } 114 | return tpl.encodeAsEquality(buf) 115 | } 116 | 117 | func (tpl *TupleEqualityList) encodeAsIN(buf *bytes.Buffer) error { 118 | buf.WriteString(tpl.Columns[0]) 119 | buf.WriteString(" in (") 120 | for i, r := range tpl.Rows { 121 | if len(r) != 1 { 122 | return errors.New("values don't match column count") 123 | } 124 | if i != 0 { 125 | buf.WriteString(", ") 126 | } 127 | if err := EncodeValue(buf, r); err != nil { 128 | return err 129 | } 130 | } 131 | buf.WriteByte(')') 132 | return nil 133 | } 134 | 135 | func (tpl *TupleEqualityList) encodeAsEquality(buf *bytes.Buffer) error { 136 | for i, r := range tpl.Rows { 137 | if i != 0 { 138 | buf.WriteString(" or ") 139 | } 140 | buf.WriteString("(") 141 | for j, c := range tpl.Columns { 142 | if j != 0 { 143 | buf.WriteString(" and ") 144 | } 145 | buf.WriteString(c) 146 | buf.WriteString(" = ") 147 | if err := EncodeValue(buf, r[j]); err != nil { 148 | return err 149 | } 150 | } 151 | buf.WriteByte(')') 152 | } 153 | return nil 154 | } 155 | 156 | func FetchBindVar(name string, bindVariables map[string]interface{}) (val interface{}, isList bool, err error) { 157 | name = name[1:] 158 | if name[0] == ':' { 159 | name = name[1:] 160 | isList = true 161 | } 162 | supplied, ok := bindVariables[name] 163 | if !ok { 164 | return nil, false, fmt.Errorf("missing bind var %s", name) 165 | } 166 | list, gotList := supplied.([]interface{}) 167 | if isList { 168 | if !gotList { 169 | return nil, false, fmt.Errorf("unexpected list arg type %T for key %s", supplied, name) 170 | } 171 | if len(list) == 0 { 172 | return nil, false, fmt.Errorf("empty list supplied for %s", name) 173 | } 174 | return list, true, nil 175 | } 176 | if gotList { 177 | return nil, false, fmt.Errorf("unexpected arg type %T for key %s", supplied, name) 178 | } 179 | return supplied, false, nil 180 | } 181 | -------------------------------------------------------------------------------- /go/sqlparser/parsed_query_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlparser 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/go-cloud/myshard/go/sqltypes" 11 | ) 12 | 13 | func TestParsedQuery(t *testing.T) { 14 | tcases := []struct { 15 | desc string 16 | query string 17 | bindVars map[string]interface{} 18 | output string 19 | }{ 20 | { 21 | "no subs", 22 | "select * from a where id = 2", 23 | map[string]interface{}{ 24 | "id": 1, 25 | }, 26 | "select * from a where id = 2", 27 | }, { 28 | "simple bindvar sub", 29 | "select * from a where id1 = :id1 and id2 = :id2", 30 | map[string]interface{}{ 31 | "id1": 1, 32 | "id2": nil, 33 | }, 34 | "select * from a where id1 = 1 and id2 = null", 35 | }, { 36 | "missing bind var", 37 | "select * from a where id1 = :id1 and id2 = :id2", 38 | map[string]interface{}{ 39 | "id1": 1, 40 | }, 41 | "missing bind var id2", 42 | }, { 43 | "unencodable bind var", 44 | "select * from a where id1 = :id", 45 | map[string]interface{}{ 46 | "id": make([]int, 1), 47 | }, 48 | "unsupported bind variable type []int: [0]", 49 | }, { 50 | "list inside bind vars", 51 | "select * from a where id in (:vals)", 52 | map[string]interface{}{ 53 | "vals": []sqltypes.Value{ 54 | sqltypes.MakeNumeric([]byte("1")), 55 | sqltypes.MakeString([]byte("aa")), 56 | }, 57 | }, 58 | "select * from a where id in (1, 'aa')", 59 | }, { 60 | "two lists inside bind vars", 61 | "select * from a where id in (:vals)", 62 | map[string]interface{}{ 63 | "vals": [][]sqltypes.Value{ 64 | []sqltypes.Value{ 65 | sqltypes.MakeNumeric([]byte("1")), 66 | sqltypes.MakeString([]byte("aa")), 67 | }, 68 | []sqltypes.Value{ 69 | sqltypes.Value{}, 70 | sqltypes.MakeString([]byte("bb")), 71 | }, 72 | }, 73 | }, 74 | "select * from a where id in ((1, 'aa'), (null, 'bb'))", 75 | }, { 76 | "list bind vars", 77 | "select * from a where id in ::vals", 78 | map[string]interface{}{ 79 | "vals": []interface{}{ 80 | 1, 81 | "aa", 82 | }, 83 | }, 84 | "select * from a where id in (1, 'aa')", 85 | }, { 86 | "list bind vars single argument", 87 | "select * from a where id in ::vals", 88 | map[string]interface{}{ 89 | "vals": []interface{}{ 90 | 1, 91 | }, 92 | }, 93 | "select * from a where id in (1)", 94 | }, { 95 | "list bind vars 0 arguments", 96 | "select * from a where id in ::vals", 97 | map[string]interface{}{ 98 | "vals": []interface{}{}, 99 | }, 100 | "empty list supplied for vals", 101 | }, { 102 | "non-list bind var supplied", 103 | "select * from a where id in ::vals", 104 | map[string]interface{}{ 105 | "vals": 1, 106 | }, 107 | "unexpected list arg type int for key vals", 108 | }, { 109 | "list bind var for non-list", 110 | "select * from a where id = :vals", 111 | map[string]interface{}{ 112 | "vals": []interface{}{1}, 113 | }, 114 | "unexpected arg type []interface {} for key vals", 115 | }, { 116 | "single column tuple equality", 117 | // We have to use an incorrect construct to get around the parser. 118 | "select * from a where b = :equality", 119 | map[string]interface{}{ 120 | "equality": TupleEqualityList{ 121 | Columns: []string{"pk"}, 122 | Rows: [][]sqltypes.Value{ 123 | []sqltypes.Value{sqltypes.MakeNumeric([]byte("1"))}, 124 | []sqltypes.Value{sqltypes.MakeString([]byte("aa"))}, 125 | }, 126 | }, 127 | }, 128 | "select * from a where b = pk in (1, 'aa')", 129 | }, { 130 | "multi column tuple equality", 131 | "select * from a where b = :equality", 132 | map[string]interface{}{ 133 | "equality": TupleEqualityList{ 134 | Columns: []string{"pk1", "pk2"}, 135 | Rows: [][]sqltypes.Value{ 136 | []sqltypes.Value{ 137 | sqltypes.MakeNumeric([]byte("1")), 138 | sqltypes.MakeString([]byte("aa")), 139 | }, 140 | []sqltypes.Value{ 141 | sqltypes.MakeNumeric([]byte("2")), 142 | sqltypes.MakeString([]byte("bb")), 143 | }, 144 | }, 145 | }, 146 | }, 147 | "select * from a where b = (pk1 = 1 and pk2 = 'aa') or (pk1 = 2 and pk2 = 'bb')", 148 | }, { 149 | "0 rows", 150 | "select * from a where b = :equality", 151 | map[string]interface{}{ 152 | "equality": TupleEqualityList{ 153 | Columns: []string{"pk"}, 154 | Rows: [][]sqltypes.Value{}, 155 | }, 156 | }, 157 | "cannot encode with 0 rows", 158 | }, { 159 | "values don't match column count", 160 | "select * from a where b = :equality", 161 | map[string]interface{}{ 162 | "equality": TupleEqualityList{ 163 | Columns: []string{"pk"}, 164 | Rows: [][]sqltypes.Value{ 165 | []sqltypes.Value{ 166 | sqltypes.MakeNumeric([]byte("1")), 167 | sqltypes.MakeString([]byte("aa")), 168 | }, 169 | }, 170 | }, 171 | }, 172 | "values don't match column count", 173 | }, 174 | } 175 | 176 | for _, tcase := range tcases { 177 | tree, err := Parse(tcase.query) 178 | if err != nil { 179 | t.Errorf("parse failed for %s: %v", tcase.desc, err) 180 | continue 181 | } 182 | buf := NewTrackedBuffer(nil) 183 | buf.Myprintf("%v", tree) 184 | pq := buf.ParsedQuery() 185 | bytes, err := pq.GenerateQuery(tcase.bindVars) 186 | var got string 187 | if err != nil { 188 | got = err.Error() 189 | } else { 190 | got = string(bytes) 191 | } 192 | if got != tcase.output { 193 | t.Errorf("for test case: %s, got: '%s', want '%s'", tcase.desc, got, tcase.output) 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /go/sqlparser/sql.go: -------------------------------------------------------------------------------- 1 | //line sql.y:6 2 | package sqlparser 3 | 4 | import __yyfmt__ "fmt" 5 | 6 | //line sql.y:6 7 | import "bytes" 8 | 9 | func SetParseTree(yylex interface{}, stmt Statement) { 10 | yylex.(*Tokenizer).ParseTree = stmt 11 | } 12 | 13 | func SetAllowComments(yylex interface{}, allow bool) { 14 | yylex.(*Tokenizer).AllowComments = allow 15 | } 16 | 17 | func ForceEOF(yylex interface{}) { 18 | yylex.(*Tokenizer).ForceEOF = true 19 | } 20 | 21 | var ( 22 | SHARE = []byte("share") 23 | MODE = []byte("mode") 24 | IF_BYTES = []byte("if") 25 | VALUES_BYTES = []byte("values") 26 | ) 27 | 28 | //line sql.y:31 29 | type yySymType struct { 30 | yys int 31 | empty struct{} 32 | statement Statement 33 | selStmt SelectStatement 34 | byt byte 35 | bytes []byte 36 | bytes2 [][]byte 37 | str string 38 | selectExprs SelectExprs 39 | selectExpr SelectExpr 40 | columns Columns 41 | colName *ColName 42 | tableExprs TableExprs 43 | tableExpr TableExpr 44 | smTableExpr SimpleTableExpr 45 | tableName *TableName 46 | indexHints *IndexHints 47 | expr Expr 48 | boolExpr BoolExpr 49 | valExpr ValExpr 50 | colTuple ColTuple 51 | valExprs ValExprs 52 | values Values 53 | rowTuple RowTuple 54 | subquery *Subquery 55 | caseExpr *CaseExpr 56 | whens []*When 57 | when *When 58 | orderBy OrderBy 59 | order *Order 60 | limit *Limit 61 | insRows InsertRows 62 | updateExprs UpdateExprs 63 | updateExpr *UpdateExpr 64 | } 65 | 66 | const LEX_ERROR = 57346 67 | const SELECT = 57347 68 | const INSERT = 57348 69 | const UPDATE = 57349 70 | const DELETE = 57350 71 | const FROM = 57351 72 | const WHERE = 57352 73 | const GROUP = 57353 74 | const HAVING = 57354 75 | const ORDER = 57355 76 | const BY = 57356 77 | const LIMIT = 57357 78 | const FOR = 57358 79 | const ALL = 57359 80 | const DISTINCT = 57360 81 | const AS = 57361 82 | const EXISTS = 57362 83 | const IN = 57363 84 | const IS = 57364 85 | const LIKE = 57365 86 | const BETWEEN = 57366 87 | const NULL = 57367 88 | const ASC = 57368 89 | const DESC = 57369 90 | const VALUES = 57370 91 | const INTO = 57371 92 | const DUPLICATE = 57372 93 | const KEY = 57373 94 | const DEFAULT = 57374 95 | const SET = 57375 96 | const LOCK = 57376 97 | const KEYRANGE = 57377 98 | const ID = 57378 99 | const STRING = 57379 100 | const NUMBER = 57380 101 | const VALUE_ARG = 57381 102 | const LIST_ARG = 57382 103 | const COMMENT = 57383 104 | const LE = 57384 105 | const GE = 57385 106 | const NE = 57386 107 | const NULL_SAFE_EQUAL = 57387 108 | const UNION = 57388 109 | const MINUS = 57389 110 | const EXCEPT = 57390 111 | const INTERSECT = 57391 112 | const JOIN = 57392 113 | const STRAIGHT_JOIN = 57393 114 | const LEFT = 57394 115 | const RIGHT = 57395 116 | const INNER = 57396 117 | const OUTER = 57397 118 | const CROSS = 57398 119 | const NATURAL = 57399 120 | const USE = 57400 121 | const FORCE = 57401 122 | const ON = 57402 123 | const OR = 57403 124 | const AND = 57404 125 | const NOT = 57405 126 | const UNARY = 57406 127 | const CASE = 57407 128 | const WHEN = 57408 129 | const THEN = 57409 130 | const ELSE = 57410 131 | const END = 57411 132 | const CREATE = 57412 133 | const ALTER = 57413 134 | const DROP = 57414 135 | const RENAME = 57415 136 | const ANALYZE = 57416 137 | const TABLE = 57417 138 | const INDEX = 57418 139 | const VIEW = 57419 140 | const TO = 57420 141 | const IGNORE = 57421 142 | const IF = 57422 143 | const UNIQUE = 57423 144 | const USING = 57424 145 | const SHOW = 57425 146 | const DESCRIBE = 57426 147 | const EXPLAIN = 57427 148 | const BEGIN = 57428 149 | const COMMIT = 57429 150 | const ROLLBACK = 57430 151 | const NAMES = 57431 152 | const REPLACE = 57432 153 | 154 | var yyToknames = []string{ 155 | "LEX_ERROR", 156 | "SELECT", 157 | "INSERT", 158 | "UPDATE", 159 | "DELETE", 160 | "FROM", 161 | "WHERE", 162 | "GROUP", 163 | "HAVING", 164 | "ORDER", 165 | "BY", 166 | "LIMIT", 167 | "FOR", 168 | "ALL", 169 | "DISTINCT", 170 | "AS", 171 | "EXISTS", 172 | "IN", 173 | "IS", 174 | "LIKE", 175 | "BETWEEN", 176 | "NULL", 177 | "ASC", 178 | "DESC", 179 | "VALUES", 180 | "INTO", 181 | "DUPLICATE", 182 | "KEY", 183 | "DEFAULT", 184 | "SET", 185 | "LOCK", 186 | "KEYRANGE", 187 | "ID", 188 | "STRING", 189 | "NUMBER", 190 | "VALUE_ARG", 191 | "LIST_ARG", 192 | "COMMENT", 193 | "LE", 194 | "GE", 195 | "NE", 196 | "NULL_SAFE_EQUAL", 197 | " (", 198 | " =", 199 | " <", 200 | " >", 201 | " ~", 202 | "UNION", 203 | "MINUS", 204 | "EXCEPT", 205 | "INTERSECT", 206 | " ,", 207 | "JOIN", 208 | "STRAIGHT_JOIN", 209 | "LEFT", 210 | "RIGHT", 211 | "INNER", 212 | "OUTER", 213 | "CROSS", 214 | "NATURAL", 215 | "USE", 216 | "FORCE", 217 | "ON", 218 | "OR", 219 | "AND", 220 | "NOT", 221 | " &", 222 | " |", 223 | " ^", 224 | " +", 225 | " -", 226 | " *", 227 | " /", 228 | " %", 229 | " .", 230 | "UNARY", 231 | "CASE", 232 | "WHEN", 233 | "THEN", 234 | "ELSE", 235 | "END", 236 | "CREATE", 237 | "ALTER", 238 | "DROP", 239 | "RENAME", 240 | "ANALYZE", 241 | "TABLE", 242 | "INDEX", 243 | "VIEW", 244 | "TO", 245 | "IGNORE", 246 | "IF", 247 | "UNIQUE", 248 | "USING", 249 | "SHOW", 250 | "DESCRIBE", 251 | "EXPLAIN", 252 | "BEGIN", 253 | "COMMIT", 254 | "ROLLBACK", 255 | "NAMES", 256 | "REPLACE", 257 | } 258 | var yyStatenames = []string{} 259 | 260 | const yyEofCode = 1 261 | const yyErrCode = 2 262 | const yyMaxDepth = 200 263 | 264 | //line yacctab:1 265 | var yyExca = []int{ 266 | -1, 1, 267 | 1, -1, 268 | -2, 0, 269 | } 270 | 271 | const yyNprod = 214 272 | const yyPrivate = 57344 273 | 274 | var yyTokenNames []string 275 | var yyStates []string 276 | 277 | const yyLast = 622 278 | 279 | var yyAct = []int{ 280 | 281 | 105, 311, 172, 381, 71, 96, 348, 263, 102, 175, 282 | 103, 213, 303, 254, 91, 101, 224, 191, 256, 149, 283 | 148, 390, 73, 174, 3, 114, 92, 390, 390, 186, 284 | 143, 245, 361, 276, 277, 278, 279, 280, 58, 281, 285 | 282, 36, 37, 38, 39, 76, 75, 309, 143, 80, 286 | 143, 245, 83, 199, 74, 46, 87, 48, 243, 62, 287 | 359, 49, 86, 113, 328, 330, 119, 97, 59, 60, 288 | 358, 357, 392, 78, 76, 110, 111, 112, 391, 389, 289 | 132, 337, 334, 332, 178, 287, 255, 270, 117, 140, 290 | 51, 82, 52, 79, 329, 145, 244, 136, 308, 297, 291 | 57, 295, 246, 176, 53, 171, 173, 177, 54, 55, 292 | 56, 115, 116, 72, 149, 148, 339, 147, 120, 133, 293 | 129, 365, 135, 185, 75, 131, 124, 75, 189, 341, 294 | 195, 194, 74, 118, 181, 74, 156, 157, 158, 159, 295 | 160, 161, 162, 163, 148, 81, 97, 219, 195, 193, 296 | 255, 68, 301, 223, 221, 222, 231, 232, 354, 235, 297 | 236, 237, 238, 239, 240, 241, 242, 233, 217, 196, 298 | 218, 210, 159, 160, 161, 162, 163, 226, 304, 209, 299 | 126, 247, 97, 97, 220, 205, 149, 148, 75, 75, 300 | 266, 304, 259, 139, 249, 251, 74, 261, 265, 252, 301 | 267, 161, 162, 163, 203, 85, 356, 262, 206, 322, 302 | 258, 234, 75, 320, 323, 355, 272, 326, 321, 122, 303 | 74, 325, 125, 324, 192, 126, 192, 286, 247, 271, 304 | 273, 142, 290, 291, 258, 288, 245, 366, 343, 268, 305 | 298, 217, 141, 18, 128, 289, 216, 376, 294, 36, 306 | 37, 38, 39, 97, 226, 375, 215, 227, 202, 204, 307 | 201, 302, 88, 225, 374, 296, 211, 300, 306, 274, 308 | 310, 126, 307, 108, 216, 178, 183, 143, 113, 188, 309 | 187, 119, 182, 180, 215, 179, 318, 319, 109, 95, 310 | 110, 111, 112, 188, 113, 336, 121, 81, 76, 100, 311 | 217, 217, 333, 117, 340, 123, 110, 111, 112, 331, 312 | 75, 315, 345, 285, 338, 346, 349, 146, 344, 90, 313 | 314, 208, 99, 207, 190, 69, 115, 116, 93, 137, 314 | 284, 134, 130, 120, 81, 127, 89, 84, 360, 276, 315 | 277, 278, 279, 280, 362, 281, 282, 387, 118, 363, 316 | 342, 67, 293, 350, 364, 394, 247, 197, 371, 370, 317 | 373, 18, 138, 372, 228, 388, 229, 230, 378, 349, 318 | 65, 264, 380, 379, 63, 382, 382, 382, 75, 383, 319 | 384, 312, 385, 250, 257, 108, 74, 353, 313, 352, 320 | 113, 395, 317, 119, 192, 396, 70, 397, 393, 377, 321 | 109, 95, 110, 111, 112, 18, 19, 20, 21, 18, 322 | 41, 100, 14, 17, 335, 117, 156, 157, 158, 159, 323 | 160, 161, 162, 163, 156, 157, 158, 159, 160, 161, 324 | 162, 163, 16, 22, 99, 15, 198, 47, 115, 116, 325 | 93, 269, 200, 50, 77, 120, 260, 386, 292, 18, 326 | 156, 157, 158, 159, 160, 161, 162, 163, 367, 347, 327 | 118, 351, 316, 299, 108, 184, 253, 107, 104, 113, 328 | 106, 248, 119, 305, 150, 98, 327, 214, 275, 109, 329 | 76, 110, 111, 112, 212, 23, 24, 26, 25, 27, 330 | 100, 94, 283, 144, 117, 64, 35, 66, 28, 29, 331 | 30, 32, 33, 34, 108, 31, 13, 12, 11, 113, 332 | 10, 9, 119, 99, 8, 18, 7, 115, 116, 109, 333 | 76, 110, 111, 112, 120, 368, 369, 6, 5, 4, 334 | 100, 2, 1, 0, 117, 113, 0, 0, 119, 118, 335 | 0, 0, 0, 0, 0, 0, 76, 110, 111, 112, 336 | 0, 0, 0, 99, 0, 0, 178, 115, 116, 0, 337 | 117, 0, 0, 0, 120, 151, 155, 153, 154, 156, 338 | 157, 158, 159, 160, 161, 162, 163, 40, 0, 118, 339 | 0, 0, 0, 115, 116, 0, 167, 168, 169, 170, 340 | 120, 164, 165, 166, 0, 0, 0, 42, 43, 44, 341 | 45, 0, 0, 0, 0, 118, 0, 0, 0, 61, 342 | 0, 0, 0, 152, 156, 157, 158, 159, 160, 161, 343 | 162, 163, 344 | } 345 | var yyPact = []int{ 346 | 347 | 400, -1000, -1000, 198, -1000, -1000, -1000, -1000, -1000, -1000, 348 | -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 349 | -1000, -1000, -1000, -35, -2, 14, 18, 10, -1000, -1000, 350 | -1000, -1000, -1000, -1000, -1000, 404, 357, -1000, -1000, -1000, 351 | 352, -1000, 322, 289, 387, 9, -22, 2, 261, -1000, 352 | 1, 261, -1000, 301, -33, 261, -33, 300, -1000, -1000, 353 | -1000, 290, -1000, -1000, 253, -1000, 255, 289, 272, 48, 354 | 289, 170, 299, -1000, 197, -1000, 42, 296, 56, 261, 355 | -1000, -1000, 295, -1000, 4, 293, 342, 127, 261, -1000, 356 | 289, 222, -1000, -1000, 298, 39, 119, 544, -1000, 484, 357 | 444, -1000, -1000, -1000, 38, 239, 237, -1000, 236, 230, 358 | -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 359 | 38, -1000, 247, 262, 288, 384, 262, -1000, 38, 261, 360 | -1000, 337, -44, -1000, 172, -1000, 287, -1000, -1000, 285, 361 | -1000, 233, 210, 253, -1000, -1000, 261, 109, 484, 484, 362 | 38, 217, 343, 38, 38, 142, 38, 38, 38, 38, 363 | 38, 38, 38, 38, -1000, -1000, -1000, -1000, -1000, -1000, 364 | -1000, -1000, 544, -48, -10, -4, 544, -1000, 510, 365, 365 | 253, -1000, 404, 269, 5, 354, 356, 262, 262, 216, 366 | -1000, 358, 484, -1000, 354, -1000, -1000, -1000, 124, 261, 367 | -1000, -6, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 368 | 356, 262, 214, 283, 294, 238, 7, -1000, -1000, -1000, 369 | -1000, -1000, 76, 354, -1000, 510, -1000, -1000, 217, 38, 370 | 38, 354, 380, -1000, 327, 99, 99, 99, 126, 126, 371 | -1000, -1000, -1000, -1000, -1000, 38, -1000, 354, -1000, -5, 372 | 253, -7, 185, 69, -1000, 484, 112, 229, 198, 125, 373 | -8, -1000, 358, 366, 374, 119, 284, -1000, -1000, 275, 374 | -1000, -1000, 170, 381, 210, 210, -1000, -1000, 157, 153, 375 | 167, 165, 161, 0, -1000, 273, -23, 266, -24, -1000, 376 | 354, 346, 38, -1000, 354, -1000, -25, -1000, 269, 32, 377 | -1000, 38, 47, -1000, 320, 183, -1000, -1000, -1000, 262, 378 | 366, -1000, 38, 38, -1000, -1000, 377, 373, 283, 92, 379 | -1000, 159, -1000, 150, -1000, -1000, -1000, -1000, -20, -21, 380 | -31, -1000, -1000, -1000, -1000, 38, 354, -1000, -74, -1000, 381 | 354, 38, 318, 229, -1000, -1000, 66, 182, -1000, 499, 382 | -1000, 358, 484, 38, 484, -1000, -1000, 218, 209, 201, 383 | 354, -1000, 354, 392, -1000, 38, 38, -1000, -1000, -1000, 384 | 366, 119, 181, 119, 261, 261, 261, 262, 354, -1000, 385 | 331, -27, -1000, -28, -34, 170, -1000, 391, 334, -1000, 386 | 261, -1000, -1000, -1000, 261, -1000, 261, -1000, 387 | } 388 | var yyPgo = []int{ 389 | 390 | 0, 532, 531, 23, 529, 528, 527, 516, 514, 511, 391 | 510, 508, 507, 506, 577, 497, 496, 495, 14, 26, 392 | 493, 492, 491, 484, 11, 478, 477, 151, 476, 3, 393 | 17, 5, 475, 474, 18, 15, 2, 16, 9, 473, 394 | 10, 470, 25, 468, 8, 467, 466, 13, 465, 463, 395 | 462, 461, 7, 459, 6, 458, 1, 447, 29, 446, 396 | 12, 4, 22, 205, 444, 443, 442, 441, 437, 436, 397 | 0, 38, 435, 432, 413, 412, 410, 398 | } 399 | var yyR1 = []int{ 400 | 401 | 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 402 | 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 403 | 4, 4, 75, 75, 5, 6, 7, 7, 72, 73, 404 | 74, 8, 8, 8, 9, 9, 9, 10, 11, 11, 405 | 11, 12, 13, 13, 13, 76, 14, 15, 15, 16, 406 | 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 407 | 19, 22, 22, 20, 20, 20, 23, 23, 24, 24, 408 | 24, 24, 21, 21, 21, 25, 25, 25, 25, 25, 409 | 25, 25, 25, 25, 26, 26, 26, 27, 27, 28, 410 | 28, 28, 28, 29, 29, 30, 30, 31, 31, 31, 411 | 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 412 | 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 413 | 37, 37, 37, 42, 38, 38, 36, 36, 36, 36, 414 | 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 415 | 36, 36, 36, 41, 41, 43, 43, 43, 45, 48, 416 | 48, 46, 46, 47, 49, 49, 44, 44, 35, 35, 417 | 35, 35, 50, 50, 51, 51, 52, 52, 53, 53, 418 | 54, 55, 55, 55, 56, 56, 56, 57, 57, 57, 419 | 58, 58, 59, 59, 60, 60, 34, 34, 39, 39, 420 | 40, 40, 61, 61, 62, 63, 63, 64, 64, 65, 421 | 65, 66, 66, 66, 66, 66, 67, 67, 68, 68, 422 | 69, 69, 70, 71, 423 | } 424 | var yyR2 = []int{ 425 | 426 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 427 | 1, 1, 1, 1, 1, 1, 1, 4, 12, 3, 428 | 7, 7, 6, 6, 8, 7, 3, 4, 1, 1, 429 | 1, 5, 8, 4, 6, 7, 4, 5, 4, 5, 430 | 5, 3, 2, 2, 2, 0, 2, 0, 2, 1, 431 | 2, 1, 1, 1, 0, 1, 1, 3, 1, 2, 432 | 3, 1, 1, 0, 1, 2, 1, 3, 3, 3, 433 | 3, 5, 0, 1, 2, 1, 1, 2, 3, 2, 434 | 3, 2, 2, 2, 1, 3, 1, 1, 3, 0, 435 | 5, 5, 5, 1, 3, 0, 2, 1, 3, 3, 436 | 2, 3, 3, 3, 4, 3, 4, 5, 6, 3, 437 | 4, 2, 6, 1, 1, 1, 1, 1, 1, 1, 438 | 3, 1, 1, 3, 1, 3, 1, 1, 1, 3, 439 | 3, 3, 3, 3, 3, 3, 3, 2, 3, 4, 440 | 5, 4, 1, 1, 1, 1, 1, 1, 5, 0, 441 | 1, 1, 2, 4, 0, 2, 1, 3, 1, 1, 442 | 1, 1, 0, 3, 0, 2, 0, 3, 1, 3, 443 | 2, 0, 1, 1, 0, 2, 4, 0, 2, 4, 444 | 0, 3, 1, 3, 0, 5, 2, 1, 1, 3, 445 | 3, 1, 1, 3, 3, 0, 2, 0, 3, 0, 446 | 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 447 | 0, 2, 1, 0, 448 | } 449 | var yyChk = []int{ 450 | 451 | -1000, -1, -2, -3, -4, -5, -6, -7, -8, -9, 452 | -10, -11, -12, -13, -75, -72, -73, -74, 5, 6, 453 | 7, 8, 33, 85, 86, 88, 87, 89, 98, 99, 454 | 100, 105, 101, 102, 103, -16, 51, 52, 53, 54, 455 | -14, -76, -14, -14, -14, -14, 90, -68, 92, 96, 456 | -65, 92, 94, 90, 90, 91, 92, 90, -71, -71, 457 | -71, -14, -3, 17, -17, 18, -15, 29, -27, 36, 458 | 9, -61, 104, -62, -44, -70, 36, -64, 95, 91, 459 | -70, 36, 90, -70, 36, -63, 95, -70, -63, 36, 460 | 29, -18, -19, 75, -22, 36, -31, -36, -32, 69, 461 | 46, -35, -44, -40, -43, -70, -41, -45, 20, 35, 462 | 37, 38, 39, 25, -42, 73, 74, 50, 95, 28, 463 | 80, 41, -27, 33, 78, -27, 55, 36, 47, 78, 464 | 36, 69, -70, -71, 36, -71, 93, 36, 20, 66, 465 | -70, -27, 9, 55, -20, -70, 19, 78, 68, 67, 466 | -33, 21, 69, 23, 24, 22, 70, 71, 72, 73, 467 | 74, 75, 76, 77, 47, 48, 49, 42, 43, 44, 468 | 45, -31, -36, -31, -3, -38, -36, -36, 46, 46, 469 | 46, -42, 46, 46, -48, -36, -58, 33, 46, -61, 470 | 36, -30, 10, -62, -36, -70, -71, 20, -69, 97, 471 | -66, 88, 86, 32, 87, 13, 36, 36, 36, -71, 472 | -58, 33, -23, -24, -26, 46, 36, -42, -19, -70, 473 | 75, -31, -31, -36, -37, 46, -42, 40, 21, 23, 474 | 24, -36, -36, 25, 69, -36, -36, -36, -36, -36, 475 | -36, -36, -36, 106, 106, 55, 106, -36, 106, -18, 476 | 18, -18, -35, -46, -47, 81, -34, 28, -3, -61, 477 | -59, -44, -30, -52, 13, -31, 66, -70, -71, -67, 478 | 93, -34, -61, -30, 55, -25, 56, 57, 58, 59, 479 | 60, 62, 63, -21, 36, 19, -24, 78, -38, -37, 480 | -36, -36, 68, 25, -36, 106, -18, 106, 55, -49, 481 | -47, 83, -31, -60, 66, -39, -40, -60, 106, 55, 482 | -52, -56, 15, 14, 36, 36, -50, 11, -24, -24, 483 | 56, 61, 56, 61, 56, 56, 56, -28, 64, 94, 484 | 65, 36, 106, 36, 106, 68, -36, 106, -35, 84, 485 | -36, 82, 30, 55, -44, -56, -36, -53, -54, -36, 486 | -71, -51, 12, 14, 66, 56, 56, 91, 91, 91, 487 | -36, 106, -36, 31, -40, 55, 55, -55, 26, 27, 488 | -52, -31, -38, -31, 46, 46, 46, 7, -36, -54, 489 | -56, -29, -70, -29, -29, -61, -57, 16, 34, 106, 490 | 55, 106, 106, 7, 21, -70, -70, -70, 491 | } 492 | var yyDef = []int{ 493 | 494 | 0, -2, 1, 2, 3, 4, 5, 6, 7, 8, 495 | 9, 10, 11, 12, 13, 14, 15, 16, 45, 45, 496 | 45, 45, 45, 208, 199, 0, 0, 0, 213, 213, 497 | 213, 45, 28, 29, 30, 0, 49, 51, 52, 53, 498 | 54, 47, 0, 0, 0, 0, 197, 0, 0, 209, 499 | 0, 0, 200, 0, 195, 0, 195, 0, 42, 43, 500 | 44, 0, 19, 50, 0, 55, 46, 0, 0, 87, 501 | 0, 26, 0, 192, 0, 156, 212, 0, 0, 0, 502 | 213, 212, 0, 213, 0, 0, 0, 0, 0, 41, 503 | 0, 17, 56, 58, 63, 212, 61, 62, 97, 0, 504 | 0, 126, 127, 128, 0, 156, 0, 142, 0, 0, 505 | 158, 159, 160, 161, 191, 145, 146, 147, 143, 144, 506 | 149, 48, 180, 0, 0, 95, 0, 27, 0, 0, 507 | 213, 0, 210, 33, 0, 36, 0, 38, 196, 0, 508 | 213, 180, 0, 0, 59, 64, 0, 0, 0, 0, 509 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 510 | 0, 0, 0, 0, 113, 114, 115, 116, 117, 118, 511 | 119, 100, 0, 0, 0, 0, 124, 137, 0, 0, 512 | 0, 111, 0, 0, 0, 150, 0, 0, 0, 95, 513 | 88, 166, 0, 193, 194, 157, 31, 198, 0, 0, 514 | 213, 206, 201, 202, 203, 204, 205, 37, 39, 40, 515 | 0, 0, 95, 66, 72, 0, 84, 86, 57, 65, 516 | 60, 98, 99, 102, 103, 0, 121, 122, 0, 0, 517 | 0, 105, 0, 109, 0, 129, 130, 131, 132, 133, 518 | 134, 135, 136, 101, 123, 0, 190, 124, 138, 0, 519 | 0, 0, 0, 154, 151, 0, 184, 0, 187, 184, 520 | 0, 182, 166, 174, 0, 96, 0, 211, 34, 0, 521 | 207, 22, 23, 162, 0, 0, 75, 76, 0, 0, 522 | 0, 0, 0, 89, 73, 0, 0, 0, 0, 104, 523 | 106, 0, 0, 110, 125, 139, 0, 141, 0, 0, 524 | 152, 0, 0, 20, 0, 186, 188, 21, 181, 0, 525 | 174, 25, 0, 0, 213, 35, 164, 0, 67, 70, 526 | 77, 0, 79, 0, 81, 82, 83, 68, 0, 0, 527 | 0, 74, 69, 85, 120, 0, 107, 140, 0, 148, 528 | 155, 0, 0, 0, 183, 24, 175, 167, 168, 171, 529 | 32, 166, 0, 0, 0, 78, 80, 0, 0, 0, 530 | 108, 112, 153, 0, 189, 0, 0, 170, 172, 173, 531 | 174, 165, 163, 71, 0, 0, 0, 0, 176, 169, 532 | 177, 0, 93, 0, 0, 185, 18, 0, 0, 90, 533 | 0, 91, 92, 178, 0, 94, 0, 179, 534 | } 535 | var yyTok1 = []int{ 536 | 537 | 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 538 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 539 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 540 | 3, 3, 3, 3, 3, 3, 3, 77, 70, 3, 541 | 46, 106, 75, 73, 55, 74, 78, 76, 3, 3, 542 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 543 | 48, 47, 49, 3, 3, 3, 3, 3, 3, 3, 544 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 545 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 546 | 3, 3, 3, 3, 72, 3, 3, 3, 3, 3, 547 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 548 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 549 | 3, 3, 3, 3, 71, 3, 50, 550 | } 551 | var yyTok2 = []int{ 552 | 553 | 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 554 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 555 | 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 556 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 557 | 42, 43, 44, 45, 51, 52, 53, 54, 56, 57, 558 | 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 559 | 68, 69, 79, 80, 81, 82, 83, 84, 85, 86, 560 | 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 561 | 97, 98, 99, 100, 101, 102, 103, 104, 105, 562 | } 563 | var yyTok3 = []int{ 564 | 0, 565 | } 566 | 567 | //line yaccpar:1 568 | 569 | /* parser for yacc output */ 570 | 571 | var yyDebug = 0 572 | 573 | type yyLexer interface { 574 | Lex(lval *yySymType) int 575 | Error(s string) 576 | } 577 | 578 | const yyFlag = -1000 579 | 580 | func yyTokname(c int) string { 581 | // 4 is TOKSTART above 582 | if c >= 4 && c-4 < len(yyToknames) { 583 | if yyToknames[c-4] != "" { 584 | return yyToknames[c-4] 585 | } 586 | } 587 | return __yyfmt__.Sprintf("tok-%v", c) 588 | } 589 | 590 | func yyStatname(s int) string { 591 | if s >= 0 && s < len(yyStatenames) { 592 | if yyStatenames[s] != "" { 593 | return yyStatenames[s] 594 | } 595 | } 596 | return __yyfmt__.Sprintf("state-%v", s) 597 | } 598 | 599 | func yylex1(lex yyLexer, lval *yySymType) int { 600 | c := 0 601 | char := lex.Lex(lval) 602 | if char <= 0 { 603 | c = yyTok1[0] 604 | goto out 605 | } 606 | if char < len(yyTok1) { 607 | c = yyTok1[char] 608 | goto out 609 | } 610 | if char >= yyPrivate { 611 | if char < yyPrivate+len(yyTok2) { 612 | c = yyTok2[char-yyPrivate] 613 | goto out 614 | } 615 | } 616 | for i := 0; i < len(yyTok3); i += 2 { 617 | c = yyTok3[i+0] 618 | if c == char { 619 | c = yyTok3[i+1] 620 | goto out 621 | } 622 | } 623 | 624 | out: 625 | if c == 0 { 626 | c = yyTok2[1] /* unknown char */ 627 | } 628 | if yyDebug >= 3 { 629 | __yyfmt__.Printf("lex %s(%d)\n", yyTokname(c), uint(char)) 630 | } 631 | return c 632 | } 633 | 634 | func yyParse(yylex yyLexer) int { 635 | var yyn int 636 | var yylval yySymType 637 | var yyVAL yySymType 638 | yyS := make([]yySymType, yyMaxDepth) 639 | 640 | Nerrs := 0 /* number of errors */ 641 | Errflag := 0 /* error recovery flag */ 642 | yystate := 0 643 | yychar := -1 644 | yyp := -1 645 | goto yystack 646 | 647 | ret0: 648 | return 0 649 | 650 | ret1: 651 | return 1 652 | 653 | yystack: 654 | /* put a state and value onto the stack */ 655 | if yyDebug >= 4 { 656 | __yyfmt__.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) 657 | } 658 | 659 | yyp++ 660 | if yyp >= len(yyS) { 661 | nyys := make([]yySymType, len(yyS)*2) 662 | copy(nyys, yyS) 663 | yyS = nyys 664 | } 665 | yyS[yyp] = yyVAL 666 | yyS[yyp].yys = yystate 667 | 668 | yynewstate: 669 | yyn = yyPact[yystate] 670 | if yyn <= yyFlag { 671 | goto yydefault /* simple state */ 672 | } 673 | if yychar < 0 { 674 | yychar = yylex1(yylex, &yylval) 675 | } 676 | yyn += yychar 677 | if yyn < 0 || yyn >= yyLast { 678 | goto yydefault 679 | } 680 | yyn = yyAct[yyn] 681 | if yyChk[yyn] == yychar { /* valid shift */ 682 | yychar = -1 683 | yyVAL = yylval 684 | yystate = yyn 685 | if Errflag > 0 { 686 | Errflag-- 687 | } 688 | goto yystack 689 | } 690 | 691 | yydefault: 692 | /* default state action */ 693 | yyn = yyDef[yystate] 694 | if yyn == -2 { 695 | if yychar < 0 { 696 | yychar = yylex1(yylex, &yylval) 697 | } 698 | 699 | /* look through exception table */ 700 | xi := 0 701 | for { 702 | if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { 703 | break 704 | } 705 | xi += 2 706 | } 707 | for xi += 2; ; xi += 2 { 708 | yyn = yyExca[xi+0] 709 | if yyn < 0 || yyn == yychar { 710 | break 711 | } 712 | } 713 | yyn = yyExca[xi+1] 714 | if yyn < 0 { 715 | goto ret0 716 | } 717 | } 718 | if yyn == 0 { 719 | /* error ... attempt to resume parsing */ 720 | switch Errflag { 721 | case 0: /* brand new error */ 722 | yylex.Error("syntax error") 723 | Nerrs++ 724 | if yyDebug >= 1 { 725 | __yyfmt__.Printf("%s", yyStatname(yystate)) 726 | __yyfmt__.Printf(" saw %s\n", yyTokname(yychar)) 727 | } 728 | fallthrough 729 | 730 | case 1, 2: /* incompletely recovered error ... try again */ 731 | Errflag = 3 732 | 733 | /* find a state where "error" is a legal shift action */ 734 | for yyp >= 0 { 735 | yyn = yyPact[yyS[yyp].yys] + yyErrCode 736 | if yyn >= 0 && yyn < yyLast { 737 | yystate = yyAct[yyn] /* simulate a shift of "error" */ 738 | if yyChk[yystate] == yyErrCode { 739 | goto yystack 740 | } 741 | } 742 | 743 | /* the current p has no shift on "error", pop stack */ 744 | if yyDebug >= 2 { 745 | __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) 746 | } 747 | yyp-- 748 | } 749 | /* there is no state on the stack with an error shift ... abort */ 750 | goto ret1 751 | 752 | case 3: /* no shift yet; clobber input char */ 753 | if yyDebug >= 2 { 754 | __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yychar)) 755 | } 756 | if yychar == yyEofCode { 757 | goto ret1 758 | } 759 | yychar = -1 760 | goto yynewstate /* try again in the same state */ 761 | } 762 | } 763 | 764 | /* reduction by production yyn */ 765 | if yyDebug >= 2 { 766 | __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) 767 | } 768 | 769 | yynt := yyn 770 | yypt := yyp 771 | _ = yypt // guard against "declared and not used" 772 | 773 | yyp -= yyR2[yyn] 774 | yyVAL = yyS[yyp+1] 775 | 776 | /* consult goto table to find next state */ 777 | yyn = yyR1[yyn] 778 | yyg := yyPgo[yyn] 779 | yyj := yyg + yyS[yyp].yys + 1 780 | 781 | if yyj >= yyLast { 782 | yystate = yyAct[yyg] 783 | } else { 784 | yystate = yyAct[yyj] 785 | if yyChk[yystate] != -yyn { 786 | yystate = yyAct[yyg] 787 | } 788 | } 789 | // dummy call; replaced with literal code 790 | switch yynt { 791 | 792 | case 1: 793 | //line sql.y:163 794 | { 795 | SetParseTree(yylex, yyS[yypt-0].statement) 796 | } 797 | case 2: 798 | //line sql.y:169 799 | { 800 | yyVAL.statement = yyS[yypt-0].selStmt 801 | } 802 | case 3: 803 | yyVAL.statement = yyS[yypt-0].statement 804 | case 4: 805 | yyVAL.statement = yyS[yypt-0].statement 806 | case 5: 807 | yyVAL.statement = yyS[yypt-0].statement 808 | case 6: 809 | yyVAL.statement = yyS[yypt-0].statement 810 | case 7: 811 | yyVAL.statement = yyS[yypt-0].statement 812 | case 8: 813 | yyVAL.statement = yyS[yypt-0].statement 814 | case 9: 815 | yyVAL.statement = yyS[yypt-0].statement 816 | case 10: 817 | yyVAL.statement = yyS[yypt-0].statement 818 | case 11: 819 | yyVAL.statement = yyS[yypt-0].statement 820 | case 12: 821 | yyVAL.statement = yyS[yypt-0].statement 822 | case 13: 823 | yyVAL.statement = yyS[yypt-0].statement 824 | case 14: 825 | yyVAL.statement = yyS[yypt-0].statement 826 | case 15: 827 | yyVAL.statement = yyS[yypt-0].statement 828 | case 16: 829 | yyVAL.statement = yyS[yypt-0].statement 830 | case 17: 831 | //line sql.y:189 832 | { 833 | yyVAL.selStmt = &SimpleSelect{Comments: Comments(yyS[yypt-2].bytes2), Distinct: yyS[yypt-1].str, SelectExprs: yyS[yypt-0].selectExprs} 834 | } 835 | case 18: 836 | //line sql.y:193 837 | { 838 | yyVAL.selStmt = &Select{Comments: Comments(yyS[yypt-10].bytes2), Distinct: yyS[yypt-9].str, SelectExprs: yyS[yypt-8].selectExprs, From: yyS[yypt-6].tableExprs, Where: NewWhere(AST_WHERE, yyS[yypt-5].boolExpr), GroupBy: GroupBy(yyS[yypt-4].valExprs), Having: NewWhere(AST_HAVING, yyS[yypt-3].boolExpr), OrderBy: yyS[yypt-2].orderBy, Limit: yyS[yypt-1].limit, Lock: yyS[yypt-0].str} 839 | } 840 | case 19: 841 | //line sql.y:197 842 | { 843 | yyVAL.selStmt = &Union{Type: yyS[yypt-1].str, Left: yyS[yypt-2].selStmt, Right: yyS[yypt-0].selStmt} 844 | } 845 | case 20: 846 | //line sql.y:203 847 | { 848 | yyVAL.statement = &Insert{Comments: Comments(yyS[yypt-5].bytes2), Table: yyS[yypt-3].tableName, Columns: yyS[yypt-2].columns, Rows: yyS[yypt-1].insRows, OnDup: OnDup(yyS[yypt-0].updateExprs)} 849 | } 850 | case 21: 851 | //line sql.y:207 852 | { 853 | cols := make(Columns, 0, len(yyS[yypt-1].updateExprs)) 854 | vals := make(ValTuple, 0, len(yyS[yypt-1].updateExprs)) 855 | for _, col := range yyS[yypt-1].updateExprs { 856 | cols = append(cols, &NonStarExpr{Expr: col.Name}) 857 | vals = append(vals, col.Expr) 858 | } 859 | yyVAL.statement = &Insert{Comments: Comments(yyS[yypt-5].bytes2), Table: yyS[yypt-3].tableName, Columns: cols, Rows: Values{vals}, OnDup: OnDup(yyS[yypt-0].updateExprs)} 860 | } 861 | case 22: 862 | //line sql.y:219 863 | { 864 | yyVAL.statement = &Replace{Comments: Comments(yyS[yypt-4].bytes2), Table: yyS[yypt-2].tableName, Columns: yyS[yypt-1].columns, Rows: yyS[yypt-0].insRows} 865 | } 866 | case 23: 867 | //line sql.y:223 868 | { 869 | cols := make(Columns, 0, len(yyS[yypt-0].updateExprs)) 870 | vals := make(ValTuple, 0, len(yyS[yypt-0].updateExprs)) 871 | for _, col := range yyS[yypt-0].updateExprs { 872 | cols = append(cols, &NonStarExpr{Expr: col.Name}) 873 | vals = append(vals, col.Expr) 874 | } 875 | yyVAL.statement = &Replace{Comments: Comments(yyS[yypt-4].bytes2), Table: yyS[yypt-2].tableName, Columns: cols, Rows: Values{vals}} 876 | } 877 | case 24: 878 | //line sql.y:235 879 | { 880 | yyVAL.statement = &Update{Comments: Comments(yyS[yypt-6].bytes2), Table: yyS[yypt-5].tableName, Exprs: yyS[yypt-3].updateExprs, Where: NewWhere(AST_WHERE, yyS[yypt-2].boolExpr), OrderBy: yyS[yypt-1].orderBy, Limit: yyS[yypt-0].limit} 881 | } 882 | case 25: 883 | //line sql.y:241 884 | { 885 | yyVAL.statement = &Delete{Comments: Comments(yyS[yypt-5].bytes2), Table: yyS[yypt-3].tableName, Where: NewWhere(AST_WHERE, yyS[yypt-2].boolExpr), OrderBy: yyS[yypt-1].orderBy, Limit: yyS[yypt-0].limit} 886 | } 887 | case 26: 888 | //line sql.y:247 889 | { 890 | yyVAL.statement = &Set{Comments: Comments(yyS[yypt-1].bytes2), Exprs: yyS[yypt-0].updateExprs} 891 | } 892 | case 27: 893 | //line sql.y:251 894 | { 895 | yyVAL.statement = &Set{Comments: Comments(yyS[yypt-2].bytes2), Exprs: UpdateExprs{&UpdateExpr{Name: &ColName{Name: []byte("names")}, Expr: StrVal(yyS[yypt-0].bytes)}}} 896 | } 897 | case 28: 898 | //line sql.y:257 899 | { 900 | yyVAL.statement = &Begin{} 901 | } 902 | case 29: 903 | //line sql.y:263 904 | { 905 | yyVAL.statement = &Commit{} 906 | } 907 | case 30: 908 | //line sql.y:269 909 | { 910 | yyVAL.statement = &Rollback{} 911 | } 912 | case 31: 913 | //line sql.y:275 914 | { 915 | yyVAL.statement = &DDL{Action: AST_CREATE, NewName: yyS[yypt-1].bytes} 916 | } 917 | case 32: 918 | //line sql.y:279 919 | { 920 | // Change this to an alter statement 921 | yyVAL.statement = &DDL{Action: AST_ALTER, Table: yyS[yypt-1].bytes, NewName: yyS[yypt-1].bytes} 922 | } 923 | case 33: 924 | //line sql.y:284 925 | { 926 | yyVAL.statement = &DDL{Action: AST_CREATE, NewName: yyS[yypt-1].bytes} 927 | } 928 | case 34: 929 | //line sql.y:290 930 | { 931 | yyVAL.statement = &DDL{Action: AST_ALTER, Table: yyS[yypt-2].bytes, NewName: yyS[yypt-2].bytes} 932 | } 933 | case 35: 934 | //line sql.y:294 935 | { 936 | // Change this to a rename statement 937 | yyVAL.statement = &DDL{Action: AST_RENAME, Table: yyS[yypt-3].bytes, NewName: yyS[yypt-0].bytes} 938 | } 939 | case 36: 940 | //line sql.y:299 941 | { 942 | yyVAL.statement = &DDL{Action: AST_ALTER, Table: yyS[yypt-1].bytes, NewName: yyS[yypt-1].bytes} 943 | } 944 | case 37: 945 | //line sql.y:305 946 | { 947 | yyVAL.statement = &DDL{Action: AST_RENAME, Table: yyS[yypt-2].bytes, NewName: yyS[yypt-0].bytes} 948 | } 949 | case 38: 950 | //line sql.y:311 951 | { 952 | yyVAL.statement = &DDL{Action: AST_DROP, Table: yyS[yypt-0].bytes} 953 | } 954 | case 39: 955 | //line sql.y:315 956 | { 957 | // Change this to an alter statement 958 | yyVAL.statement = &DDL{Action: AST_ALTER, Table: yyS[yypt-0].bytes, NewName: yyS[yypt-0].bytes} 959 | } 960 | case 40: 961 | //line sql.y:320 962 | { 963 | yyVAL.statement = &DDL{Action: AST_DROP, Table: yyS[yypt-1].bytes} 964 | } 965 | case 41: 966 | //line sql.y:326 967 | { 968 | yyVAL.statement = &DDL{Action: AST_ALTER, Table: yyS[yypt-0].bytes, NewName: yyS[yypt-0].bytes} 969 | } 970 | case 42: 971 | //line sql.y:332 972 | { 973 | yyVAL.statement = &Other{} 974 | } 975 | case 43: 976 | //line sql.y:336 977 | { 978 | yyVAL.statement = &Other{} 979 | } 980 | case 44: 981 | //line sql.y:340 982 | { 983 | yyVAL.statement = &Other{} 984 | } 985 | case 45: 986 | //line sql.y:345 987 | { 988 | SetAllowComments(yylex, true) 989 | } 990 | case 46: 991 | //line sql.y:349 992 | { 993 | yyVAL.bytes2 = yyS[yypt-0].bytes2 994 | SetAllowComments(yylex, false) 995 | } 996 | case 47: 997 | //line sql.y:355 998 | { 999 | yyVAL.bytes2 = nil 1000 | } 1001 | case 48: 1002 | //line sql.y:359 1003 | { 1004 | yyVAL.bytes2 = append(yyS[yypt-1].bytes2, yyS[yypt-0].bytes) 1005 | } 1006 | case 49: 1007 | //line sql.y:365 1008 | { 1009 | yyVAL.str = AST_UNION 1010 | } 1011 | case 50: 1012 | //line sql.y:369 1013 | { 1014 | yyVAL.str = AST_UNION_ALL 1015 | } 1016 | case 51: 1017 | //line sql.y:373 1018 | { 1019 | yyVAL.str = AST_SET_MINUS 1020 | } 1021 | case 52: 1022 | //line sql.y:377 1023 | { 1024 | yyVAL.str = AST_EXCEPT 1025 | } 1026 | case 53: 1027 | //line sql.y:381 1028 | { 1029 | yyVAL.str = AST_INTERSECT 1030 | } 1031 | case 54: 1032 | //line sql.y:386 1033 | { 1034 | yyVAL.str = "" 1035 | } 1036 | case 55: 1037 | //line sql.y:390 1038 | { 1039 | yyVAL.str = AST_DISTINCT 1040 | } 1041 | case 56: 1042 | //line sql.y:396 1043 | { 1044 | yyVAL.selectExprs = SelectExprs{yyS[yypt-0].selectExpr} 1045 | } 1046 | case 57: 1047 | //line sql.y:400 1048 | { 1049 | yyVAL.selectExprs = append(yyVAL.selectExprs, yyS[yypt-0].selectExpr) 1050 | } 1051 | case 58: 1052 | //line sql.y:406 1053 | { 1054 | yyVAL.selectExpr = &StarExpr{} 1055 | } 1056 | case 59: 1057 | //line sql.y:410 1058 | { 1059 | yyVAL.selectExpr = &NonStarExpr{Expr: yyS[yypt-1].expr, As: yyS[yypt-0].bytes} 1060 | } 1061 | case 60: 1062 | //line sql.y:414 1063 | { 1064 | yyVAL.selectExpr = &StarExpr{TableName: yyS[yypt-2].bytes} 1065 | } 1066 | case 61: 1067 | //line sql.y:420 1068 | { 1069 | yyVAL.expr = yyS[yypt-0].boolExpr 1070 | } 1071 | case 62: 1072 | //line sql.y:424 1073 | { 1074 | yyVAL.expr = yyS[yypt-0].valExpr 1075 | } 1076 | case 63: 1077 | //line sql.y:429 1078 | { 1079 | yyVAL.bytes = nil 1080 | } 1081 | case 64: 1082 | //line sql.y:433 1083 | { 1084 | yyVAL.bytes = yyS[yypt-0].bytes 1085 | } 1086 | case 65: 1087 | //line sql.y:437 1088 | { 1089 | yyVAL.bytes = yyS[yypt-0].bytes 1090 | } 1091 | case 66: 1092 | //line sql.y:443 1093 | { 1094 | yyVAL.tableExprs = TableExprs{yyS[yypt-0].tableExpr} 1095 | } 1096 | case 67: 1097 | //line sql.y:447 1098 | { 1099 | yyVAL.tableExprs = append(yyVAL.tableExprs, yyS[yypt-0].tableExpr) 1100 | } 1101 | case 68: 1102 | //line sql.y:453 1103 | { 1104 | yyVAL.tableExpr = &AliasedTableExpr{Expr: yyS[yypt-2].smTableExpr, As: yyS[yypt-1].bytes, Hints: yyS[yypt-0].indexHints} 1105 | } 1106 | case 69: 1107 | //line sql.y:457 1108 | { 1109 | yyVAL.tableExpr = &ParenTableExpr{Expr: yyS[yypt-1].tableExpr} 1110 | } 1111 | case 70: 1112 | //line sql.y:461 1113 | { 1114 | yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyS[yypt-2].tableExpr, Join: yyS[yypt-1].str, RightExpr: yyS[yypt-0].tableExpr} 1115 | } 1116 | case 71: 1117 | //line sql.y:465 1118 | { 1119 | yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyS[yypt-4].tableExpr, Join: yyS[yypt-3].str, RightExpr: yyS[yypt-2].tableExpr, On: yyS[yypt-0].boolExpr} 1120 | } 1121 | case 72: 1122 | //line sql.y:470 1123 | { 1124 | yyVAL.bytes = nil 1125 | } 1126 | case 73: 1127 | //line sql.y:474 1128 | { 1129 | yyVAL.bytes = yyS[yypt-0].bytes 1130 | } 1131 | case 74: 1132 | //line sql.y:478 1133 | { 1134 | yyVAL.bytes = yyS[yypt-0].bytes 1135 | } 1136 | case 75: 1137 | //line sql.y:484 1138 | { 1139 | yyVAL.str = AST_JOIN 1140 | } 1141 | case 76: 1142 | //line sql.y:488 1143 | { 1144 | yyVAL.str = AST_STRAIGHT_JOIN 1145 | } 1146 | case 77: 1147 | //line sql.y:492 1148 | { 1149 | yyVAL.str = AST_LEFT_JOIN 1150 | } 1151 | case 78: 1152 | //line sql.y:496 1153 | { 1154 | yyVAL.str = AST_LEFT_JOIN 1155 | } 1156 | case 79: 1157 | //line sql.y:500 1158 | { 1159 | yyVAL.str = AST_RIGHT_JOIN 1160 | } 1161 | case 80: 1162 | //line sql.y:504 1163 | { 1164 | yyVAL.str = AST_RIGHT_JOIN 1165 | } 1166 | case 81: 1167 | //line sql.y:508 1168 | { 1169 | yyVAL.str = AST_JOIN 1170 | } 1171 | case 82: 1172 | //line sql.y:512 1173 | { 1174 | yyVAL.str = AST_CROSS_JOIN 1175 | } 1176 | case 83: 1177 | //line sql.y:516 1178 | { 1179 | yyVAL.str = AST_NATURAL_JOIN 1180 | } 1181 | case 84: 1182 | //line sql.y:522 1183 | { 1184 | yyVAL.smTableExpr = &TableName{Name: yyS[yypt-0].bytes} 1185 | } 1186 | case 85: 1187 | //line sql.y:526 1188 | { 1189 | yyVAL.smTableExpr = &TableName{Qualifier: yyS[yypt-2].bytes, Name: yyS[yypt-0].bytes} 1190 | } 1191 | case 86: 1192 | //line sql.y:530 1193 | { 1194 | yyVAL.smTableExpr = yyS[yypt-0].subquery 1195 | } 1196 | case 87: 1197 | //line sql.y:536 1198 | { 1199 | yyVAL.tableName = &TableName{Name: yyS[yypt-0].bytes} 1200 | } 1201 | case 88: 1202 | //line sql.y:540 1203 | { 1204 | yyVAL.tableName = &TableName{Qualifier: yyS[yypt-2].bytes, Name: yyS[yypt-0].bytes} 1205 | } 1206 | case 89: 1207 | //line sql.y:545 1208 | { 1209 | yyVAL.indexHints = nil 1210 | } 1211 | case 90: 1212 | //line sql.y:549 1213 | { 1214 | yyVAL.indexHints = &IndexHints{Type: AST_USE, Indexes: yyS[yypt-1].bytes2} 1215 | } 1216 | case 91: 1217 | //line sql.y:553 1218 | { 1219 | yyVAL.indexHints = &IndexHints{Type: AST_IGNORE, Indexes: yyS[yypt-1].bytes2} 1220 | } 1221 | case 92: 1222 | //line sql.y:557 1223 | { 1224 | yyVAL.indexHints = &IndexHints{Type: AST_FORCE, Indexes: yyS[yypt-1].bytes2} 1225 | } 1226 | case 93: 1227 | //line sql.y:563 1228 | { 1229 | yyVAL.bytes2 = [][]byte{yyS[yypt-0].bytes} 1230 | } 1231 | case 94: 1232 | //line sql.y:567 1233 | { 1234 | yyVAL.bytes2 = append(yyS[yypt-2].bytes2, yyS[yypt-0].bytes) 1235 | } 1236 | case 95: 1237 | //line sql.y:572 1238 | { 1239 | yyVAL.boolExpr = nil 1240 | } 1241 | case 96: 1242 | //line sql.y:576 1243 | { 1244 | yyVAL.boolExpr = yyS[yypt-0].boolExpr 1245 | } 1246 | case 97: 1247 | yyVAL.boolExpr = yyS[yypt-0].boolExpr 1248 | case 98: 1249 | //line sql.y:583 1250 | { 1251 | yyVAL.boolExpr = &AndExpr{Left: yyS[yypt-2].boolExpr, Right: yyS[yypt-0].boolExpr} 1252 | } 1253 | case 99: 1254 | //line sql.y:587 1255 | { 1256 | yyVAL.boolExpr = &OrExpr{Left: yyS[yypt-2].boolExpr, Right: yyS[yypt-0].boolExpr} 1257 | } 1258 | case 100: 1259 | //line sql.y:591 1260 | { 1261 | yyVAL.boolExpr = &NotExpr{Expr: yyS[yypt-0].boolExpr} 1262 | } 1263 | case 101: 1264 | //line sql.y:595 1265 | { 1266 | yyVAL.boolExpr = &ParenBoolExpr{Expr: yyS[yypt-1].boolExpr} 1267 | } 1268 | case 102: 1269 | //line sql.y:601 1270 | { 1271 | yyVAL.boolExpr = &ComparisonExpr{Left: yyS[yypt-2].valExpr, Operator: yyS[yypt-1].str, Right: yyS[yypt-0].valExpr} 1272 | } 1273 | case 103: 1274 | //line sql.y:605 1275 | { 1276 | yyVAL.boolExpr = &ComparisonExpr{Left: yyS[yypt-2].valExpr, Operator: AST_IN, Right: yyS[yypt-0].colTuple} 1277 | } 1278 | case 104: 1279 | //line sql.y:609 1280 | { 1281 | yyVAL.boolExpr = &ComparisonExpr{Left: yyS[yypt-3].valExpr, Operator: AST_NOT_IN, Right: yyS[yypt-0].colTuple} 1282 | } 1283 | case 105: 1284 | //line sql.y:613 1285 | { 1286 | yyVAL.boolExpr = &ComparisonExpr{Left: yyS[yypt-2].valExpr, Operator: AST_LIKE, Right: yyS[yypt-0].valExpr} 1287 | } 1288 | case 106: 1289 | //line sql.y:617 1290 | { 1291 | yyVAL.boolExpr = &ComparisonExpr{Left: yyS[yypt-3].valExpr, Operator: AST_NOT_LIKE, Right: yyS[yypt-0].valExpr} 1292 | } 1293 | case 107: 1294 | //line sql.y:621 1295 | { 1296 | yyVAL.boolExpr = &RangeCond{Left: yyS[yypt-4].valExpr, Operator: AST_BETWEEN, From: yyS[yypt-2].valExpr, To: yyS[yypt-0].valExpr} 1297 | } 1298 | case 108: 1299 | //line sql.y:625 1300 | { 1301 | yyVAL.boolExpr = &RangeCond{Left: yyS[yypt-5].valExpr, Operator: AST_NOT_BETWEEN, From: yyS[yypt-2].valExpr, To: yyS[yypt-0].valExpr} 1302 | } 1303 | case 109: 1304 | //line sql.y:629 1305 | { 1306 | yyVAL.boolExpr = &NullCheck{Operator: AST_IS_NULL, Expr: yyS[yypt-2].valExpr} 1307 | } 1308 | case 110: 1309 | //line sql.y:633 1310 | { 1311 | yyVAL.boolExpr = &NullCheck{Operator: AST_IS_NOT_NULL, Expr: yyS[yypt-3].valExpr} 1312 | } 1313 | case 111: 1314 | //line sql.y:637 1315 | { 1316 | yyVAL.boolExpr = &ExistsExpr{Subquery: yyS[yypt-0].subquery} 1317 | } 1318 | case 112: 1319 | //line sql.y:641 1320 | { 1321 | yyVAL.boolExpr = &KeyrangeExpr{Start: yyS[yypt-3].valExpr, End: yyS[yypt-1].valExpr} 1322 | } 1323 | case 113: 1324 | //line sql.y:647 1325 | { 1326 | yyVAL.str = AST_EQ 1327 | } 1328 | case 114: 1329 | //line sql.y:651 1330 | { 1331 | yyVAL.str = AST_LT 1332 | } 1333 | case 115: 1334 | //line sql.y:655 1335 | { 1336 | yyVAL.str = AST_GT 1337 | } 1338 | case 116: 1339 | //line sql.y:659 1340 | { 1341 | yyVAL.str = AST_LE 1342 | } 1343 | case 117: 1344 | //line sql.y:663 1345 | { 1346 | yyVAL.str = AST_GE 1347 | } 1348 | case 118: 1349 | //line sql.y:667 1350 | { 1351 | yyVAL.str = AST_NE 1352 | } 1353 | case 119: 1354 | //line sql.y:671 1355 | { 1356 | yyVAL.str = AST_NSE 1357 | } 1358 | case 120: 1359 | //line sql.y:677 1360 | { 1361 | yyVAL.colTuple = ValTuple(yyS[yypt-1].valExprs) 1362 | } 1363 | case 121: 1364 | //line sql.y:681 1365 | { 1366 | yyVAL.colTuple = yyS[yypt-0].subquery 1367 | } 1368 | case 122: 1369 | //line sql.y:685 1370 | { 1371 | yyVAL.colTuple = ListArg(yyS[yypt-0].bytes) 1372 | } 1373 | case 123: 1374 | //line sql.y:691 1375 | { 1376 | yyVAL.subquery = &Subquery{yyS[yypt-1].selStmt} 1377 | } 1378 | case 124: 1379 | //line sql.y:697 1380 | { 1381 | yyVAL.valExprs = ValExprs{yyS[yypt-0].valExpr} 1382 | } 1383 | case 125: 1384 | //line sql.y:701 1385 | { 1386 | yyVAL.valExprs = append(yyS[yypt-2].valExprs, yyS[yypt-0].valExpr) 1387 | } 1388 | case 126: 1389 | //line sql.y:707 1390 | { 1391 | yyVAL.valExpr = yyS[yypt-0].valExpr 1392 | } 1393 | case 127: 1394 | //line sql.y:711 1395 | { 1396 | yyVAL.valExpr = yyS[yypt-0].colName 1397 | } 1398 | case 128: 1399 | //line sql.y:715 1400 | { 1401 | yyVAL.valExpr = yyS[yypt-0].rowTuple 1402 | } 1403 | case 129: 1404 | //line sql.y:719 1405 | { 1406 | yyVAL.valExpr = &BinaryExpr{Left: yyS[yypt-2].valExpr, Operator: AST_BITAND, Right: yyS[yypt-0].valExpr} 1407 | } 1408 | case 130: 1409 | //line sql.y:723 1410 | { 1411 | yyVAL.valExpr = &BinaryExpr{Left: yyS[yypt-2].valExpr, Operator: AST_BITOR, Right: yyS[yypt-0].valExpr} 1412 | } 1413 | case 131: 1414 | //line sql.y:727 1415 | { 1416 | yyVAL.valExpr = &BinaryExpr{Left: yyS[yypt-2].valExpr, Operator: AST_BITXOR, Right: yyS[yypt-0].valExpr} 1417 | } 1418 | case 132: 1419 | //line sql.y:731 1420 | { 1421 | yyVAL.valExpr = &BinaryExpr{Left: yyS[yypt-2].valExpr, Operator: AST_PLUS, Right: yyS[yypt-0].valExpr} 1422 | } 1423 | case 133: 1424 | //line sql.y:735 1425 | { 1426 | yyVAL.valExpr = &BinaryExpr{Left: yyS[yypt-2].valExpr, Operator: AST_MINUS, Right: yyS[yypt-0].valExpr} 1427 | } 1428 | case 134: 1429 | //line sql.y:739 1430 | { 1431 | yyVAL.valExpr = &BinaryExpr{Left: yyS[yypt-2].valExpr, Operator: AST_MULT, Right: yyS[yypt-0].valExpr} 1432 | } 1433 | case 135: 1434 | //line sql.y:743 1435 | { 1436 | yyVAL.valExpr = &BinaryExpr{Left: yyS[yypt-2].valExpr, Operator: AST_DIV, Right: yyS[yypt-0].valExpr} 1437 | } 1438 | case 136: 1439 | //line sql.y:747 1440 | { 1441 | yyVAL.valExpr = &BinaryExpr{Left: yyS[yypt-2].valExpr, Operator: AST_MOD, Right: yyS[yypt-0].valExpr} 1442 | } 1443 | case 137: 1444 | //line sql.y:751 1445 | { 1446 | if num, ok := yyS[yypt-0].valExpr.(NumVal); ok { 1447 | switch yyS[yypt-1].byt { 1448 | case '-': 1449 | yyVAL.valExpr = append(NumVal("-"), num...) 1450 | case '+': 1451 | yyVAL.valExpr = num 1452 | default: 1453 | yyVAL.valExpr = &UnaryExpr{Operator: yyS[yypt-1].byt, Expr: yyS[yypt-0].valExpr} 1454 | } 1455 | } else { 1456 | yyVAL.valExpr = &UnaryExpr{Operator: yyS[yypt-1].byt, Expr: yyS[yypt-0].valExpr} 1457 | } 1458 | } 1459 | case 138: 1460 | //line sql.y:766 1461 | { 1462 | yyVAL.valExpr = &FuncExpr{Name: yyS[yypt-2].bytes} 1463 | } 1464 | case 139: 1465 | //line sql.y:770 1466 | { 1467 | yyVAL.valExpr = &FuncExpr{Name: yyS[yypt-3].bytes, Exprs: yyS[yypt-1].selectExprs} 1468 | } 1469 | case 140: 1470 | //line sql.y:774 1471 | { 1472 | yyVAL.valExpr = &FuncExpr{Name: yyS[yypt-4].bytes, Distinct: true, Exprs: yyS[yypt-1].selectExprs} 1473 | } 1474 | case 141: 1475 | //line sql.y:778 1476 | { 1477 | yyVAL.valExpr = &FuncExpr{Name: yyS[yypt-3].bytes, Exprs: yyS[yypt-1].selectExprs} 1478 | } 1479 | case 142: 1480 | //line sql.y:782 1481 | { 1482 | yyVAL.valExpr = yyS[yypt-0].caseExpr 1483 | } 1484 | case 143: 1485 | //line sql.y:788 1486 | { 1487 | yyVAL.bytes = IF_BYTES 1488 | } 1489 | case 144: 1490 | //line sql.y:792 1491 | { 1492 | yyVAL.bytes = VALUES_BYTES 1493 | } 1494 | case 145: 1495 | //line sql.y:798 1496 | { 1497 | yyVAL.byt = AST_UPLUS 1498 | } 1499 | case 146: 1500 | //line sql.y:802 1501 | { 1502 | yyVAL.byt = AST_UMINUS 1503 | } 1504 | case 147: 1505 | //line sql.y:806 1506 | { 1507 | yyVAL.byt = AST_TILDA 1508 | } 1509 | case 148: 1510 | //line sql.y:812 1511 | { 1512 | yyVAL.caseExpr = &CaseExpr{Expr: yyS[yypt-3].valExpr, Whens: yyS[yypt-2].whens, Else: yyS[yypt-1].valExpr} 1513 | } 1514 | case 149: 1515 | //line sql.y:817 1516 | { 1517 | yyVAL.valExpr = nil 1518 | } 1519 | case 150: 1520 | //line sql.y:821 1521 | { 1522 | yyVAL.valExpr = yyS[yypt-0].valExpr 1523 | } 1524 | case 151: 1525 | //line sql.y:827 1526 | { 1527 | yyVAL.whens = []*When{yyS[yypt-0].when} 1528 | } 1529 | case 152: 1530 | //line sql.y:831 1531 | { 1532 | yyVAL.whens = append(yyS[yypt-1].whens, yyS[yypt-0].when) 1533 | } 1534 | case 153: 1535 | //line sql.y:837 1536 | { 1537 | yyVAL.when = &When{Cond: yyS[yypt-2].boolExpr, Val: yyS[yypt-0].valExpr} 1538 | } 1539 | case 154: 1540 | //line sql.y:842 1541 | { 1542 | yyVAL.valExpr = nil 1543 | } 1544 | case 155: 1545 | //line sql.y:846 1546 | { 1547 | yyVAL.valExpr = yyS[yypt-0].valExpr 1548 | } 1549 | case 156: 1550 | //line sql.y:852 1551 | { 1552 | yyVAL.colName = &ColName{Name: yyS[yypt-0].bytes} 1553 | } 1554 | case 157: 1555 | //line sql.y:856 1556 | { 1557 | yyVAL.colName = &ColName{Qualifier: yyS[yypt-2].bytes, Name: yyS[yypt-0].bytes} 1558 | } 1559 | case 158: 1560 | //line sql.y:862 1561 | { 1562 | yyVAL.valExpr = StrVal(yyS[yypt-0].bytes) 1563 | } 1564 | case 159: 1565 | //line sql.y:866 1566 | { 1567 | yyVAL.valExpr = NumVal(yyS[yypt-0].bytes) 1568 | } 1569 | case 160: 1570 | //line sql.y:870 1571 | { 1572 | yyVAL.valExpr = ValArg(yyS[yypt-0].bytes) 1573 | } 1574 | case 161: 1575 | //line sql.y:874 1576 | { 1577 | yyVAL.valExpr = &NullVal{} 1578 | } 1579 | case 162: 1580 | //line sql.y:879 1581 | { 1582 | yyVAL.valExprs = nil 1583 | } 1584 | case 163: 1585 | //line sql.y:883 1586 | { 1587 | yyVAL.valExprs = yyS[yypt-0].valExprs 1588 | } 1589 | case 164: 1590 | //line sql.y:888 1591 | { 1592 | yyVAL.boolExpr = nil 1593 | } 1594 | case 165: 1595 | //line sql.y:892 1596 | { 1597 | yyVAL.boolExpr = yyS[yypt-0].boolExpr 1598 | } 1599 | case 166: 1600 | //line sql.y:897 1601 | { 1602 | yyVAL.orderBy = nil 1603 | } 1604 | case 167: 1605 | //line sql.y:901 1606 | { 1607 | yyVAL.orderBy = yyS[yypt-0].orderBy 1608 | } 1609 | case 168: 1610 | //line sql.y:907 1611 | { 1612 | yyVAL.orderBy = OrderBy{yyS[yypt-0].order} 1613 | } 1614 | case 169: 1615 | //line sql.y:911 1616 | { 1617 | yyVAL.orderBy = append(yyS[yypt-2].orderBy, yyS[yypt-0].order) 1618 | } 1619 | case 170: 1620 | //line sql.y:917 1621 | { 1622 | yyVAL.order = &Order{Expr: yyS[yypt-1].valExpr, Direction: yyS[yypt-0].str} 1623 | } 1624 | case 171: 1625 | //line sql.y:922 1626 | { 1627 | yyVAL.str = AST_ASC 1628 | } 1629 | case 172: 1630 | //line sql.y:926 1631 | { 1632 | yyVAL.str = AST_ASC 1633 | } 1634 | case 173: 1635 | //line sql.y:930 1636 | { 1637 | yyVAL.str = AST_DESC 1638 | } 1639 | case 174: 1640 | //line sql.y:935 1641 | { 1642 | yyVAL.limit = nil 1643 | } 1644 | case 175: 1645 | //line sql.y:939 1646 | { 1647 | yyVAL.limit = &Limit{Rowcount: yyS[yypt-0].valExpr} 1648 | } 1649 | case 176: 1650 | //line sql.y:943 1651 | { 1652 | yyVAL.limit = &Limit{Offset: yyS[yypt-2].valExpr, Rowcount: yyS[yypt-0].valExpr} 1653 | } 1654 | case 177: 1655 | //line sql.y:948 1656 | { 1657 | yyVAL.str = "" 1658 | } 1659 | case 178: 1660 | //line sql.y:952 1661 | { 1662 | yyVAL.str = AST_FOR_UPDATE 1663 | } 1664 | case 179: 1665 | //line sql.y:956 1666 | { 1667 | if !bytes.Equal(yyS[yypt-1].bytes, SHARE) { 1668 | yylex.Error("expecting share") 1669 | return 1 1670 | } 1671 | if !bytes.Equal(yyS[yypt-0].bytes, MODE) { 1672 | yylex.Error("expecting mode") 1673 | return 1 1674 | } 1675 | yyVAL.str = AST_SHARE_MODE 1676 | } 1677 | case 180: 1678 | //line sql.y:969 1679 | { 1680 | yyVAL.columns = nil 1681 | } 1682 | case 181: 1683 | //line sql.y:973 1684 | { 1685 | yyVAL.columns = yyS[yypt-1].columns 1686 | } 1687 | case 182: 1688 | //line sql.y:979 1689 | { 1690 | yyVAL.columns = Columns{&NonStarExpr{Expr: yyS[yypt-0].colName}} 1691 | } 1692 | case 183: 1693 | //line sql.y:983 1694 | { 1695 | yyVAL.columns = append(yyVAL.columns, &NonStarExpr{Expr: yyS[yypt-0].colName}) 1696 | } 1697 | case 184: 1698 | //line sql.y:988 1699 | { 1700 | yyVAL.updateExprs = nil 1701 | } 1702 | case 185: 1703 | //line sql.y:992 1704 | { 1705 | yyVAL.updateExprs = yyS[yypt-0].updateExprs 1706 | } 1707 | case 186: 1708 | //line sql.y:998 1709 | { 1710 | yyVAL.insRows = yyS[yypt-0].values 1711 | } 1712 | case 187: 1713 | //line sql.y:1002 1714 | { 1715 | yyVAL.insRows = yyS[yypt-0].selStmt 1716 | } 1717 | case 188: 1718 | //line sql.y:1008 1719 | { 1720 | yyVAL.values = Values{yyS[yypt-0].rowTuple} 1721 | } 1722 | case 189: 1723 | //line sql.y:1012 1724 | { 1725 | yyVAL.values = append(yyS[yypt-2].values, yyS[yypt-0].rowTuple) 1726 | } 1727 | case 190: 1728 | //line sql.y:1018 1729 | { 1730 | yyVAL.rowTuple = ValTuple(yyS[yypt-1].valExprs) 1731 | } 1732 | case 191: 1733 | //line sql.y:1022 1734 | { 1735 | yyVAL.rowTuple = yyS[yypt-0].subquery 1736 | } 1737 | case 192: 1738 | //line sql.y:1028 1739 | { 1740 | yyVAL.updateExprs = UpdateExprs{yyS[yypt-0].updateExpr} 1741 | } 1742 | case 193: 1743 | //line sql.y:1032 1744 | { 1745 | yyVAL.updateExprs = append(yyS[yypt-2].updateExprs, yyS[yypt-0].updateExpr) 1746 | } 1747 | case 194: 1748 | //line sql.y:1038 1749 | { 1750 | yyVAL.updateExpr = &UpdateExpr{Name: yyS[yypt-2].colName, Expr: yyS[yypt-0].valExpr} 1751 | } 1752 | case 195: 1753 | //line sql.y:1043 1754 | { 1755 | yyVAL.empty = struct{}{} 1756 | } 1757 | case 196: 1758 | //line sql.y:1045 1759 | { 1760 | yyVAL.empty = struct{}{} 1761 | } 1762 | case 197: 1763 | //line sql.y:1048 1764 | { 1765 | yyVAL.empty = struct{}{} 1766 | } 1767 | case 198: 1768 | //line sql.y:1050 1769 | { 1770 | yyVAL.empty = struct{}{} 1771 | } 1772 | case 199: 1773 | //line sql.y:1053 1774 | { 1775 | yyVAL.empty = struct{}{} 1776 | } 1777 | case 200: 1778 | //line sql.y:1055 1779 | { 1780 | yyVAL.empty = struct{}{} 1781 | } 1782 | case 201: 1783 | //line sql.y:1059 1784 | { 1785 | yyVAL.empty = struct{}{} 1786 | } 1787 | case 202: 1788 | //line sql.y:1061 1789 | { 1790 | yyVAL.empty = struct{}{} 1791 | } 1792 | case 203: 1793 | //line sql.y:1063 1794 | { 1795 | yyVAL.empty = struct{}{} 1796 | } 1797 | case 204: 1798 | //line sql.y:1065 1799 | { 1800 | yyVAL.empty = struct{}{} 1801 | } 1802 | case 205: 1803 | //line sql.y:1067 1804 | { 1805 | yyVAL.empty = struct{}{} 1806 | } 1807 | case 206: 1808 | //line sql.y:1070 1809 | { 1810 | yyVAL.empty = struct{}{} 1811 | } 1812 | case 207: 1813 | //line sql.y:1072 1814 | { 1815 | yyVAL.empty = struct{}{} 1816 | } 1817 | case 208: 1818 | //line sql.y:1075 1819 | { 1820 | yyVAL.empty = struct{}{} 1821 | } 1822 | case 209: 1823 | //line sql.y:1077 1824 | { 1825 | yyVAL.empty = struct{}{} 1826 | } 1827 | case 210: 1828 | //line sql.y:1080 1829 | { 1830 | yyVAL.empty = struct{}{} 1831 | } 1832 | case 211: 1833 | //line sql.y:1082 1834 | { 1835 | yyVAL.empty = struct{}{} 1836 | } 1837 | case 212: 1838 | //line sql.y:1086 1839 | { 1840 | yyVAL.bytes = bytes.ToLower(yyS[yypt-0].bytes) 1841 | } 1842 | case 213: 1843 | //line sql.y:1091 1844 | { 1845 | ForceEOF(yylex) 1846 | } 1847 | } 1848 | goto yystack /* stack new state and value */ 1849 | } 1850 | -------------------------------------------------------------------------------- /go/sqlparser/sql.y: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | %{ 6 | package sqlparser 7 | 8 | import "bytes" 9 | 10 | func SetParseTree(yylex interface{}, stmt Statement) { 11 | yylex.(*Tokenizer).ParseTree = stmt 12 | } 13 | 14 | func SetAllowComments(yylex interface{}, allow bool) { 15 | yylex.(*Tokenizer).AllowComments = allow 16 | } 17 | 18 | func ForceEOF(yylex interface{}) { 19 | yylex.(*Tokenizer).ForceEOF = true 20 | } 21 | 22 | var ( 23 | SHARE = []byte("share") 24 | MODE = []byte("mode") 25 | IF_BYTES = []byte("if") 26 | VALUES_BYTES = []byte("values") 27 | ) 28 | 29 | %} 30 | 31 | %union { 32 | empty struct{} 33 | statement Statement 34 | selStmt SelectStatement 35 | byt byte 36 | bytes []byte 37 | bytes2 [][]byte 38 | str string 39 | selectExprs SelectExprs 40 | selectExpr SelectExpr 41 | columns Columns 42 | colName *ColName 43 | tableExprs TableExprs 44 | tableExpr TableExpr 45 | smTableExpr SimpleTableExpr 46 | tableName *TableName 47 | indexHints *IndexHints 48 | expr Expr 49 | boolExpr BoolExpr 50 | valExpr ValExpr 51 | colTuple ColTuple 52 | valExprs ValExprs 53 | values Values 54 | rowTuple RowTuple 55 | subquery *Subquery 56 | caseExpr *CaseExpr 57 | whens []*When 58 | when *When 59 | orderBy OrderBy 60 | order *Order 61 | limit *Limit 62 | insRows InsertRows 63 | updateExprs UpdateExprs 64 | updateExpr *UpdateExpr 65 | } 66 | 67 | %token LEX_ERROR 68 | %token SELECT INSERT UPDATE DELETE FROM WHERE GROUP HAVING ORDER BY LIMIT FOR 69 | %token ALL DISTINCT AS EXISTS IN IS LIKE BETWEEN NULL ASC DESC VALUES INTO DUPLICATE KEY DEFAULT SET LOCK KEYRANGE 70 | %token ID STRING NUMBER VALUE_ARG LIST_ARG COMMENT 71 | %token LE GE NE NULL_SAFE_EQUAL 72 | %token '(' '=' '<' '>' '~' 73 | 74 | %left UNION MINUS EXCEPT INTERSECT 75 | %left ',' 76 | %left JOIN STRAIGHT_JOIN LEFT RIGHT INNER OUTER CROSS NATURAL USE FORCE 77 | %left ON 78 | %left OR 79 | %left AND 80 | %right NOT 81 | %left '&' '|' '^' 82 | %left '+' '-' 83 | %left '*' '/' '%' 84 | %nonassoc '.' 85 | %left UNARY 86 | %right CASE, WHEN, THEN, ELSE 87 | %left END 88 | 89 | // DDL Tokens 90 | %token CREATE ALTER DROP RENAME ANALYZE 91 | %token TABLE INDEX VIEW TO IGNORE IF UNIQUE USING 92 | %token SHOW DESCRIBE EXPLAIN 93 | 94 | // Transaction Tokens 95 | %token BEGIN COMMIT ROLLBACK 96 | 97 | // Charset Tokens 98 | %token NAMES 99 | 100 | // Replace 101 | %token REPLACE 102 | 103 | %start any_command 104 | 105 | %type command 106 | %type select_statement 107 | %type insert_statement update_statement delete_statement set_statement 108 | %type create_statement alter_statement rename_statement drop_statement 109 | %type analyze_statement other_statement 110 | %type comment_opt comment_list 111 | %type union_op 112 | %type distinct_opt 113 | %type select_expression_list 114 | %type select_expression 115 | %type as_lower_opt as_opt 116 | %type expression 117 | %type table_expression_list 118 | %type table_expression 119 | %type join_type 120 | %type simple_table_expression 121 | %type dml_table_expression 122 | %type index_hint_list 123 | %type index_list 124 | %type where_expression_opt 125 | %type boolean_expression condition 126 | %type compare 127 | %type row_list 128 | %type value value_expression 129 | %type col_tuple 130 | %type value_expression_list 131 | %type tuple_list 132 | %type row_tuple 133 | %type keyword_as_func 134 | %type subquery 135 | %type unary_operator 136 | %type column_name 137 | %type case_expression 138 | %type when_expression_list 139 | %type when_expression 140 | %type value_expression_opt else_expression_opt 141 | %type group_by_opt 142 | %type having_opt 143 | %type order_by_opt order_list 144 | %type order 145 | %type asc_desc_opt 146 | %type limit_opt 147 | %type lock_opt 148 | %type column_list_opt column_list 149 | %type on_dup_opt 150 | %type update_list 151 | %type update_expression 152 | %type exists_opt not_exists_opt ignore_opt non_rename_operation to_opt constraint_opt using_opt 153 | %type sql_id 154 | %type force_eof 155 | 156 | %type begin_statement commit_statement rollback_statement 157 | %type replace_statement 158 | 159 | %% 160 | 161 | any_command: 162 | command 163 | { 164 | SetParseTree(yylex, $1) 165 | } 166 | 167 | command: 168 | select_statement 169 | { 170 | $$ = $1 171 | } 172 | | insert_statement 173 | | update_statement 174 | | delete_statement 175 | | set_statement 176 | | create_statement 177 | | alter_statement 178 | | rename_statement 179 | | drop_statement 180 | | analyze_statement 181 | | other_statement 182 | | replace_statement 183 | | begin_statement 184 | | commit_statement 185 | | rollback_statement 186 | 187 | select_statement: 188 | SELECT comment_opt distinct_opt select_expression_list 189 | { 190 | $$ = &SimpleSelect{Comments: Comments($2), Distinct: $3, SelectExprs: $4} 191 | } 192 | | SELECT comment_opt distinct_opt select_expression_list FROM table_expression_list where_expression_opt group_by_opt having_opt order_by_opt limit_opt lock_opt 193 | { 194 | $$ = &Select{Comments: Comments($2), Distinct: $3, SelectExprs: $4, From: $6, Where: NewWhere(AST_WHERE, $7), GroupBy: GroupBy($8), Having: NewWhere(AST_HAVING, $9), OrderBy: $10, Limit: $11, Lock: $12} 195 | } 196 | | select_statement union_op select_statement %prec UNION 197 | { 198 | $$ = &Union{Type: $2, Left: $1, Right: $3} 199 | } 200 | 201 | insert_statement: 202 | INSERT comment_opt INTO dml_table_expression column_list_opt row_list on_dup_opt 203 | { 204 | $$ = &Insert{Comments: Comments($2), Table: $4, Columns: $5, Rows: $6, OnDup: OnDup($7)} 205 | } 206 | | INSERT comment_opt INTO dml_table_expression SET update_list on_dup_opt 207 | { 208 | cols := make(Columns, 0, len($6)) 209 | vals := make(ValTuple, 0, len($6)) 210 | for _, col := range $6 { 211 | cols = append(cols, &NonStarExpr{Expr: col.Name}) 212 | vals = append(vals, col.Expr) 213 | } 214 | $$ = &Insert{Comments: Comments($2), Table: $4, Columns: cols, Rows: Values{vals}, OnDup: OnDup($7)} 215 | } 216 | 217 | replace_statement: 218 | REPLACE comment_opt INTO dml_table_expression column_list_opt row_list 219 | { 220 | $$ = &Replace{Comments: Comments($2), Table: $4, Columns: $5, Rows: $6} 221 | } 222 | | REPLACE comment_opt INTO dml_table_expression SET update_list 223 | { 224 | cols := make(Columns, 0, len($6)) 225 | vals := make(ValTuple, 0, len($6)) 226 | for _, col := range $6 { 227 | cols = append(cols, &NonStarExpr{Expr: col.Name}) 228 | vals = append(vals, col.Expr) 229 | } 230 | $$ = &Replace{Comments: Comments($2), Table: $4, Columns: cols, Rows: Values{vals}} 231 | } 232 | 233 | update_statement: 234 | UPDATE comment_opt dml_table_expression SET update_list where_expression_opt order_by_opt limit_opt 235 | { 236 | $$ = &Update{Comments: Comments($2), Table: $3, Exprs: $5, Where: NewWhere(AST_WHERE, $6), OrderBy: $7, Limit: $8} 237 | } 238 | 239 | delete_statement: 240 | DELETE comment_opt FROM dml_table_expression where_expression_opt order_by_opt limit_opt 241 | { 242 | $$ = &Delete{Comments: Comments($2), Table: $4, Where: NewWhere(AST_WHERE, $5), OrderBy: $6, Limit: $7} 243 | } 244 | 245 | set_statement: 246 | SET comment_opt update_list 247 | { 248 | $$ = &Set{Comments: Comments($2), Exprs: $3} 249 | } 250 | | SET comment_opt NAMES ID 251 | { 252 | $$ = &Set{Comments: Comments($2), Exprs: UpdateExprs{&UpdateExpr{Name: &ColName{Name:[]byte("names")}, Expr: StrVal($4)}}} 253 | } 254 | 255 | begin_statement: 256 | BEGIN 257 | { 258 | $$ = &Begin{} 259 | } 260 | 261 | commit_statement: 262 | COMMIT 263 | { 264 | $$ = &Commit{} 265 | } 266 | 267 | rollback_statement: 268 | ROLLBACK 269 | { 270 | $$ = &Rollback{} 271 | } 272 | 273 | create_statement: 274 | CREATE TABLE not_exists_opt ID force_eof 275 | { 276 | $$ = &DDL{Action: AST_CREATE, NewName: $4} 277 | } 278 | | CREATE constraint_opt INDEX sql_id using_opt ON ID force_eof 279 | { 280 | // Change this to an alter statement 281 | $$ = &DDL{Action: AST_ALTER, Table: $7, NewName: $7} 282 | } 283 | | CREATE VIEW sql_id force_eof 284 | { 285 | $$ = &DDL{Action: AST_CREATE, NewName: $3} 286 | } 287 | 288 | alter_statement: 289 | ALTER ignore_opt TABLE ID non_rename_operation force_eof 290 | { 291 | $$ = &DDL{Action: AST_ALTER, Table: $4, NewName: $4} 292 | } 293 | | ALTER ignore_opt TABLE ID RENAME to_opt ID 294 | { 295 | // Change this to a rename statement 296 | $$ = &DDL{Action: AST_RENAME, Table: $4, NewName: $7} 297 | } 298 | | ALTER VIEW sql_id force_eof 299 | { 300 | $$ = &DDL{Action: AST_ALTER, Table: $3, NewName: $3} 301 | } 302 | 303 | rename_statement: 304 | RENAME TABLE ID TO ID 305 | { 306 | $$ = &DDL{Action: AST_RENAME, Table: $3, NewName: $5} 307 | } 308 | 309 | drop_statement: 310 | DROP TABLE exists_opt ID 311 | { 312 | $$ = &DDL{Action: AST_DROP, Table: $4} 313 | } 314 | | DROP INDEX sql_id ON ID 315 | { 316 | // Change this to an alter statement 317 | $$ = &DDL{Action: AST_ALTER, Table: $5, NewName: $5} 318 | } 319 | | DROP VIEW exists_opt sql_id force_eof 320 | { 321 | $$ = &DDL{Action: AST_DROP, Table: $4} 322 | } 323 | 324 | analyze_statement: 325 | ANALYZE TABLE ID 326 | { 327 | $$ = &DDL{Action: AST_ALTER, Table: $3, NewName: $3} 328 | } 329 | 330 | other_statement: 331 | SHOW force_eof 332 | { 333 | $$ = &Other{} 334 | } 335 | | DESCRIBE force_eof 336 | { 337 | $$ = &Other{} 338 | } 339 | | EXPLAIN force_eof 340 | { 341 | $$ = &Other{} 342 | } 343 | 344 | comment_opt: 345 | { 346 | SetAllowComments(yylex, true) 347 | } 348 | comment_list 349 | { 350 | $$ = $2 351 | SetAllowComments(yylex, false) 352 | } 353 | 354 | comment_list: 355 | { 356 | $$ = nil 357 | } 358 | | comment_list COMMENT 359 | { 360 | $$ = append($1, $2) 361 | } 362 | 363 | union_op: 364 | UNION 365 | { 366 | $$ = AST_UNION 367 | } 368 | | UNION ALL 369 | { 370 | $$ = AST_UNION_ALL 371 | } 372 | | MINUS 373 | { 374 | $$ = AST_SET_MINUS 375 | } 376 | | EXCEPT 377 | { 378 | $$ = AST_EXCEPT 379 | } 380 | | INTERSECT 381 | { 382 | $$ = AST_INTERSECT 383 | } 384 | 385 | distinct_opt: 386 | { 387 | $$ = "" 388 | } 389 | | DISTINCT 390 | { 391 | $$ = AST_DISTINCT 392 | } 393 | 394 | select_expression_list: 395 | select_expression 396 | { 397 | $$ = SelectExprs{$1} 398 | } 399 | | select_expression_list ',' select_expression 400 | { 401 | $$ = append($$, $3) 402 | } 403 | 404 | select_expression: 405 | '*' 406 | { 407 | $$ = &StarExpr{} 408 | } 409 | | expression as_lower_opt 410 | { 411 | $$ = &NonStarExpr{Expr: $1, As: $2} 412 | } 413 | | ID '.' '*' 414 | { 415 | $$ = &StarExpr{TableName: $1} 416 | } 417 | 418 | expression: 419 | boolean_expression 420 | { 421 | $$ = $1 422 | } 423 | | value_expression 424 | { 425 | $$ = $1 426 | } 427 | 428 | as_lower_opt: 429 | { 430 | $$ = nil 431 | } 432 | | sql_id 433 | { 434 | $$ = $1 435 | } 436 | | AS sql_id 437 | { 438 | $$ = $2 439 | } 440 | 441 | table_expression_list: 442 | table_expression 443 | { 444 | $$ = TableExprs{$1} 445 | } 446 | | table_expression_list ',' table_expression 447 | { 448 | $$ = append($$, $3) 449 | } 450 | 451 | table_expression: 452 | simple_table_expression as_opt index_hint_list 453 | { 454 | $$ = &AliasedTableExpr{Expr:$1, As: $2, Hints: $3} 455 | } 456 | | '(' table_expression ')' 457 | { 458 | $$ = &ParenTableExpr{Expr: $2} 459 | } 460 | | table_expression join_type table_expression %prec JOIN 461 | { 462 | $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3} 463 | } 464 | | table_expression join_type table_expression ON boolean_expression %prec JOIN 465 | { 466 | $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3, On: $5} 467 | } 468 | 469 | as_opt: 470 | { 471 | $$ = nil 472 | } 473 | | ID 474 | { 475 | $$ = $1 476 | } 477 | | AS ID 478 | { 479 | $$ = $2 480 | } 481 | 482 | join_type: 483 | JOIN 484 | { 485 | $$ = AST_JOIN 486 | } 487 | | STRAIGHT_JOIN 488 | { 489 | $$ = AST_STRAIGHT_JOIN 490 | } 491 | | LEFT JOIN 492 | { 493 | $$ = AST_LEFT_JOIN 494 | } 495 | | LEFT OUTER JOIN 496 | { 497 | $$ = AST_LEFT_JOIN 498 | } 499 | | RIGHT JOIN 500 | { 501 | $$ = AST_RIGHT_JOIN 502 | } 503 | | RIGHT OUTER JOIN 504 | { 505 | $$ = AST_RIGHT_JOIN 506 | } 507 | | INNER JOIN 508 | { 509 | $$ = AST_JOIN 510 | } 511 | | CROSS JOIN 512 | { 513 | $$ = AST_CROSS_JOIN 514 | } 515 | | NATURAL JOIN 516 | { 517 | $$ = AST_NATURAL_JOIN 518 | } 519 | 520 | simple_table_expression: 521 | ID 522 | { 523 | $$ = &TableName{Name: $1} 524 | } 525 | | ID '.' ID 526 | { 527 | $$ = &TableName{Qualifier: $1, Name: $3} 528 | } 529 | | subquery 530 | { 531 | $$ = $1 532 | } 533 | 534 | dml_table_expression: 535 | ID 536 | { 537 | $$ = &TableName{Name: $1} 538 | } 539 | | ID '.' ID 540 | { 541 | $$ = &TableName{Qualifier: $1, Name: $3} 542 | } 543 | 544 | index_hint_list: 545 | { 546 | $$ = nil 547 | } 548 | | USE INDEX '(' index_list ')' 549 | { 550 | $$ = &IndexHints{Type: AST_USE, Indexes: $4} 551 | } 552 | | IGNORE INDEX '(' index_list ')' 553 | { 554 | $$ = &IndexHints{Type: AST_IGNORE, Indexes: $4} 555 | } 556 | | FORCE INDEX '(' index_list ')' 557 | { 558 | $$ = &IndexHints{Type: AST_FORCE, Indexes: $4} 559 | } 560 | 561 | index_list: 562 | sql_id 563 | { 564 | $$ = [][]byte{$1} 565 | } 566 | | index_list ',' sql_id 567 | { 568 | $$ = append($1, $3) 569 | } 570 | 571 | where_expression_opt: 572 | { 573 | $$ = nil 574 | } 575 | | WHERE boolean_expression 576 | { 577 | $$ = $2 578 | } 579 | 580 | boolean_expression: 581 | condition 582 | | boolean_expression AND boolean_expression 583 | { 584 | $$ = &AndExpr{Left: $1, Right: $3} 585 | } 586 | | boolean_expression OR boolean_expression 587 | { 588 | $$ = &OrExpr{Left: $1, Right: $3} 589 | } 590 | | NOT boolean_expression 591 | { 592 | $$ = &NotExpr{Expr: $2} 593 | } 594 | | '(' boolean_expression ')' 595 | { 596 | $$ = &ParenBoolExpr{Expr: $2} 597 | } 598 | 599 | condition: 600 | value_expression compare value_expression 601 | { 602 | $$ = &ComparisonExpr{Left: $1, Operator: $2, Right: $3} 603 | } 604 | | value_expression IN col_tuple 605 | { 606 | $$ = &ComparisonExpr{Left: $1, Operator: AST_IN, Right: $3} 607 | } 608 | | value_expression NOT IN col_tuple 609 | { 610 | $$ = &ComparisonExpr{Left: $1, Operator: AST_NOT_IN, Right: $4} 611 | } 612 | | value_expression LIKE value_expression 613 | { 614 | $$ = &ComparisonExpr{Left: $1, Operator: AST_LIKE, Right: $3} 615 | } 616 | | value_expression NOT LIKE value_expression 617 | { 618 | $$ = &ComparisonExpr{Left: $1, Operator: AST_NOT_LIKE, Right: $4} 619 | } 620 | | value_expression BETWEEN value_expression AND value_expression 621 | { 622 | $$ = &RangeCond{Left: $1, Operator: AST_BETWEEN, From: $3, To: $5} 623 | } 624 | | value_expression NOT BETWEEN value_expression AND value_expression 625 | { 626 | $$ = &RangeCond{Left: $1, Operator: AST_NOT_BETWEEN, From: $4, To: $6} 627 | } 628 | | value_expression IS NULL 629 | { 630 | $$ = &NullCheck{Operator: AST_IS_NULL, Expr: $1} 631 | } 632 | | value_expression IS NOT NULL 633 | { 634 | $$ = &NullCheck{Operator: AST_IS_NOT_NULL, Expr: $1} 635 | } 636 | | EXISTS subquery 637 | { 638 | $$ = &ExistsExpr{Subquery: $2} 639 | } 640 | | KEYRANGE '(' value ',' value ')' 641 | { 642 | $$ = &KeyrangeExpr{Start: $3, End: $5} 643 | } 644 | 645 | compare: 646 | '=' 647 | { 648 | $$ = AST_EQ 649 | } 650 | | '<' 651 | { 652 | $$ = AST_LT 653 | } 654 | | '>' 655 | { 656 | $$ = AST_GT 657 | } 658 | | LE 659 | { 660 | $$ = AST_LE 661 | } 662 | | GE 663 | { 664 | $$ = AST_GE 665 | } 666 | | NE 667 | { 668 | $$ = AST_NE 669 | } 670 | | NULL_SAFE_EQUAL 671 | { 672 | $$ = AST_NSE 673 | } 674 | 675 | col_tuple: 676 | '(' value_expression_list ')' 677 | { 678 | $$ = ValTuple($2) 679 | } 680 | | subquery 681 | { 682 | $$ = $1 683 | } 684 | | LIST_ARG 685 | { 686 | $$ = ListArg($1) 687 | } 688 | 689 | subquery: 690 | '(' select_statement ')' 691 | { 692 | $$ = &Subquery{$2} 693 | } 694 | 695 | value_expression_list: 696 | value_expression 697 | { 698 | $$ = ValExprs{$1} 699 | } 700 | | value_expression_list ',' value_expression 701 | { 702 | $$ = append($1, $3) 703 | } 704 | 705 | value_expression: 706 | value 707 | { 708 | $$ = $1 709 | } 710 | | column_name 711 | { 712 | $$ = $1 713 | } 714 | | row_tuple 715 | { 716 | $$ = $1 717 | } 718 | | value_expression '&' value_expression 719 | { 720 | $$ = &BinaryExpr{Left: $1, Operator: AST_BITAND, Right: $3} 721 | } 722 | | value_expression '|' value_expression 723 | { 724 | $$ = &BinaryExpr{Left: $1, Operator: AST_BITOR, Right: $3} 725 | } 726 | | value_expression '^' value_expression 727 | { 728 | $$ = &BinaryExpr{Left: $1, Operator: AST_BITXOR, Right: $3} 729 | } 730 | | value_expression '+' value_expression 731 | { 732 | $$ = &BinaryExpr{Left: $1, Operator: AST_PLUS, Right: $3} 733 | } 734 | | value_expression '-' value_expression 735 | { 736 | $$ = &BinaryExpr{Left: $1, Operator: AST_MINUS, Right: $3} 737 | } 738 | | value_expression '*' value_expression 739 | { 740 | $$ = &BinaryExpr{Left: $1, Operator: AST_MULT, Right: $3} 741 | } 742 | | value_expression '/' value_expression 743 | { 744 | $$ = &BinaryExpr{Left: $1, Operator: AST_DIV, Right: $3} 745 | } 746 | | value_expression '%' value_expression 747 | { 748 | $$ = &BinaryExpr{Left: $1, Operator: AST_MOD, Right: $3} 749 | } 750 | | unary_operator value_expression %prec UNARY 751 | { 752 | if num, ok := $2.(NumVal); ok { 753 | switch $1 { 754 | case '-': 755 | $$ = append(NumVal("-"), num...) 756 | case '+': 757 | $$ = num 758 | default: 759 | $$ = &UnaryExpr{Operator: $1, Expr: $2} 760 | } 761 | } else { 762 | $$ = &UnaryExpr{Operator: $1, Expr: $2} 763 | } 764 | } 765 | | sql_id '(' ')' 766 | { 767 | $$ = &FuncExpr{Name: $1} 768 | } 769 | | sql_id '(' select_expression_list ')' 770 | { 771 | $$ = &FuncExpr{Name: $1, Exprs: $3} 772 | } 773 | | sql_id '(' DISTINCT select_expression_list ')' 774 | { 775 | $$ = &FuncExpr{Name: $1, Distinct: true, Exprs: $4} 776 | } 777 | | keyword_as_func '(' select_expression_list ')' 778 | { 779 | $$ = &FuncExpr{Name: $1, Exprs: $3} 780 | } 781 | | case_expression 782 | { 783 | $$ = $1 784 | } 785 | 786 | keyword_as_func: 787 | IF 788 | { 789 | $$ = IF_BYTES 790 | } 791 | | VALUES 792 | { 793 | $$ = VALUES_BYTES 794 | } 795 | 796 | unary_operator: 797 | '+' 798 | { 799 | $$ = AST_UPLUS 800 | } 801 | | '-' 802 | { 803 | $$ = AST_UMINUS 804 | } 805 | | '~' 806 | { 807 | $$ = AST_TILDA 808 | } 809 | 810 | case_expression: 811 | CASE value_expression_opt when_expression_list else_expression_opt END 812 | { 813 | $$ = &CaseExpr{Expr: $2, Whens: $3, Else: $4} 814 | } 815 | 816 | value_expression_opt: 817 | { 818 | $$ = nil 819 | } 820 | | value_expression 821 | { 822 | $$ = $1 823 | } 824 | 825 | when_expression_list: 826 | when_expression 827 | { 828 | $$ = []*When{$1} 829 | } 830 | | when_expression_list when_expression 831 | { 832 | $$ = append($1, $2) 833 | } 834 | 835 | when_expression: 836 | WHEN boolean_expression THEN value_expression 837 | { 838 | $$ = &When{Cond: $2, Val: $4} 839 | } 840 | 841 | else_expression_opt: 842 | { 843 | $$ = nil 844 | } 845 | | ELSE value_expression 846 | { 847 | $$ = $2 848 | } 849 | 850 | column_name: 851 | sql_id 852 | { 853 | $$ = &ColName{Name: $1} 854 | } 855 | | ID '.' sql_id 856 | { 857 | $$ = &ColName{Qualifier: $1, Name: $3} 858 | } 859 | 860 | value: 861 | STRING 862 | { 863 | $$ = StrVal($1) 864 | } 865 | | NUMBER 866 | { 867 | $$ = NumVal($1) 868 | } 869 | | VALUE_ARG 870 | { 871 | $$ = ValArg($1) 872 | } 873 | | NULL 874 | { 875 | $$ = &NullVal{} 876 | } 877 | 878 | group_by_opt: 879 | { 880 | $$ = nil 881 | } 882 | | GROUP BY value_expression_list 883 | { 884 | $$ = $3 885 | } 886 | 887 | having_opt: 888 | { 889 | $$ = nil 890 | } 891 | | HAVING boolean_expression 892 | { 893 | $$ = $2 894 | } 895 | 896 | order_by_opt: 897 | { 898 | $$ = nil 899 | } 900 | | ORDER BY order_list 901 | { 902 | $$ = $3 903 | } 904 | 905 | order_list: 906 | order 907 | { 908 | $$ = OrderBy{$1} 909 | } 910 | | order_list ',' order 911 | { 912 | $$ = append($1, $3) 913 | } 914 | 915 | order: 916 | value_expression asc_desc_opt 917 | { 918 | $$ = &Order{Expr: $1, Direction: $2} 919 | } 920 | 921 | asc_desc_opt: 922 | { 923 | $$ = AST_ASC 924 | } 925 | | ASC 926 | { 927 | $$ = AST_ASC 928 | } 929 | | DESC 930 | { 931 | $$ = AST_DESC 932 | } 933 | 934 | limit_opt: 935 | { 936 | $$ = nil 937 | } 938 | | LIMIT value_expression 939 | { 940 | $$ = &Limit{Rowcount: $2} 941 | } 942 | | LIMIT value_expression ',' value_expression 943 | { 944 | $$ = &Limit{Offset: $2, Rowcount: $4} 945 | } 946 | 947 | lock_opt: 948 | { 949 | $$ = "" 950 | } 951 | | FOR UPDATE 952 | { 953 | $$ = AST_FOR_UPDATE 954 | } 955 | | LOCK IN sql_id sql_id 956 | { 957 | if !bytes.Equal($3, SHARE) { 958 | yylex.Error("expecting share") 959 | return 1 960 | } 961 | if !bytes.Equal($4, MODE) { 962 | yylex.Error("expecting mode") 963 | return 1 964 | } 965 | $$ = AST_SHARE_MODE 966 | } 967 | 968 | column_list_opt: 969 | { 970 | $$ = nil 971 | } 972 | | '(' column_list ')' 973 | { 974 | $$ = $2 975 | } 976 | 977 | column_list: 978 | column_name 979 | { 980 | $$ = Columns{&NonStarExpr{Expr: $1}} 981 | } 982 | | column_list ',' column_name 983 | { 984 | $$ = append($$, &NonStarExpr{Expr: $3}) 985 | } 986 | 987 | on_dup_opt: 988 | { 989 | $$ = nil 990 | } 991 | | ON DUPLICATE KEY UPDATE update_list 992 | { 993 | $$ = $5 994 | } 995 | 996 | row_list: 997 | VALUES tuple_list 998 | { 999 | $$ = $2 1000 | } 1001 | | select_statement 1002 | { 1003 | $$ = $1 1004 | } 1005 | 1006 | tuple_list: 1007 | row_tuple 1008 | { 1009 | $$ = Values{$1} 1010 | } 1011 | | tuple_list ',' row_tuple 1012 | { 1013 | $$ = append($1, $3) 1014 | } 1015 | 1016 | row_tuple: 1017 | '(' value_expression_list ')' 1018 | { 1019 | $$ = ValTuple($2) 1020 | } 1021 | | subquery 1022 | { 1023 | $$ = $1 1024 | } 1025 | 1026 | update_list: 1027 | update_expression 1028 | { 1029 | $$ = UpdateExprs{$1} 1030 | } 1031 | | update_list ',' update_expression 1032 | { 1033 | $$ = append($1, $3) 1034 | } 1035 | 1036 | update_expression: 1037 | column_name '=' value_expression 1038 | { 1039 | $$ = &UpdateExpr{Name: $1, Expr: $3} 1040 | } 1041 | 1042 | exists_opt: 1043 | { $$ = struct{}{} } 1044 | | IF EXISTS 1045 | { $$ = struct{}{} } 1046 | 1047 | not_exists_opt: 1048 | { $$ = struct{}{} } 1049 | | IF NOT EXISTS 1050 | { $$ = struct{}{} } 1051 | 1052 | ignore_opt: 1053 | { $$ = struct{}{} } 1054 | | IGNORE 1055 | { $$ = struct{}{} } 1056 | 1057 | non_rename_operation: 1058 | ALTER 1059 | { $$ = struct{}{} } 1060 | | DEFAULT 1061 | { $$ = struct{}{} } 1062 | | DROP 1063 | { $$ = struct{}{} } 1064 | | ORDER 1065 | { $$ = struct{}{} } 1066 | | ID 1067 | { $$ = struct{}{} } 1068 | 1069 | to_opt: 1070 | { $$ = struct{}{} } 1071 | | TO 1072 | { $$ = struct{}{} } 1073 | 1074 | constraint_opt: 1075 | { $$ = struct{}{} } 1076 | | UNIQUE 1077 | { $$ = struct{}{} } 1078 | 1079 | using_opt: 1080 | { $$ = struct{}{} } 1081 | | USING sql_id 1082 | { $$ = struct{}{} } 1083 | 1084 | sql_id: 1085 | ID 1086 | { 1087 | $$ = bytes.ToLower($1) 1088 | } 1089 | 1090 | force_eof: 1091 | { 1092 | ForceEOF(yylex) 1093 | } 1094 | -------------------------------------------------------------------------------- /go/sqlparser/sql_test.go: -------------------------------------------------------------------------------- 1 | package sqlparser 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func testParse(t *testing.T, sql string) { 8 | _, err := Parse(sql) 9 | if err != nil { 10 | t.Fatal(err) 11 | } 12 | 13 | } 14 | 15 | func TestSet(t *testing.T) { 16 | sql := "set names gbk" 17 | testParse(t, sql) 18 | } 19 | 20 | func TestSimpleSelect(t *testing.T) { 21 | sql := "select last_insert_id() as a" 22 | testParse(t, sql) 23 | } 24 | -------------------------------------------------------------------------------- /go/sqlparser/token.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlparser 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "strings" 11 | 12 | "github.com/go-cloud/myshard/go/sqltypes" 13 | ) 14 | 15 | const EOFCHAR = 0x100 16 | 17 | // Tokenizer is the struct used to generate SQL 18 | // tokens for the parser. 19 | type Tokenizer struct { 20 | InStream *strings.Reader 21 | AllowComments bool 22 | ForceEOF bool 23 | lastChar uint16 24 | Position int 25 | errorToken []byte 26 | LastError string 27 | posVarIndex int 28 | ParseTree Statement 29 | } 30 | 31 | // NewStringTokenizer creates a new Tokenizer for the 32 | // sql string. 33 | func NewStringTokenizer(sql string) *Tokenizer { 34 | return &Tokenizer{InStream: strings.NewReader(sql)} 35 | } 36 | 37 | var keywords = map[string]int{ 38 | "all": ALL, 39 | "alter": ALTER, 40 | "analyze": ANALYZE, 41 | "and": AND, 42 | "as": AS, 43 | "asc": ASC, 44 | "between": BETWEEN, 45 | "by": BY, 46 | "case": CASE, 47 | "create": CREATE, 48 | "cross": CROSS, 49 | "default": DEFAULT, 50 | "delete": DELETE, 51 | "desc": DESC, 52 | "describe": DESCRIBE, 53 | "distinct": DISTINCT, 54 | "drop": DROP, 55 | "duplicate": DUPLICATE, 56 | "else": ELSE, 57 | "end": END, 58 | "except": EXCEPT, 59 | "exists": EXISTS, 60 | "explain": EXPLAIN, 61 | "for": FOR, 62 | "force": FORCE, 63 | "from": FROM, 64 | "group": GROUP, 65 | "having": HAVING, 66 | "if": IF, 67 | "ignore": IGNORE, 68 | "in": IN, 69 | "index": INDEX, 70 | "inner": INNER, 71 | "insert": INSERT, 72 | "intersect": INTERSECT, 73 | "into": INTO, 74 | "is": IS, 75 | "join": JOIN, 76 | "key": KEY, 77 | "keyrange": KEYRANGE, 78 | "left": LEFT, 79 | "like": LIKE, 80 | "limit": LIMIT, 81 | "lock": LOCK, 82 | "minus": MINUS, 83 | "natural": NATURAL, 84 | "not": NOT, 85 | "null": NULL, 86 | "on": ON, 87 | "or": OR, 88 | "order": ORDER, 89 | "outer": OUTER, 90 | "rename": RENAME, 91 | "right": RIGHT, 92 | "select": SELECT, 93 | "set": SET, 94 | "show": SHOW, 95 | "straight_join": STRAIGHT_JOIN, 96 | "table": TABLE, 97 | "then": THEN, 98 | "to": TO, 99 | "union": UNION, 100 | "unique": UNIQUE, 101 | "update": UPDATE, 102 | "use": USE, 103 | "using": USING, 104 | "values": VALUES, 105 | "view": VIEW, 106 | "when": WHEN, 107 | "where": WHERE, 108 | 109 | //for myshard token 110 | "begin": BEGIN, 111 | "rollback": ROLLBACK, 112 | "commit": COMMIT, 113 | 114 | "names": NAMES, 115 | "replace": REPLACE, 116 | } 117 | 118 | // Lex returns the next token form the Tokenizer. 119 | // This function is used by go yacc. 120 | func (tkn *Tokenizer) Lex(lval *yySymType) int { 121 | typ, val := tkn.Scan() 122 | for typ == COMMENT { 123 | if tkn.AllowComments { 124 | break 125 | } 126 | typ, val = tkn.Scan() 127 | } 128 | switch typ { 129 | case ID, STRING, NUMBER, VALUE_ARG, LIST_ARG, COMMENT: 130 | lval.bytes = val 131 | } 132 | tkn.errorToken = val 133 | return typ 134 | } 135 | 136 | // Error is called by go yacc if there's a parsing error. 137 | func (tkn *Tokenizer) Error(err string) { 138 | buf := bytes.NewBuffer(make([]byte, 0, 32)) 139 | if tkn.errorToken != nil { 140 | fmt.Fprintf(buf, "%s at position %v near %s", err, tkn.Position, tkn.errorToken) 141 | } else { 142 | fmt.Fprintf(buf, "%s at position %v", err, tkn.Position) 143 | } 144 | tkn.LastError = buf.String() 145 | } 146 | 147 | // Scan scans the tokenizer for the next token and returns 148 | // the token type and an optional value. 149 | func (tkn *Tokenizer) Scan() (int, []byte) { 150 | if tkn.ForceEOF { 151 | return 0, nil 152 | } 153 | 154 | if tkn.lastChar == 0 { 155 | tkn.next() 156 | } 157 | tkn.skipBlank() 158 | switch ch := tkn.lastChar; { 159 | case isLetter(ch): 160 | return tkn.scanIdentifier() 161 | case isDigit(ch): 162 | return tkn.scanNumber(false) 163 | case ch == ':': 164 | return tkn.scanBindVar() 165 | default: 166 | tkn.next() 167 | switch ch { 168 | case EOFCHAR: 169 | return 0, nil 170 | case '=', ',', ';', '(', ')', '+', '*', '%', '&', '|', '^', '~': 171 | return int(ch), nil 172 | case '?': 173 | tkn.posVarIndex++ 174 | buf := new(bytes.Buffer) 175 | fmt.Fprintf(buf, ":v%d", tkn.posVarIndex) 176 | return VALUE_ARG, buf.Bytes() 177 | case '.': 178 | if isDigit(tkn.lastChar) { 179 | return tkn.scanNumber(true) 180 | } else { 181 | return int(ch), nil 182 | } 183 | case '/': 184 | switch tkn.lastChar { 185 | case '/': 186 | tkn.next() 187 | return tkn.scanCommentType1("//") 188 | case '*': 189 | tkn.next() 190 | return tkn.scanCommentType2() 191 | default: 192 | return int(ch), nil 193 | } 194 | case '-': 195 | if tkn.lastChar == '-' { 196 | tkn.next() 197 | return tkn.scanCommentType1("--") 198 | } else { 199 | return int(ch), nil 200 | } 201 | case '<': 202 | switch tkn.lastChar { 203 | case '>': 204 | tkn.next() 205 | return NE, nil 206 | case '=': 207 | tkn.next() 208 | switch tkn.lastChar { 209 | case '>': 210 | tkn.next() 211 | return NULL_SAFE_EQUAL, nil 212 | default: 213 | return LE, nil 214 | } 215 | default: 216 | return int(ch), nil 217 | } 218 | case '>': 219 | if tkn.lastChar == '=' { 220 | tkn.next() 221 | return GE, nil 222 | } else { 223 | return int(ch), nil 224 | } 225 | case '!': 226 | if tkn.lastChar == '=' { 227 | tkn.next() 228 | return NE, nil 229 | } else { 230 | return LEX_ERROR, []byte("!") 231 | } 232 | case '\'', '"': 233 | return tkn.scanString(ch, STRING) 234 | case '`': 235 | return tkn.scanLiteralIdentifier() 236 | default: 237 | return LEX_ERROR, []byte{byte(ch)} 238 | } 239 | } 240 | } 241 | 242 | func (tkn *Tokenizer) skipBlank() { 243 | ch := tkn.lastChar 244 | for ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' { 245 | tkn.next() 246 | ch = tkn.lastChar 247 | } 248 | } 249 | 250 | func (tkn *Tokenizer) scanIdentifier() (int, []byte) { 251 | buffer := bytes.NewBuffer(make([]byte, 0, 8)) 252 | buffer.WriteByte(byte(tkn.lastChar)) 253 | for tkn.next(); isLetter(tkn.lastChar) || isDigit(tkn.lastChar); tkn.next() { 254 | buffer.WriteByte(byte(tkn.lastChar)) 255 | } 256 | lowered := bytes.ToLower(buffer.Bytes()) 257 | if keywordId, found := keywords[string(lowered)]; found { 258 | return keywordId, lowered 259 | } 260 | return ID, buffer.Bytes() 261 | } 262 | 263 | func (tkn *Tokenizer) scanLiteralIdentifier() (int, []byte) { 264 | buffer := bytes.NewBuffer(make([]byte, 0, 8)) 265 | buffer.WriteByte(byte(tkn.lastChar)) 266 | if !isLetter(tkn.lastChar) { 267 | return LEX_ERROR, buffer.Bytes() 268 | } 269 | for tkn.next(); isLetter(tkn.lastChar) || isDigit(tkn.lastChar); tkn.next() { 270 | buffer.WriteByte(byte(tkn.lastChar)) 271 | } 272 | if tkn.lastChar != '`' { 273 | return LEX_ERROR, buffer.Bytes() 274 | } 275 | tkn.next() 276 | return ID, buffer.Bytes() 277 | } 278 | 279 | func (tkn *Tokenizer) scanBindVar() (int, []byte) { 280 | buffer := bytes.NewBuffer(make([]byte, 0, 8)) 281 | buffer.WriteByte(byte(tkn.lastChar)) 282 | token := VALUE_ARG 283 | tkn.next() 284 | if tkn.lastChar == ':' { 285 | token = LIST_ARG 286 | buffer.WriteByte(byte(tkn.lastChar)) 287 | tkn.next() 288 | } 289 | if !isLetter(tkn.lastChar) { 290 | return LEX_ERROR, buffer.Bytes() 291 | } 292 | for isLetter(tkn.lastChar) || isDigit(tkn.lastChar) || tkn.lastChar == '.' { 293 | buffer.WriteByte(byte(tkn.lastChar)) 294 | tkn.next() 295 | } 296 | return token, buffer.Bytes() 297 | } 298 | 299 | func (tkn *Tokenizer) scanMantissa(base int, buffer *bytes.Buffer) { 300 | for digitVal(tkn.lastChar) < base { 301 | tkn.ConsumeNext(buffer) 302 | } 303 | } 304 | 305 | func (tkn *Tokenizer) scanNumber(seenDecimalPoint bool) (int, []byte) { 306 | buffer := bytes.NewBuffer(make([]byte, 0, 8)) 307 | if seenDecimalPoint { 308 | buffer.WriteByte('.') 309 | tkn.scanMantissa(10, buffer) 310 | goto exponent 311 | } 312 | 313 | if tkn.lastChar == '0' { 314 | // int or float 315 | tkn.ConsumeNext(buffer) 316 | if tkn.lastChar == 'x' || tkn.lastChar == 'X' { 317 | // hexadecimal int 318 | tkn.ConsumeNext(buffer) 319 | tkn.scanMantissa(16, buffer) 320 | } else { 321 | // octal int or float 322 | seenDecimalDigit := false 323 | tkn.scanMantissa(8, buffer) 324 | if tkn.lastChar == '8' || tkn.lastChar == '9' { 325 | // illegal octal int or float 326 | seenDecimalDigit = true 327 | tkn.scanMantissa(10, buffer) 328 | } 329 | if tkn.lastChar == '.' || tkn.lastChar == 'e' || tkn.lastChar == 'E' { 330 | goto fraction 331 | } 332 | // octal int 333 | if seenDecimalDigit { 334 | return LEX_ERROR, buffer.Bytes() 335 | } 336 | } 337 | goto exit 338 | } 339 | 340 | // decimal int or float 341 | tkn.scanMantissa(10, buffer) 342 | 343 | fraction: 344 | if tkn.lastChar == '.' { 345 | tkn.ConsumeNext(buffer) 346 | tkn.scanMantissa(10, buffer) 347 | } 348 | 349 | exponent: 350 | if tkn.lastChar == 'e' || tkn.lastChar == 'E' { 351 | tkn.ConsumeNext(buffer) 352 | if tkn.lastChar == '+' || tkn.lastChar == '-' { 353 | tkn.ConsumeNext(buffer) 354 | } 355 | tkn.scanMantissa(10, buffer) 356 | } 357 | 358 | exit: 359 | return NUMBER, buffer.Bytes() 360 | } 361 | 362 | func (tkn *Tokenizer) scanString(delim uint16, typ int) (int, []byte) { 363 | buffer := bytes.NewBuffer(make([]byte, 0, 8)) 364 | for { 365 | ch := tkn.lastChar 366 | tkn.next() 367 | if ch == delim { 368 | if tkn.lastChar == delim { 369 | tkn.next() 370 | } else { 371 | break 372 | } 373 | } else if ch == '\\' { 374 | if tkn.lastChar == EOFCHAR { 375 | return LEX_ERROR, buffer.Bytes() 376 | } 377 | if decodedChar := sqltypes.SqlDecodeMap[byte(tkn.lastChar)]; decodedChar == sqltypes.DONTESCAPE { 378 | ch = tkn.lastChar 379 | } else { 380 | ch = uint16(decodedChar) 381 | } 382 | tkn.next() 383 | } 384 | if ch == EOFCHAR { 385 | return LEX_ERROR, buffer.Bytes() 386 | } 387 | buffer.WriteByte(byte(ch)) 388 | } 389 | return typ, buffer.Bytes() 390 | } 391 | 392 | func (tkn *Tokenizer) scanCommentType1(prefix string) (int, []byte) { 393 | buffer := bytes.NewBuffer(make([]byte, 0, 8)) 394 | buffer.WriteString(prefix) 395 | for tkn.lastChar != EOFCHAR { 396 | if tkn.lastChar == '\n' { 397 | tkn.ConsumeNext(buffer) 398 | break 399 | } 400 | tkn.ConsumeNext(buffer) 401 | } 402 | return COMMENT, buffer.Bytes() 403 | } 404 | 405 | func (tkn *Tokenizer) scanCommentType2() (int, []byte) { 406 | buffer := bytes.NewBuffer(make([]byte, 0, 8)) 407 | buffer.WriteString("/*") 408 | for { 409 | if tkn.lastChar == '*' { 410 | tkn.ConsumeNext(buffer) 411 | if tkn.lastChar == '/' { 412 | tkn.ConsumeNext(buffer) 413 | break 414 | } 415 | continue 416 | } 417 | if tkn.lastChar == EOFCHAR { 418 | return LEX_ERROR, buffer.Bytes() 419 | } 420 | tkn.ConsumeNext(buffer) 421 | } 422 | return COMMENT, buffer.Bytes() 423 | } 424 | 425 | func (tkn *Tokenizer) ConsumeNext(buffer *bytes.Buffer) { 426 | if tkn.lastChar == EOFCHAR { 427 | // This should never happen. 428 | panic("unexpected EOF") 429 | } 430 | buffer.WriteByte(byte(tkn.lastChar)) 431 | tkn.next() 432 | } 433 | 434 | func (tkn *Tokenizer) next() { 435 | if ch, err := tkn.InStream.ReadByte(); err != nil { 436 | // Only EOF is possible. 437 | tkn.lastChar = EOFCHAR 438 | } else { 439 | tkn.lastChar = uint16(ch) 440 | } 441 | tkn.Position++ 442 | } 443 | 444 | func isLetter(ch uint16) bool { 445 | return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch == '@' 446 | } 447 | 448 | func digitVal(ch uint16) int { 449 | switch { 450 | case '0' <= ch && ch <= '9': 451 | return int(ch) - '0' 452 | case 'a' <= ch && ch <= 'f': 453 | return int(ch) - 'a' + 10 454 | case 'A' <= ch && ch <= 'F': 455 | return int(ch) - 'A' + 10 456 | } 457 | return 16 // larger than any legal digit val 458 | } 459 | 460 | func isDigit(ch uint16) bool { 461 | return '0' <= ch && ch <= '9' 462 | } 463 | -------------------------------------------------------------------------------- /go/sqlparser/tracked_buffer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlparser 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | ) 11 | 12 | // TrackedBuffer is used to rebuild a query from the ast. 13 | // bindLocations keeps track of locations in the buffer that 14 | // use bind variables for efficient future substitutions. 15 | // nodeFormatter is the formatting function the buffer will 16 | // use to format a node. By default(nil), it's FormatNode. 17 | // But you can supply a different formatting function if you 18 | // want to generate a query that's different from the default. 19 | type TrackedBuffer struct { 20 | *bytes.Buffer 21 | bindLocations []bindLocation 22 | nodeFormatter func(buf *TrackedBuffer, node SQLNode) 23 | } 24 | 25 | func NewTrackedBuffer(nodeFormatter func(buf *TrackedBuffer, node SQLNode)) *TrackedBuffer { 26 | buf := &TrackedBuffer{ 27 | Buffer: bytes.NewBuffer(make([]byte, 0, 128)), 28 | bindLocations: make([]bindLocation, 0, 4), 29 | nodeFormatter: nodeFormatter, 30 | } 31 | return buf 32 | } 33 | 34 | // Myprintf mimics fmt.Fprintf(buf, ...), but limited to Node(%v), 35 | // Node.Value(%s) and string(%s). It also allows a %a for a value argument, in 36 | // which case it adds tracking info for future substitutions. 37 | // 38 | // The name must be something other than the usual Printf() to avoid "go vet" 39 | // warnings due to our custom format specifiers. 40 | func (buf *TrackedBuffer) Myprintf(format string, values ...interface{}) { 41 | end := len(format) 42 | fieldnum := 0 43 | for i := 0; i < end; { 44 | lasti := i 45 | for i < end && format[i] != '%' { 46 | i++ 47 | } 48 | if i > lasti { 49 | buf.WriteString(format[lasti:i]) 50 | } 51 | if i >= end { 52 | break 53 | } 54 | i++ // '%' 55 | switch format[i] { 56 | case 'c': 57 | switch v := values[fieldnum].(type) { 58 | case byte: 59 | buf.WriteByte(v) 60 | case rune: 61 | buf.WriteRune(v) 62 | default: 63 | panic(fmt.Sprintf("unexpected type %T", v)) 64 | } 65 | case 's': 66 | switch v := values[fieldnum].(type) { 67 | case []byte: 68 | buf.Write(v) 69 | case string: 70 | buf.WriteString(v) 71 | default: 72 | panic(fmt.Sprintf("unexpected type %T", v)) 73 | } 74 | case 'v': 75 | node := values[fieldnum].(SQLNode) 76 | if buf.nodeFormatter == nil { 77 | node.Format(buf) 78 | } else { 79 | buf.nodeFormatter(buf, node) 80 | } 81 | case 'a': 82 | buf.WriteArg(values[fieldnum].(string)) 83 | default: 84 | panic("unexpected") 85 | } 86 | fieldnum++ 87 | i++ 88 | } 89 | } 90 | 91 | // WriteArg writes a value argument into the buffer. arg should not contain 92 | // the ':' prefix. It also adds tracking info for future substitutions. 93 | func (buf *TrackedBuffer) WriteArg(arg string) { 94 | buf.bindLocations = append(buf.bindLocations, bindLocation{ 95 | offset: buf.Len(), 96 | length: len(arg), 97 | }) 98 | buf.WriteString(arg) 99 | } 100 | 101 | func (buf *TrackedBuffer) ParsedQuery() *ParsedQuery { 102 | return &ParsedQuery{Query: buf.String(), bindLocations: buf.bindLocations} 103 | } 104 | 105 | func (buf *TrackedBuffer) HasBindVars() bool { 106 | return len(buf.bindLocations) != 0 107 | } 108 | -------------------------------------------------------------------------------- /go/sqltypes/sqltypes.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Google Inc. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package sqltypes implements interfaces and types that represent SQL values. 6 | package sqltypes 7 | 8 | import ( 9 | "encoding/base64" 10 | "encoding/gob" 11 | "encoding/json" 12 | "fmt" 13 | "strconv" 14 | "time" 15 | 16 | "github.com/siddontang/go/hack" 17 | ) 18 | 19 | var ( 20 | NULL = Value{} 21 | DONTESCAPE = byte(255) 22 | nullstr = []byte("null") 23 | ) 24 | 25 | // BinWriter interface is used for encoding values. 26 | // Types like bytes.Buffer conform to this interface. 27 | // We expect the writer objects to be in-memory buffers. 28 | // So, we don't expect the write operations to fail. 29 | type BinWriter interface { 30 | Write([]byte) (int, error) 31 | WriteByte(byte) error 32 | } 33 | 34 | // Value can store any SQL value. NULL is stored as nil. 35 | type Value struct { 36 | Inner InnerValue 37 | } 38 | 39 | // Numeric represents non-fractional SQL number. 40 | type Numeric []byte 41 | 42 | // Fractional represents fractional types like float and decimal 43 | // It's functionally equivalent to Numeric other than how it's constructed 44 | type Fractional []byte 45 | 46 | // String represents any SQL type that needs to be represented using quotes. 47 | type String []byte 48 | 49 | // MakeNumeric makes a Numeric from a []byte without validation. 50 | func MakeNumeric(b []byte) Value { 51 | return Value{Numeric(b)} 52 | } 53 | 54 | // MakeFractional makes a Fractional value from a []byte without validation. 55 | func MakeFractional(b []byte) Value { 56 | return Value{Fractional(b)} 57 | } 58 | 59 | // MakeString makes a String value from a []byte. 60 | func MakeString(b []byte) Value { 61 | return Value{String(b)} 62 | } 63 | 64 | // Raw returns the raw bytes. All types are currently implemented as []byte. 65 | func (v Value) Raw() []byte { 66 | if v.Inner == nil { 67 | return nil 68 | } 69 | return v.Inner.raw() 70 | } 71 | 72 | // String returns the raw value as a string 73 | func (v Value) String() string { 74 | if v.Inner == nil { 75 | return "" 76 | } 77 | return hack.String(v.Inner.raw()) 78 | } 79 | 80 | // ParseInt64 will parse a Numeric value into an int64 81 | func (v Value) ParseInt64() (val int64, err error) { 82 | if v.Inner == nil { 83 | return 0, fmt.Errorf("value is null") 84 | } 85 | n, ok := v.Inner.(Numeric) 86 | if !ok { 87 | return 0, fmt.Errorf("value is not Numeric") 88 | } 89 | return strconv.ParseInt(string(n.raw()), 10, 64) 90 | } 91 | 92 | // ParseUint64 will parse a Numeric value into a uint64 93 | func (v Value) ParseUint64() (val uint64, err error) { 94 | if v.Inner == nil { 95 | return 0, fmt.Errorf("value is null") 96 | } 97 | n, ok := v.Inner.(Numeric) 98 | if !ok { 99 | return 0, fmt.Errorf("value is not Numeric") 100 | } 101 | return strconv.ParseUint(string(n.raw()), 10, 64) 102 | } 103 | 104 | // EncodeSql encodes the value into an SQL statement. Can be binary. 105 | func (v Value) EncodeSql(b BinWriter) { 106 | if v.Inner == nil { 107 | if _, err := b.Write(nullstr); err != nil { 108 | panic(err) 109 | } 110 | } else { 111 | v.Inner.encodeSql(b) 112 | } 113 | } 114 | 115 | // EncodeAscii encodes the value using 7-bit clean ascii bytes. 116 | func (v Value) EncodeAscii(b BinWriter) { 117 | if v.Inner == nil { 118 | if _, err := b.Write(nullstr); err != nil { 119 | panic(err) 120 | } 121 | } else { 122 | v.Inner.encodeAscii(b) 123 | } 124 | } 125 | 126 | func (v Value) IsNull() bool { 127 | return v.Inner == nil 128 | } 129 | 130 | func (v Value) IsNumeric() (ok bool) { 131 | if v.Inner != nil { 132 | _, ok = v.Inner.(Numeric) 133 | } 134 | return ok 135 | } 136 | 137 | func (v Value) IsFractional() (ok bool) { 138 | if v.Inner != nil { 139 | _, ok = v.Inner.(Fractional) 140 | } 141 | return ok 142 | } 143 | 144 | func (v Value) IsString() (ok bool) { 145 | if v.Inner != nil { 146 | _, ok = v.Inner.(String) 147 | } 148 | return ok 149 | } 150 | 151 | // MarshalJSON should only be used for testing. 152 | // It's not a complete implementation. 153 | func (v Value) MarshalJSON() ([]byte, error) { 154 | return json.Marshal(v.Inner) 155 | } 156 | 157 | // UnmarshalJSON should only be used for testing. 158 | // It's not a complete implementation. 159 | func (v *Value) UnmarshalJSON(b []byte) error { 160 | if len(b) == 0 { 161 | return fmt.Errorf("error unmarshaling empty bytes") 162 | } 163 | var val interface{} 164 | var err error 165 | switch b[0] { 166 | case '-': 167 | var ival int64 168 | err = json.Unmarshal(b, &ival) 169 | val = ival 170 | case '"': 171 | var bval []byte 172 | err = json.Unmarshal(b, &bval) 173 | val = bval 174 | case 'n': // null 175 | err = json.Unmarshal(b, &val) 176 | default: 177 | var uval uint64 178 | err = json.Unmarshal(b, &uval) 179 | val = uval 180 | } 181 | if err != nil { 182 | return err 183 | } 184 | *v, err = BuildValue(val) 185 | return err 186 | } 187 | 188 | // InnerValue defines methods that need to be supported by all non-null value types. 189 | type InnerValue interface { 190 | raw() []byte 191 | encodeSql(BinWriter) 192 | encodeAscii(BinWriter) 193 | } 194 | 195 | func BuildValue(goval interface{}) (v Value, err error) { 196 | switch bindVal := goval.(type) { 197 | case nil: 198 | // no op 199 | case int: 200 | v = Value{Numeric(strconv.AppendInt(nil, int64(bindVal), 10))} 201 | case int32: 202 | v = Value{Numeric(strconv.AppendInt(nil, int64(bindVal), 10))} 203 | case int64: 204 | v = Value{Numeric(strconv.AppendInt(nil, int64(bindVal), 10))} 205 | case uint: 206 | v = Value{Numeric(strconv.AppendUint(nil, uint64(bindVal), 10))} 207 | case uint32: 208 | v = Value{Numeric(strconv.AppendUint(nil, uint64(bindVal), 10))} 209 | case uint64: 210 | v = Value{Numeric(strconv.AppendUint(nil, uint64(bindVal), 10))} 211 | case float64: 212 | v = Value{Fractional(strconv.AppendFloat(nil, bindVal, 'f', -1, 64))} 213 | case string: 214 | v = Value{String([]byte(bindVal))} 215 | case []byte: 216 | v = Value{String(bindVal)} 217 | case time.Time: 218 | v = Value{String([]byte(bindVal.Format("'2006-01-02 15:04:05'")))} 219 | case Numeric, Fractional, String: 220 | v = Value{bindVal.(InnerValue)} 221 | case Value: 222 | v = bindVal 223 | default: 224 | return Value{}, fmt.Errorf("unsupported bind variable type %T: %v", goval, goval) 225 | } 226 | return v, nil 227 | } 228 | 229 | // BuildNumeric builds a Numeric type that represents any whole number. 230 | // It normalizes the representation to ensure 1:1 mapping between the 231 | // number and its representation. 232 | func BuildNumeric(val string) (n Value, err error) { 233 | if val[0] == '-' || val[0] == '+' { 234 | signed, err := strconv.ParseInt(val, 0, 64) 235 | if err != nil { 236 | return Value{}, err 237 | } 238 | n = Value{Numeric(strconv.AppendInt(nil, signed, 10))} 239 | } else { 240 | unsigned, err := strconv.ParseUint(val, 0, 64) 241 | if err != nil { 242 | return Value{}, err 243 | } 244 | n = Value{Numeric(strconv.AppendUint(nil, unsigned, 10))} 245 | } 246 | return n, nil 247 | } 248 | 249 | func (n Numeric) raw() []byte { 250 | return []byte(n) 251 | } 252 | 253 | func (n Numeric) encodeSql(b BinWriter) { 254 | if _, err := b.Write(n.raw()); err != nil { 255 | panic(err) 256 | } 257 | } 258 | 259 | func (n Numeric) encodeAscii(b BinWriter) { 260 | if _, err := b.Write(n.raw()); err != nil { 261 | panic(err) 262 | } 263 | } 264 | 265 | func (n Numeric) MarshalJSON() ([]byte, error) { 266 | return n.raw(), nil 267 | } 268 | 269 | func (f Fractional) raw() []byte { 270 | return []byte(f) 271 | } 272 | 273 | func (f Fractional) encodeSql(b BinWriter) { 274 | if _, err := b.Write(f.raw()); err != nil { 275 | panic(err) 276 | } 277 | } 278 | 279 | func (f Fractional) encodeAscii(b BinWriter) { 280 | if _, err := b.Write(f.raw()); err != nil { 281 | panic(err) 282 | } 283 | } 284 | 285 | func (s String) raw() []byte { 286 | return []byte(s) 287 | } 288 | 289 | func (s String) encodeSql(b BinWriter) { 290 | writebyte(b, '\'') 291 | for _, ch := range s.raw() { 292 | if encodedChar := SqlEncodeMap[ch]; encodedChar == DONTESCAPE { 293 | writebyte(b, ch) 294 | } else { 295 | writebyte(b, '\\') 296 | writebyte(b, encodedChar) 297 | } 298 | } 299 | writebyte(b, '\'') 300 | } 301 | 302 | func (s String) encodeAscii(b BinWriter) { 303 | writebyte(b, '\'') 304 | encoder := base64.NewEncoder(base64.StdEncoding, b) 305 | encoder.Write(s.raw()) 306 | encoder.Close() 307 | writebyte(b, '\'') 308 | } 309 | 310 | func writebyte(b BinWriter, c byte) { 311 | if err := b.WriteByte(c); err != nil { 312 | panic(err) 313 | } 314 | } 315 | 316 | // SqlEncodeMap specifies how to escape binary data with '\'. 317 | // Complies to http://dev.mysql.com/doc/refman/5.1/en/string-syntax.html 318 | var SqlEncodeMap [256]byte 319 | 320 | // SqlDecodeMap is the reverse of SqlEncodeMap 321 | var SqlDecodeMap [256]byte 322 | 323 | var encodeRef = map[byte]byte{ 324 | '\x00': '0', 325 | '\'': '\'', 326 | '"': '"', 327 | '\b': 'b', 328 | '\n': 'n', 329 | '\r': 'r', 330 | '\t': 't', 331 | 26: 'Z', // ctl-Z 332 | '\\': '\\', 333 | } 334 | 335 | func init() { 336 | for i := range SqlEncodeMap { 337 | SqlEncodeMap[i] = DONTESCAPE 338 | SqlDecodeMap[i] = DONTESCAPE 339 | } 340 | for i := range SqlEncodeMap { 341 | if to, ok := encodeRef[byte(i)]; ok { 342 | SqlEncodeMap[byte(i)] = to 343 | SqlDecodeMap[to] = byte(i) 344 | } 345 | } 346 | gob.Register(Numeric(nil)) 347 | gob.Register(Fractional(nil)) 348 | gob.Register(String(nil)) 349 | } 350 | -------------------------------------------------------------------------------- /go/topo/agent.go: -------------------------------------------------------------------------------- 1 | package topo 2 | 3 | import ( 4 | "fmt" 5 | "github.com/go-cloud/go-zookeeper/zk" 6 | "github.com/go-cloud/zkhelper" 7 | "path" 8 | "sort" 9 | ) 10 | 11 | // agent: 12 | func (t *Topo) GetAgentBasePath() string { 13 | return fmt.Sprintf("/zk/%s/agents", t.Name) 14 | } 15 | 16 | func (t *Topo) CreateAgent(nodeAddr string) (string, error) { 17 | zkhelper.CreateRecursive(t.conn, t.GetAgentBasePath(), "", 0, zkhelper.DefaultDirACLs()) 18 | 19 | return t.conn.Create(path.Join(t.GetAgentBasePath(), nodeAddr), nil, zk.FlagEphemeral, zkhelper.DefaultFileACLs()) 20 | } 21 | 22 | func (t *Topo) DeleteAgent(nodeAddr string) error { 23 | return t.conn.Delete(path.Join(t.GetAgentBasePath(), nodeAddr), -1) 24 | } 25 | 26 | func (t *Topo) ListAgents() ([]string, error) { 27 | as, _, err := t.conn.Children(t.GetAgentBasePath()) 28 | sort.Strings(as) 29 | return as, err 30 | } 31 | -------------------------------------------------------------------------------- /go/topo/group.go: -------------------------------------------------------------------------------- 1 | package topo 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/go-cloud/myshard/go/model" 7 | "github.com/go-cloud/zkhelper" 8 | "path" 9 | "sort" 10 | ) 11 | 12 | func (t *Topo) GetGroupBasePath() string { 13 | return fmt.Sprintf("/zk/%s/groups", t.Name) 14 | } 15 | 16 | func (t *Topo) GetGroupPath(groupID int) string { 17 | return path.Join(t.GetGroupBasePath(), fmt.Sprintf("group_%06d", groupID)) 18 | } 19 | 20 | func (t *Topo) GetGroupNodePath(groupID int, addr string) string { 21 | return path.Join(t.GetGroupPath(groupID), addr) 22 | } 23 | 24 | // group: 25 | // /zk/myshard/groups/group_000001 26 | // /zk/myshard/groups/group_000002 27 | func (t *Topo) CreateGroup(groupID int) (string, error) { 28 | group := model.Group{groupID, model.GroupUpStatus, nil} 29 | 30 | zkhelper.CreateRecursive(t.conn, t.GetGroupBasePath(), "", 0, zkhelper.DefaultDirACLs()) 31 | 32 | data, _ := json.Marshal(group) 33 | 34 | return t.conn.Create(t.GetGroupPath(groupID), data, 0, zkhelper.DefaultDirACLs()) 35 | } 36 | 37 | func (t *Topo) DeleteGroup(groupID int) error { 38 | return t.conn.Delete(t.GetGroupPath(groupID), -1) 39 | } 40 | 41 | func (t *Topo) SetGroupStatus(groupID int, status string) error { 42 | group, err := t.getGroup(groupID) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | group.Status = status 48 | 49 | data, _ := json.Marshal(group) 50 | 51 | _, err = t.conn.Set(t.GetGroupPath(groupID), data, -1) 52 | return err 53 | } 54 | 55 | func (t *Topo) GetGroup(groupID int) (*model.Group, error) { 56 | group, err := t.getGroup(groupID) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | p := t.GetGroupPath(groupID) 62 | children, _, err := t.conn.Children(p) 63 | if err != nil { 64 | return nil, err 65 | } 66 | 67 | group.Nodes = make([]model.Node, 0, len(children)) 68 | 69 | var data []byte 70 | for _, child := range children { 71 | if data, _, err = t.conn.Get(path.Join(p, child)); err != nil { 72 | return nil, err 73 | } 74 | 75 | var node model.Node 76 | 77 | if err = json.Unmarshal(data, &node); err != nil { 78 | return nil, err 79 | } 80 | 81 | group.Nodes = append(group.Nodes, node) 82 | } 83 | 84 | sort.Sort(model.NodeSlice(group.Nodes)) 85 | 86 | return group, nil 87 | } 88 | 89 | func (t *Topo) getGroup(groupID int) (*model.Group, error) { 90 | var group model.Group 91 | 92 | p := t.GetGroupPath(groupID) 93 | 94 | data, _, err := t.conn.Get(p) 95 | if err != nil { 96 | return nil, err 97 | } 98 | 99 | if err = json.Unmarshal(data, &group); err != nil { 100 | return nil, err 101 | } 102 | 103 | return &group, nil 104 | } 105 | 106 | func (t *Topo) AddGroupNode(groupID int, addr string, tp string, status string, weight int) (string, error) { 107 | node := model.Node{GroupID: groupID, Addr: addr, Type: tp, Status: status, Weight: weight} 108 | 109 | data, _ := json.Marshal(node) 110 | 111 | return t.conn.Create(t.GetGroupNodePath(groupID, addr), data, 0, zkhelper.DefaultDirACLs()) 112 | } 113 | 114 | func (t *Topo) SetGroupNodeStatus(groupID int, addr string, status string) error { 115 | p := t.GetGroupNodePath(groupID, addr) 116 | node, err := t.GetGroupNode(groupID, addr) 117 | if err != nil { 118 | return err 119 | } 120 | 121 | node.Status = status 122 | data, _ := json.Marshal(node) 123 | 124 | _, err = t.conn.Set(p, data, -1) 125 | return err 126 | } 127 | 128 | func (t *Topo) SetGroupNodeWeight(groupID int, addr string, weight int) error { 129 | p := t.GetGroupNodePath(groupID, addr) 130 | node, err := t.GetGroupNode(groupID, addr) 131 | if err != nil { 132 | return err 133 | } 134 | 135 | node.Weight = weight 136 | data, _ := json.Marshal(node) 137 | 138 | _, err = t.conn.Set(p, data, -1) 139 | return err 140 | } 141 | 142 | func (t *Topo) DeleteGroupNode(groupID int, addr string) error { 143 | return t.conn.Delete(t.GetGroupNodePath(groupID, addr), -1) 144 | } 145 | 146 | func (t *Topo) GetGroupNode(groupID int, addr string) (*model.Node, error) { 147 | p := t.GetGroupNodePath(groupID, addr) 148 | data, _, err := t.conn.Get(p) 149 | if err != nil { 150 | return nil, err 151 | } 152 | 153 | var node model.Node 154 | if err = json.Unmarshal(data, &node); err != nil { 155 | return nil, err 156 | } 157 | 158 | return &node, nil 159 | } 160 | -------------------------------------------------------------------------------- /go/topo/proxy.go: -------------------------------------------------------------------------------- 1 | package topo 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/go-cloud/go-zookeeper/zk" 7 | "github.com/go-cloud/myshard/go/model" 8 | "github.com/go-cloud/zkhelper" 9 | "path" 10 | ) 11 | 12 | func (t *Topo) GetProxyBasePath() string { 13 | return fmt.Sprintf("/zk/%s/proxys", t.Name) 14 | } 15 | 16 | func (t *Topo) CreateProxy(p *model.Proxy) (string, error) { 17 | data, err := json.Marshal(p) 18 | if err != nil { 19 | return "", err 20 | } 21 | 22 | base := t.GetProxyBasePath() 23 | 24 | zkhelper.CreateRecursive(t.conn, base, "", 0, zkhelper.DefaultDirACLs()) 25 | 26 | return t.conn.Create(path.Join(base, p.Addr), data, zk.FlagEphemeral, zkhelper.DefaultDirACLs()) 27 | } 28 | 29 | func (t *Topo) DeleteProxy(addr string) error { 30 | return t.conn.Delete(path.Join(t.GetProxyBasePath(), addr), -1) 31 | } 32 | 33 | func (t *Topo) ListProxys() ([]*model.Proxy, error) { 34 | names, _, err := t.conn.Children(t.GetProxyBasePath()) 35 | 36 | if err != nil && !zkhelper.ZkErrorEqual(err, zk.ErrNoNode) { 37 | return nil, err 38 | } 39 | 40 | ps := make([]*model.Proxy, 0, len(names)) 41 | for _, n := range names { 42 | p, err := t.GetProxy(n) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | ps = append(ps, p) 48 | } 49 | 50 | return ps, nil 51 | } 52 | 53 | func (t *Topo) GetProxy(addr string) (*model.Proxy, error) { 54 | var p model.Proxy 55 | 56 | data, _, err := t.conn.Get(path.Join(t.GetProxyBasePath(), addr)) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | if err = json.Unmarshal(data, &p); err != nil { 62 | return nil, err 63 | } 64 | 65 | return &p, nil 66 | } 67 | 68 | func (t *Topo) SetProxyStatus(addr string, status string) error { 69 | p, err := t.GetProxy(addr) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | p.Status = status 75 | 76 | b, _ := json.Marshal(p) 77 | 78 | _, err = t.conn.Set(path.Join(t.GetProxyBasePath(), addr), b, -1) 79 | 80 | return err 81 | } 82 | -------------------------------------------------------------------------------- /go/topo/schema.go: -------------------------------------------------------------------------------- 1 | package topo 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/go-cloud/myshard/go/model" 7 | "github.com/go-cloud/zkhelper" 8 | "path" 9 | "sort" 10 | ) 11 | 12 | func (t *Topo) GetSchemaBasePath() string { 13 | return fmt.Sprintf("/zk/%s/schemas", t.Name) 14 | } 15 | 16 | func (t *Topo) GetSchemaPath(db string) string { 17 | return path.Join(t.GetSchemaBasePath(), db) 18 | } 19 | 20 | func (t *Topo) GetSchemaTablePath(db string, table string) string { 21 | return path.Join(t.GetSchemaPath(db), table) 22 | } 23 | 24 | func checkGroupIDExist(checkGroupID int, groupIDs []int) bool { 25 | found := false 26 | for _, groupID := range groupIDs { 27 | if groupID == checkGroupID { 28 | found = true 29 | break 30 | } 31 | } 32 | 33 | return found 34 | } 35 | 36 | func (t *Topo) CreateSchema(db string, groupIDs []int, defaultGroupID int) (string, error) { 37 | s := model.Schema{Name: db, GroupIDs: groupIDs, DefaultGroupID: defaultGroupID, Status: ""} 38 | 39 | sort.Ints(groupIDs) 40 | 41 | if !checkGroupIDExist(defaultGroupID, groupIDs) { 42 | return "", fmt.Errorf("group %d not in schema groups", defaultGroupID) 43 | } 44 | 45 | zkhelper.CreateRecursive(t.conn, t.GetSchemaBasePath(), "", 0, zkhelper.DefaultDirACLs()) 46 | 47 | data, _ := json.Marshal(s) 48 | 49 | return t.conn.Create(t.GetSchemaPath(db), data, 0, zkhelper.DefaultDirACLs()) 50 | } 51 | 52 | func (t *Topo) DeleteSchema(db string) error { 53 | return t.conn.Delete(t.GetSchemaPath(db), -1) 54 | } 55 | 56 | func (t *Topo) GetSchema(db string) (*model.Schema, error) { 57 | p := t.GetSchemaPath(db) 58 | data, _, err := t.conn.Get(p) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | var s model.Schema 64 | 65 | if err = json.Unmarshal(data, &s); err != nil { 66 | return nil, err 67 | } 68 | 69 | return &s, nil 70 | } 71 | 72 | func (t *Topo) UpdateSchemaDefaultGroup(db string, defaultGroupID int) error { 73 | s, err := t.GetSchema(db) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | if !checkGroupIDExist(defaultGroupID, s.GroupIDs) { 79 | return fmt.Errorf("group %d not in schema groups", defaultGroupID) 80 | } 81 | 82 | s.DefaultGroupID = defaultGroupID 83 | 84 | data, _ := json.Marshal(s) 85 | 86 | _, err = t.conn.Set(t.GetSchemaPath(db), data, -1) 87 | return err 88 | } 89 | 90 | func (t *Topo) AddSchemaGroup(db string, groupID int) error { 91 | s, err := t.GetSchema(db) 92 | if err != nil { 93 | return err 94 | } 95 | 96 | if checkGroupIDExist(groupID, s.GroupIDs) { 97 | return nil 98 | } 99 | 100 | s.GroupIDs = append(s.GroupIDs, groupID) 101 | sort.Ints(s.GroupIDs) 102 | 103 | data, _ := json.Marshal(s) 104 | 105 | _, err = t.conn.Set(t.GetSchemaPath(db), data, -1) 106 | return err 107 | } 108 | 109 | func (t *Topo) DeleteSchemaGroup(db string, groupID int) error { 110 | s, err := t.GetSchema(db) 111 | if err != nil { 112 | return err 113 | } 114 | 115 | if !checkGroupIDExist(groupID, s.GroupIDs) { 116 | return fmt.Errorf("group %d not in schema groups", groupID) 117 | } 118 | 119 | groupIDs := make([]int, 0, len(s.GroupIDs)) 120 | for _, id := range s.GroupIDs { 121 | if id != groupID { 122 | groupIDs = append(groupIDs, id) 123 | } 124 | } 125 | 126 | s.GroupIDs = groupIDs 127 | 128 | data, _ := json.Marshal(s) 129 | _, err = t.conn.Set(t.GetSchemaPath(db), data, -1) 130 | return err 131 | } 132 | -------------------------------------------------------------------------------- /go/topo/topo.go: -------------------------------------------------------------------------------- 1 | package topo 2 | 3 | import ( 4 | "fmt" 5 | "github.com/go-cloud/go-zookeeper/zk" 6 | "github.com/go-cloud/zkhelper" 7 | ) 8 | 9 | // We use zookeeper to store the configuration and cooperate 10 | // all services 11 | type Topo struct { 12 | // for the base zk directory name 13 | Name string 14 | 15 | conn zkhelper.Conn 16 | } 17 | 18 | func NewTopo(name string, conn zkhelper.Conn) *Topo { 19 | t := new(Topo) 20 | t.Name = name 21 | t.conn = conn 22 | return t 23 | } 24 | 25 | func (t *Topo) Close() { 26 | t.conn.Close() 27 | } 28 | 29 | // Clear all zk data, very dangerous to use 30 | func (t *Topo) clear() error { 31 | p := fmt.Sprintf("/zk/%s", t.Name) 32 | 33 | err := zkhelper.DeleteRecursive(t.conn, p, -1) 34 | if zkhelper.ZkErrorEqual(err, zk.ErrNoNode) { 35 | return nil 36 | } else { 37 | return err 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /go/topo/topo_test.go: -------------------------------------------------------------------------------- 1 | package topo 2 | 3 | import ( 4 | "flag" 5 | "github.com/go-cloud/myshard/go/model" 6 | "github.com/go-cloud/zkhelper" 7 | . "gopkg.in/check.v1" 8 | "path" 9 | "testing" 10 | ) 11 | 12 | var testZK = flag.String("zk", "", "Use zookeeper for test if set") 13 | 14 | func Test(t *testing.T) { 15 | TestingT(t) 16 | } 17 | 18 | type topoTestSuite struct { 19 | t *Topo 20 | } 21 | 22 | var _ = Suite(&topoTestSuite{}) 23 | 24 | func (s *topoTestSuite) SetUpSuite(c *C) { 25 | var conn zkhelper.Conn 26 | 27 | if len(*testZK) == 0 { 28 | //use fake zk 29 | conn = zkhelper.NewConn() 30 | } else { 31 | var err error 32 | conn, err = zkhelper.ConnectToZk(*testZK) 33 | c.Assert(err, IsNil) 34 | } 35 | 36 | s.t = NewTopo("myshard_test", conn) 37 | 38 | err := s.t.clear() 39 | c.Assert(err, IsNil) 40 | } 41 | 42 | func (s *topoTestSuite) TearDownSuite(c *C) { 43 | s.t.Close() 44 | } 45 | 46 | func (s *topoTestSuite) TestAgent(c *C) { 47 | agent1 := "127.0.0.1:3306" 48 | agent2 := "127.0.0.1:3307" 49 | 50 | s1, err := s.t.CreateAgent(agent1) 51 | c.Assert(err, IsNil) 52 | c.Assert(s1, Equals, path.Join(s.t.GetAgentBasePath(), agent1)) 53 | 54 | s2, err := s.t.CreateAgent(agent2) 55 | c.Assert(err, IsNil) 56 | c.Assert(s2, Equals, path.Join(s.t.GetAgentBasePath(), agent2)) 57 | 58 | as, err := s.t.ListAgents() 59 | c.Assert(err, IsNil) 60 | 61 | c.Assert(as, DeepEquals, []string{agent1, agent2}) 62 | } 63 | 64 | func (s *topoTestSuite) TestProxy(c *C) { 65 | p1 := &model.Proxy{"127.0.0.1:4000", "127.0.0.1:14000", "up"} 66 | p2 := &model.Proxy{"127.0.0.1:4001", "127.0.0.1:14001", "up"} 67 | 68 | _, err := s.t.CreateProxy(p1) 69 | c.Assert(err, IsNil) 70 | 71 | _, err = s.t.CreateProxy(p2) 72 | c.Assert(err, IsNil) 73 | 74 | ps, err := s.t.ListProxys() 75 | c.Assert(err, IsNil) 76 | c.Assert(ps, HasLen, 2) 77 | 78 | err = s.t.SetProxyStatus(p1.Addr, "down") 79 | c.Assert(err, IsNil) 80 | 81 | p, err := s.t.GetProxy(p1.Addr) 82 | c.Assert(err, IsNil) 83 | 84 | c.Assert(p.Status, Equals, "down") 85 | } 86 | 87 | func (s *topoTestSuite) TestGroup(c *C) { 88 | _, err := s.t.CreateGroup(1) 89 | c.Assert(err, IsNil) 90 | 91 | _, err = s.t.AddGroupNode(1, "127.0.0.1:3306", model.NodeMasterType, model.NodeDownStatus, 0) 92 | c.Assert(err, IsNil) 93 | 94 | _, err = s.t.AddGroupNode(1, "127.0.0.1:3307", model.NodeSlaveType, model.NodeDownStatus, 0) 95 | c.Assert(err, IsNil) 96 | 97 | err = s.t.SetGroupNodeStatus(1, "127.0.0.1:3306", model.NodeUpStatus) 98 | c.Assert(err, IsNil) 99 | 100 | err = s.t.SetGroupNodeStatus(1, "127.0.0.1:3307", model.NodeUpStatus) 101 | c.Assert(err, IsNil) 102 | 103 | g, err := s.t.GetGroup(1) 104 | c.Assert(err, IsNil) 105 | c.Assert(g.ID, Equals, 1) 106 | c.Assert(g.Nodes, DeepEquals, []model.Node{ 107 | model.Node{1, "127.0.0.1:3306", model.NodeMasterType, model.NodeUpStatus, 0}, 108 | model.Node{1, "127.0.0.1:3307", model.NodeSlaveType, model.NodeUpStatus, 0}, 109 | }) 110 | 111 | err = s.t.DeleteGroup(1) 112 | c.Assert(err, NotNil) 113 | 114 | err = s.t.DeleteGroupNode(1, "127.0.0.1:3306") 115 | c.Assert(err, IsNil) 116 | 117 | err = s.t.DeleteGroupNode(1, "127.0.0.1:3307") 118 | c.Assert(err, IsNil) 119 | 120 | err = s.t.DeleteGroup(1) 121 | c.Assert(err, IsNil) 122 | } 123 | -------------------------------------------------------------------------------- /vitess_license: -------------------------------------------------------------------------------- 1 | Copyright 2012, Google Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | --------------------------------------------------------------------------------