@@ -20,47 +20,79 @@ import (
2020 "unicode"
2121)
2222
23+ // parserState defines the state of the SQL parser's state machine.
2324type parserState int
2425
2526const (
2627 stateNormal parserState = iota
28+ // String states
2729 stateInSingleQuoteString
2830 stateInDoubleQuoteString
2931 stateInTripleSingleQuoteString
3032 stateInTripleDoubleQuoteString
31- stateInSingleLineCommentDash
32- stateInSingleLineCommentHash
33- stateInMultiLineComment
3433 stateInRawSingleQuoteString
3534 stateInRawDoubleQuoteString
3635 stateInRawTripleSingleQuoteString
3736 stateInRawTripleDoubleQuoteString
37+ // Comment states
38+ stateInSingleLineCommentDash
39+ stateInSingleLineCommentHash
40+ stateInMultiLineComment
41+ )
42+
43+ // SQL statement verbs
44+ const (
45+ verbCreate = "create"
46+ verbAlter = "alter"
47+ verbDrop = "drop"
48+ verbSelect = "select"
49+ verbInsert = "insert"
50+ verbUpdate = "update"
51+ verbDelete = "delete"
52+ verbMerge = "merge"
3853)
3954
4055var tableFollowsKeywords = map [string ]bool {
4156 "from" : true ,
4257 "join" : true ,
43- "into" : true ,
58+ "into" : true , // INSERT INTO, MERGE INTO
4459 "update" : true ,
45- "table" : true ,
46- "using" : true ,
47- "insert" : true ,
48- "merge" : true ,
60+ "table" : true , // CREATE TABLE, ALTER TABLE
61+ "using" : true , // MERGE ... USING
62+ "insert" : true , // INSERT my_table
63+ "merge" : true , // MERGE my_table
4964}
5065
5166var tableContextExitKeywords = map [string ]bool {
5267 "where" : true ,
53- "group" : true ,
54- "order" : true ,
68+ "group" : true , // GROUP BY
69+ "order" : true , // ORDER BY
5570 "having" : true ,
5671 "limit" : true ,
5772 "window" : true ,
5873 "union" : true ,
5974 "intersect" : true ,
6075 "except" : true ,
61- "on" : true ,
62- "set" : true ,
63- "when" : true ,
76+ "on" : true , // JOIN ... ON
77+ "set" : true , // UPDATE ... SET
78+ "when" : true , // MERGE ... WHEN
79+ }
80+
81+ var sqlStatementVerbs = map [string ]bool {
82+ verbCreate : true ,
83+ verbAlter : true ,
84+ verbDrop : true ,
85+ verbSelect : true ,
86+ verbInsert : true ,
87+ verbUpdate : true ,
88+ verbDelete : true ,
89+ verbMerge : true ,
90+ }
91+
92+ var schemaOperationVerbs = map [string ]bool {
93+ verbCreate : true ,
94+ verbAlter : true ,
95+ verbDrop : true ,
6496}
6597
6698// hasPrefix checks if the runes starting at offset match the given prefix.
@@ -270,7 +302,7 @@ func parseSQL(sql, defaultProjectID string, tableIDSet map[string]struct{}, visi
270302 if keyword == "call" {
271303 return 0 , fmt .Errorf ("CALL is not allowed when dataset restrictions are in place" )
272304 }
273- if ( statementVerb == "create" || statementVerb == "alter" || statementVerb == "drop" ) &&
305+ if schemaOperationVerbs [ statementVerb ] &&
274306 (keyword == "schema" || keyword == "dataset" ) {
275307 return 0 , fmt .Errorf ("dataset-level operations like '%s %s' are not allowed" , strings .ToUpper (statementVerb ), strings .ToUpper (keyword ))
276308 }
@@ -364,7 +396,7 @@ func parseSQL(sql, defaultProjectID string, tableIDSet map[string]struct{}, visi
364396 lastToken = keyword
365397 }
366398 // Also track statement verb for schema checks
367- if keyword == "select" || keyword == "insert" || keyword == "update" || keyword == "delete" || keyword == "merge" || keyword == "create" || keyword == "alter" || keyword == "drop" {
399+ if sqlStatementVerbs [ keyword ] {
368400 if statementVerb == "" || statementVerb == "with" {
369401 statementVerb = keyword
370402 }
0 commit comments