diff --git a/sql/parser.go b/sql/parser.go new file mode 100644 index 00000000..abe561c2 --- /dev/null +++ b/sql/parser.go @@ -0,0 +1,58 @@ +package sql + +import ( + "bufio" + "io" +) + +// Scanner represents a SQL statement scanner. +type Scanner struct { + r *bufio.Reader + c []rune +} + +// NewScanner returns a new instance of Scanner. +func NewScanner(r io.Reader) *Scanner { + return &Scanner{ + r: bufio.NewReader(r), + c: make([]rune, 0), + } +} + +// read reads the next rune from the bufferred reader. +// Returns the rune(0) if an error occurs (or io.EOF is returned). +func (s *Scanner) read() rune { + ch, _, err := s.r.ReadRune() + if err != nil { + return eof + } + return ch +} + +// Scan returns the next SQL statement. +func (s *Scanner) Scan() string { + for { + if ch := s.read(); ch == eof { + break + } else if ch == '\'' { + // Check for ' in c + } else if !isLetter(ch) && !isDigit(ch) && ch != '_' { + s.unread() + break + } else { + _, _ = buf.WriteRune(ch) + } + } +} + +// isWhitespace returns true if the rune is a space, tab, or newline. +func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\n' } + +// isLetter returns true if the rune is a letter. +func isLetter(ch rune) bool { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') } + +// isDigit returns true if the rune is a digit. +func isDigit(ch rune) bool { return (ch >= '0' && ch <= '9') } + +// eof represents a marker rune for the end of the reader. +var eof = rune(0) diff --git a/sql/parser_test.go b/sql/parser_test.go new file mode 100644 index 00000000..d92ffd14 --- /dev/null +++ b/sql/parser_test.go @@ -0,0 +1,12 @@ +package sql + +import ( + "testing" +) + +func Test_ScannerNew(t *testing.T) { + s := NewScanner(nil) + if s == nil { + t.Fatalf("failed to create basic Scanner") + } +}