yy_parser.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. // Copyright 2015 PingCAP, Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. package parser
  14. import (
  15. "fmt"
  16. "math"
  17. "regexp"
  18. "strconv"
  19. "unicode"
  20. "github.com/pingcap/errors"
  21. "github.com/pingcap/parser/ast"
  22. "github.com/pingcap/parser/auth"
  23. "github.com/pingcap/parser/mysql"
  24. "github.com/pingcap/parser/terror"
  25. )
  26. var (
  27. // ErrSyntax returns for sql syntax error.
  28. ErrSyntax = terror.ClassParser.NewStd(mysql.ErrSyntax)
  29. // ErrParse returns for sql parse error.
  30. ErrParse = terror.ClassParser.NewStd(mysql.ErrParse)
  31. // ErrUnknownCharacterSet returns for no character set found error.
  32. ErrUnknownCharacterSet = terror.ClassParser.NewStd(mysql.ErrUnknownCharacterSet)
  33. // ErrInvalidYearColumnLength returns for illegal column length for year type.
  34. ErrInvalidYearColumnLength = terror.ClassParser.NewStd(mysql.ErrInvalidYearColumnLength)
  35. // ErrWrongArguments returns for illegal argument.
  36. ErrWrongArguments = terror.ClassParser.NewStd(mysql.ErrWrongArguments)
  37. // ErrWrongFieldTerminators returns for illegal field terminators.
  38. ErrWrongFieldTerminators = terror.ClassParser.NewStd(mysql.ErrWrongFieldTerminators)
  39. // ErrTooBigDisplayWidth returns for data display width exceed limit .
  40. ErrTooBigDisplayWidth = terror.ClassParser.NewStd(mysql.ErrTooBigDisplaywidth)
  41. // ErrTooBigPrecision returns for data precision exceed limit.
  42. ErrTooBigPrecision = terror.ClassParser.NewStd(mysql.ErrTooBigPrecision)
  43. // ErrUnknownAlterLock returns for no alter lock type found error.
  44. ErrUnknownAlterLock = terror.ClassParser.NewStd(mysql.ErrUnknownAlterLock)
  45. // ErrUnknownAlterAlgorithm returns for no alter algorithm found error.
  46. ErrUnknownAlterAlgorithm = terror.ClassParser.NewStd(mysql.ErrUnknownAlterAlgorithm)
  47. // ErrWrongValue returns for wrong value
  48. ErrWrongValue = terror.ClassParser.NewStd(mysql.ErrWrongValue)
  49. // ErrWarnDeprecatedSyntaxNoReplacement return when the syntax was deprecated and there is no replacement.
  50. ErrWarnDeprecatedSyntaxNoReplacement = terror.ClassParser.NewStd(mysql.ErrWarnDeprecatedSyntaxNoReplacement)
  51. // ErrWarnDeprecatedIntegerDisplayWidth share the same code 1681, and it will be returned when length is specified in integer.
  52. ErrWarnDeprecatedIntegerDisplayWidth = terror.ClassParser.NewStdErr(mysql.ErrWarnDeprecatedSyntaxNoReplacement, mysql.Message("Integer display width is deprecated and will be removed in a future release.", nil))
  53. // ErrWrongUsage returns for incorrect usages.
  54. ErrWrongUsage = terror.ClassParser.NewStd(mysql.ErrWrongUsage)
  55. // SpecFieldPattern special result field pattern
  56. SpecFieldPattern = regexp.MustCompile(`(\/\*!(M?[0-9]{5,6})?|\*\/)`)
  57. specCodeStart = regexp.MustCompile(`^\/\*!(M?[0-9]{5,6})?[ \t]*`)
  58. specCodeEnd = regexp.MustCompile(`[ \t]*\*\/$`)
  59. )
  60. // TrimComment trim comment for special comment code of MySQL.
  61. func TrimComment(txt string) string {
  62. txt = specCodeStart.ReplaceAllString(txt, "")
  63. return specCodeEnd.ReplaceAllString(txt, "")
  64. }
  65. type ParserConfig struct {
  66. EnableWindowFunction bool
  67. EnableStrictDoubleTypeCheck bool
  68. }
  69. // Parser represents a parser instance. Some temporary objects are stored in it to reduce object allocation during Parse function.
  70. type Parser struct {
  71. charset string
  72. collation string
  73. result []ast.StmtNode
  74. src string
  75. lexer Scanner
  76. hintParser *hintParser
  77. explicitCharset bool
  78. strictDoubleFieldType bool
  79. // the following fields are used by yyParse to reduce allocation.
  80. cache []yySymType
  81. yylval yySymType
  82. yyVAL *yySymType
  83. }
  84. func yySetOffset(yyVAL *yySymType, offset int) {
  85. if yyVAL.expr != nil {
  86. yyVAL.expr.SetOriginTextPosition(offset)
  87. }
  88. }
  89. func yyhintSetOffset(_ *yyhintSymType, _ int) {
  90. }
  91. type stmtTexter interface {
  92. stmtText() string
  93. }
  94. // New returns a Parser object with default SQL mode.
  95. func New() *Parser {
  96. if ast.NewValueExpr == nil ||
  97. ast.NewParamMarkerExpr == nil ||
  98. ast.NewHexLiteral == nil ||
  99. ast.NewBitLiteral == nil {
  100. panic("no parser driver (forgotten import?) https://github.com/pingcap/parser/issues/43")
  101. }
  102. p := &Parser{
  103. cache: make([]yySymType, 200),
  104. }
  105. p.EnableWindowFunc(true)
  106. p.SetStrictDoubleTypeCheck(true)
  107. mode, _ := mysql.GetSQLMode(mysql.DefaultSQLMode)
  108. p.SetSQLMode(mode)
  109. return p
  110. }
  111. func (parser *Parser) SetStrictDoubleTypeCheck(val bool) {
  112. parser.strictDoubleFieldType = val
  113. }
  114. func (parser *Parser) SetParserConfig(config ParserConfig) {
  115. parser.EnableWindowFunc(config.EnableWindowFunction)
  116. parser.SetStrictDoubleTypeCheck(config.EnableStrictDoubleTypeCheck)
  117. }
  118. // Parse parses a query string to raw ast.StmtNode.
  119. // If charset or collation is "", default charset and collation will be used.
  120. func (parser *Parser) Parse(sql, charset, collation string) (stmt []ast.StmtNode, warns []error, err error) {
  121. if charset == "" {
  122. charset = mysql.DefaultCharset
  123. }
  124. if collation == "" {
  125. collation = mysql.DefaultCollationName
  126. }
  127. parser.charset = charset
  128. parser.collation = collation
  129. parser.src = sql
  130. parser.result = parser.result[:0]
  131. var l yyLexer
  132. parser.lexer.reset(sql)
  133. l = &parser.lexer
  134. yyParse(l, parser)
  135. warns, errs := l.Errors()
  136. if len(warns) > 0 {
  137. warns = append([]error(nil), warns...)
  138. } else {
  139. warns = nil
  140. }
  141. if len(errs) != 0 {
  142. return nil, warns, errors.Trace(errs[0])
  143. }
  144. for _, stmt := range parser.result {
  145. ast.SetFlag(stmt)
  146. }
  147. return parser.result, warns, nil
  148. }
  149. func (parser *Parser) lastErrorAsWarn() {
  150. parser.lexer.lastErrorAsWarn()
  151. }
  152. // ParseOneStmt parses a query and returns an ast.StmtNode.
  153. // The query must have one statement, otherwise ErrSyntax is returned.
  154. func (parser *Parser) ParseOneStmt(sql, charset, collation string) (ast.StmtNode, error) {
  155. stmts, _, err := parser.Parse(sql, charset, collation)
  156. if err != nil {
  157. return nil, errors.Trace(err)
  158. }
  159. if len(stmts) != 1 {
  160. return nil, ErrSyntax
  161. }
  162. ast.SetFlag(stmts[0])
  163. return stmts[0], nil
  164. }
  165. // SetSQLMode sets the SQL mode for parser.
  166. func (parser *Parser) SetSQLMode(mode mysql.SQLMode) {
  167. parser.lexer.SetSQLMode(mode)
  168. }
  169. // EnableWindowFunc controls whether the parser to parse syntax related with window function.
  170. func (parser *Parser) EnableWindowFunc(val bool) {
  171. parser.lexer.EnableWindowFunc(val)
  172. }
  173. // ParseErrorWith returns "You have a syntax error near..." error message compatible with mysql.
  174. func ParseErrorWith(errstr string, lineno int) error {
  175. if len(errstr) > mysql.ErrTextLength {
  176. errstr = errstr[:mysql.ErrTextLength]
  177. }
  178. return fmt.Errorf("near '%-.80s' at line %d", errstr, lineno)
  179. }
  180. // The select statement is not at the end of the whole statement, if the last
  181. // field text was set from its offset to the end of the src string, update
  182. // the last field text.
  183. func (parser *Parser) setLastSelectFieldText(st *ast.SelectStmt, lastEnd int) {
  184. if st.Kind != ast.SelectStmtKindSelect {
  185. return
  186. }
  187. lastField := st.Fields.Fields[len(st.Fields.Fields)-1]
  188. if lastField.Offset+len(lastField.Text()) >= len(parser.src)-1 {
  189. lastField.SetText(parser.src[lastField.Offset:lastEnd])
  190. }
  191. }
  192. func (parser *Parser) startOffset(v *yySymType) int {
  193. return v.offset
  194. }
  195. func (parser *Parser) endOffset(v *yySymType) int {
  196. offset := v.offset
  197. for offset > 0 && unicode.IsSpace(rune(parser.src[offset-1])) {
  198. offset--
  199. }
  200. return offset
  201. }
  202. func (parser *Parser) parseHint(input string) ([]*ast.TableOptimizerHint, []error) {
  203. if parser.hintParser == nil {
  204. parser.hintParser = newHintParser()
  205. }
  206. return parser.hintParser.parse(input, parser.lexer.GetSQLMode(), parser.lexer.lastHintPos)
  207. }
  208. func toInt(l yyLexer, lval *yySymType, str string) int {
  209. n, err := strconv.ParseUint(str, 10, 64)
  210. if err != nil {
  211. e := err.(*strconv.NumError)
  212. if e.Err == strconv.ErrRange {
  213. // TODO: toDecimal maybe out of range still.
  214. // This kind of error should be throw to higher level, because truncated data maybe legal.
  215. // For example, this SQL returns error:
  216. // create table test (id decimal(30, 0));
  217. // insert into test values(123456789012345678901234567890123094839045793405723406801943850);
  218. // While this SQL:
  219. // select 1234567890123456789012345678901230948390457934057234068019438509023041874359081325875128590860234789847359871045943057;
  220. // get value 99999999999999999999999999999999999999999999999999999999999999999
  221. return toDecimal(l, lval, str)
  222. }
  223. l.AppendError(l.Errorf("integer literal: %v", err))
  224. return int(unicode.ReplacementChar)
  225. }
  226. switch {
  227. case n <= math.MaxInt64:
  228. lval.item = int64(n)
  229. default:
  230. lval.item = n
  231. }
  232. return intLit
  233. }
  234. func toDecimal(l yyLexer, lval *yySymType, str string) int {
  235. dec, err := ast.NewDecimal(str)
  236. if err != nil {
  237. l.AppendError(l.Errorf("decimal literal: %v", err))
  238. }
  239. lval.item = dec
  240. return decLit
  241. }
  242. func toFloat(l yyLexer, lval *yySymType, str string) int {
  243. n, err := strconv.ParseFloat(str, 64)
  244. if err != nil {
  245. l.AppendError(l.Errorf("float literal: %v", err))
  246. return int(unicode.ReplacementChar)
  247. }
  248. lval.item = n
  249. return floatLit
  250. }
  251. // See https://dev.mysql.com/doc/refman/5.7/en/hexadecimal-literals.html
  252. func toHex(l yyLexer, lval *yySymType, str string) int {
  253. h, err := ast.NewHexLiteral(str)
  254. if err != nil {
  255. l.AppendError(l.Errorf("hex literal: %v", err))
  256. return int(unicode.ReplacementChar)
  257. }
  258. lval.item = h
  259. return hexLit
  260. }
  261. // See https://dev.mysql.com/doc/refman/5.7/en/bit-type.html
  262. func toBit(l yyLexer, lval *yySymType, str string) int {
  263. b, err := ast.NewBitLiteral(str)
  264. if err != nil {
  265. l.AppendError(l.Errorf("bit literal: %v", err))
  266. return int(unicode.ReplacementChar)
  267. }
  268. lval.item = b
  269. return bitLit
  270. }
  271. func getUint64FromNUM(num interface{}) uint64 {
  272. switch v := num.(type) {
  273. case int64:
  274. return uint64(v)
  275. case uint64:
  276. return v
  277. }
  278. return 0
  279. }
  280. func getInt64FromNUM(num interface{}) (val int64, errMsg string) {
  281. switch v := num.(type) {
  282. case int64:
  283. return v, ""
  284. }
  285. return -1, fmt.Sprintf("%d is out of range [–9223372036854775808,9223372036854775807]", num)
  286. }
  287. // convertToRole tries to convert elements of roleOrPrivList to RoleIdentity
  288. func convertToRole(roleOrPrivList []*ast.RoleOrPriv) ([]*auth.RoleIdentity, error) {
  289. var roles []*auth.RoleIdentity
  290. for _, elem := range roleOrPrivList {
  291. role, err := elem.ToRole()
  292. if err != nil {
  293. return nil, err
  294. }
  295. roles = append(roles, role)
  296. }
  297. return roles, nil
  298. }
  299. // convertToPriv tries to convert elements of roleOrPrivList to PrivElem
  300. func convertToPriv(roleOrPrivList []*ast.RoleOrPriv) ([]*ast.PrivElem, error) {
  301. var privileges []*ast.PrivElem
  302. for _, elem := range roleOrPrivList {
  303. priv, err := elem.ToPriv()
  304. if err != nil {
  305. return nil, err
  306. }
  307. privileges = append(privileges, priv)
  308. }
  309. return privileges, nil
  310. }