Skip to content

Commit 97e879b

Browse files
committed
parse error on invalid SQL
1 parent a457ad8 commit 97e879b

3 files changed

Lines changed: 113 additions & 85 deletions

File tree

lib/sql-parser/parser.rex

Lines changed: 53 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,64 +16,70 @@ macro
1616
IDENT \w+
1717

1818
rule
19-
# [:state] pattern [actions]
19+
# [:state] pattern [actions]
2020

2121
# literals
22-
\"{DATE}\" { [:date_string, Date.parse(text)] }
23-
\'{DATE}\' { [:date_string, Date.parse(text)] }
22+
\"{DATE}\" { [:date_string, Date.parse(text)] }
23+
\'{DATE}\' { [:date_string, Date.parse(text)] }
2424

25-
\' { @state = :STRS; [:quote, text] }
26-
:STRS \' { @state = nil; [:quote, text] }
25+
\' { @state = :STRS; [:quote, text] }
26+
:STRS \' { @state = nil; [:quote, text] }
2727
:STRS ([^\\']|\\.|'')* { [:character_string_literal, text.gsub(/''|\\'/, "'").gsub(/""|\\"/, '"')] }
2828
29-
\" { @state = :STRD; [:quote, text] }
30-
:STRD \" { @state = nil; [:quote, text] }
29+
\" { @state = :STRD; [:quote, text] }
30+
:STRD \" { @state = nil; [:quote, text] }
3131
:STRD ([^\\"]|\\.|"")* { [:character_string_literal, text.gsub(/''|\\'/, "'").gsub(/""|\\"/, '"')] }
3232
33-
{UINT} { [:unsigned_integer, text.to_i] }
33+
{UINT} { [:unsigned_integer, text.to_i] }
3434
3535
# skip
36-
{BLANK} # no action
36+
{BLANK} # no action
3737
3838
# keywords
39-
SELECT { [:SELECT, text] }
40-
DATE { [:DATE, text] }
41-
ASC { [:ASC, text] }
42-
AS { [:AS, text] }
43-
FROM { [:FROM, text] }
44-
WHERE { [:WHERE, text] }
45-
BETWEEN { [:BETWEEN, text] }
46-
AND { [:AND, text] }
47-
NOT { [:NOT, text] }
48-
INNER { [:INNER, text] }
49-
INSERT { [:INSERT, text] }
50-
INTO { [:INTO, text] }
51-
IN { [:IN, text] }
52-
ORDER { [:ORDER, text] }
53-
OR { [:OR, text] }
54-
LIKE { [:LIKE, text] }
55-
IS { [:IS, text] }
56-
NULL { [:NULL, text] }
57-
COUNT { [:COUNT, text] }
58-
AVG { [:AVG, text] }
59-
MAX { [:MAX, text] }
60-
MIN { [:MIN, text] }
61-
SUM { [:SUM, text] }
62-
GROUP { [:GROUP, text] }
63-
BY { [:BY, text] }
64-
HAVING { [:HAVING, text] }
65-
CROSS { [:CROSS, text] }
66-
JOIN { [:JOIN, text] }
67-
ON { [:ON, text] }
68-
LEFT { [:LEFT, text] }
69-
OUTER { [:OUTER, text] }
70-
RIGHT { [:RIGHT, text] }
71-
FULL { [:FULL, text] }
72-
USING { [:USING, text] }
73-
EXISTS { [:EXISTS, text] }
74-
DESC { [:DESC, text] }
75-
CURRENT_USER { [:CURRENT_USER, text] }
76-
VALUES { [:VALUES, text] }
39+
SELECT(?!\w) { [:SELECT, text] }
40+
DATE(?!\w) { [:DATE, text] }
41+
ASC(?!\w) { [:ASC, text] }
42+
AS(?!\w) { [:AS, text] }
43+
FROM(?!\w) { [:FROM, text] }
44+
WHERE(?!\w) { [:WHERE, text] }
45+
BETWEEN(?!\w) { [:BETWEEN, text] }
46+
AND(?!\w) { [:AND, text] }
47+
NOT(?!\w) { [:NOT, text] }
48+
INNER(?!\w) { [:INNER, text] }
49+
INSERT(?!\w) { [:INSERT, text] }
50+
INTO(?!\w) { [:INTO, text] }
51+
IN(?!\w) { [:IN, text] }
52+
ORDER(?!\w) { [:ORDER, text] }
53+
OR(?!\w) { [:OR, text] }
54+
LIKE(?!\w) { [:LIKE, text] }
55+
IS(?!\w) { [:IS, text] }
56+
NULL(?!\w) { [:NULL, text] }
57+
COUNT(?!\w) { [:COUNT, text] }
58+
AVG(?!\w) { [:AVG, text] }
59+
MAX(?!\w) { [:MAX, text] }
60+
MIN(?!\w) { [:MIN, text] }
61+
SUM(?!\w) { [:SUM, text] }
62+
GROUP(?!\w) { [:GROUP, text] }
63+
BY(?!\w) { [:BY, text] }
64+
HAVING(?!\w) { [:HAVING, text] }
65+
CROSS(?!\w) { [:CROSS, text] }
66+
JOIN(?!\w) { [:JOIN, text] }
67+
ON(?!\w) { [:ON, text] }
68+
LEFT(?!\w) { [:LEFT, text] }
69+
OUTER(?!\w) { [:OUTER, text] }
70+
RIGHT(?!\w) { [:RIGHT, text] }
71+
FULL(?!\w) { [:FULL, text] }
72+
USING(?!\w) { [:USING, text] }
73+
EXISTS(?!\w) { [:EXISTS, text] }
74+
DESC(?!\w) { [:DESC, text] }
75+
CURRENT_USER(?!\w) { [:CURRENT_USER, text] }
76+
VALUES(?!\w) { [:VALUES, text] }
77+
FOR(?!\w) { [:FOR, text] }
78+
UPDATE(?!\w) { [:UPDATE, text] }
79+
DELETE(?!\w) { [:DELETE, text] }
80+
SET(?!\w) { [:SET, text] }
81+
DISTINCT(?!\w) { [:DISTINCT, text] }
82+
COALESCE(?!\w) { [:COALESCE, text] }
7783
7884
# tokens
7985
E { [:E, text] }

lib/sql-parser/parser.rex.rb

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -75,120 +75,138 @@ def _next_token
7575
when (text = @ss.scan(/\s+/i))
7676
;
7777

78-
when (text = @ss.scan(/SELECT/i))
78+
when (text = @ss.scan(/SELECT(?!\w)/i))
7979
action { [:SELECT, text] }
8080

81-
when (text = @ss.scan(/DATE/i))
81+
when (text = @ss.scan(/DATE(?!\w)/i))
8282
action { [:DATE, text] }
8383

84-
when (text = @ss.scan(/ASC/i))
84+
when (text = @ss.scan(/ASC(?!\w)/i))
8585
action { [:ASC, text] }
8686

87-
when (text = @ss.scan(/AS/i))
87+
when (text = @ss.scan(/AS(?!\w)/i))
8888
action { [:AS, text] }
8989

90-
when (text = @ss.scan(/FROM/i))
90+
when (text = @ss.scan(/FROM(?!\w)/i))
9191
action { [:FROM, text] }
9292

93-
when (text = @ss.scan(/WHERE/i))
93+
when (text = @ss.scan(/WHERE(?!\w)/i))
9494
action { [:WHERE, text] }
9595

96-
when (text = @ss.scan(/BETWEEN/i))
96+
when (text = @ss.scan(/BETWEEN(?!\w)/i))
9797
action { [:BETWEEN, text] }
9898

99-
when (text = @ss.scan(/AND/i))
99+
when (text = @ss.scan(/AND(?!\w)/i))
100100
action { [:AND, text] }
101101

102-
when (text = @ss.scan(/NOT/i))
102+
when (text = @ss.scan(/NOT(?!\w)/i))
103103
action { [:NOT, text] }
104104

105-
when (text = @ss.scan(/INNER/i))
105+
when (text = @ss.scan(/INNER(?!\w)/i))
106106
action { [:INNER, text] }
107107

108-
when (text = @ss.scan(/INSERT/i))
108+
when (text = @ss.scan(/INSERT(?!\w)/i))
109109
action { [:INSERT, text] }
110110

111-
when (text = @ss.scan(/INTO/i))
111+
when (text = @ss.scan(/INTO(?!\w)/i))
112112
action { [:INTO, text] }
113113

114-
when (text = @ss.scan(/IN/i))
114+
when (text = @ss.scan(/IN(?!\w)/i))
115115
action { [:IN, text] }
116116

117-
when (text = @ss.scan(/ORDER/i))
117+
when (text = @ss.scan(/ORDER(?!\w)/i))
118118
action { [:ORDER, text] }
119119

120-
when (text = @ss.scan(/OR/i))
120+
when (text = @ss.scan(/OR(?!\w)/i))
121121
action { [:OR, text] }
122122

123-
when (text = @ss.scan(/LIKE/i))
123+
when (text = @ss.scan(/LIKE(?!\w)/i))
124124
action { [:LIKE, text] }
125125

126-
when (text = @ss.scan(/IS/i))
126+
when (text = @ss.scan(/IS(?!\w)/i))
127127
action { [:IS, text] }
128128

129-
when (text = @ss.scan(/NULL/i))
129+
when (text = @ss.scan(/NULL(?!\w)/i))
130130
action { [:NULL, text] }
131131

132-
when (text = @ss.scan(/COUNT/i))
132+
when (text = @ss.scan(/COUNT(?!\w)/i))
133133
action { [:COUNT, text] }
134134

135-
when (text = @ss.scan(/AVG/i))
135+
when (text = @ss.scan(/AVG(?!\w)/i))
136136
action { [:AVG, text] }
137137

138-
when (text = @ss.scan(/MAX/i))
138+
when (text = @ss.scan(/MAX(?!\w)/i))
139139
action { [:MAX, text] }
140140

141-
when (text = @ss.scan(/MIN/i))
141+
when (text = @ss.scan(/MIN(?!\w)/i))
142142
action { [:MIN, text] }
143143

144-
when (text = @ss.scan(/SUM/i))
144+
when (text = @ss.scan(/SUM(?!\w)/i))
145145
action { [:SUM, text] }
146146

147-
when (text = @ss.scan(/GROUP/i))
147+
when (text = @ss.scan(/GROUP(?!\w)/i))
148148
action { [:GROUP, text] }
149149

150-
when (text = @ss.scan(/BY/i))
150+
when (text = @ss.scan(/BY(?!\w)/i))
151151
action { [:BY, text] }
152152

153-
when (text = @ss.scan(/HAVING/i))
153+
when (text = @ss.scan(/HAVING(?!\w)/i))
154154
action { [:HAVING, text] }
155155

156-
when (text = @ss.scan(/CROSS/i))
156+
when (text = @ss.scan(/CROSS(?!\w)/i))
157157
action { [:CROSS, text] }
158158

159-
when (text = @ss.scan(/JOIN/i))
159+
when (text = @ss.scan(/JOIN(?!\w)/i))
160160
action { [:JOIN, text] }
161161

162-
when (text = @ss.scan(/ON/i))
162+
when (text = @ss.scan(/ON(?!\w)/i))
163163
action { [:ON, text] }
164164

165-
when (text = @ss.scan(/LEFT/i))
165+
when (text = @ss.scan(/LEFT(?!\w)/i))
166166
action { [:LEFT, text] }
167167

168-
when (text = @ss.scan(/OUTER/i))
168+
when (text = @ss.scan(/OUTER(?!\w)/i))
169169
action { [:OUTER, text] }
170170

171-
when (text = @ss.scan(/RIGHT/i))
171+
when (text = @ss.scan(/RIGHT(?!\w)/i))
172172
action { [:RIGHT, text] }
173173

174-
when (text = @ss.scan(/FULL/i))
174+
when (text = @ss.scan(/FULL(?!\w)/i))
175175
action { [:FULL, text] }
176176

177-
when (text = @ss.scan(/USING/i))
177+
when (text = @ss.scan(/USING(?!\w)/i))
178178
action { [:USING, text] }
179179

180-
when (text = @ss.scan(/EXISTS/i))
180+
when (text = @ss.scan(/EXISTS(?!\w)/i))
181181
action { [:EXISTS, text] }
182182

183-
when (text = @ss.scan(/DESC/i))
183+
when (text = @ss.scan(/DESC(?!\w)/i))
184184
action { [:DESC, text] }
185185

186-
when (text = @ss.scan(/CURRENT_USER/i))
186+
when (text = @ss.scan(/CURRENT_USER(?!\w)/i))
187187
action { [:CURRENT_USER, text] }
188188

189-
when (text = @ss.scan(/VALUES/i))
189+
when (text = @ss.scan(/VALUES(?!\w)/i))
190190
action { [:VALUES, text] }
191191

192+
when (text = @ss.scan(/FOR(?!\w)/i))
193+
action { [:FOR, text] }
194+
195+
when (text = @ss.scan(/UPDATE(?!\w)/i))
196+
action { [:UPDATE, text] }
197+
198+
when (text = @ss.scan(/DELETE(?!\w)/i))
199+
action { [:DELETE, text] }
200+
201+
when (text = @ss.scan(/SET(?!\w)/i))
202+
action { [:SET, text] }
203+
204+
when (text = @ss.scan(/DISTINCT(?!\w)/i))
205+
action { [:DISTINCT, text] }
206+
207+
when (text = @ss.scan(/COALESCE(?!\w)/i))
208+
action { [:COALESCE, text] }
209+
192210
when (text = @ss.scan(/E/i))
193211
action { [:E, text] }
194212

test/test_parser.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,10 @@ def test_unsigned_integer
368368
assert_understands 'SELECT 10'
369369
end
370370

371+
def test_invalid
372+
assert_raise(Racc::ParseError) { SQLParser::Parser.parse('SELECT1') }
373+
end
374+
371375
private
372376

373377
def assert_sql(expected, given)

0 commit comments

Comments
 (0)