## Lexer ``` // Returns a tokenised string analyse(statement string) ``` ### Tokens ``` SELECT * FROM mydatabase.people [(keyword, SELECT), (operator, *), (keyword FROM), (table_reference mydatabase.people)] SHOW TABLE FROM mydatabase.people # this table should probably be removed [(keyword, SHOW), (keyword, TABLE), (keyword FROM), (table_reference mydatabase.people), (comment, #), (comment_string, "this table should ...")] ``` ``` keyword: [SELECT, FROM, WHERE, LIMIT, LEFT, RIGHT, OUTER, INNER, JOIN] operator: [*, +, -, /] comment: [#, --] separator: [ ] ``` ## Ramblings & Ideas - Write it in go? - Maybe rename `table_reference` to `literal`? - We can use regex for most of the tokenizing. - Split on whitespace (spaces, tabs, newlines) for the tokenizer ### Interface - Should be able to read from a file, or stdin (or a string?) **file** ``` mysql-go myfile.sql ``` **stdin** ``` echo "SELECT * FROM 5 WHERE l" | mysql-go ``` **string(?)** ``` mysql-go "SELECT * FROM 5 WHERE l" ``` ### Warnings & Messages - All of them should have line number and column number **Missing semicolon** ``` SELECT * FROM address WHERE 6:14 Missing semicolon ``` **No condition in a where clause** ``` SELECT * FROM address WHERE 6:14 No condition in where clause ``` **No where clause in DELETE/UPDATE (destructive operation)** ``` DELETE FROM address 8:13 DELETE/UPDATE has no WHERE, is that what you want? ``` **Database doesn't exist** Works on SELECT, INSERT, UPDATE etc... ``` SELECT `address_line_1` FROM `some_database`.address 9:15 database `some_database` does not exist ``` **Table doesn't exist** Works on SELECT, INSERT, UPDATE etc.. ``` SELECT `address_line_1` FROM some_table 9:15 table `some_table` does not exist ``` **Column doesn't exist** Works on SELECT, INSERT, UPDATE etc... ``` SELECT `non_existent_column` FROM address 9:15 column `non_existent_column` does not exist in table `address` ``` ``` INSERT INTO address (`non_existent_column`) VALUES (3) 9:15 column `non_existent_column` does not exist in table `address` ``` etc... **Trailing comma** ``` UPDATE price_band SET band_1_modifier = 0.95, default_band_2_modifier = 0.85, WHERE id = 43;"; 12:43 Trailing comma after column `default_band_2_modifier` ``` **Bring back MySQL errors too** If MySQL brings back any errors, then we should too. ### Formatter? Maybe create a formatter too. Should accept, file, string or stdin. `mysql-go format file.sql` ### Structure main.go Lexer.go Parser.go warnings/ interface.go non-existent-table.go non-existent-column.go etc... Parser should contain an array of checks to go through, all checks should follow an interface. each check should have a `parse()` method which takes a string, the SQL statement. #### Error struct ``` { column int line int message string } ``` #### Example (kinda) ``` package main import "fmt" type Checker interface { Check() int } type CheckError struct { line int column int message string } type MissingColumn struct { SqlQuery string } type MissingTable struct { SqlQuery string } func (mc MissingColumn) Check() int { return 1 } func (mt MissingTable) Check() int { return 2 } func main() { a := MissingColumn{"SELECT * FROM SOMETHING"} b := MissingTable{"SELECT * FROM SOMETHING"} checks := []Checker{a ,b} for _, check := range checks { fmt.Println(check.Check()) } } ``` ## References https://dev.mysql.com/doc/refman/8.0/en/sql-syntax.html