in sqlutil/scanner.go [62:172]
func (s *Scanner) scan() Token {
r, ok := s.next()
if !ok {
return eof
}
for unicode.IsSpace(r) {
if r, ok = s.next(); !ok {
return eof
}
}
s.start = s.pos - utf8.RuneLen(r)
if r == '_' || unicode.IsLetter(r) {
return s.scanKeywordOrIdentifier(r != '_')
} else if unicode.IsDigit(r) {
return s.scanNumericLiteral()
}
switch r {
case '\'':
// Standard string literal.
return s.scanStringLiteral()
case '"':
// Standard double-quoted identifier.
//
// NOTE(axw) MySQL will treat " as a
// string literal delimiter by default,
// but we assume standard SQL and treat
// it as a identifier delimiter.
return s.scanQuotedIdentifier('"')
case '[':
// T-SQL bracket-quoted identifier.
return s.scanQuotedIdentifier(']')
case '`':
// MySQL-style backtick-quoted identifier.
return s.scanQuotedIdentifier('`')
case '(':
return LPAREN
case ')':
return RPAREN
case '-':
if next, ok := s.peek(); ok && next == '-' {
// -- comment
s.next()
return s.scanSimpleComment()
}
return OTHER
case '/':
if next, ok := s.peek(); ok {
switch next {
case '*':
// /* comment */
s.next()
return s.scanBracketedComment()
case '/':
// // comment
s.next()
return s.scanSimpleComment()
}
}
return OTHER
case '.':
return PERIOD
case '$':
next, ok := s.peek()
if !ok {
break
}
if unicode.IsDigit(next) {
// This is a variable like "$1".
for {
if next, ok := s.peek(); !ok || !unicode.IsDigit(next) {
break
}
s.next()
}
return OTHER
} else if next == '$' || next == '_' || unicode.IsLetter(next) {
// PostgreSQL supports dollar-quoted string literal syntax,
// like $foo$...$foo$. The tag (foo in this case) is optional,
// and if present follows identifier rules.
for {
r, ok := s.next()
if !ok {
// Unknown token starting with $ until
// EOF, just ignore it.
return OTHER
}
switch {
case r == '$':
// This marks the end of the initial $foo$.
tag := s.Text()
if i := strings.Index(s.input[s.pos:], tag); i >= 0 {
s.end += i + len(tag)
s.pos += i + len(tag)
return STRING
}
case unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_':
// Identifier rune, consume.
case unicode.IsSpace(r):
// Unknown token starting with $,
// consume runes until space.
s.end -= utf8.RuneLen(r)
return OTHER
}
}
}
return OTHER
}
return OTHER
}