Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ParserTest.java
Go to the documentation of this file.
1 // Copyright 2013 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.cloudera.impala.analysis;
16 
17 import static org.junit.Assert.assertEquals;
18 import static org.junit.Assert.assertNotNull;
19 import static org.junit.Assert.assertTrue;
20 import static org.junit.Assert.fail;
21 
22 import java.io.StringReader;
23 import java.math.BigInteger;
24 import java.util.ArrayList;
25 import java.util.List;
26 
27 import org.junit.Test;
28 
31 import com.google.common.base.Preconditions;
32 import com.google.common.collect.Lists;
33 
34 public class ParserTest {
35 
36  // Representative operands for testing.
37  private final static String[] operands_ =
38  new String[] {"i", "5", "true", "NULL", "'a'", "(1.5 * 8)" };
39 
43  public Object ParsesOk(String stmt) {
44  SqlScanner input = new SqlScanner(new StringReader(stmt));
45  SqlParser parser = new SqlParser(input);
46  Object result = null;
47  try {
48  result = parser.parse().value;
49  } catch (Exception e) {
50  System.err.println(parser.getErrorMsg(stmt));
51  e.printStackTrace();
52  fail("\n" + parser.getErrorMsg(stmt));
53  }
54  assertNotNull(result);
55  return result;
56  }
57 
62  public <C extends Expr> Object ParsesOk(String selectStmtSql, Class<C> cl) {
63  Object parseNode = ParsesOk(selectStmtSql);
64  if (!(parseNode instanceof SelectStmt)) {
65  fail(String.format("Statement parsed ok but it is not a select stmt: %s",
66  selectStmtSql));
67  }
68  SelectStmt selectStmt = (SelectStmt) parseNode;
69  Expr firstExpr = selectStmt.getSelectList().getItems().get(0).getExpr();
70  // Check the class of the first select-list expression.
71  assertTrue(String.format(
72  "Expression is of class '%s'. Expected class '%s'",
73  firstExpr.getClass().getSimpleName(), cl.getSimpleName()),
74  firstExpr.getClass().equals(cl));
75  return parseNode;
76  }
77 
81  public void ParserError(String stmt, String expectedErrorString) {
82  SqlScanner input = new SqlScanner(new StringReader(stmt));
83  SqlParser parser = new SqlParser(input);
84  Object result = null; // Save this object to make debugging easier
85  try {
86  result = parser.parse().value;
87  } catch (Exception e) {
88  if (expectedErrorString != null) {
89  String errorString = parser.getErrorMsg(stmt);
90  assertTrue(errorString.startsWith(expectedErrorString));
91  }
92  return;
93  }
94  fail("Stmt didn't result in parsing error: " + stmt);
95  }
96 
101  public void ParserError(String stmt) {
102  ParserError(stmt, null);
103  }
104 
105  @Test
106  public void TestNoFromClause() {
107  ParsesOk("select 1 + 1, 'two', f(3), a + b");
108  ParserError("select 1 + 1 'two' f(3) a + b");
109  ParserError("select a, 2 where a > 2");
110  ParserError("select a, 2 group by");
111  ParserError("select a, 2 order by 1");
112  ParserError("select a, 2 limit 1");
113  ParserError("select a, 2 order by 1 limit 1");
114  }
115 
116  @Test
117  public void TestSelect() {
118  ParsesOk("select a from tbl");
119  ParsesOk("select a, b, c, d from tbl");
120  ParsesOk("select true, false, NULL from tbl");
121  ParsesOk("select all a, b, c from tbl");
122  ParserError("a from tbl");
123  ParserError("select a b c from tbl");
124  ParserError("select all from tbl");
125  }
126 
131  @Test
132  public void TestAlias() {
133  char[] quotes = {'\'', '"', '`', ' '};
134  for (int i = 0; i < quotes.length; ++i) {
135  char quote = quotes[i];
136  // Column aliases.
137  ParsesOk("select a 'b' from tbl".replace('\'', quote));
138  ParsesOk("select a as 'b' from tbl".replace('\'', quote));
139  ParsesOk("select a 'x', b as 'y', c 'z' from tbl".replace('\'', quote));
140  ParsesOk(
141  "select a 'x', b as 'y', sum(x) over () 'z' from tbl".replace('\'', quote));
142  ParsesOk("select a.b 'x' from tbl".replace('\'', quote));
143  ParsesOk("select a.b as 'x' from tbl".replace('\'', quote));
144  ParsesOk("select a.b.c.d 'x' from tbl".replace('\'', quote));
145  ParsesOk("select a.b.c.d as 'x' from tbl".replace('\'', quote));
146  // Table aliases.
147  ParsesOk("select a from tbl 'b'".replace('\'', quote));
148  ParsesOk("select a from tbl as 'b'".replace('\'', quote));
149  ParsesOk("select a from db.tbl 'b'".replace('\'', quote));
150  ParsesOk("select a from db.tbl as 'b'".replace('\'', quote));
151  ParsesOk("select a from db.tbl.col 'b'".replace('\'', quote));
152  ParsesOk("select a from db.tbl.col as 'b'".replace('\'', quote));
153  ParsesOk("select a from (select * from tbl) 'b'".replace('\'', quote));
154  ParsesOk("select a from (select * from tbl) as 'b'".replace('\'', quote));
155  ParsesOk("select a from (select * from tbl b) as 'b'".replace('\'', quote));
156  // With-clause view aliases.
157  ParsesOk("with 't' as (select 1) select * from t".replace('\'', quote));
158  }
159  ParserError("a from tbl");
160  ParserError("select a as a, b c d from tbl");
161  }
162 
163  @Test
164  public void TestStar() {
165  ParsesOk("select * from tbl");
166  ParsesOk("select tbl.* from tbl");
167  ParsesOk("select db.tbl.* from tbl");
168  ParsesOk("select db.tbl.struct_col.* from tbl");
169  ParserError("select * + 5 from tbl");
170  ParserError("select (*) from tbl");
171  ParserError("select *.id from tbl");
172  ParserError("select * from tbl.*");
173  ParserError("select * from tbl where * = 5");
174  ParsesOk("select * from tbl where f(*) = 5");
175  ParserError("select * from tbl where tbl.* = 5");
176  ParserError("select * from tbl where f(tbl.*) = 5");
177  }
178 
182  @Test
183  public void TestMultilineComment() {
184  ParserError("/**/");
185  ParserError("/*****/");
186  ParserError("/* select 1 */");
187  ParserError("/*/ select 1");
188  ParserError("select 1 /*/");
189  ParsesOk("/**/select 1");
190  ParsesOk("select/* */1");
191  ParsesOk("/** */ select 1");
192  ParsesOk("select 1/* **/");
193  ParsesOk("/*/*/select 1");
194  ParsesOk("/*//*/select 1");
195  ParsesOk("select 1/***/");
196  ParsesOk("/*****/select 1");
197  ParsesOk("/**//**/select 1");
198  ParserError("/**/**/select 1");
199  ParsesOk("\nselect 1/**/");
200  ParsesOk("/*\n*/select 1");
201  ParsesOk("/*\r*/select 1");
202  ParsesOk("/*\r\n*/select 1");
203  ParsesOk("/**\n* Doc style\n*/select 1");
204  ParsesOk("/************\n*\n* Header style\n*\n***********/select 1");
205  ParsesOk("/* 1 */ select 1 /* 2 */");
206  ParsesOk("select\n/**/\n1");
207  ParserError("/**// select 1");
208  ParserError("/**/*/ select 1");
209  ParserError("/ **/ select 1");
210  ParserError("/** / select 1");
211  ParserError("/\n**/ select 1");
212  ParserError("/**\n/ select 1");
213  ParsesOk("/*--*/ select 1");
214  ParsesOk("/* --foo */ select 1");
215  ParsesOk("/*\n--foo */ select 1");
216  ParsesOk("/*\n--foo\n*/ select 1");
217  ParserError("select 1 /* --bar");
218  ParserError("select 1 /*--");
219  ParsesOk("/* select 1; */ select 1");
220  ParsesOk("/** select 1; */ select 1");
221  ParsesOk("/* select */ select 1 /* 1 */");
222  }
223 
227  @Test
228  public void TestSinglelineComment() {
229  ParserError("--");
230  ParserError("--select 1");
231  ParsesOk("select 1--");
232  ParsesOk("select 1 --foo");
233  ParsesOk("select 1 --\ncol_name");
234  ParsesOk("--foo\nselect 1 --bar");
235  ParsesOk("--foo\r\nselect 1 --bar");
236  ParsesOk("--/* foo */\n select 1");
237  ParsesOk("select 1 --/**/");
238  ParsesOk("-- foo /*\nselect 1");
239  ParserError("-- baz /*\nselect 1*/");
240  ParsesOk("select -- blah\n 1");
241  ParsesOk("select -- select 1\n 1");
242  }
243 
249  private void TestJoinHints(String stmt, String... expectedHints) {
250  SelectStmt selectStmt = (SelectStmt) ParsesOk(stmt);
251  Preconditions.checkState(selectStmt.getTableRefs().size() > 1);
252  List<String> actualHints = Lists.newArrayList();
253  assertEquals(null, selectStmt.getTableRefs().get(0).getJoinHints());
254  for (int i = 1; i < selectStmt.getTableRefs().size(); ++i) {
255  List<String> hints = selectStmt.getTableRefs().get(i).getJoinHints();
256  if (hints != null) actualHints.addAll(hints);
257  }
258  if (actualHints.isEmpty()) actualHints = Lists.<String>newArrayList((String) null);
259  assertEquals(Lists.newArrayList(expectedHints), actualHints);
260  }
261 
266  private void TestSelectListHints(String stmt, String... expectedHints) {
267  SelectStmt selectStmt = (SelectStmt) ParsesOk(stmt);
268  List<String> actualHints = selectStmt.getSelectList().getPlanHints();
269  if (actualHints == null) actualHints = Lists.<String>newArrayList((String) null);
270  assertEquals(Lists.newArrayList(expectedHints), actualHints);
271  }
272 
276  private void TestInsertHints(String stmt, String... expectedHints) {
277  InsertStmt insertStmt = (InsertStmt) ParsesOk(stmt);
278  List<String> actualHints = insertStmt.getPlanHints();
279  if (actualHints == null) actualHints = Lists.<String>newArrayList((String) null);
280  assertEquals(Lists.newArrayList(expectedHints), actualHints);
281  }
282 
283  @Test
284  public void TestPlanHints() {
285  // All plan-hint styles embed a comma-separated list of hints.
286  String[][] hintStyles = new String[][] {
287  new String[] { "/* +", "*/" }, // traditional commented hint
288  new String[] { "-- +", "\n" }, // eol commented hint
289  new String[] { "\n-- +", "\n" }, // eol commented hint
290  new String[] { "[", "]" } // legacy style
291  };
292  String[][] commentStyles = new String[][] {
293  new String[] { "/*", "*/" }, // traditional comment
294  new String[] { "--", "\n" } // eol comment
295  };
296  for (String[] hintStyle: hintStyles) {
297  String prefix = hintStyle[0];
298  String suffix = hintStyle[1];
299  // Test join hints.
300  TestJoinHints(String.format(
301  "select * from functional.alltypes a join %sbroadcast%s " +
302  "functional.alltypes b", prefix, suffix), "broadcast");
303  TestJoinHints(String.format(
304  "select * from functional.alltypes a join %sbroadcast%s " +
305  "functional.alltypes b using(id)", prefix, suffix), "broadcast");
306  TestJoinHints(String.format(
307  "select * from functional.alltypes a join %sbroadcast%s " +
308  "functional.alltypes b on(a.id = b.id)", prefix, suffix), "broadcast");
309  TestJoinHints(String.format(
310  "select * from functional.alltypes a cross join %sbroadcast%s " +
311  "functional.alltypes b", prefix, suffix), "broadcast");
312  // Multiple comma-separated hints.
313  TestJoinHints(String.format(
314  "select * from functional.alltypes a join " +
315  "%sbroadcast,shuffle,foo,bar%s " +
316  "functional.alltypes b using(id)", prefix, suffix),
317  "broadcast", "shuffle", "foo", "bar");
318  // Test hints in a multi-way join.
319  TestJoinHints(String.format(
320  "select * from functional.alltypes a " +
321  "join %sbroadcast%s functional.alltypes b using(id) " +
322  "join %sshuffle%s functional.alltypes c using(int_col) " +
323  "join %sbroadcast%s functional.alltypes d using(int_col) " +
324  "join %sshuffle%s functional.alltypes e using(string_col)",
325  prefix, suffix, prefix, suffix, prefix, suffix, prefix, suffix),
326  "broadcast", "shuffle", "broadcast", "shuffle");
327  // Test hints in a multi-way join (flipped prefix/suffix -> bad hint start/ends).
328  ParserError(String.format(
329  "select * from functional.alltypes a " +
330  "join %sbroadcast%s functional.alltypes b using(id) " +
331  "join %sshuffle%s functional.alltypes c using(int_col) " +
332  "join %sbroadcast%s functional.alltypes d using(int_col) " +
333  "join %sshuffle%s functional.alltypes e using(string_col)",
334  prefix, suffix, suffix, prefix, prefix, suffix, suffix, prefix));
335  // Test hints in a multi-way join (missing prefixes/suffixes).
336  ParserError(String.format(
337  "select * from functional.alltypes a " +
338  "join %sbroadcast%s functional.alltypes b using(id) " +
339  "join %sshuffle%s functional.alltypes c using(int_col) " +
340  "join %sbroadcast%s functional.alltypes d using(int_col) " +
341  "join %sshuffle%s functional.alltypes e using(string_col)",
342  suffix, suffix, suffix, suffix, prefix, "", "", ""));
343 
344  // Test insert hints.
345  TestInsertHints(String.format(
346  "insert into t %snoshuffle%s select * from t", prefix, suffix),
347  "noshuffle");
348  TestInsertHints(String.format(
349  "insert overwrite t %snoshuffle%s select * from t", prefix, suffix),
350  "noshuffle");
351  TestInsertHints(String.format(
352  "insert into t partition(x, y) %snoshuffle%s select * from t",
353  prefix, suffix), "noshuffle");
354  TestInsertHints(String.format(
355  "insert into t(a, b) partition(x, y) %sshuffle%s select * from t",
356  prefix, suffix), "shuffle");
357  TestInsertHints(String.format(
358  "insert overwrite t(a, b) partition(x, y) %sfoo,bar,baz%s select * from t",
359  prefix, suffix), "foo", "bar", "baz");
360 
361  // Test select-list hints (e.g., straight_join). The legacy-style hint has no
362  // prefix and suffix.
363  if (prefix.contains("[")) {
364  prefix = "";
365  suffix = "";
366  }
367  TestSelectListHints(String.format(
368  "select %sstraight_join%s * from functional.alltypes a", prefix, suffix),
369  "straight_join");
370  // Only the new hint-style is recognized
371  if (!prefix.equals("")) {
372  TestSelectListHints(String.format(
373  "select %sfoo,bar,baz%s * from functional.alltypes a", prefix, suffix),
374  "foo", "bar", "baz");
375  }
376  if (prefix.isEmpty()) continue;
377 
378  // Test mixing commented hints and comments.
379  for (String[] commentStyle: commentStyles) {
380  String commentPrefix = commentStyle[0];
381  String commentSuffix = commentStyle[1];
382  String queryTemplate =
383  "$1comment$2 select $1comment$2 $3straight_join$4 $1comment$2 * " +
384  "from $1comment$2 functional.alltypes a join $1comment$2 $3shuffle$4 " +
385  "$1comment$2 functional.alltypes b $1comment$2 on $1comment$2 " +
386  "(a.id = b.id)";
387  String query = queryTemplate.replaceAll("\\$1", commentPrefix)
388  .replaceAll("\\$2", commentSuffix).replaceAll("\\$3", prefix)
389  .replaceAll("\\$4", suffix);
390  TestSelectListHints(query, "straight_join");
391  TestJoinHints(query, "shuffle");
392  }
393  }
394  // No "+" at the beginning so the comment is not recognized as a hint.
395  TestJoinHints("select * from functional.alltypes a join /* comment */" +
396  "functional.alltypes b using (int_col)", (String) null);
397  TestSelectListHints("select /* comment */ * from functional.alltypes",
398  (String) null);
399  TestInsertHints("insert into t(a, b) partition(x, y) /* comment */ select 1",
400  (String) null);
401  TestSelectListHints("select /* -- +straight_join */ * from functional.alltypes",
402  (String) null);
403  TestSelectListHints("select /* abcdef +straight_join */ * from functional.alltypes",
404  (String) null);
405  TestSelectListHints("select \n-- abcdef +straight_join\n * from functional.alltypes",
406  (String) null);
407  TestSelectListHints("select \n-- /*+straight_join\n * from functional.alltypes",
408  (String) null);
409 
410  // Commented hints cannot span lines (recognized as comments instead).
411  TestSelectListHints("select /*\n +straight_join */ * from functional.alltypes",
412  (String) null);
413  TestSelectListHints("select /* +straight_join \n*/ * from functional.alltypes",
414  (String) null);
415  TestSelectListHints("select /* +straight_\njoin */ * from functional.alltypes",
416  (String) null);
417  ParserError("select -- +straight_join * from functional.alltypes");
418  ParserError("select \n-- +straight_join * from functional.alltypes");
419 
420  // Missing "/*" or "/*"
421  ParserError("select * from functional.alltypes a join + */" +
422  "functional.alltypes b using (int_col)");
423  ParserError("select * from functional.alltypes a join /* + " +
424  "functional.alltypes b using (int_col)");
425 
426  // Test empty hint tokens.
427  TestSelectListHints("select /* +straight_join, ,, */ * from functional.alltypes",
428  "straight_join");
429  // Traditional commented hints are not parsed inside a comment.
430  ParserError("select /* /* +straight_join */ */ * from functional.alltypes");
431  }
432 
433  @Test
434  public void TestFromClause() {
435  String tblRefs[] = new String[] { "tbl", "db.tbl", "db.tbl.col", "db.tbl.col.fld" };
436  for (String tbl: tblRefs) {
437  ParsesOk(
438  ("select * from $TBL src1 " +
439  "left outer join $TBL src2 on " +
440  " src1.key = src2.key and src1.key < 10 and src2.key > 10 " +
441  "right outer join $TBL src3 on " +
442  " src2.key = src3.key and src3.key < 10 " +
443  "full outer join $TBL src3 on " +
444  " src2.key = src3.key and src3.key < 10 " +
445  "left semi join $TBL src3 on " +
446  " src2.key = src3.key and src3.key < 10 " +
447  "left anti join $TBL src3 on " +
448  " src2.key = src3.key and src3.key < 10 " +
449  "right semi join $TBL src3 on " +
450  " src2.key = src3.key and src3.key < 10 " +
451  "right anti join $TBL src3 on " +
452  " src2.key = src3.key and src3.key < 10 " +
453  "join $TBL src3 on " +
454  " src2.key = src3.key and src3.key < 10 " +
455  "inner join $TBL src3 on " +
456  " src2.key = src3.key and src3.key < 10 ").replace("$TBL", tbl));
457  ParsesOk(
458  ("select * from $TBL src1 " +
459  "left outer join $TBL src2 using (a, b, c) " +
460  "right outer join $TBL src3 using (d, e, f) " +
461  "full outer join $TBL src4 using (d, e, f) " +
462  "left semi join $TBL src5 using (d, e, f) " +
463  "left anti join $TBL src6 using (d, e, f) " +
464  "right semi join $TBL src7 using (d, e, f) " +
465  "right anti join $TBL src8 using (d, e, f) " +
466  "join $TBL src9 using (d, e, f) " +
467  "inner join $TBL src10 using (d, e, f) ").replace("$TBL", tbl));
468 
469  // Test cross joins
470  ParsesOk("select * from $TBL cross join $TBL".replace("$TBL", tbl));
471  }
472 
473  // Test NULLs in on clause.
474  ParsesOk("select * from src src1 " +
475  "left outer join src src2 on NULL " +
476  "right outer join src src3 on (NULL) " +
477  "full outer join src src3 on NULL " +
478  "left semi join src src3 on (NULL) " +
479  "left anti join src src3 on (NULL) " +
480  "right semi join src src3 on (NULL) " +
481  "right anti join src src3 on (NULL) " +
482  "join src src3 on NULL " +
483  "inner join src src3 on (NULL) " +
484  "where src2.bla = src3.bla " +
485  "order by src1.key, src1.value, src2.key, src2.value, src3.key, src3.value");
486  // Arbitrary exprs in on clause parse ok.
487  ParsesOk("select * from src src1 join src src2 on ('a')");
488  ParsesOk("select * from src src1 join src src2 on (f(a, b))");
489  ParserError("select * from src src1 " +
490  "left outer join src src2 on (src1.key = src2.key and)");
491 
492  // Using clause requires SlotRef.
493  ParserError("select * from src src1 join src src2 using (1)");
494  ParserError("select * from src src1 join src src2 using (f(id))");
495  // Using clause required parenthesis.
496  ParserError("select * from src src1 join src src2 using id");
497 
498  // Cross joins do not accept on/using
499  ParserError("select * from a cross join b on (a.id = b.id)");
500  ParserError("select * from a cross join b using (id)");
501  }
502 
503  @Test
504  public void TestWhereClause() {
505  ParsesOk("select a, b from t where a > 15");
506  ParsesOk("select a, b from t where true");
507  ParsesOk("select a, b from t where NULL");
508  // Non-predicate exprs that return boolean.
509  ParsesOk("select a, b from t where case a when b then true else false end");
510  ParsesOk("select a, b from t where if (a > b, true, false)");
511  ParsesOk("select a, b from t where bool_col");
512  // Arbitrary non-predicate exprs parse ok but are semantically incorrect.
513  ParsesOk("select a, b from t where 10.5");
514  ParsesOk("select a, b from t where trim('abc')");
515  ParsesOk("select a, b from t where s + 20");
516  ParserError("select a, b from t where a > 15 from test");
517  ParserError("select a, b where a > 15");
518  ParserError("select where a, b from t");
519  }
520 
521  @Test
522  public void TestGroupBy() {
523  ParsesOk("select a, b, count(c) from test group by 1, 2");
524  ParsesOk("select a, b, count(c) from test group by a, b");
525  ParsesOk("select a, b, count(c) from test group by true, false, NULL");
526  // semantically wrong but parses fine
527  ParsesOk("select a, b, count(c) from test group by 1, b");
528  ParserError("select a, b, count(c) from test group 1, 2");
529  ParserError("select a, b, count(c) from test group by order by a");
530  }
531 
532  @Test
533  public void TestOrderBy() {
534  ParsesOk("select int_col, string_col, bigint_col, count(*) from alltypes " +
535  "order by string_col, 15.7 * float_col, int_col + bigint_col");
536  ParsesOk("select int_col, string_col, bigint_col, count(*) from alltypes " +
537  "order by string_col asc, 15.7 * float_col desc, int_col + bigint_col asc");
538  ParsesOk("select int_col, string_col, bigint_col, count(*) from alltypes " +
539  "order by string_col asc, float_col desc, int_col + bigint_col " +
540  "asc nulls first");
541  ParsesOk("select int_col, string_col, bigint_col, count(*) from alltypes " +
542  "order by string_col asc, float_col desc, int_col + bigint_col " +
543  "desc nulls last");
544  ParsesOk("select int_col, string_col, bigint_col, count(*) from alltypes " +
545  "order by string_col asc, float_col desc, int_col + bigint_col " +
546  "nulls first");
547  ParsesOk("select int_col, string_col, bigint_col, count(*) from alltypes " +
548  "order by string_col asc, float_col desc nulls last, int_col + bigint_col " +
549  "nulls first");
550  ParsesOk("select int_col from alltypes order by true, false, NULL");
551  ParserError("select int_col, string_col, bigint_col, count(*) from alltypes " +
552  "order by by string_col asc desc");
553  ParserError("select int_col, string_col, bigint_col, count(*) from alltypes " +
554  "nulls first");
555  ParserError("select int_col, string_col, bigint_col, count(*) from alltypes " +
556  "order by string_col nulls");
557  ParserError("select int_col, string_col, bigint_col, count(*) from alltypes " +
558  "order by string_col nulls first asc");
559  ParserError("select int_col, string_col, bigint_col, count(*) from alltypes " +
560  "order by string_col nulls first last");
561  }
562 
563  @Test
564  public void TestHaving() {
565  ParsesOk("select a, b, count(c) from test group by a, b having count(*) > 5");
566  ParsesOk("select a, b, count(c) from test group by a, b having NULL");
567  ParsesOk("select a, b, count(c) from test group by a, b having true");
568  ParsesOk("select a, b, count(c) from test group by a, b having false");
569  // Non-predicate exprs that return boolean.
570  ParsesOk("select count(c) from test group by a having if (a > b, true, false)");
571  ParsesOk("select count(c) from test group by a " +
572  "having case a when b then true else false end");
573  // Arbitrary non-predicate exprs parse ok but are semantically incorrect.
574  ParsesOk("select a, b, count(c) from test group by a, b having 5");
575  ParserError("select a, b, count(c) from test group by a, b having order by 5");
576  ParserError("select a, b, count(c) from test having count(*) > 5 group by a, b");
577  }
578 
579  @Test
580  public void TestLimit() {
581  ParsesOk("select a, b, c from test inner join test2 using(a) limit 10");
582  ParsesOk("select a, b, c from test inner join test2 using(a) limit 10 + 10");
583  // The following will parse because limit takes an expr, though they will fail in
584  // analysis
585  ParsesOk("select a, b, c from test inner join test2 using(a) limit 'a'");
586  ParsesOk("select a, b, c from test inner join test2 using(a) limit a");
587  ParsesOk("select a, b, c from test inner join test2 using(a) limit true");
588  ParsesOk("select a, b, c from test inner join test2 using(a) limit false");
589  ParsesOk("select a, b, c from test inner join test2 using(a) limit NULL");
590  // Not an expr, will not parse
591  ParserError("select a, b, c from test inner join test2 using(a) limit 10 " +
592  "where a > 10");
593  }
594 
595  @Test
596  public void TestOffset() {
597  ParsesOk("select a from test order by a limit 10 offset 5");
598  ParsesOk("select a from test order by a limit 10 offset 0");
599  ParsesOk("select a from test order by a limit 10 offset 0 + 5 / 2");
600  ParsesOk("select a from test order by a asc limit 10 offset 5");
601  ParsesOk("select a from test order by a offset 5");
602  ParsesOk("select a from test limit 10 offset 5"); // Parses OK, doesn't analyze
603  ParsesOk("select a from test offset 5"); // Parses OK, doesn't analyze
604  ParsesOk("select a from (select a from test offset 5) A"); // Doesn't analyze
605  ParsesOk("select a from (select a from test order by a offset 5) A");
606  ParserError("select a from test order by a limit offset");
607  ParserError("select a from test order by a limit offset 5");
608  }
609 
610  @Test
611  public void TestUnion() {
612  // Single union test.
613  ParsesOk("select a from test union select a from test");
614  ParsesOk("select a from test union all select a from test");
615  ParsesOk("select a from test union distinct select a from test");
616  // Chained union test.
617  ParsesOk("select a from test union select a from test " +
618  "union select a from test union select a from test");
619  ParsesOk("select a from test union all select a from test " +
620  "union all select a from test union all select a from test");
621  ParsesOk("select a from test union distinct select a from test " +
622  "union distinct select a from test union distinct select a from test ");
623  // Mixed union with all and distinct.
624  ParsesOk("select a from test union select a from test " +
625  "union all select a from test union distinct select a from test");
626  // No from clause.
627  ParsesOk("select sin() union select cos()");
628  ParsesOk("select sin() union all select cos()");
629  ParsesOk("select sin() union distinct select cos()");
630 
631  // All select blocks in parenthesis.
632  ParsesOk("(select a from test) union (select a from test) " +
633  "union (select a from test) union (select a from test)");
634  // Union with order by,
635  ParsesOk("(select a from test) union (select a from test) " +
636  "union (select a from test) union (select a from test) order by a");
637  ParsesOk("(select a from test) union (select a from test) " +
638  "union (select a from test) union (select a from test) order by a nulls first");
639  // Union with limit.
640  ParsesOk("(select a from test) union (select a from test) " +
641  "union (select a from test) union (select a from test) limit 10");
642  // Union with order by, offset and limit.
643  ParsesOk("(select a from test) union (select a from test) " +
644  "union (select a from test) union (select a from test) order by a limit 10");
645  ParsesOk("(select a from test) union (select a from test) " +
646  "union (select a from test) union (select a from test) order by a " +
647  "nulls first limit 10");
648  ParsesOk("(select a from test) union (select a from test) " +
649  "union (select a from test) union (select a from test) order by a " +
650  "nulls first offset 10");
651  ParserError("select a from test union (select a from test) " +
652  "union (select a from test) union (select a from test) offset 10");
653  // Union with some select blocks in parenthesis, and others not.
654  ParsesOk("(select a from test) union select a from test " +
655  "union (select a from test) union select a from test");
656  ParsesOk("select a from test union (select a from test) " +
657  "union select a from test union (select a from test)");
658  // Union with order by, offset and limit binding to last select.
659  ParsesOk("(select a from test) union (select a from test) " +
660  "union select a from test union select a from test order by a limit 10");
661  ParsesOk("(select a from test) union (select a from test) " +
662  "union select a from test union select a from test order by a offset 10");
663  ParsesOk("(select a from test) union (select a from test) " +
664  "union select a from test union select a from test order by a");
665  // Union with order by and limit.
666  // Last select with order by and limit is in parenthesis.
667  ParsesOk("select a from test union (select a from test) " +
668  "union select a from test union (select a from test order by a limit 10) " +
669  "order by a limit 1");
670  ParsesOk("select a from test union (select a from test) " +
671  "union select a from test union (select a from test order by a offset 10) " +
672  "order by a limit 1");
673  ParsesOk("select a from test union (select a from test) " +
674  "union select a from test union (select a from test order by a) " +
675  "order by a limit 1");
676  // Union with order by, offset in first operand.
677  ParsesOk("select a from test order by a union select a from test");
678  ParsesOk("select a from test order by a offset 5 union select a from test");
679  ParsesOk("select a from test offset 5 union select a from test");
680  // Union with order by and limit.
681  // Last select with order by and limit is not in parenthesis.
682  ParsesOk("select a from test union select a from test " +
683  "union select a from test union select a from test order by a limit 10 " +
684  "order by a limit 1");
685 
686  // Nested unions with order by and limit.
687  ParsesOk("select a union " +
688  "((select b) union (select c) order by 1 limit 1)");
689  ParsesOk("select a union " +
690  "((select b) union " +
691  " ((select c) union (select d) " +
692  " order by 1 limit 1) " +
693  " order by 1 limit 1)");
694 
695  // Union in insert query.
696  ParsesOk("insert into table t select a from test union select a from test");
697  ParsesOk("insert into table t select a from test union select a from test " +
698  "union select a from test union select a from test");
699  ParsesOk("insert overwrite table t select a from test union select a from test");
700  ParsesOk("insert overwrite table t select a from test union select a from test " +
701  "union select a from test union select a from test");
702 
703  // No complete select statement on lhs.
704  ParserError("a from test union select a from test");
705  // No complete select statement on rhs.
706  ParserError("select a from test union a from test");
707  // Union cannot be a column or table since it's a keyword.
708  ParserError("select union from test");
709  ParserError("select a from union");
710  }
711 
712  @Test
713  public void TestValuesStmt() throws AnalysisException {
714  // Values stmt with a single row.
715  ParsesOk("values(1, 'a', abc, 1.0, *)");
716  ParsesOk("select * from (values(1, 'a', abc, 1.0, *)) as t");
717  ParsesOk("values(1, 'a', abc, 1.0, *) union all values(1, 'a', abc, 1.0, *)");
718  ParsesOk("insert into t values(1, 'a', abc, 1.0, *)");
719  // Values stmt with multiple rows.
720  ParsesOk("values(1, abc), ('x', cde), (2), (efg, fgh, ghi)");
721  ParsesOk("select * from (values(1, abc), ('x', cde), (2), (efg, fgh, ghi)) as t");
722  ParsesOk("values(1, abc), ('x', cde), (2), (efg, fgh, ghi) " +
723  "union all values(1, abc), ('x', cde), (2), (efg, fgh, ghi)");
724  ParsesOk("insert into t values(1, abc), ('x', cde), (2), (efg, fgh, ghi)");
725  // Test additional parenthesis.
726  ParsesOk("(values(1, abc), ('x', cde), (2), (efg, fgh, ghi))");
727  ParsesOk("values((1, abc), ('x', cde), (2), (efg, fgh, ghi))");
728  ParsesOk("(values((1, abc), ('x', cde), (2), (efg, fgh, ghi)))");
729  // Test alias inside select list to assign column names.
730  ParsesOk("values(1 as x, 2 as y, 3 as z)");
731  // Test order by and limit.
732  ParsesOk("values(1, 'a') limit 10");
733  ParsesOk("values(1, 'a') order by 1");
734  ParsesOk("values(1, 'a') order by 1 limit 10");
735  ParsesOk("values(1, 'a') order by 1 offset 10");
736  ParsesOk("values(1, 'a') offset 10");
737  ParsesOk("values(1, 'a'), (2, 'b') order by 1 limit 10");
738  ParsesOk("values((1, 'a'), (2, 'b')) order by 1 limit 10");
739 
740  ParserError("values()");
741  ParserError("values 1, 'a', abc, 1.0");
742  ParserError("values(1, 'a') values(1, 'a')");
743  ParserError("select values(1, 'a')");
744  ParserError("select * from values(1, 'a', abc, 1.0) as t");
745  ParserError("values((1, 2, 3), values(1, 2, 3))");
746  ParserError("values((1, 'a'), (1, 'a') order by 1)");
747  ParserError("values((1, 'a'), (1, 'a') limit 10)");
748  }
749 
750  @Test
751  public void TestWithClause() throws AnalysisException {
752  ParsesOk("with t as (select 1 as a) select a from t");
753  ParsesOk("with t as (select c from tab) select * from t");
754  ParsesOk("with t as (values(1, 2, 3), (4, 5, 6)) select * from t");
755  ParsesOk("with t1 as (select 1 as a), t2 as (select 2 as a) select a from t1");
756  ParsesOk("with t1 as (select c from tab), t2 as (select c from tab)" +
757  "select c from t2");
758  // With clause and union statement.
759  ParsesOk("with t1 as (select 1 as a), t2 as (select 2 as a)" +
760  "select a from t1 union all select a from t2");
761  // With clause and join.
762  ParsesOk("with t1 as (select 1 as a), t2 as (select 2 as a)" +
763  "select a from t1 inner join t2 on t1.a = t2.a");
764  // With clause in inline view.
765  ParsesOk("select * from (with t as (select 1 as a) select * from t) as a");
766  // With clause in query statement of insert statement.
767  ParsesOk("insert into x with t as (select * from tab) select * from t");
768  ParsesOk("insert into x with t as (values(1, 2, 3)) select * from t");
769  // With clause before insert statement.
770  ParsesOk("with t as (select 1) insert into x select * from t");
771 
772  // Test quoted identifier or string literal as table alias.
773  ParsesOk("with `t1` as (select 1 a), 't2' as (select 2 a), \"t3\" as (select 3 a)" +
774  "select a from t1 union all select a from t2 union all select a from t3");
775 
776  // Multiple with clauses. Operands must be in parenthesis to
777  // have their own with clause.
778  ParsesOk("with t as (select 1) " +
779  "(with t as (select 2) select * from t) union all " +
780  "(with t as (select 3) select * from t)");
781  ParsesOk("with t as (select 1) " +
782  "(with t as (select 2) select * from t) union all " +
783  "(with t as (select 3) select * from t) order by 1 limit 1");
784  // Multiple with clauses. One before the insert and one inside the query statement.
785  ParsesOk("with t as (select 1) insert into x with t as (select 2) select * from t");
786 
787  // Empty with clause.
788  ParserError("with t as () select 1");
789  // Missing select, union or insert statement after with clause.
790  ParserError("select * from (with t as (select 1 as a)) as a");
791  ParserError("with t as (select 1)");
792  // Missing parenthesis around with query statement.
793  ParserError("with t as select 1 as a select a from t");
794  ParserError("with t as select 1 as a union all select a from t");
795  ParserError("with t1 as (select 1 as a), t2 as select 2 as a select a from t");
796  ParserError("with t as select 1 as a select a from t");
797  // Insert in with clause is not valid.
798  ParserError("with t as (insert into x select * from tab) select * from t");
799  // Union operands need to be parenthesized to have their own with clause.
800  ParserError("select * from t union all with t as (select 2) select * from t");
801  }
802 
803  @Test
805  // Test integer types.
806  ParsesOk(String.format("select %s", Byte.toString(Byte.MIN_VALUE)));
807  ParsesOk(String.format("select %s", Byte.toString(Byte.MAX_VALUE)));
808  ParsesOk(String.format("select %s", Short.toString(Short.MIN_VALUE)));
809  ParsesOk(String.format("select %s", Short.toString(Short.MAX_VALUE)));
810  ParsesOk(String.format("select %s", Integer.toString(Integer.MIN_VALUE)));
811  ParsesOk(String.format("select %s", Integer.toString(Integer.MAX_VALUE)));
812  ParsesOk(String.format("select %s", Long.toString(Long.MIN_VALUE)));
813  ParsesOk(String.format("select %s", Long.toString(Long.MAX_VALUE)));
814 
815  // Overflowing long integers parse ok. Analysis will handle it.
816  ParsesOk(String.format("select %s1", Long.toString(Long.MIN_VALUE)));
817  ParsesOk(String.format("select %s1", Long.toString(Long.MAX_VALUE)));
818  // Test min int64-1.
819  BigInteger minMinusOne = BigInteger.valueOf(Long.MAX_VALUE);
820  minMinusOne = minMinusOne.add(BigInteger.ONE);
821  ParsesOk(String.format("select %s", minMinusOne.toString()));
822  // Test max int64+1.
823  BigInteger maxPlusOne = BigInteger.valueOf(Long.MAX_VALUE);
824  maxPlusOne = maxPlusOne.add(BigInteger.ONE);
825  ParsesOk(String.format("select %s", maxPlusOne.toString()));
826 
827  // Test floating-point types.
828  ParsesOk(String.format("select %s", Float.toString(Float.MIN_VALUE)));
829  ParsesOk(String.format("select %s", Float.toString(Float.MAX_VALUE)));
830  ParsesOk(String.format("select -%s", Float.toString(Float.MIN_VALUE)));
831  ParsesOk(String.format("select -%s", Float.toString(Float.MAX_VALUE)));
832  ParsesOk(String.format("select %s", Double.toString(Double.MIN_VALUE)));
833  ParsesOk(String.format("select %s", Double.toString(Double.MAX_VALUE)));
834  ParsesOk(String.format("select -%s", Double.toString(Double.MIN_VALUE)));
835  ParsesOk(String.format("select -%s", Double.toString(Double.MAX_VALUE)));
836 
837  // Test overflow and underflow
838  ParsesOk(String.format("select %s1", Double.toString(Double.MIN_VALUE)));
839  ParsesOk(String.format("select %s1", Double.toString(Double.MAX_VALUE)));
840  }
841 
842  @Test
843  public void TestIdentQuoting() {
844  ParsesOk("select a from `t`");
845  ParsesOk("select a from `default`.`t`");
846  ParsesOk("select a from `default`.t");
847  ParsesOk("select a from default.`t`");
848  ParsesOk("select 01a from default.`01_t`");
849 
850  ParsesOk("select `a` from default.t");
851  ParsesOk("select `tbl`.`a` from default.t");
852  ParsesOk("select `db`.`tbl`.`a` from default.t");
853  ParsesOk("select `12db`.`tbl`.`12_a` from default.t");
854 
855  // Make sure quoted float literals are identifiers.
856  ParsesOk("select `8e6`", SlotRef.class);
857  ParsesOk("select `4.5e2`", SlotRef.class);
858  ParsesOk("select `.7e9`", SlotRef.class);
859 
860  // Mixed quoting
861  ParsesOk("select `db`.tbl.`a` from default.t");
862  ParsesOk("select `db.table.a` from default.t");
863 
864  // Identifiers consisting of only whitespace not allowed.
865  ParserError("select a from ` `");
866  ParserError("select a from ` `");
867  // Empty quoted identifier doesn't parse.
868  ParserError("select a from ``");
869 
870  // Whitespace can be interspersed with other characters.
871  // Whitespace is trimmed from the beginning and end of an identifier.
872  ParsesOk("select a from `a a a `");
873  ParsesOk("select a from ` a a a`");
874  ParsesOk("select a from ` a a a `");
875 
876  // Quoted identifiers can contain any characters except "`".
877  ParsesOk("select a from `all types`");
878  ParsesOk("select a from `default`.`all types`");
879  ParsesOk("select a from `~!@#$%^&*()-_=+|;:'\",<.>/?`");
880  // Quoted identifiers do not unescape escape sequences.
881  ParsesOk("select a from `ab\rabc`");
882  ParsesOk("select a from `ab\tabc`");
883  ParsesOk("select a from `ab\fabc`");
884  ParsesOk("select a from `ab\babc`");
885  ParsesOk("select a from `ab\nabc`");
886  // Test non-printable control characters inside quoted identifiers.
887  ParsesOk("select a from `abc\u0000abc`");
888  ParsesOk("select a from `abc\u0019abc`");
889  ParsesOk("select a from `abc\u007fabc`");
890 
891  // Quoted identifiers can contain keywords.
892  ParsesOk("select `select`, `insert` from `table` where `where` = 10");
893 
894  // Quoted identifiers cannot contain "`"
895  ParserError("select a from `abcde`abcde`");
896  ParserError("select a from `abc\u0060abc`");
897 
898  // Wrong quotes
899  ParserError("select a from 'default'.'t'");
900 
901  // Lots of quoting
902  ParsesOk(
903  "select `db`.`tbl`.`a` from `default`.`t` `alias` where `alias`.`col` = 'string'"
904  + " group by `alias`.`col`");
905  }
906 
907  @Test
908  public void TestLiteralExprs() {
909  // negative integer literal
910  ParsesOk("select -1 from t where -1", NumericLiteral.class);
911  ParsesOk("select - 1 from t where - 1", NumericLiteral.class);
912  ParsesOk("select a - - 1 from t where a - - 1", ArithmeticExpr.class);
913  ParsesOk("select a - - - 1 from t where a - - - 1", ArithmeticExpr.class);
914 
915  // positive integer literal
916  ParsesOk("select +1 from t where +1", NumericLiteral.class);
917  ParsesOk("select + 1 from t where + 1", NumericLiteral.class);
918  ParsesOk("select a + + 1 from t where a + + 1", ArithmeticExpr.class);
919  ParsesOk("select a + + + 1 from t where a + + + 1", ArithmeticExpr.class);
920 
921  // float literals
922  ParsesOk("select +1.0 from t where +1.0", NumericLiteral.class);
923  ParsesOk("select +-1.0 from t where +-1.0", NumericLiteral.class);
924  ParsesOk("select +1.-0 from t where +1.-0", ArithmeticExpr.class);
925 
926  // test scientific notation
927  ParsesOk("select 8e6 from t where 8e6", NumericLiteral.class);
928  ParsesOk("select +8e6 from t where +8e6", NumericLiteral.class);
929  ParsesOk("select 8e+6 from t where 8e+6", NumericLiteral.class);
930  ParsesOk("select -8e6 from t where -8e6", NumericLiteral.class);
931  ParsesOk("select 8e-6 from t where 8e-6", NumericLiteral.class);
932  ParsesOk("select -8e-6 from t where -8e-6", NumericLiteral.class);
933  // with a decimal point
934  ParsesOk("select 4.5e2 from t where 4.5e2", NumericLiteral.class);
935  ParsesOk("select +4.5e2 from t where +4.5e2", NumericLiteral.class);
936  ParsesOk("select 4.5e+2 from t where 4.5e+2", NumericLiteral.class);
937  ParsesOk("select -4.5e2 from t where -4.5e2", NumericLiteral.class);
938  ParsesOk("select 4.5e-2 from t where 4.5e-2", NumericLiteral.class);
939  ParsesOk("select -4.5e-2 from t where -4.5e-2", NumericLiteral.class);
940  // with a decimal point but without a number before the decimal
941  ParsesOk("select .7e9 from t where .7e9", NumericLiteral.class);
942  ParsesOk("select +.7e9 from t where +.7e9", NumericLiteral.class);
943  ParsesOk("select .7e+9 from t where .7e+9", NumericLiteral.class);
944  ParsesOk("select -.7e9 from t where -.7e9", NumericLiteral.class);
945  ParsesOk("select .7e-9 from t where .7e-9", NumericLiteral.class);
946  ParsesOk("select -.7e-9 from t where -.7e-9", NumericLiteral.class);
947 
948  // mixed signs
949  ParsesOk("select -+-1 from t where -+-1", NumericLiteral.class);
950  ParsesOk("select - +- 1 from t where - +- 1", NumericLiteral.class);
951  ParsesOk("select 1 + -+ 1 from t where 1 + -+ 1", ArithmeticExpr.class);
952 
953  // Boolean literals
954  ParsesOk("select true from t where true", BoolLiteral.class);
955  ParsesOk("select false from t where false", BoolLiteral.class);
956 
957  // Null literal
958  ParsesOk("select NULL from t where NULL", NullLiteral.class);
959 
960  // -- is parsed as a comment starter
961  ParserError("select --1");
962 
963  // Postfix operators must be binary
964  ParserError("select 1- from t");
965  ParserError("select 1 + from t");
966 
967  // Only - and + can be unary operators
968  ParserError("select /1 from t");
969  ParserError("select *1 from t");
970  ParserError("select &1 from t");
971  ParserError("select =1 from t");
972 
973  // test string literals with and without quotes in the literal
974  ParsesOk("select 'five', 5, 5.0, i + 5 from t", StringLiteral.class);
975  ParsesOk("select \"\\\"five\\\"\" from t\n", StringLiteral.class);
976  ParsesOk("select \"\'five\'\" from t\n", StringLiteral.class);
977  ParsesOk("select \"\'five\" from t\n", StringLiteral.class);
978 
979  // missing quotes
980  ParserError("select \'5 from t");
981  ParserError("select \"5 from t");
982  ParserError("select '5 from t");
983  ParserError("select `5 from t");
984  ParserError("select \"\"five\"\" from t\n");
985  ParserError("select 5.0.5 from t");
986 
987  // we implement MySQL-style escape sequences just like Hive:
988  // http://dev.mysql.com/doc/refman/5.0/en/string-literals.html
989  // test escape sequences with single and double quoted strings
990  testStringLiteral("\\0");
991  testStringLiteral("\\\\");
992  testStringLiteral("\\b");
993  testStringLiteral("\\n");
994  testStringLiteral("\\r");
995  testStringLiteral("\\t");
996  testStringLiteral("\\Z");
997  // MySQL deals with escapes and "%" and "_" specially for pattern matching
998  testStringLiteral("\\%");
999  testStringLiteral("\\\\%");
1000  testStringLiteral("\\_");
1001  testStringLiteral("\\\\_");
1002  // all escape sequences back-to-back
1003  testStringLiteral("\\0\\\\\\b\\n\\r\\t\\Z\\%\\\\%\\_\\\\_");
1004  // mixed regular chars and escape sequences
1005  testStringLiteral("a\\0b\\\\c\\bd\\ne\\rf\\tg\\Zh\\%i\\\\%j\\_k\\\\_l");
1006  // escaping non-escape chars should scan ok and result in the character itself
1007  testStringLiteral("\\a\\b\\c\\d\\1\\2\\3\\$\\&\\*");
1008  // Single backslash is a scanner error.
1009  ParserError("select \"\\\" from t",
1010  "Syntax error in line 1:\n" +
1011  "select \"\\\" from t\n" +
1012  " ^\n" +
1013  "Encountered: Unexpected character");
1014  // Unsupported character
1015  ParserError("@",
1016  "Syntax error in line 1:\n" +
1017  "@\n" +
1018  "^\n" +
1019  "Encountered: Unexpected character");
1020  ParsesOk("SELECT '@'");
1021  }
1022 
1023  // test string literal s with single and double quotes
1024  private void testStringLiteral(String s) {
1025  String singleQuoteQuery = "select " + "'" + s + "'" + " from t";
1026  String doubleQuoteQuery = "select " + "\"" + s + "\"" + " from t";
1027  ParsesOk(singleQuoteQuery, StringLiteral.class);
1028  ParsesOk(doubleQuoteQuery, StringLiteral.class);
1029  }
1030 
1031  @Test
1032  public void TestFunctionCallExprs() {
1033  ParsesOk("select f1(5), f2('five'), f3(5.0, i + 5) from t");
1034  ParsesOk("select f1(true), f2(true and false), f3(null) from t");
1035  ParsesOk("select f1(*)");
1036  ParsesOk("select f1(distinct col)");
1037  ParsesOk("select f1(distinct col, col2)");
1038  ParsesOk("select decode(col, col2, col3)");
1039  ParserError("select f( from t");
1040  ParserError("select f(5.0 5.0) from t");
1041  }
1042 
1043  @Test
1044  public void TestArithmeticExprs() {
1045  for (String lop: operands_) {
1046  for (String rop: operands_) {
1047  for (ArithmeticExpr.Operator op : ArithmeticExpr.Operator.values()) {
1048  // Test BITNOT separately.
1049  if (op == ArithmeticExpr.Operator.BITNOT) {
1050  continue;
1051  }
1052  String expr = String.format("%s %s %s", lop, op.toString(), rop);
1053  ParsesOk(String.format("select %s from t where %s", expr, expr));
1054  }
1055  }
1056  // Test BITNOT.
1057  String bitNotExpr = String.format("%s %s",
1058  ArithmeticExpr.Operator.BITNOT.toString(), lop);
1059  ParsesOk(String.format("select %s from t where %s", bitNotExpr, bitNotExpr));
1060  }
1061  ParserError("select (i + 5)(1 - i) from t");
1062  ParserError("select %a from t");
1063  ParserError("select *a from t");
1064  ParserError("select /a from t");
1065  ParserError("select &a from t");
1066  ParserError("select |a from t");
1067  ParserError("select ^a from t");
1068  ParserError("select a ~ a from t");
1069  }
1070 
1079  @Test
1081  // Tests all valid time units.
1082  for (TimeUnit timeUnit : TimeUnit.values()) {
1083  // Non-function call like versions.
1084  ParsesOk("select a + interval b " + timeUnit.toString());
1085  ParsesOk("select a - interval b " + timeUnit.toString());
1086  ParsesOk("select NULL + interval NULL " + timeUnit.toString());
1087  ParsesOk("select NULL - interval NULL " + timeUnit.toString());
1088  // Reversed interval and timestamp is ok for addition.
1089  ParsesOk("select interval b " + timeUnit.toString() + " + a");
1090  ParsesOk("select interval NULL " + timeUnit.toString() + " + NULL");
1091  // Reversed interval and timestamp is an error for subtraction.
1092  ParserError("select interval b " + timeUnit.toString() + " - a");
1093  // Function-call like versions.
1094  ParsesOk("select date_add(a, interval b " + timeUnit.toString() + ")");
1095  ParsesOk("select date_sub(a, interval b " + timeUnit.toString() + ")");
1096  ParsesOk("select date_add(NULL, interval NULL " + timeUnit.toString() + ")");
1097  ParsesOk("select date_sub(NULL, interval NULL " + timeUnit.toString() + ")");
1098  // Invalid function name for timestamp arithmetic expr should parse ok.
1099  ParsesOk("select error(a, interval b " + timeUnit.toString() + ")");
1100  // Invalid time unit parses ok.
1101  ParsesOk("select error(a, interval b error)");
1102  // Missing 'interval' keyword. Note that the non-function-call like version will
1103  // pass without 'interval' because the time unit is recognized as an alias.
1104  ParserError("select date_add(a, b " + timeUnit.toString() + ")");
1105  ParserError("select date_sub(a, b " + timeUnit.toString() + ")");
1106 
1107  ParserError("select date_sub(distinct NULL, interval NULL " +
1108  timeUnit.toString() + ")");
1109  ParserError("select date_sub(*, interval NULL " + timeUnit.toString() + ")");
1110  }
1111 
1112  // Test chained timestamp arithmetic exprs.
1113  ParsesOk("select a + interval b years + interval c months + interval d days");
1114  ParsesOk("select a - interval b years - interval c months - interval d days");
1115  ParsesOk("select a + interval b years - interval c months + interval d days");
1116  // Starting with interval.
1117  ParsesOk("select interval b years + a + interval c months + interval d days");
1118  ParsesOk("select interval b years + a - interval c months - interval d days");
1119  ParsesOk("select interval b years + a - interval c months + interval d days");
1120 
1121  // To many arguments.
1122  ParserError("select date_sub(a, c, interval b year)");
1123  ParserError("select date_sub(a, interval b year, c)");
1124  }
1125 
1126  @Test
1127  public void TestCaseExprs() {
1128  // Test regular exps.
1129  ParsesOk("select case a when '5' then x when '6' then y else z end from t");
1130  ParsesOk("select case when 'a' then x when false then y else z end from t");
1131  // Test predicates in case, when, then, and else exprs.
1132  ParsesOk("select case when a > 2 then x when false then false else true end from t");
1133  ParsesOk("select case false when a > 2 then x when '6' then false else true end " +
1134  "from t");
1135  // Test NULLs;
1136  ParsesOk("select case NULL when NULL then NULL when NULL then NULL else NULL end " +
1137  "from t");
1138  ParsesOk("select case when NULL then NULL when NULL then NULL else NULL end from t");
1139  // Missing end.
1140  ParserError("select case a when true then x when false then y else z from t");
1141  // Missing else after first when.
1142  ParserError("select case a when true when false then y else z end from t");
1143  // Incorrectly placed comma.
1144  ParserError("select case a when true, false then y else z end from t");
1145  }
1146 
1147  @Test
1148  public void TestCastExprs() {
1149  ParsesOk("select cast(a + 5.0 as string) from t");
1150  ParsesOk("select cast(NULL as string) from t");
1151  ParserError("select cast(a + 5.0 as badtype) from t");
1152  ParserError("select cast(a + 5.0, string) from t");
1153  }
1154 
1155  @Test
1156  public void TestConditionalExprs() {
1157  ParsesOk("select if(TRUE, TRUE, FALSE) from t");
1158  ParsesOk("select if(NULL, NULL, NULL) from t");
1159  ParsesOk("select c1, c2, if(TRUE, TRUE, FALSE) from t");
1160  ParsesOk("select if(1 = 2, c1, c2) from t");
1161  ParsesOk("select if(1 = 2, c1, c2)");
1162  ParserError("select if()");
1163  }
1164 
1165  @Test
1166  public void TestAggregateExprs() {
1167  ParsesOk("select count(*), count(a), count(distinct a, b) from t");
1168  ParsesOk("select count(NULL), count(TRUE), count(FALSE), " +
1169  "count(distinct TRUE, FALSE, NULL) from t");
1170  ParsesOk("select count(all *) from t");
1171  ParsesOk("select count(all 1) from t");
1172  ParsesOk("select min(a), min(distinct a) from t");
1173  ParsesOk("select max(a), max(distinct a) from t");
1174  ParsesOk("select sum(a), sum(distinct a) from t");
1175  ParsesOk("select avg(a), avg(distinct a) from t");
1176  ParsesOk("select distinct a, b, c from t");
1177  ParsesOk("select distinctpc(a), distinctpc(distinct a) from t");
1178  ParsesOk("select distinctpcsa(a), distinctpcsa(distinct a) from t");
1179  ParsesOk("select ndv(a), ndv(distinct a) from t");
1180  ParsesOk("select group_concat(a) from t");
1181  ParsesOk("select group_concat(a, ', ') from t");
1182  ParsesOk("select group_concat(a, ', ', c) from t");
1183  }
1184 
1185  @Test
1186  public void TestAnalyticExprs() {
1187  ParsesOk("select sum(v) over (partition by a, 2*b order by 3*c rows between "
1188  + "2+2 preceding and 2-2 following) from t");
1189  ParsesOk("select sum(v) over (order by 3*c rows between "
1190  + "unbounded preceding and unbounded following) from t");
1191  ParsesOk("select sum(v) over (partition by a, 2*b) from t");
1192  ParsesOk("select sum(v) over (partition by a, 2*b order by 3*c range between "
1193  + "unbounded preceding and unbounded following) from t");
1194  ParsesOk("select sum(v) over (order by 3*c range between "
1195  + "2 following and 4 following) from t");
1196  ParsesOk("select sum(v) over (partition by a, 2*b) from t");
1197  ParsesOk("select 2 * x, sum(v) over (partition by a, 2*b order by 3*c rows between "
1198  + "2+2 preceding and 2-2 following), rank() over (), y from t");
1199  // not a function call
1200  ParserError("select v over (partition by a, 2*b order by 3*c rows between 2 "
1201  + "preceding and 2 following) from t");
1202  // something missing
1203  ParserError("select sum(v) over (partition a, 2*b order by 3*c rows between "
1204  + "unbounded preceding and current row) from t");
1205  ParserError("select sum(v) over (partition by a, 2*b order 3*c rows between 2 "
1206  + "preceding and 2 following) from t");
1207  ParserError("select sum(v) over (partition by a, 2*b order by 3*c rows 2 "
1208  + "preceding and 2 following) from t");
1209  ParsesOk("select sum(v) over (partition by a, 2*b) from t");
1210  // Special case for DECODE, which results in a parse error when used in
1211  // an analytic context. Note that "ecode() over ()" would parse fine since
1212  // that is handled by the standard function call lookup.
1213  ParserError("select decode(1, 2, 3) over () from t");
1214  }
1215 
1216  @Test
1217  public void TestPredicates() {
1218  ArrayList<String> operations = new ArrayList<String>();
1219  for (BinaryPredicate.Operator op : BinaryPredicate.Operator.values()) {
1220  operations.add(op.toString());
1221  }
1222  operations.add("like");
1223  operations.add("rlike");
1224  operations.add("regexp");
1225 
1226  for (String lop: operands_) {
1227  for (String rop: operands_) {
1228  for (String op : operations) {
1229  String expr = String.format("%s %s %s", lop, op.toString(), rop);
1230  ParsesOk(String.format("select %s from t where %s", expr, expr));
1231  }
1232  }
1233  String isNullExr = String.format("%s is null", lop);
1234  String isNotNullExr = String.format("%s is not null", lop);
1235  ParsesOk(String.format("select %s from t where %s", isNullExr, isNullExr));
1236  ParsesOk(String.format("select %s from t where %s", isNotNullExr, isNotNullExr));
1237  }
1238  }
1239 
1240  private void testCompoundPredicates(String andStr, String orStr, String notStr) {
1241  // select a, b, c from t where a = 5 and f(b)
1242  ParsesOk("select a, b, c from t where a = 5 " + andStr + " f(b)");
1243  // select a, b, c from t where a = 5 or f(b)
1244  ParsesOk("select a, b, c from t where a = 5 " + orStr + " f(b)");
1245  // select a, b, c from t where (a = 5 or f(b)) and c = 7
1246  ParsesOk("select a, b, c from t where (a = 5 " + orStr + " f(b)) " +
1247  andStr + " c = 7");
1248  // select a, b, c from t where not a = 5
1249  ParsesOk("select a, b, c from t where " + notStr + "a = 5");
1250  // select a, b, c from t where not f(a)
1251  ParsesOk("select a, b, c from t where " + notStr + "f(a)");
1252  // select a, b, c from t where (not a = 5 or not f(b)) and not c = 7
1253  ParsesOk("select a, b, c from t where (" + notStr + "a = 5 " + orStr + " " +
1254  notStr + "f(b)) " + andStr + " " + notStr + "c = 7");
1255  // select a, b, c from t where (!(!a = 5))
1256  ParsesOk("select a, b, c from t where (" + notStr + "(" + notStr + "a = 5))");
1257  // select a, b, c from t where (!(!f(a)))
1258  ParsesOk("select a, b, c from t where (" + notStr + "(" + notStr + "f(a)))");
1259  // semantically incorrect negation, but parses ok
1260  ParsesOk("select a, b, c from t where a = " + notStr + "5");
1261  // unbalanced parentheses
1262  ParserError("select a, b, c from t where " +
1263  "(a = 5 " + orStr + " b = 6) " + andStr + " c = 7)");
1264  ParserError("select a, b, c from t where " +
1265  "((a = 5 " + orStr + " b = 6) " + andStr + " c = 7");
1266  // incorrectly positioned negation (!)
1267  ParserError("select a, b, c from t where a = 5 " + orStr + " " + notStr);
1268  ParserError("select a, b, c from t where " + notStr + "(a = 5) " + orStr + " " + notStr);
1269  }
1270 
1271  private void testLiteralTruthValues(String andStr, String orStr, String notStr) {
1272  String[] truthValues = {"true", "false", "null"};
1273  for (String l: truthValues) {
1274  for (String r: truthValues) {
1275  String andExpr = String.format("%s %s %s", l, andStr, r);
1276  String orExpr = String.format("%s %s %s", l, orStr, r);
1277  ParsesOk(String.format("select %s from t where %s", andExpr, andExpr));
1278  ParsesOk(String.format("select %s from t where %s", orExpr, orExpr));
1279  }
1280  String notExpr = String.format("%s %s", notStr, l);
1281  ParsesOk(String.format("select %s from t where %s", notExpr, notExpr));
1282  }
1283  }
1284 
1285  @Test
1286  public void TestCompoundPredicates() {
1287  String[] andStrs = { "and", "&&" };
1288  String[] orStrs = { "or", "||" };
1289  // Note the trailing space in "not ". We want to test "!" without a space.
1290  String[] notStrs = { "!", "not " };
1291  // Test all combinations of representations for 'or', 'and', and 'not'.
1292  for (String andStr : andStrs) {
1293  for (String orStr : orStrs) {
1294  for (String notStr : notStrs) {
1295  testCompoundPredicates(andStr, orStr, notStr);
1296  testLiteralTruthValues(andStr, orStr, notStr);
1297  }
1298  }
1299  }
1300 
1301  // Test right associativity of NOT.
1302  for (String notStr : notStrs) {
1303  SelectStmt stmt =
1304  (SelectStmt) ParsesOk(String.format("select %s a != b", notStr));
1305  // The NOT should be applied on the result of a != b, and not on a only.
1306  Expr e = stmt.getSelectList().getItems().get(0).getExpr();
1307  assertTrue(e instanceof CompoundPredicate);
1308  CompoundPredicate cp = (CompoundPredicate) e;
1309  assertEquals(CompoundPredicate.Operator.NOT, cp.getOp());
1310  assertEquals(1, cp.getChildren().size());
1311  assertTrue(cp.getChild(0) instanceof BinaryPredicate);
1312  }
1313  }
1314 
1315  @Test
1316  public void TestBetweenPredicate() {
1317  ParsesOk("select a, b, c from t where i between x and y");
1318  ParsesOk("select a, b, c from t where i not between x and y");
1319  ParsesOk("select a, b, c from t where true not between false and NULL");
1320  ParsesOk("select a, b, c from t where 'abc' between 'a' like 'a' and 'b' like 'b'");
1321  // Additional conditions before and after between predicate.
1322  ParsesOk("select a, b, c from t where true and false and i between x and y");
1323  ParsesOk("select a, b, c from t where i between x and y and true and false");
1324  ParsesOk("select a, b, c from t where i between x and (y and true) and false");
1325  ParsesOk("select a, b, c from t where i between x and (y and (true and false))");
1326  // Chaining/nesting of between predicates.
1327  ParsesOk("select a, b, c from t " +
1328  "where true between false and true and 'b' between 'a' and 'c'");
1329  // true between ('b' between 'a' and 'b') and ('bb' between 'aa' and 'cc)
1330  ParsesOk("select a, b, c from t " +
1331  "where true between 'b' between 'a' and 'c' and 'bb' between 'aa' and 'cc'");
1332  // Missing condition expr.
1333  ParserError("select a, b, c from t where between 5 and 10");
1334  // Missing lower bound.
1335  ParserError("select a, b, c from t where i between and 10");
1336  // Missing upper bound.
1337  ParserError("select a, b, c from t where i between 5 and");
1338  // Missing exprs after between.
1339  ParserError("select a, b, c from t where i between");
1340  // AND has a higher precedence than OR.
1341  ParserError("select a, b, c from t where true between 5 or 10 and 20");
1342  }
1343 
1344  @Test
1345  public void TestInPredicate() {
1346  ParsesOk("select a, b, c from t where i in (x, y, z)");
1347  ParsesOk("select a, b, c from t where i not in (x, y, z)");
1348  // Test NULL and boolean literals.
1349  ParsesOk("select a, b, c from t where NULL in (NULL, NULL, NULL)");
1350  ParsesOk("select a, b, c from t where true in (true, false, true)");
1351  ParsesOk("select a, b, c from t where NULL not in (NULL, NULL, NULL)");
1352  ParsesOk("select a, b, c from t where true not in (true, false, true)");
1353  // Missing condition expr.
1354  ParserError("select a, b, c from t where in (x, y, z)");
1355  // Missing parentheses around in list.
1356  ParserError("select a, b, c from t where i in x, y, z");
1357  ParserError("select a, b, c from t where i in (x, y, z");
1358  ParserError("select a, b, c from t where i in x, y, z)");
1359  // Missing in list.
1360  ParserError("select a, b, c from t where i in");
1361  ParserError("select a, b, c from t where i in ( )");
1362  }
1363 
1364  @Test
1365  public void TestSlotRef() {
1366  ParsesOk("select a from t where b > 5");
1367  ParsesOk("select a.b from a where b > 5");
1368  ParsesOk("select a.b.c from a.b where b > 5");
1369  ParsesOk("select a.b.c.d from a.b where b > 5");
1370  }
1371 
1375  private void testInsert() {
1376  for (String qualifier: new String[] {"overwrite", "into"}) {
1377  for (String optTbl: new String[] {"", "table"}) {
1378  // Entire unpartitioned table.
1379  ParsesOk(String.format("insert %s %s t select a from src where b > 5",
1380  qualifier, optTbl));
1381  // Static partition with one partitioning key.
1382  ParsesOk(String.format(
1383  "insert %s %s t partition (pk1=10) select a from src where b > 5",
1384  qualifier, optTbl));
1385  // Dynamic partition with one partitioning key.
1386  ParsesOk(String.format(
1387  "insert %s %s t partition (pk1) select a from src where b > 5",
1388  qualifier, optTbl));
1389  // Static partition with two partitioning keys.
1390  ParsesOk(String.format("insert %s %s t partition (pk1=10, pk2=20) " +
1391  "select a from src where b > 5",
1392  qualifier, optTbl));
1393  // Fully dynamic partition with two partitioning keys.
1394  ParsesOk(String.format(
1395  "insert %s %s t partition (pk1, pk2) select a from src where b > 5",
1396  qualifier, optTbl));
1397  // Partially dynamic partition with two partitioning keys.
1398  ParsesOk(String.format(
1399  "insert %s %s t partition (pk1=10, pk2) select a from src where b > 5",
1400  qualifier, optTbl));
1401  // Partially dynamic partition with two partitioning keys.
1402  ParsesOk(String.format(
1403  "insert %s %s t partition (pk1, pk2=20) select a from src where b > 5",
1404  qualifier, optTbl));
1405  // Static partition with two NULL partitioning keys.
1406  ParsesOk(String.format("insert %s %s t partition (pk1=NULL, pk2=NULL) " +
1407  "select a from src where b > 5",
1408  qualifier, optTbl));
1409  // Static partition with boolean partitioning keys.
1410  ParsesOk(String.format("insert %s %s t partition (pk1=false, pk2=true) " +
1411  "select a from src where b > 5",
1412  qualifier, optTbl));
1413  // Static partition with arbitrary exprs as partitioning keys.
1414  ParsesOk(String.format("insert %s %s t partition (pk1=abc, pk2=(5*8+10)) " +
1415  "select a from src where b > 5",
1416  qualifier, optTbl));
1417  ParsesOk(String.format(
1418  "insert %s %s t partition (pk1=f(a), pk2=!true and false) " +
1419  "select a from src where b > 5",
1420  qualifier, optTbl));
1421  // Permutation
1422  ParsesOk(String.format("insert %s %s t(a,b,c) values(1,2,3)",
1423  qualifier, optTbl));
1424  // Permutation with mismatched select list (should parse fine)
1425  ParsesOk(String.format("insert %s %s t(a,b,c) values(1,2,3,4,5,6)",
1426  qualifier, optTbl));
1427  // Permutation and partition
1428  ParsesOk(String.format("insert %s %s t(a,b,c) partition(d) values(1,2,3,4)",
1429  qualifier, optTbl));
1430  // Empty permutation list
1431  ParsesOk(String.format("insert %s %s t() select 1 from a",
1432  qualifier, optTbl));
1433  // Permutation with optional query statement
1434  ParsesOk(String.format("insert %s %s t() partition(d) ",
1435  qualifier, optTbl));
1436  ParsesOk(String.format("insert %s %s t() ",
1437  qualifier, optTbl));
1438  // No comma in permutation list
1439  ParserError(String.format("insert %s %s t(a b c) select 1 from a",
1440  qualifier, optTbl));
1441  // Can't use strings as identifiers in permutation list
1442  ParserError(String.format("insert %s %s t('a') select 1 from a",
1443  qualifier, optTbl));
1444  // Expressions not allowed in permutation list
1445  ParserError(String.format("insert %s %s t(a=1, b) select 1 from a",
1446  qualifier, optTbl));
1447  }
1448  }
1449  }
1450 
1451  @Test
1452  public void TestInsert() {
1453  // Positive tests.
1454  testInsert();
1455  // Missing query statement
1456  ParserError("insert into table t");
1457  // Missing 'overwrite/insert'.
1458  ParserError("insert table t select a from src where b > 5");
1459  // Missing target table identifier.
1460  ParserError("insert overwrite table select a from src where b > 5");
1461  // Missing target table identifier.
1462  ParserError("insert into table select a from src where b > 5");
1463  // Missing select statement.
1464  ParserError("insert overwrite table t");
1465  // Missing select statement.
1466  ParserError("insert into table t");
1467  // Missing parentheses around 'partition'.
1468  ParserError("insert overwrite table t partition pk1=10 " +
1469  "select a from src where b > 5");
1470  // Missing parentheses around 'partition'.
1471  ParserError("insert into table t partition pk1=10 " +
1472  "select a from src where b > 5");
1473  // Missing comma in partition list.
1474  ParserError("insert overwrite table t partition (pk1=10 pk2=20) " +
1475  "select a from src where b > 5");
1476  // Missing comma in partition list.
1477  ParserError("insert into table t partition (pk1=10 pk2=20) " +
1478  "select a from src where b > 5");
1479  // Misplaced plan hints.
1480  ParserError("insert [shuffle] into table t partition (pk1=10 pk2=20) " +
1481  "select a from src where b > 5");
1482  ParserError("insert into [shuffle] table t partition (pk1=10 pk2=20) " +
1483  "select a from src where b > 5");
1484  ParserError("insert into table t [shuffle] partition (pk1=10 pk2=20) " +
1485  "select a from src where b > 5");
1486  ParserError("insert into table t partition [shuffle] (pk1=10 pk2=20) " +
1487  "select a from src where b > 5");
1488  }
1489 
1490  @Test
1491  public void TestUse() {
1492  ParserError("USE");
1493  ParserError("USE db1 db2");
1494  ParsesOk("USE db1");
1495  }
1496 
1497  @Test
1498  public void TestShow() {
1499  // Short form ok
1500  ParsesOk("SHOW TABLES");
1501  // Well-formed pattern
1502  ParsesOk("SHOW TABLES 'tablename|othername'");
1503  // Empty pattern ok
1504  ParsesOk("SHOW TABLES ''");
1505  // Databases
1506  ParsesOk("SHOW DATABASES");
1507  ParsesOk("SHOW SCHEMAS");
1508  ParsesOk("SHOW DATABASES LIKE 'pattern'");
1509  ParsesOk("SHOW SCHEMAS LIKE 'p*ttern'");
1510  // Data sources
1511  ParsesOk("SHOW DATA SOURCES");
1512  ParsesOk("SHOW DATA SOURCES 'pattern'");
1513  ParsesOk("SHOW DATA SOURCES LIKE 'pattern'");
1514  ParsesOk("SHOW DATA SOURCES LIKE 'p*ttern'");
1515 
1516  // Functions
1517  for (String fnType: new String[] { "", "AGGREGATE", "ANALYTIC"}) {
1518  ParsesOk(String.format("SHOW %s FUNCTIONS", fnType));
1519  ParsesOk(String.format("SHOW %s FUNCTIONS LIKE 'pattern'", fnType));
1520  ParsesOk(String.format("SHOW %s FUNCTIONS LIKE 'p*ttern'", fnType));
1521  ParsesOk(String.format("SHOW %s FUNCTIONS", fnType));
1522  ParsesOk(String.format("SHOW %s FUNCTIONS in DB LIKE 'pattern'", fnType));
1523  ParsesOk(String.format("SHOW %s FUNCTIONS in DB", fnType));
1524  }
1525 
1526  // Show table/column stats.
1527  ParsesOk("SHOW TABLE STATS tbl");
1528  ParsesOk("SHOW TABLE STATS db.tbl");
1529  ParsesOk("SHOW TABLE STATS `db`.`tbl`");
1530  ParsesOk("SHOW COLUMN STATS tbl");
1531  ParsesOk("SHOW COLUMN STATS db.tbl");
1532  ParsesOk("SHOW COLUMN STATS `db`.`tbl`");
1533 
1534  // Show partitions
1535  ParsesOk("SHOW PARTITIONS tbl");
1536  ParsesOk("SHOW PARTITIONS db.tbl");
1537  ParsesOk("SHOW PARTITIONS `db`.`tbl`");
1538 
1539  // Show files of table
1540  ParsesOk("SHOW FILES IN tbl");
1541  ParsesOk("SHOW FILES IN db.tbl");
1542  ParsesOk("SHOW FILES IN `db`.`tbl`");
1543  ParsesOk("SHOW FILES IN db.tbl PARTITION(x='a',y='b')");
1544 
1545  // Missing arguments
1546  ParserError("SHOW");
1547  // Malformed pattern (no quotes)
1548  ParserError("SHOW TABLES tablename");
1549  // Invalid SHOW DATA SOURCE statements
1550  ParserError("SHOW DATA");
1551  ParserError("SHOW SOURCE");
1552  ParserError("SHOW DATA SOURCE LIKE NotStrLiteral");
1553  ParserError("SHOW UNKNOWN FUNCTIONS");
1554  // Missing table/column qualifier.
1555  ParserError("SHOW STATS tbl");
1556  // Missing table.
1557  ParserError("SHOW TABLE STATS");
1558  ParserError("SHOW COLUMN STATS");
1559  // String literal not accepted.
1560  ParserError("SHOW TABLE STATS 'strlit'");
1561  // Missing table.
1562  ParserError("SHOW FILES IN");
1563  // Invalid partition.
1564  ParserError("SHOW FILES IN db.tbl PARTITION(p)");
1565  }
1566 
1567  @Test
1568  public void TestShowCreateTable() {
1569  ParsesOk("SHOW CREATE TABLE x");
1570  ParsesOk("SHOW CREATE TABLE db.x");
1571  ParserError("SHOW CREATE TABLE");
1572  ParserError("SHOW CREATE TABLE x y z");
1573  }
1574 
1575  @Test
1576  public void TestDescribe() {
1577  // Missing argument
1578  ParserError("DESCRIBE");
1579  ParserError("DESCRIBE FORMATTED");
1580 
1581  // Unqualified table ok
1582  ParsesOk("DESCRIBE tablename");
1583  ParsesOk("DESCRIBE FORMATTED tablename");
1584 
1585  // Fully-qualified table ok
1586  ParsesOk("DESCRIBE databasename.tablename");
1587  ParsesOk("DESCRIBE FORMATTED databasename.tablename");
1588  }
1589 
1590  @Test
1591  public void TestCreateDatabase() {
1592  // Both CREATE DATABASE and CREATE SCHEMA are valid (and equivalent)
1593  String [] dbKeywords = {"DATABASE", "SCHEMA"};
1594  for (String kw: dbKeywords) {
1595  ParsesOk(String.format("CREATE %s Foo", kw));
1596  ParsesOk(String.format("CREATE %s IF NOT EXISTS Foo", kw));
1597 
1598  ParsesOk(String.format("CREATE %s Foo COMMENT 'Some comment'", kw));
1599  ParsesOk(String.format("CREATE %s Foo LOCATION '/hdfs_location'", kw));
1600  ParsesOk(String.format("CREATE %s Foo LOCATION '/hdfs_location'", kw));
1601  ParsesOk(String.format(
1602  "CREATE %s Foo COMMENT 'comment' LOCATION '/hdfs_location'", kw));
1603 
1604  // Only string literals are supported
1605  ParserError(String.format("CREATE %s Foo COMMENT mytable", kw));
1606  ParserError(String.format("CREATE %s Foo LOCATION /hdfs_location", kw));
1607 
1608  // COMMENT needs to be *before* LOCATION
1609  ParserError(String.format(
1610  "CREATE %s Foo LOCATION '/hdfs/location' COMMENT 'comment'", kw));
1611 
1612  ParserError(String.format("CREATE %s Foo COMMENT LOCATION '/hdfs_location'", kw));
1613  ParserError(String.format("CREATE %s Foo LOCATION", kw));
1614  ParserError(String.format("CREATE %s Foo LOCATION 'dfsd' 'dafdsf'", kw));
1615 
1616  ParserError(String.format("CREATE Foo", kw));
1617  ParserError(String.format("CREATE %s 'Foo'", kw));
1618  ParserError(String.format("CREATE %s", kw));
1619  ParserError(String.format("CREATE %s IF EXISTS Foo", kw));
1620 
1621  ParserError(String.format("CREATE %sS Foo", kw));
1622  }
1623  }
1624 
1625  @Test
1626  public void TestCreateFunction() {
1627  ParsesOk("CREATE FUNCTION Foo() RETURNS INT LOCATION 'f.jar' SYMBOL='class.Udf'");
1628  ParsesOk("CREATE FUNCTION Foo(INT, INT) RETURNS STRING LOCATION " +
1629  "'f.jar' SYMBOL='class.Udf'");
1630  ParsesOk("CREATE FUNCTION Foo(INT, DOUBLE) RETURNS STRING LOCATION " +
1631  "'f.jar' SYMBOL='class.Udf'");
1632  ParsesOk("CREATE FUNCTION Foo() RETURNS STRING LOCATION " +
1633  "'f.jar' SYMBOL='class.Udf' COMMENT='hi'");
1634  ParsesOk("CREATE FUNCTION IF NOT EXISTS Foo() RETURNS INT LOCATION 'foo.jar' " +
1635  "SYMBOL='class.Udf'");
1636 
1637  // Try more interesting function names
1638  ParsesOk("CREATE FUNCTION User.Foo() RETURNS INT LOCATION 'a'");
1639  ParsesOk("CREATE FUNCTION `Foo`() RETURNS INT LOCATION 'a'");
1640  ParsesOk("CREATE FUNCTION `Foo.Bar`() RETURNS INT LOCATION 'a'");
1641  ParsesOk("CREATE FUNCTION `Foo`.Bar() RETURNS INT LOCATION 'a'");
1642 
1643  // Bad function name
1644  ParserError("CREATE FUNCTION User.() RETURNS INT LOCATION 'a'");
1645  ParserError("CREATE FUNCTION User.Foo.() RETURNS INT LOCATION 'a'");
1646  ParserError("CREATE FUNCTION User..Foo() RETURNS INT LOCATION 'a'");
1647  // Bad function name that parses but won't analyze.
1648  ParsesOk("CREATE FUNCTION A.B.C.D.Foo() RETURNS INT LOCATION 'a'");
1649 
1650  // Missing location
1651  ParserError("CREATE FUNCTION FOO() RETURNS INT");
1652 
1653  // Missing return type
1654  ParserError("CREATE FUNCTION FOO() LOCATION 'foo.jar'");
1655 
1656  // Bad opt args
1657  ParserError("CREATE FUNCTION Foo() RETURNS INT SYMBOL='1' LOCATION 'a'");
1658  ParserError("CREATE FUNCTION Foo() RETURNS INT LOCATION 'a' SYMBOL");
1659  ParserError("CREATE FUNCTION Foo() RETURNS INT LOCATION 'a' SYMBOL='1' SYMBOL='2'");
1660 
1661  // Missing arguments
1662  ParserError("CREATE FUNCTION Foo RETURNS INT LOCATION 'f.jar'");
1663  ParserError("CREATE FUNCTION Foo(INT,) RETURNS INT LOCATION 'f.jar'");
1664  ParserError("CREATE FUNCTION FOO RETURNS INT LOCATION 'foo.jar'");
1665 
1666  // NULL return type or argument type.
1667  ParserError("CREATE FUNCTION Foo(NULL) RETURNS INT LOCATION 'f.jar'");
1668  ParserError("CREATE FUNCTION Foo(NULL, INT) RETURNS INT LOCATION 'f.jar'");
1669  ParserError("CREATE FUNCTION Foo(INT, NULL) RETURNS INT LOCATION 'f.jar'");
1670  ParserError("CREATE FUNCTION Foo() RETURNS NULL LOCATION 'f.jar'");
1671  }
1672 
1673  @Test
1675  String fnCreates[] = {"CREATE FUNCTION ", "CREATE AGGREGATE FUNCTION " };
1676  for (String fnCreate: fnCreates) {
1677  ParsesOk(fnCreate + "Foo(int...) RETURNS INT LOCATION 'f.jar'");
1678  ParsesOk(fnCreate + "Foo(int ...) RETURNS INT LOCATION 'f.jar'");
1679  ParsesOk(fnCreate + "Foo(int, double ...) RETURNS INT LOCATION 'f.jar'");
1680 
1681  ParserError(fnCreate + "Foo(...) RETURNS INT LOCATION 'f.jar'");
1682  ParserError(fnCreate + "Foo(int..., double) RETURNS INT LOCATION 'f.jar'");
1683  ParserError(fnCreate + "Foo(int) RETURNS INT... LOCATION 'f.jar'");
1684  ParserError(fnCreate + "Foo(int. . .) RETURNS INT... LOCATION 'f.jar'");
1685  ParserError(fnCreate + "Foo(int, ...) RETURNS INT... LOCATION 'f.jar'");
1686  }
1687  }
1688 
1689  @Test
1690  public void TestCreateAggregate() {
1691  String loc = " LOCATION 'f.so' UPDATE_FN='class' ";
1692  String c = "CREATE AGGREGATE FUNCTION Foo() RETURNS INT ";
1693 
1694  ParsesOk(c + loc);
1695  ParsesOk(c + "INTERMEDIATE STRING" + loc + "comment='c'");
1696  ParsesOk(c + loc + "comment='abcd'");
1697  ParsesOk(c + loc + "init_fn='InitFnSymbol'");
1698  ParsesOk(c + loc + "init_fn='I' merge_fn='M'");
1699  ParsesOk(c + loc + "merge_fn='M' init_fn='I'");
1700  ParsesOk(c + loc + "merge_fn='M' Init_fn='I' serialize_fn='S' Finalize_fn='F'");
1701  ParsesOk(c + loc + "Init_fn='M' Finalize_fn='I' merge_fn='S' serialize_fn='F'");
1702  ParsesOk(c + loc + "merge_fn='M'");
1703  ParsesOk(c + "INTERMEDIATE CHAR(10)" + loc);
1704 
1705  ParserError("CREATE UNKNOWN FUNCTION " + "Foo() RETURNS INT" + loc);
1706  ParserError(c + loc + "init_fn='1' init_fn='1'");
1707  ParserError(c + loc + "unknown='1'");
1708 
1709  // CHAR must specify size
1710  ParserError(c + "INTERMEDIATE CHAR()" + loc);
1711  ParserError(c + "INTERMEDIATE CHAR(ab)" + loc);
1712  ParserError(c + "INTERMEDIATE CHAR('')" + loc);
1713  ParserError(c + "INTERMEDIATE CHAR('10')" + loc);
1714  ParserError(c + "INTERMEDIATE CHAR(-10)" + loc);
1715  // Parses okay, will fail in analysis
1716  ParsesOk(c + "INTERMEDIATE CHAR(0)" + loc);
1717 
1718  // Optional args must be at the end
1719  ParserError("CREATE UNKNOWN FUNCTION " + "Foo() RETURNS INT" + loc);
1720  ParserError("CREATE AGGREGATE FUNCTION Foo() init_fn='1' RETURNS INT" + loc);
1721  ParserError(c + "init_fn='1'" + loc);
1722 
1723  // Variadic args
1724  ParsesOk("CREATE AGGREGATE FUNCTION Foo(INT...) RETURNS INT LOCATION 'f.jar'");
1725  }
1726 
1727  @Test
1729  String[] addReplaceKw = {"ADD", "REPLACE"};
1730  for (String addReplace: addReplaceKw) {
1731  ParsesOk(String.format(
1732  "ALTER TABLE Foo %s COLUMNS (i int, s string)", addReplace));
1733  ParsesOk(String.format(
1734  "ALTER TABLE TestDb.Foo %s COLUMNS (i int, s string)", addReplace));
1735  ParsesOk(String.format(
1736  "ALTER TABLE TestDb.Foo %s COLUMNS (i int)", addReplace));
1737  ParsesOk(String.format(
1738  "ALTER TABLE TestDb.Foo %s COLUMNS (i int comment 'hi')", addReplace));
1739 
1740  // Negative syntax tests
1741  ParserError(String.format("ALTER TABLE TestDb.Foo %s COLUMNS i int", addReplace));
1742  ParserError(String.format(
1743  "ALTER TABLE TestDb.Foo %s COLUMNS (int i)", addReplace));
1744  ParserError(String.format(
1745  "ALTER TABLE TestDb.Foo %s COLUMNS (i int COMMENT)", addReplace));
1746  ParserError(String.format("ALTER TestDb.Foo %s COLUMNS (i int)", addReplace));
1747  ParserError(String.format("ALTER TestDb.Foo %s COLUMNS", addReplace));
1748  ParserError(String.format("ALTER TestDb.Foo %s COLUMNS ()", addReplace));
1749  ParserError(String.format("ALTER Foo %s COLUMNS (i int, s string)", addReplace));
1750  ParserError(String.format("ALTER TABLE %s COLUMNS (i int, s string)", addReplace));
1751  // Don't yet support ALTER TABLE ADD COLUMN syntax
1752  ParserError(String.format("ALTER TABLE Foo %s COLUMN i int", addReplace));
1753  ParserError(String.format("ALTER TABLE Foo %s COLUMN (i int)", addReplace));
1754  }
1755  }
1756 
1757  @Test
1759  ParsesOk("ALTER TABLE Foo ADD PARTITION (i=1)");
1760  ParsesOk("ALTER TABLE TestDb.Foo ADD IF NOT EXISTS PARTITION (i=1, s='Hello')");
1761  ParsesOk("ALTER TABLE TestDb.Foo ADD PARTITION (i=1, s='Hello') LOCATION '/a/b'");
1762  ParsesOk("ALTER TABLE Foo ADD PARTITION (i=NULL)");
1763  ParsesOk("ALTER TABLE Foo ADD PARTITION (i=NULL, j=2, k=NULL)");
1764  ParsesOk("ALTER TABLE Foo ADD PARTITION (i=abc, j=(5*8+10), k=!true and false)");
1765 
1766  // Cannot use dynamic partition syntax
1767  ParserError("ALTER TABLE TestDb.Foo ADD PARTITION (partcol)");
1768  ParserError("ALTER TABLE TestDb.Foo ADD PARTITION (i=1, partcol)");
1769  // Location needs to be a string literal
1770  ParserError("ALTER TABLE TestDb.Foo ADD PARTITION (i=1, s='Hello') LOCATION a/b");
1771 
1772  // Caching ops
1773  ParsesOk("ALTER TABLE Foo ADD PARTITION (j=2) CACHED IN 'pool'");
1774  ParsesOk("ALTER TABLE Foo ADD PARTITION (j=2) CACHED IN 'pool'");
1775  ParserError("ALTER TABLE Foo ADD PARTITION (j=2) CACHED 'pool'");
1776  ParserError("ALTER TABLE Foo ADD PARTITION (j=2) CACHED IN");
1777  ParserError("ALTER TABLE Foo ADD PARTITION (j=2) CACHED");
1778  ParsesOk("ALTER TABLE Foo ADD PARTITION (j=2) CACHED IN 'pool' WITH replication = 3");
1779  ParserError("ALTER TABLE Foo ADD PARTITION (j=2) CACHED IN 'pool' " +
1780  "with replication = -1");
1781  ParsesOk("ALTER TABLE Foo ADD PARTITION (j=2) UNCACHED");
1782  ParsesOk("ALTER TABLE Foo ADD PARTITION (j=2) LOCATION 'a/b' UNCACHED");
1783  ParsesOk("ALTER TABLE Foo ADD PARTITION (j=2) LOCATION 'a/b' CACHED IN 'pool'");
1784  ParsesOk("ALTER TABLE Foo ADD PARTITION (j=2) LOCATION 'a/b' CACHED IN 'pool' " +
1785  "with replication = 3");
1786  ParserError("ALTER TABLE Foo ADD PARTITION (j=2) CACHED IN 'pool' LOCATION 'a/b'");
1787  ParserError("ALTER TABLE Foo ADD PARTITION (j=2) UNCACHED LOCATION 'a/b'");
1788 
1789  ParserError("ALTER TABLE Foo ADD IF EXISTS PARTITION (i=1, s='Hello')");
1790  ParserError("ALTER TABLE TestDb.Foo ADD (i=1, s='Hello')");
1791  ParserError("ALTER TABLE TestDb.Foo ADD (i=1)");
1792  ParserError("ALTER TABLE Foo (i=1)");
1793  ParserError("ALTER TABLE TestDb.Foo PARTITION (i=1)");
1794  ParserError("ALTER TABLE Foo ADD PARTITION");
1795  ParserError("ALTER TABLE TestDb.Foo ADD PARTITION ()");
1796  ParserError("ALTER Foo ADD PARTITION (i=1)");
1797  ParserError("ALTER TABLE ADD PARTITION (i=1)");
1798  ParserError("ALTER TABLE ADD");
1799  ParserError("ALTER TABLE DROP");
1800  }
1801 
1802  @Test
1804  // KW_COLUMN is optional
1805  String[] columnKw = {"COLUMN", ""};
1806  for (String kw: columnKw) {
1807  ParsesOk(String.format("ALTER TABLE Foo DROP %s col1", kw));
1808  ParsesOk(String.format("ALTER TABLE TestDb.Foo DROP %s col1", kw));
1809 
1810  // Negative syntax tests
1811  ParserError(String.format("ALTER TABLE TestDb.Foo DROP %s col1, col2", kw));
1812  ParserError(String.format("ALTER TABLE TestDb.Foo DROP %s", kw));
1813  ParserError(String.format("ALTER TABLE Foo DROP %s 'col1'", kw));
1814  ParserError(String.format("ALTER Foo DROP %s col1", kw));
1815  ParserError(String.format("ALTER TABLE DROP %s col1", kw));
1816  ParserError(String.format("ALTER TABLE DROP %s", kw));
1817  }
1818  }
1819 
1820  @Test
1822  ParsesOk("ALTER TABLE Foo DROP PARTITION (i=1)");
1823  ParsesOk("ALTER TABLE TestDb.Foo DROP IF EXISTS PARTITION (i=1, s='Hello')");
1824  ParsesOk("ALTER TABLE Foo DROP PARTITION (i=NULL)");
1825  ParsesOk("ALTER TABLE Foo DROP PARTITION (i=NULL, j=2, k=NULL)");
1826  ParsesOk("ALTER TABLE Foo DROP PARTITION (i=abc, j=(5*8+10), k=!true and false)");
1827 
1828  // Cannot use dynamic partition syntax
1829  ParserError("ALTER TABLE Foo DROP PARTITION (partcol)");
1830  ParserError("ALTER TABLE Foo DROP PARTITION (i=1, j)");
1831 
1832  ParserError("ALTER TABLE Foo DROP IF NOT EXISTS PARTITION (i=1, s='Hello')");
1833  ParserError("ALTER TABLE TestDb.Foo DROP (i=1, s='Hello')");
1834  ParserError("ALTER TABLE TestDb.Foo DROP (i=1)");
1835  ParserError("ALTER TABLE Foo (i=1)");
1836  ParserError("ALTER TABLE TestDb.Foo PARTITION (i=1)");
1837  ParserError("ALTER TABLE Foo DROP PARTITION");
1838  ParserError("ALTER TABLE TestDb.Foo DROP PARTITION ()");
1839  ParserError("ALTER Foo DROP PARTITION (i=1)");
1840  ParserError("ALTER TABLE DROP PARTITION (i=1)");
1841  }
1842 
1843  @Test
1845  // KW_COLUMN is optional
1846  String[] columnKw = {"COLUMN", ""};
1847  for (String kw: columnKw) {
1848  ParsesOk(String.format("ALTER TABLE Foo.Bar CHANGE %s c1 c2 int", kw));
1849  ParsesOk(String.format("ALTER TABLE Foo CHANGE %s c1 c2 int comment 'hi'", kw));
1850 
1851  // Negative syntax tests
1852  ParserError(String.format("ALTER TABLE Foo CHANGE %s c1 int c2", kw));
1853  ParserError(String.format("ALTER TABLE Foo CHANGE %s col1 int", kw));
1854  ParserError(String.format("ALTER TABLE Foo CHANGE %s col1", kw));
1855  ParserError(String.format("ALTER TABLE Foo CHANGE %s", kw));
1856  ParserError(String.format("ALTER TABLE CHANGE %s c1 c2 int", kw));
1857  }
1858  }
1859 
1860  @Test
1861  public void TestAlterTableSet() {
1862  // Supported file formats
1863  String [] supportedFileFormats =
1864  {"TEXTFILE", "SEQUENCEFILE", "PARQUET", "PARQUETFILE", "RCFILE", "AVRO"};
1865  for (String format: supportedFileFormats) {
1866  ParsesOk("ALTER TABLE Foo SET FILEFORMAT " + format);
1867  ParsesOk("ALTER TABLE TestDb.Foo SET FILEFORMAT " + format);
1868  ParsesOk("ALTER TABLE TestDb.Foo PARTITION (a=1) SET FILEFORMAT " + format);
1869  ParsesOk("ALTER TABLE Foo PARTITION (s='str') SET FILEFORMAT " + format);
1870  ParserError("ALTER TABLE TestDb.Foo PARTITION (i=5) SET " + format);
1871  ParserError("ALTER TABLE TestDb.Foo SET " + format);
1872  ParserError("ALTER TABLE TestDb.Foo " + format);
1873  }
1874  ParserError("ALTER TABLE TestDb.Foo SET FILEFORMAT");
1875 
1876  ParsesOk("ALTER TABLE Foo SET LOCATION '/a/b/c'");
1877  ParsesOk("ALTER TABLE TestDb.Foo SET LOCATION '/a/b/c'");
1878 
1879  ParsesOk("ALTER TABLE Foo PARTITION (i=1,s='str') SET LOCATION '/a/i=1/s=str'");
1880  ParsesOk("ALTER TABLE Foo PARTITION (s='str') SET LOCATION '/a/i=1/s=str'");
1881 
1882  ParserError("ALTER TABLE Foo PARTITION (s) SET LOCATION '/a'");
1883  ParserError("ALTER TABLE Foo PARTITION () SET LOCATION '/a'");
1884  ParserError("ALTER TABLE Foo PARTITION ('str') SET FILEFORMAT TEXTFILE");
1885  ParserError("ALTER TABLE Foo PARTITION (a=1, 5) SET FILEFORMAT TEXTFILE");
1886  ParserError("ALTER TABLE Foo PARTITION () SET FILEFORMAT PARQUETFILE");
1887  ParserError("ALTER TABLE Foo PARTITION (,) SET FILEFORMAT PARQUET");
1888  ParserError("ALTER TABLE Foo PARTITION (a=1) SET FILEFORMAT");
1889  ParserError("ALTER TABLE Foo PARTITION (a=1) SET LOCATION");
1890  ParserError("ALTER TABLE TestDb.Foo SET LOCATION abc");
1891  ParserError("ALTER TABLE TestDb.Foo SET LOCATION");
1892  ParserError("ALTER TABLE TestDb.Foo SET");
1893 
1894  String[] tblPropTypes = {"TBLPROPERTIES", "SERDEPROPERTIES"};
1895  String[] partClauses = {"", "PARTITION(k1=10, k2=20)"};
1896  for (String propType: tblPropTypes) {
1897  for (String part: partClauses) {
1898  ParsesOk(String.format("ALTER TABLE Foo %s SET %s ('a'='b')", part, propType));
1899  ParsesOk(String.format("ALTER TABLE Foo %s SET %s ('abc'='123')",
1900  part, propType));
1901  ParsesOk(String.format("ALTER TABLE Foo %s SET %s ('abc'='123', 'a'='1')",
1902  part, propType));
1903  ParsesOk(String.format("ALTER TABLE Foo %s SET %s ('a'='1', 'b'='2', 'c'='3')",
1904  part, propType));
1905  ParserError(String.format("ALTER TABLE Foo %s SET %s ( )", part, propType));
1906  ParserError(String.format("ALTER TABLE Foo %s SET %s ('a', 'b')",
1907  part, propType));
1908  ParserError(String.format("ALTER TABLE Foo %s SET %s ('a'='b',)",
1909  part, propType));
1910  ParserError(String.format("ALTER TABLE Foo %s SET %s ('a'=b)", part, propType));
1911  ParserError(String.format("ALTER TABLE Foo %s SET %s (a='b')", part, propType));
1912  ParserError(String.format("ALTER TABLE Foo %s SET %s (a=b)", part, propType));
1913  }
1914  }
1915 
1916  for (String cacheClause: Lists.newArrayList("UNCACHED", "CACHED in 'pool'",
1917  "CACHED in 'pool' with replication = 4")) {
1918  ParsesOk("ALTER TABLE Foo SET " + cacheClause);
1919  ParsesOk("ALTER TABLE Foo PARTITION(j=0) SET " + cacheClause);
1920  ParserError("ALTER TABLE Foo PARTITION(j=0) " + cacheClause);
1921  }
1922  }
1923 
1924  @Test
1926  for (String entity: Lists.newArrayList("TABLE", "VIEW")) {
1927  ParsesOk(String.format("ALTER %s TestDb.Foo RENAME TO TestDb.Foo2", entity));
1928  ParsesOk(String.format("ALTER %s Foo RENAME TO TestDb.Foo2", entity));
1929  ParsesOk(String.format("ALTER %s TestDb.Foo RENAME TO Foo2", entity));
1930  ParsesOk(String.format("ALTER %s Foo RENAME TO Foo2", entity));
1931  ParserError(String.format("ALTER %s Foo RENAME TO 'Foo2'", entity));
1932  ParserError(String.format("ALTER %s Foo RENAME Foo2", entity));
1933  ParserError(String.format("ALTER %s Foo RENAME TO", entity));
1934  ParserError(String.format("ALTER %s Foo TO Foo2", entity));
1935  ParserError(String.format("ALTER %s Foo TO Foo2", entity));
1936  }
1937  }
1938 
1939  @Test
1940  public void TestCreateTable() {
1941  // Support unqualified and fully-qualified table names
1942  ParsesOk("CREATE TABLE Foo (i int)");
1943  ParsesOk("CREATE TABLE Foo.Bar (i int)");
1944  ParsesOk("CREATE TABLE IF NOT EXISTS Foo.Bar (i int)");
1945  ParsesOk("CREATE TABLE Foo.Bar2 LIKE Foo.Bar1");
1946  ParsesOk("CREATE TABLE IF NOT EXISTS Bar2 LIKE Bar1");
1947  ParsesOk("CREATE EXTERNAL TABLE IF NOT EXISTS Bar2 LIKE Bar1");
1948  ParsesOk("CREATE EXTERNAL TABLE IF NOT EXISTS Bar2 LIKE Bar1 LOCATION '/a/b'");
1949  ParsesOk("CREATE TABLE Foo2 LIKE Foo COMMENT 'sdafsdf'");
1950  ParsesOk("CREATE TABLE Foo2 LIKE Foo COMMENT ''");
1951  ParsesOk("CREATE TABLE Foo2 LIKE Foo STORED AS PARQUETFILE");
1952  ParsesOk("CREATE TABLE Foo2 LIKE Foo COMMENT 'tbl' " +
1953  "STORED AS PARQUETFILE LOCATION '/a/b'");
1954  ParsesOk("CREATE TABLE Foo2 LIKE Foo STORED AS TEXTFILE LOCATION '/a/b'");
1955 
1956  // Table and column names starting with digits.
1957  ParsesOk("CREATE TABLE 01_Foo (01_i int, 02_j string)");
1958 
1959  // Unpartitioned tables
1960  ParsesOk("CREATE TABLE Foo (i int, s string)");
1961  ParsesOk("CREATE EXTERNAL TABLE Foo (i int, s string)");
1962  ParsesOk("CREATE EXTERNAL TABLE Foo (i int, s string) LOCATION '/test-warehouse/'");
1963  ParsesOk("CREATE TABLE Foo (i int, s string) COMMENT 'hello' LOCATION '/a/b/'");
1964  ParsesOk("CREATE TABLE Foo (i int, s string) COMMENT 'hello' LOCATION '/a/b/' " +
1965  "TBLPROPERTIES ('123'='1234')");
1966  // No column definitions.
1967  ParsesOk("CREATE TABLE Foo COMMENT 'hello' LOCATION '/a/b/' " +
1968  "TBLPROPERTIES ('123'='1234')");
1969 
1970  // Partitioned tables
1971  ParsesOk("CREATE TABLE Foo (i int) PARTITIONED BY (j string)");
1972  ParsesOk("CREATE TABLE Foo (i int) PARTITIONED BY (s string, d double)");
1973  ParsesOk("CREATE TABLE Foo (i int, s string) PARTITIONED BY (s string, d double)" +
1974  " COMMENT 'hello' LOCATION '/a/b/'");
1975  // No column definitions.
1976  ParsesOk("CREATE TABLE Foo PARTITIONED BY (s string, d double)" +
1977  " COMMENT 'hello' LOCATION '/a/b/'");
1978  ParserError("CREATE TABLE Foo (i int) PARTITIONED BY (int)");
1979  ParserError("CREATE TABLE Foo (i int) PARTITIONED BY ()");
1980  ParserError("CREATE TABLE Foo (i int) PARTITIONED BY");
1981 
1982  // Column comments
1983  ParsesOk("CREATE TABLE Foo (i int COMMENT 'hello', s string)");
1984  ParsesOk("CREATE TABLE Foo (i int COMMENT 'hello', s string COMMENT 'hi')");
1985  ParsesOk("CREATE TABLE T (i int COMMENT 'hi') PARTITIONED BY (j int COMMENT 'bye')");
1986 
1987  // Supported file formats
1988  String [] supportedFileFormats =
1989  {"TEXTFILE", "SEQUENCEFILE", "PARQUET", "PARQUETFILE", "RCFILE", "AVRO"};
1990  for (String format: supportedFileFormats) {
1991  ParsesOk("CREATE TABLE Foo (i int, s string) STORED AS " + format);
1992  ParsesOk("CREATE EXTERNAL TABLE Foo (i int, s string) STORED AS " + format);
1993  ParsesOk(String.format(
1994  "CREATE TABLE Foo (i int, s string) STORED AS %s LOCATION '/b'", format));
1995  ParsesOk(String.format(
1996  "CREATE EXTERNAL TABLE Foo (f float) COMMENT 'c' STORED AS %s LOCATION '/b'",
1997  format));
1998  // No column definitions.
1999  ParsesOk(String.format(
2000  "CREATE EXTERNAL TABLE Foo COMMENT 'c' STORED AS %s LOCATION '/b'", format));
2001  }
2002 
2003  // Table Properties
2004  String[] tblPropTypes = {"TBLPROPERTIES", "WITH SERDEPROPERTIES"};
2005  for (String propType: tblPropTypes) {
2006  ParsesOk(String.format(
2007  "CREATE TABLE Foo (i int) %s ('a'='b', 'c'='d', 'e'='f')", propType));
2008  ParserError(String.format("CREATE TABLE Foo (i int) %s", propType));
2009  ParserError(String.format("CREATE TABLE Foo (i int) %s ()", propType));
2010  ParserError(String.format("CREATE TABLE Foo (i int) %s ('a')", propType));
2011  ParserError(String.format("CREATE TABLE Foo (i int) %s ('a'=)", propType));
2012  ParserError(String.format("CREATE TABLE Foo (i int) %s ('a'=c)", propType));
2013  ParserError(String.format("CREATE TABLE Foo (i int) %s (a='c')", propType));
2014  }
2015  ParsesOk("CREATE TABLE Foo (i int) WITH SERDEPROPERTIES ('a'='b') " +
2016  "TBLPROPERTIES ('c'='d', 'e'='f')");
2017  // TBLPROPERTIES must go after SERDEPROPERTIES
2018  ParserError("CREATE TABLE Foo (i int) TBLPROPERTIES ('c'='d', 'e'='f') " +
2019  "WITH SERDEPROPERTIES ('a'='b')");
2020 
2021  ParserError("CREATE TABLE Foo (i int) SERDEPROPERTIES ('a'='b')");
2022 
2023  ParserError("CREATE TABLE Foo (i int, s string) STORED AS SEQFILE");
2024  ParserError("CREATE TABLE Foo (i int, s string) STORED TEXTFILE");
2025  ParserError("CREATE TABLE Foo LIKE Bar STORED AS TEXT");
2026  ParserError("CREATE TABLE Foo LIKE Bar COMMENT");
2027  ParserError("CREATE TABLE Foo LIKE Bar STORED TEXTFILE");
2028  ParserError("CREATE TABLE Foo LIKE Bar STORED AS");
2029  ParserError("CREATE TABLE Foo LIKE Bar LOCATION");
2030 
2031  // Row format syntax
2032  ParsesOk("CREATE TABLE T (i int) ROW FORMAT DELIMITED");
2033  ParsesOk("CREATE TABLE T (i int) ROW FORMAT DELIMITED FIELDS TERMINATED BY '|'");
2034  ParsesOk("CREATE TABLE T (i int) ROW FORMAT DELIMITED LINES TERMINATED BY '|'");
2035  ParsesOk("CREATE TABLE T (i int) ROW FORMAT DELIMITED ESCAPED BY '\'");
2036  ParsesOk("CREATE TABLE T (i int) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\0'" +
2037  " ESCAPED BY '\3' LINES TERMINATED BY '\1'");
2038  ParsesOk("CREATE TABLE T (i int) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\0'" +
2039  " LINES TERMINATED BY '\1' STORED AS TEXTFILE");
2040  ParsesOk("CREATE TABLE T (i int) COMMENT 'hi' ROW FORMAT DELIMITED STORED AS RCFILE");
2041  ParsesOk("CREATE TABLE T (i int) COMMENT 'hello' ROW FORMAT DELIMITED FIELDS " +
2042  "TERMINATED BY '\0' LINES TERMINATED BY '\1' STORED AS TEXTFILE LOCATION '/a'");
2043 
2044  // Negative row format syntax
2045  ParserError("CREATE TABLE T (i int) ROW FORMAT DELIMITED TERMINATED BY '\0'");
2046  ParserError("CREATE TABLE T (i int) ROW FORMAT DELIMITED FIELDS TERMINATED BY");
2047  ParserError("CREATE TABLE T (i int) ROW FORMAT DELIMITED LINES TERMINATED BY");
2048  ParserError("CREATE TABLE T (i int) ROW FORMAT DELIMITED ESCAPED BY");
2049  ParserError("CREATE TABLE T (i int) ROW FORMAT DELIMITED FIELDS TERMINATED '|'");
2050  ParserError("CREATE TABLE T (i int) ROW FORMAT DELIMITED FIELDS TERMINATED BY |");
2051  ParserError("CREATE TABLE T (i int) ROW FORMAT DELIMITED FIELDS BY '\0'");
2052  ParserError("CREATE TABLE T (i int) ROW FORMAT DELIMITED LINES BY '\n'");
2053  ParserError("CREATE TABLE T (i int) FIELDS TERMINATED BY '\0'");
2054  ParserError("CREATE TABLE T (i int) ROWS TERMINATED BY '\0'");
2055  ParserError("CREATE TABLE T (i int) ESCAPED BY '\0'");
2056 
2057  // Order should be: [comment] [partition by cols] [row format] [serdeproperties (..)]
2058  // [stored as FILEFORMAT] [location] [cache spec] [tblproperties (...)]
2059  ParserError("CREATE TABLE Foo (d double) COMMENT 'c' PARTITIONED BY (i int)");
2060  ParserError("CREATE TABLE Foo (d double) STORED AS TEXTFILE COMMENT 'c'");
2061  ParserError("CREATE TABLE Foo (d double) STORED AS TEXTFILE ROW FORMAT DELIMITED");
2062  ParserError("CREATE TABLE Foo (d double) ROW FORMAT DELIMITED COMMENT 'c'");
2063  ParserError("CREATE TABLE Foo (d double) LOCATION 'a' COMMENT 'c'");
2064  ParserError("CREATE TABLE Foo (d double) UNCACHED LOCATION '/a/b'");
2065  ParserError("CREATE TABLE Foo (d double) CACHED IN 'pool' LOCATION '/a/b'");
2066  ParserError("CREATE TABLE Foo (d double) CACHED IN 'pool' REPLICATION = 8 " +
2067  "LOCATION '/a/b'");
2068  ParserError("CREATE TABLE Foo (d double) LOCATION 'a' COMMENT 'c' STORED AS RCFILE");
2069  ParserError("CREATE TABLE Foo (d double) LOCATION 'a' STORED AS RCFILE");
2070  ParserError("CREATE TABLE Foo (d double) TBLPROPERTIES('a'='b') LOCATION 'a'");
2071  ParserError("CREATE TABLE Foo (i int) LOCATION 'a' WITH SERDEPROPERTIES('a'='b')");
2072 
2073  // Location and comment need to be string literals, file format is not
2074  ParserError("CREATE TABLE Foo (d double) LOCATION a");
2075  ParserError("CREATE TABLE Foo (d double) COMMENT c");
2076  ParserError("CREATE TABLE Foo (d double COMMENT c)");
2077  ParserError("CREATE TABLE Foo (d double COMMENT 'c') PARTITIONED BY (j COMMENT hi)");
2078  ParserError("CREATE TABLE Foo (d double) STORED AS 'TEXTFILE'");
2079 
2080  // Caching
2081  ParsesOk("CREATE TABLE Foo (i int) CACHED IN 'myPool'");
2082  ParsesOk("CREATE TABLE Foo (i int) CACHED IN 'myPool' WITH REPLICATION = 4");
2083  ParsesOk("CREATE TABLE Foo (i int) PARTITIONED BY(j int) CACHED IN 'myPool'");
2084  ParsesOk("CREATE TABLE Foo (i int) PARTITIONED BY(j int) CACHED IN 'myPool'" +
2085  " WITH REPLICATION = 4");
2086  ParsesOk("CREATE TABLE Foo (i int) PARTITIONED BY(j int) CACHED IN 'myPool'");
2087  ParsesOk("CREATE TABLE Foo (i int) PARTITIONED BY(j int) LOCATION '/a' " +
2088  "CACHED IN 'myPool'");
2089  ParserError("CREATE TABLE Foo (i int) CACHED IN myPool");
2090  ParserError("CREATE TABLE Foo (i int) PARTITIONED BY(j int) CACHED IN");
2091  ParserError("CREATE TABLE Foo (i int) CACHED 'myPool'");
2092  ParserError("CREATE TABLE Foo (i int) IN 'myPool'");
2093  ParserError("CREATE TABLE Foo (i int) PARTITIONED BY(j int) CACHED IN 'myPool' " +
2094  "LOCATION '/a'");
2095  ParserError("CREATE TABLE Foo (i int) CACHED IN 'myPool' WITH REPLICATION = -1");
2096  ParserError("CREATE TABLE Foo (i int) CACHED IN 'myPool' WITH REPLICATION = 1.0");
2097  ParserError("CREATE TABLE Foo (i int) CACHED IN 'myPool' " +
2098  "WITH REPLICATION = cast(1 as double)");
2099 
2100  // Invalid syntax
2101  ParserError("CREATE TABLE IF EXISTS Foo.Bar (i int)");
2102  ParserError("CREATE TABLE Bar LIKE Bar2 (i int)");
2103  ParserError("CREATE IF NOT EXISTS TABLE Foo.Bar (i int)");
2104  ParserError("CREATE TABLE Foo (d double) STORED TEXTFILE");
2105  ParserError("CREATE TABLE Foo (d double) AS TEXTFILE");
2106  ParserError("CREATE TABLE Foo i int");
2107  ParserError("CREATE TABLE Foo (i intt)");
2108  ParserError("CREATE TABLE Foo (int i)");
2109  ParserError("CREATE TABLE Foo ()");
2110  ParserError("CREATE TABLE");
2111  ParserError("CREATE EXTERNAL");
2112  ParserError("CREATE");
2113 
2114  // Valid syntax for tables PRODUCED BY DATA SOURCE
2115  ParsesOk("CREATE TABLE Foo (i int, s string) PRODUCED BY DATA SOURCE Bar");
2116  ParsesOk("CREATE TABLE Foo (i int, s string) PRODUCED BY DATA SOURCE Bar(\"\")");
2117  ParsesOk("CREATE TABLE Foo (i int) PRODUCED BY DATA SOURCE " +
2118  "Bar(\"Foo \\!@#$%^&*()\")");
2119  ParsesOk("CREATE TABLE IF NOT EXISTS Foo (i int) PRODUCED BY DATA SOURCE Bar(\"\")");
2120 
2121  // Invalid syntax for tables PRODUCED BY DATA SOURCE
2122  ParserError("CREATE TABLE Foo (i int) PRODUCED BY DATA Foo");
2123  ParserError("CREATE TABLE Foo (i int) PRODUCED BY DATA SRC Foo");
2124  ParserError("CREATE TABLE Foo (i int) PRODUCED BY DATA SOURCE Foo.Bar");
2125  ParserError("CREATE TABLE Foo (i int) PRODUCED BY DATA SOURCE Foo()");
2126  ParserError("CREATE EXTERNAL TABLE Foo (i int) PRODUCED BY DATA SOURCE Foo(\"\")");
2127  ParserError("CREATE TABLE Foo (i int) PRODUCED BY DATA SOURCE Foo(\"\") " +
2128  "LOCATION 'x'");
2129  ParserError("CREATE TABLE Foo (i int) PRODUCED BY DATA SOURCE Foo(\"\") " +
2130  "ROW FORMAT DELIMITED");
2131  ParserError("CREATE TABLE Foo (i int) PARTITIONED BY (j string) PRODUCED BY DATA " +
2132  "SOURCE Foo(\"\")");
2133  }
2134 
2135  @Test
2136  public void TestCreateDataSource() {
2137  ParsesOk("CREATE DATA SOURCE foo LOCATION '/foo.jar' CLASS 'com.bar.Foo' " +
2138  "API_VERSION 'V1'");
2139  ParsesOk("CREATE DATA SOURCE foo LOCATION \"/foo.jar\" CLASS \"com.bar.Foo\" " +
2140  "API_VERSION \"V1\"");
2141  ParsesOk("CREATE DATA SOURCE foo LOCATION '/x/foo@hi_^!#.jar' CLASS 'com.bar.Foo' " +
2142  "API_VERSION 'V1'");
2143 
2144  ParserError("CREATE DATA foo LOCATION '/foo.jar' CLASS 'com.bar.Foo' " +
2145  "API_VERSION 'V1'");
2146  ParserError("CREATE DATA SRC foo.bar LOCATION '/foo.jar' CLASS 'com.bar.Foo' " +
2147  "API_VERSION 'V1'");
2148  ParserError("CREATE DATA SOURCE foo.bar LOCATION '/x/foo.jar' CLASS 'com.bar.Foo' " +
2149  "API_VERSION 'V1'");
2150  ParserError("CREATE DATA SOURCE foo LOCATION /x/foo.jar CLASS 'com.bar.Foo' " +
2151  "API_VERSION 'V1'");
2152  ParserError("CREATE DATA SOURCE foo LOCATION '/x/foo.jar' CLASS com.bar.Foo " +
2153  "API_VERSION 'V1'");
2154  ParserError("CREATE DATA SOURCE foo LOCATION '/x/foo.jar' CLASS 'com.bar.Foo' " +
2155  "API_VERSION V1");
2156  ParserError("CREATE DATA SOURCE LOCATION '/x/foo.jar' CLASS 'com.bar.Foo' " +
2157  "API_VERSION 'V1'");
2158  ParserError("CREATE DATA SOURCE foo CLASS 'com.bar.Foo' " +
2159  "API_VERSION 'V1'");
2160  ParserError("CREATE DATA SOURCE foo LOCATION CLASS 'com.bar.Foo' " +
2161  "API_VERSION 'V1'");
2162  ParserError("CREATE DATA SOURCE foo LOCATION '/foo.jar' API_VERSION 'V1'");
2163  ParserError("CREATE DATA SOURCE foo LOCATION '/foo.jar' CLASS API_VERSION 'V1'");
2164  ParserError("CREATE DATA SOURCE foo LOCATION '/foo.jar' CLASS 'com.bar.Foo'");
2165  ParserError("CREATE DATA SOURCE foo LOCATION '/foo.jar' CLASS 'Foo' API_VERSION");
2166  ParserError("CREATE DATA SOURCE foo CLASS 'com.bar.Foo' LOCATION '/x/foo.jar' " +
2167  "API_VERSION 'V1'");
2168  ParserError("CREATE DATA SOURCE foo CLASS 'com.bar.Foo' API_VERSION 'V1' " +
2169  "LOCATION '/x/foo.jar' ");
2170  ParserError("CREATE DATA SOURCE foo API_VERSION 'V1' LOCATION '/x/foo.jar' " +
2171  "CLASS 'com.bar.Foo'");
2172  }
2173 
2174  @Test
2175  public void TestDropDataSource() {
2176  ParsesOk("DROP DATA SOURCE foo");
2177 
2178  ParserError("DROP DATA foo");
2179  ParserError("DROP DATA SRC foo");
2180  ParserError("DROP DATA SOURCE foo.bar");
2181  ParserError("DROP DATA SOURCE");
2182  }
2183 
2184  @Test
2185  public void TestCreateView() {
2186  ParsesOk("CREATE VIEW Bar AS SELECT a, b, c from t");
2187  ParsesOk("CREATE VIEW Bar COMMENT 'test' AS SELECT a, b, c from t");
2188  ParsesOk("CREATE VIEW Bar (x, y, z) AS SELECT a, b, c from t");
2189  ParsesOk("CREATE VIEW Bar (x, y COMMENT 'foo', z) AS SELECT a, b, c from t");
2190  ParsesOk("CREATE VIEW Bar (x, y, z) COMMENT 'test' AS SELECT a, b, c from t");
2191  ParsesOk("CREATE VIEW IF NOT EXISTS Bar AS SELECT a, b, c from t");
2192 
2193  ParsesOk("CREATE VIEW Foo.Bar AS SELECT a, b, c from t");
2194  ParsesOk("CREATE VIEW Foo.Bar COMMENT 'test' AS SELECT a, b, c from t");
2195  ParsesOk("CREATE VIEW Foo.Bar (x, y, z) AS SELECT a, b, c from t");
2196  ParsesOk("CREATE VIEW Foo.Bar (x, y, z COMMENT 'foo') AS SELECT a, b, c from t");
2197  ParsesOk("CREATE VIEW Foo.Bar (x, y, z) COMMENT 'test' AS SELECT a, b, c from t");
2198  ParsesOk("CREATE VIEW IF NOT EXISTS Foo.Bar AS SELECT a, b, c from t");
2199 
2200  // Test all valid query statements as view definitions.
2201  ParsesOk("CREATE VIEW Bar AS SELECT 1, 2, 3");
2202  ParsesOk("CREATE VIEW Bar AS VALUES(1, 2, 3)");
2203  ParsesOk("CREATE VIEW Bar AS SELECT 1, 2, 3 UNION ALL select 4, 5, 6");
2204  ParsesOk("CREATE VIEW Bar AS WITH t AS (SELECT 1, 2, 3) SELECT * FROM t");
2205 
2206  // Mismatched number of columns in column definition and view definition parses ok.
2207  ParsesOk("CREATE VIEW Bar (x, y) AS SELECT 1, 2, 3");
2208 
2209  // No view name.
2210  ParserError("CREATE VIEW AS SELECT c FROM t");
2211  // Missing AS keyword
2212  ParserError("CREATE VIEW Bar SELECT c FROM t");
2213  // Empty column definition not allowed.
2214  ParserError("CREATE VIEW Foo.Bar () AS SELECT c FROM t");
2215  // Column definitions cannot include types.
2216  ParserError("CREATE VIEW Foo.Bar (x int) AS SELECT c FROM t");
2217  ParserError("CREATE VIEW Foo.Bar (x int COMMENT 'x') AS SELECT c FROM t");
2218  // A type does not parse as an identifier.
2219  ParserError("CREATE VIEW Foo.Bar (int COMMENT 'x') AS SELECT c FROM t");
2220  // Missing view definition.
2221  ParserError("CREATE VIEW Foo.Bar (x) AS");
2222  // Invalid view definitions. A view definition must be a query statement.
2223  ParserError("CREATE VIEW Foo.Bar (x) AS INSERT INTO t select * from t");
2224  ParserError("CREATE VIEW Foo.Bar (x) AS CREATE TABLE Wrong (i int)");
2225  ParserError("CREATE VIEW Foo.Bar (x) AS ALTER TABLE Foo COLUMNS (i int, s string)");
2226  ParserError("CREATE VIEW Foo.Bar (x) AS CREATE VIEW Foo.Bar AS SELECT 1");
2227  ParserError("CREATE VIEW Foo.Bar (x) AS ALTER VIEW Foo.Bar AS SELECT 1");
2228  }
2229 
2230  @Test
2231  public void TestAlterView() {
2232  ParsesOk("ALTER VIEW Bar AS SELECT 1, 2, 3");
2233  ParsesOk("ALTER VIEW Bar AS SELECT a, b, c FROM t");
2234  ParsesOk("ALTER VIEW Bar AS VALUES(1, 2, 3)");
2235  ParsesOk("ALTER VIEW Bar AS SELECT 1, 2, 3 UNION ALL select 4, 5, 6");
2236 
2237  ParsesOk("ALTER VIEW Foo.Bar AS SELECT 1, 2, 3");
2238  ParsesOk("ALTER VIEW Foo.Bar AS SELECT a, b, c FROM t");
2239  ParsesOk("ALTER VIEW Foo.Bar AS VALUES(1, 2, 3)");
2240  ParsesOk("ALTER VIEW Foo.Bar AS SELECT 1, 2, 3 UNION ALL select 4, 5, 6");
2241  ParsesOk("ALTER VIEW Foo.Bar AS WITH t AS (SELECT 1, 2, 3) SELECT * FROM t");
2242 
2243  // Must be ALTER VIEW not ALTER TABLE.
2244  ParserError("ALTER TABLE Foo.Bar AS SELECT 1, 2, 3");
2245  // Missing view name.
2246  ParserError("ALTER VIEW AS SELECT 1, 2, 3");
2247  // Missing AS name.
2248  ParserError("ALTER VIEW Foo.Bar SELECT 1, 2, 3");
2249  // Missing view definition.
2250  ParserError("ALTER VIEW Foo.Bar AS");
2251  // Invalid view definitions. A view definition must be a query statement.
2252  ParserError("ALTER VIEW Foo.Bar AS INSERT INTO t select * from t");
2253  ParserError("ALTER VIEW Foo.Bar AS CREATE TABLE Wrong (i int)");
2254  ParserError("ALTER VIEW Foo.Bar AS ALTER TABLE Foo COLUMNS (i int, s string)");
2255  ParserError("ALTER VIEW Foo.Bar AS CREATE VIEW Foo.Bar AS SELECT 1, 2, 3");
2256  ParserError("ALTER VIEW Foo.Bar AS ALTER VIEW Foo.Bar AS SELECT 1, 2, 3");
2257  }
2258 
2259  @Test
2260  public void TestCreateTableAsSelect() {
2261  ParsesOk("CREATE TABLE Foo AS SELECT 1, 2, 3");
2262  ParsesOk("CREATE TABLE Foo AS SELECT * from foo.bar");
2263  ParsesOk("CREATE TABLE Foo.Bar AS SELECT int_col, bool_col from tbl limit 10");
2264  ParsesOk("CREATE TABLE Foo.Bar LOCATION '/a/b' AS SELECT * from foo");
2265  ParsesOk("CREATE TABLE IF NOT EXISTS Foo.Bar LOCATION '/a/b' AS SELECT * from foo");
2266  ParsesOk("CREATE TABLE Foo STORED AS PARQUET AS SELECT 1");
2267  ParsesOk("CREATE TABLE Foo ROW FORMAT DELIMITED STORED AS PARQUETFILE AS SELECT 1");
2268  ParsesOk("CREATE TABLE Foo TBLPROPERTIES ('a'='b', 'c'='d') AS SELECT * from bar");
2269 
2270  // With clause works
2271  ParsesOk("CREATE TABLE Foo AS with t1 as (select 1) select * from t1");
2272 
2273  // Incomplete AS SELECT statement
2274  ParserError("CREATE TABLE Foo ROW FORMAT DELIMITED STORED AS PARQUET AS SELECT");
2275  ParserError("CREATE TABLE Foo ROW FORMAT DELIMITED STORED AS PARQUET AS WITH");
2276  ParserError("CREATE TABLE Foo ROW FORMAT DELIMITED STORED AS PARQUET AS");
2277 
2278  // INSERT statements are not allowed
2279  ParserError("CREATE TABLE Foo AS INSERT INTO Foo SELECT 1");
2280 
2281  // Column and partition definitions not allowed
2282  ParserError("CREATE TABLE Foo(i int) AS SELECT 1");
2283  ParserError("CREATE TABLE Foo PARTITIONED BY(i int) AS SELECT 1");
2284  }
2285 
2286  @Test
2287  public void TestDrop() {
2288  ParsesOk("DROP TABLE Foo");
2289  ParsesOk("DROP TABLE Foo.Bar");
2290  ParsesOk("DROP TABLE IF EXISTS Foo.Bar");
2291  ParsesOk("DROP VIEW Foo");
2292  ParsesOk("DROP VIEW Foo.Bar");
2293  ParsesOk("DROP VIEW IF EXISTS Foo.Bar");
2294  ParsesOk("DROP DATABASE Foo");
2295  ParsesOk("DROP SCHEMA Foo");
2296  ParsesOk("DROP DATABASE IF EXISTS Foo");
2297  ParsesOk("DROP SCHEMA IF EXISTS Foo");
2298  ParsesOk("DROP FUNCTION Foo()");
2299  ParsesOk("DROP AGGREGATE FUNCTION Foo(INT)");
2300  ParsesOk("DROP FUNCTION Foo.Foo(INT)");
2301  ParsesOk("DROP AGGREGATE FUNCTION IF EXISTS Foo()");
2302  ParsesOk("DROP FUNCTION IF EXISTS Foo(INT)");
2303  ParsesOk("DROP FUNCTION IF EXISTS Foo(INT...)");
2304 
2305  ParserError("DROP");
2306  ParserError("DROP Foo");
2307  ParserError("DROP DATABASE Foo.Bar");
2308  ParserError("DROP SCHEMA Foo.Bar");
2309  ParserError("DROP DATABASE Foo Bar");
2310  ParserError("DROP SCHEMA Foo Bar");
2311  ParserError("DROP TABLE IF Foo");
2312  ParserError("DROP TABLE EXISTS Foo");
2313  ParserError("DROP IF EXISTS TABLE Foo");
2314  ParserError("DROP TBL Foo");
2315  ParserError("DROP VIEW IF Foo");
2316  ParserError("DROP VIEW EXISTS Foo");
2317  ParserError("DROP IF EXISTS VIEW Foo");
2318  ParserError("DROP VIW Foo");
2319  ParserError("DROP FUNCTION Foo)");
2320  ParserError("DROP FUNCTION Foo(");
2321  ParserError("DROP FUNCTION Foo");
2322  ParserError("DROP FUNCTION");
2323  ParserError("DROP BLAH FUNCTION");
2324  ParserError("DROP IF EXISTS FUNCTION Foo()");
2325  ParserError("DROP FUNCTION Foo(INT) RETURNS INT");
2326  ParserError("DROP FUNCTION Foo.(INT) RETURNS INT");
2327  ParserError("DROP FUNCTION Foo..(INT) RETURNS INT");
2328  ParserError("DROP FUNCTION Foo(NULL) RETURNS INT");
2329  ParserError("DROP FUNCTION Foo(INT) RETURNS NULL");
2330  ParserError("DROP BLAH FUNCTION IF EXISTS Foo.A.Foo(INT)");
2331  ParserError("DROP FUNCTION IF EXISTS Foo(...)");
2332  }
2333 
2334  @Test
2335  public void TestLoadData() {
2336  ParsesOk("LOAD DATA INPATH '/a/b' INTO TABLE Foo");
2337  ParsesOk("LOAD DATA INPATH '/a/b' INTO TABLE Foo.Bar");
2338  ParsesOk("LOAD DATA INPATH '/a/b' OVERWRITE INTO TABLE Foo.Bar");
2339  ParsesOk("LOAD DATA INPATH '/a/b' INTO TABLE Foo PARTITION(a=1, b='asdf')");
2340  ParsesOk("LOAD DATA INPATH '/a/b' INTO TABLE Foo PARTITION(a=1)");
2341 
2342  ParserError("LOAD DATA INPATH '/a/b' INTO Foo PARTITION(a=1)");
2343  ParserError("LOAD DATA INPATH '/a/b' INTO Foo PARTITION(a)");
2344  ParserError("LOAD DATA INPATH '/a/b' INTO Foo PARTITION");
2345  ParserError("LOAD DATA INPATH /a/b/c INTO Foo");
2346  ParserError("LOAD DATA INPATH /a/b/c INTO Foo");
2347 
2348  // Loading data from a 'LOCAL' path is not supported.
2349  ParserError("LOAD DATA LOCAL INPATH '/a/b' INTO TABLE Foo");
2350  }
2351 
2356  private void TypeDefsParseOk(String... typeDefs) {
2357  for (String typeDefStr: typeDefs) {
2358  ParsesOk(String.format("CREATE TABLE t (i %s)", typeDefStr));
2359  ParsesOk(String.format("SELECT CAST (i AS %s)", typeDefStr));
2360  // Test typeDefStr in complex types.
2361  ParsesOk(String.format("CREATE TABLE t (i MAP<%s, %s>)", typeDefStr, typeDefStr));
2362  ParsesOk(String.format("CREATE TABLE t (i ARRAY<%s>)", typeDefStr));
2363  ParsesOk(String.format("CREATE TABLE t (i STRUCT<f:%s>)", typeDefStr));
2364  }
2365  }
2366 
2370  private void TypeDefsError(String... typeDefs) {
2371  for (String typeDefStr: typeDefs) {
2372  ParserError(String.format("CREATE TABLE t (i %s)", typeDefStr));
2373  ParserError(String.format("SELECT CAST (i AS %s)", typeDefStr));
2374  }
2375  }
2376 
2377  @Test
2378  public void TestTypes() {
2379  // Test primitive types.
2380  TypeDefsParseOk("BOOLEAN");
2381  TypeDefsParseOk("TINYINT");
2382  TypeDefsParseOk("SMALLINT");
2383  TypeDefsParseOk("INT", "INTEGER");
2384  TypeDefsParseOk("BIGINT");
2385  TypeDefsParseOk("FLOAT");
2386  TypeDefsParseOk("DOUBLE", "REAL");
2387  TypeDefsParseOk("STRING");
2388  TypeDefsParseOk("CHAR(1)", "CHAR(20)");
2389  TypeDefsParseOk("BINARY");
2390  TypeDefsParseOk("DECIMAL");
2391  TypeDefsParseOk("TIMESTAMP");
2392 
2393  // Test decimal.
2394  TypeDefsParseOk("DECIMAL");
2395  TypeDefsParseOk("DECIMAL(1)");
2396  TypeDefsParseOk("DECIMAL(1, 2)");
2397  TypeDefsParseOk("DECIMAL(2, 1)");
2398  TypeDefsParseOk("DECIMAL(6, 6)");
2399  TypeDefsParseOk("DECIMAL(100, 0)");
2400  TypeDefsParseOk("DECIMAL(0, 0)");
2401 
2402  TypeDefsError("DECIMAL()");
2403  TypeDefsError("DECIMAL(a)");
2404  TypeDefsError("DECIMAL(1, a)");
2405  TypeDefsError("DECIMAL(1, 2, 3)");
2406  TypeDefsError("DECIMAL(-1)");
2407 
2408  // Test complex types.
2409  TypeDefsParseOk("ARRAY<BIGINT>");
2410  TypeDefsParseOk("MAP<TINYINT, DOUBLE>");
2411  TypeDefsParseOk("STRUCT<f:TINYINT>");
2412  TypeDefsParseOk("STRUCT<a:TINYINT, b:BIGINT, c:DOUBLE>");
2413  TypeDefsParseOk("STRUCT<a:TINYINT COMMENT 'x', b:BIGINT, c:DOUBLE COMMENT 'y'>");
2414 
2415  TypeDefsError("CHAR()");
2416  TypeDefsError("CHAR(1, 1)");
2417  TypeDefsError("ARRAY<>");
2418  TypeDefsError("ARRAY BIGINT");
2419  TypeDefsError("MAP<>");
2420  TypeDefsError("MAP<TINYINT>");
2421  TypeDefsError("MAP<TINYINT, BIGINT, DOUBLE>");
2422  TypeDefsError("STRUCT<>");
2423  TypeDefsError("STRUCT<TINYINT>");
2424  TypeDefsError("STRUCT<a TINYINT>");
2425  TypeDefsError("STRUCT<'a':TINYINT>");
2426  }
2427 
2428  @Test
2429  public void TestResetMetadata() {
2430  ParsesOk("invalidate metadata");
2431  ParsesOk("invalidate metadata Foo");
2432  ParsesOk("invalidate metadata Foo.S");
2433  ParsesOk("refresh Foo");
2434  ParsesOk("refresh Foo.S");
2435 
2436  ParserError("invalidate");
2437  ParserError("invalidate metadata Foo.S.S");
2438  ParserError("REFRESH Foo.S.S");
2439  ParserError("refresh");
2440  }
2441 
2442  @Test
2443  public void TestComputeDropStats() {
2444  String[] prefixes = {"compute", "drop"};
2445 
2446  for (String prefix: prefixes) {
2447  ParsesOk(prefix + " stats bar");
2448  ParsesOk(prefix + " stats `bar`");
2449  ParsesOk(prefix + " stats foo.bar");
2450  ParsesOk(prefix + " stats `foo`.`bar`");
2451 
2452  // Missing table name.
2453  ParserError(prefix + " stats");
2454  // Missing 'stats' keyword.
2455  ParserError(prefix + " foo");
2456  // Cannot use string literal as table name.
2457  ParserError(prefix + " stats 'foo'");
2458  // Cannot analyze multiple tables in one stmt.
2459  ParserError(prefix + " stats foo bar");
2460  }
2461  }
2462 
2463  @Test
2464  public void TestGetErrorMsg() {
2465 
2466  // missing select
2467  ParserError("c, b, c from t",
2468  "Syntax error in line 1:\n" +
2469  "c, b, c from t\n" +
2470  "^\n" +
2471  "Encountered: IDENTIFIER\n" +
2472  "Expected: ALTER, COMPUTE, CREATE, DESCRIBE, DROP, EXPLAIN, GRANT, " +
2473  "INSERT, INVALIDATE, LOAD, REFRESH, REVOKE, SELECT, SET, SHOW, USE, " +
2474  "VALUES, WITH\n");
2475 
2476  // missing select list
2477  ParserError("select from t",
2478  "Syntax error in line 1:\n" +
2479  "select from t\n" +
2480  " ^\n" +
2481  "Encountered: FROM\n" +
2482  "Expected: ALL, CASE, CAST, DISTINCT, EXISTS, " +
2483  "FALSE, IF, INTERVAL, NOT, NULL, " +
2484  "STRAIGHT_JOIN, TRUE, IDENTIFIER\n");
2485 
2486  // missing from
2487  ParserError("select c, b, c where a = 5",
2488  "Syntax error in line 1:\n" +
2489  "select c, b, c where a = 5\n" +
2490  " ^\n" +
2491  "Encountered: WHERE\n" +
2492  "Expected: AND, AS, BETWEEN, DIV, FROM, IN, IS, LIKE, LIMIT, NOT, OR, " +
2493  "ORDER, REGEXP, RLIKE, UNION, COMMA, IDENTIFIER\n");
2494 
2495  // missing table list
2496  ParserError("select c, b, c from where a = 5",
2497  "Syntax error in line 1:\n" +
2498  "select c, b, c from where a = 5\n" +
2499  " ^\n" +
2500  "Encountered: WHERE\n" +
2501  "Expected: IDENTIFIER\n");
2502 
2503  // missing predicate in where clause (no group by)
2504  ParserError("select c, b, c from t where",
2505  "Syntax error in line 1:\n" +
2506  "select c, b, c from t where\n" +
2507  " ^\n" +
2508  "Encountered: EOF\n" +
2509  "Expected: CASE, CAST, EXISTS, FALSE, " +
2510  "IF, INTERVAL, NOT, NULL, TRUE, IDENTIFIER\n");
2511 
2512  // missing predicate in where clause (group by)
2513  ParserError("select c, b, c from t where group by a, b",
2514  "Syntax error in line 1:\n" +
2515  "select c, b, c from t where group by a, b\n" +
2516  " ^\n" +
2517  "Encountered: GROUP\n" +
2518  "Expected: CASE, CAST, EXISTS, FALSE, " +
2519  "IF, INTERVAL, NOT, NULL, TRUE, IDENTIFIER\n");
2520 
2521  // unmatched string literal starting with "
2522  ParserError("select c, \"b, c from t",
2523  "Unmatched string literal in line 1:\n" +
2524  "select c, \"b, c from t\n" +
2525  " ^\n");
2526 
2527  // unmatched string literal starting with '
2528  ParserError("select c, 'b, c from t",
2529  "Unmatched string literal in line 1:\n" +
2530  "select c, 'b, c from t\n" +
2531  " ^\n");
2532 
2533  // test placement of error indicator ^ on queries with multiple lines
2534  ParserError("select (i + 5)(1 - i) from t",
2535  "Syntax error in line 1:\n" +
2536  "select (i + 5)(1 - i) from t\n" +
2537  " ^\n" +
2538  "Encountered: (\n" +
2539  "Expected:");
2540 
2541  ParserError("select (i + 5)\n(1 - i) from t",
2542  "Syntax error in line 2:\n" +
2543  "(1 - i) from t\n" +
2544  "^\n" +
2545  "Encountered: (\n" +
2546  "Expected");
2547 
2548  ParserError("select (i + 5)\n(1 - i)\nfrom t",
2549  "Syntax error in line 2:\n" +
2550  "(1 - i)\n" +
2551  "^\n" +
2552  "Encountered: (\n" +
2553  "Expected");
2554 
2555  // Long line: error in the middle
2556  ParserError("select c, b, c,c,c,c,c,c,c,c,c,a a a,c,c,c,c,c,c,c,cd,c,d,d,,c, from t",
2557  "Syntax error in line 1:\n" +
2558  "... b, c,c,c,c,c,c,c,c,c,a a a,c,c,c,c,c,c,c,cd,c,d,d,,c,...\n" +
2559  " ^\n" +
2560  "Encountered: IDENTIFIER\n" +
2561  "Expected: CROSS, FROM, FULL, GROUP, HAVING, INNER, JOIN, LEFT, LIMIT, OFFSET, " +
2562  "ON, ORDER, RIGHT, UNION, USING, WHERE, COMMA\n");
2563 
2564  // Long line: error close to the start
2565  ParserError("select a a a, b, c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,cd,c,d,d,,c, from t",
2566  "Syntax error in line 1:\n" +
2567  "select a a a, b, c,c,c,c,c,c,c,c,c,c,c,...\n" +
2568  " ^\n" +
2569  "Encountered: IDENTIFIER\n" +
2570  "Expected: CROSS, FROM, FULL, GROUP, HAVING, INNER, JOIN, LEFT, LIMIT, OFFSET, " +
2571  "ON, ORDER, RIGHT, UNION, USING, WHERE, COMMA\n");
2572 
2573  // Long line: error close to the end
2574  ParserError("select a, b, c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,cd,c,d,d, ,c, from t",
2575  "Syntax error in line 1:\n" +
2576  "...c,c,c,c,c,c,c,c,cd,c,d,d, ,c, from t\n" +
2577  " ^\n" +
2578  "Encountered: COMMA\n" +
2579  "Expected: CASE, CAST, EXISTS, FALSE, " +
2580  "IF, INTERVAL, NOT, NULL, TRUE, IDENTIFIER\n");
2581 
2582  // Parsing identifiers that have different names printed as EXPECTED
2583  ParserError("DROP DATA SRC foo",
2584  "Syntax error in line 1:\n" +
2585  "DROP DATA SRC foo\n" +
2586  " ^\n" +
2587  "Encountered: IDENTIFIER\n" +
2588  "Expected: SOURCE\n");
2589  ParserError("SHOW DATA SRCS",
2590  "Syntax error in line 1:\n" +
2591  "SHOW DATA SRCS\n" +
2592  " ^\n" +
2593  "Encountered: IDENTIFIER\n" +
2594  "Expected: SOURCES\n");
2595  ParserError("USE ` `",
2596  "Syntax error in line 1:\n" +
2597  "USE ` `\n" +
2598  " ^\n" +
2599  "Encountered: EMPTY IDENTIFIER\n" +
2600  "Expected: IDENTIFIER\n");
2601 
2602  // Expecting = token
2603  ParserError("SET foo",
2604  "Syntax error in line 1:\n" +
2605  "SET foo\n" +
2606  " ^\n" +
2607  "Encountered: EOF\n" +
2608  "Expected: =\n");
2609  }
2610 
2611  @Test
2612  public void TestExplain() {
2613  ParsesOk("explain select a from tbl");
2614  ParsesOk("explain insert into tbl select a, b, c, d from tbl");
2615  ParserError("explain");
2616  // cannot EXPLAIN an explain stmt
2617  ParserError("explain explain select a from tbl");
2618  // cannot EXPLAIN DDL stmt
2619  ParserError("explain CREATE TABLE Foo (i int)");
2620  }
2621 
2622  @Test
2623  public void TestSubqueries() {
2624  // Binary nested predicates
2625  String subquery = "(SELECT count(*) FROM bar)";
2626  String[] operators = {"=", "!=", "<>", ">", ">=", "<", "<="};
2627  for (String op: operators) {
2628  ParsesOk(String.format("SELECT * FROM foo WHERE a %s %s", op, subquery));
2629  ParsesOk(String.format("SELECT * FROM foo WHERE %s %s a", subquery, op));
2630  }
2631  // Binary predicate with an arithmetic expr
2632  ParsesOk("SELECT * FROM foo WHERE a+1 > (SELECT count(a) FROM bar)");
2633  ParsesOk("SELECT * FROM foo WHERE (SELECT count(a) FROM bar) < a+1");
2634 
2635  // [NOT] IN nested predicates
2636  ParsesOk("SELECT * FROM foo WHERE a IN (SELECT a FROM bar)");
2637  ParsesOk("SELECT * FROM foo WHERE a NOT IN (SELECT a FROM bar)");
2638 
2639  // [NOT] EXISTS predicates
2640  ParsesOk("SELECT * FROM foo WHERE EXISTS (SELECT a FROM bar WHERE b > 0)");
2641  ParsesOk("SELECT * FROM foo WHERE NOT EXISTS (SELECT a FROM bar WHERE b > 0)");
2642  ParsesOk("SELECT * FROM foo WHERE NOT (EXISTS (SELECT a FROM bar))");
2643 
2644  // Compound nested predicates
2645  ParsesOk("SELECT * FROM foo WHERE a = (SELECT count(a) FROM bar) AND " +
2646  "b != (SELECT count(b) FROM baz) and c IN (SELECT c FROM qux)");
2647  ParsesOk("SELECT * FROM foo WHERE EXISTS (SELECT a FROM bar WHERE b < 0) AND " +
2648  "NOT EXISTS (SELECT a FROM baz WHERE b > 0)");
2649  ParsesOk("SELECT * FROM foo WHERE EXISTS (SELECT a from bar) AND " +
2650  "NOT EXISTS (SELECT a FROM baz) AND b IN (SELECT b FROM bar) AND " +
2651  "c NOT IN (SELECT c FROM qux) AND d = (SELECT max(d) FROM quux)");
2652 
2653  // Nested parentheses
2654  ParsesOk("SELECT * FROM foo WHERE EXISTS ((SELECT * FROM bar))");
2655  ParsesOk("SELECT * FROM foo WHERE EXISTS (((SELECT * FROM bar)))");
2656  ParsesOk("SELECT * FROM foo WHERE a IN ((SELECT a FROM bar))");
2657  ParsesOk("SELECT * FROM foo WHERE a = ((SELECT max(a) FROM bar))");
2658 
2659  // More than one nesting level
2660  ParsesOk("SELECT * FROM foo WHERE a IN (SELECT a FROM bar WHERE b IN " +
2661  "(SELECT b FROM baz))");
2662  ParsesOk("SELECT * FROM foo WHERE EXISTS (SELECT a FROM bar WHERE b NOT IN " +
2663  "(SELECT b FROM baz WHERE c < 10 AND d = (SELECT max(d) FROM qux)))");
2664 
2665  // Binary predicate between subqueries
2666  for (String op: operators) {
2667  ParsesOk(String.format("SELECT * FROM foo WHERE %s %s %s", subquery, op,
2668  subquery));
2669  }
2670 
2671  // Malformed nested subqueries
2672  // Missing or misplaced parenthesis around a subquery
2673  ParserError("SELECT * FROM foo WHERE a IN SELECT a FROM bar");
2674  ParserError("SELECT * FROM foo WHERE a = SELECT count(*) FROM bar");
2675  ParserError("SELECT * FROM foo WHERE EXISTS SELECT * FROM bar");
2676  ParserError("SELECT * FROM foo WHERE a IN (SELECT a FROM bar");
2677  ParserError("SELECT * FROM foo WHERE a IN SELECT a FROM bar)");
2678  ParserError("SELECT * FROM foo WHERE a IN (SELECT) a FROM bar");
2679 
2680  // Invalid syntax for [NOT] EXISTS
2681  ParserError("SELECT * FROM foo WHERE a EXISTS (SELECT * FROM bar)");
2682  ParserError("SELECT * FROM foo WHERE a NOT EXISTS (SELECT * FROM bar)");
2683 
2684  // Set operations between subqueries
2685  ParserError("SELECT * FROM foo WHERE EXISTS ((SELECT a FROM bar) UNION " +
2686  "(SELECT a FROM baz))");
2687 
2688  // Nested predicate in the HAVING clause
2689  ParsesOk("SELECT a, count(*) FROM foo GROUP BY a HAVING count(*) > " +
2690  "(SELECT count(*) FROM bar)");
2691  ParsesOk("SELECT a, count(*) FROM foo GROUP BY a HAVING 10 > " +
2692  "(SELECT count(*) FROM bar)");
2693 
2694  // Subquery in the SELECT clause
2695  ParsesOk("SELECT a, b, (SELECT c FROM foo) FROM foo");
2696  ParsesOk("SELECT (SELECT a FROM foo), b, c FROM bar");
2697  ParsesOk("SELECT (SELECT (SELECT a FROM foo) FROM bar) FROM baz");
2698  ParsesOk("SELECT (SELECT a FROM foo)");
2699 
2700  // Malformed subquery in the SELECT clause
2701  ParserError("SELECT SELECT a FROM foo FROM bar");
2702  ParserError("SELECT (SELECT a FROM foo FROM bar");
2703  ParserError("SELECT SELECT a FROM foo) FROM bar");
2704  ParserError("SELECT (SELECT) a FROM foo");
2705 
2706  // Subquery in the GROUP BY clause
2707  ParsesOk("SELECT a, count(*) FROM foo GROUP BY (SELECT a FROM bar)");
2708  ParsesOk("SELECT a, count(*) FROM foo GROUP BY a, (SELECT b FROM bar)");
2709 
2710  // Malformed subquery in the GROUP BY clause
2711  ParserError("SELECT a, count(*) FROM foo GROUP BY SELECT a FROM bar");
2712  ParserError("SELECT a, count(*) FROM foo GROUP BY (SELECT) a FROM bar");
2713  ParserError("SELECT a, count(*) FROM foo GROUP BY (SELECT a FROM bar");
2714 
2715  // Subquery in the ORDER BY clause
2716  ParsesOk("SELECT a, b FROM foo ORDER BY (SELECT a FROM bar)");
2717  ParsesOk("SELECT a, b FROM foo ORDER BY (SELECT a FROM bar) DESC");
2718  ParsesOk("SELECT a, b FROM foo ORDER BY a ASC, (SELECT a FROM bar) DESC");
2719 
2720  // Malformed subquery in the ORDER BY clause
2721  ParserError("SELECT a, count(*) FROM foo ORDER BY SELECT a FROM bar");
2722  ParserError("SELECT a, count(*) FROM foo ORDER BY (SELECT) a FROM bar DESC");
2723  ParserError("SELECT a, count(*) FROM foo ORDER BY (SELECT a FROM bar ASC");
2724  }
2725 
2726  @Test
2727  public void TestSet() {
2728  ParsesOk("SET foo='bar'");
2729  ParsesOk("SET foo=\"bar\"");
2730  ParsesOk("SET foo=bar");
2731  ParsesOk("SET foo = bar");
2732  ParsesOk("SET foo=1");
2733  ParsesOk("SET foo=true");
2734  ParsesOk("SET foo=false");
2735  ParsesOk("SET foo=1.2");
2736  ParsesOk("SET foo=null");
2737  ParsesOk("SET foo=10g");
2738  ParsesOk("SET `foo`=0");
2739  ParsesOk("SET foo=''");
2740  ParsesOk("SET");
2741 
2742  ParserError("SET foo");
2743  ParserError("SET foo=");
2744  ParserError("SET foo=1+2");
2745  ParserError("SET foo = '10");
2746  }
2747 
2748  @Test
2749  public void TestCreateDropRole() {
2750  ParsesOk("CREATE ROLE foo");
2751  ParsesOk("DROP ROLE foo");
2752  ParsesOk("DROP ROLE foo");
2753  ParsesOk("CREATE ROLE `role`");
2754  ParsesOk("DROP ROLE `role`");
2755  ParserError("CREATE ROLE");
2756  ParserError("DROP ROLE");
2757  ParserError("CREATE ROLE 'foo'");
2758  ParserError("DROP ROLE 'foo'");
2759  }
2760 
2761  @Test
2762  public void TestGrantRevokeRole() {
2763  ParsesOk("GRANT ROLE foo TO GROUP bar");
2764  ParsesOk("REVOKE ROLE foo FROM GROUP bar");
2765  ParsesOk("GRANT ROLE `foo` TO GROUP `bar`");
2766 
2767  ParserError("GRANT ROLE foo TO GROUP");
2768  ParserError("GRANT ROLE foo FROM GROUP bar");
2769 
2770  ParserError("REVOKE ROLE foo FROM GROUP");
2771  ParserError("REVOKE ROLE foo TO GROUP bar");
2772  }
2773 
2774  @Test
2776  Object[][] grantRevFormatStrs = {{"GRANT", "TO"}, {"REVOKE", "FROM"}};
2777  for (Object[] formatStr: grantRevFormatStrs) {
2778  ParsesOk(String.format("%s ALL ON TABLE foo %s myRole", formatStr));
2779 
2780  // KW_ROLE is optional (Hive requires KW_ROLE, but Impala does not).
2781  ParsesOk(String.format("%s ALL ON TABLE foo %s ROLE myRole", formatStr));
2782 
2783  ParsesOk(String.format("%s ALL ON DATABASE foo %s myRole", formatStr));
2784  ParsesOk(String.format("%s ALL ON URI 'foo' %s myRole", formatStr));
2785 
2786  ParsesOk(String.format("%s INSERT ON TABLE foo %s myRole", formatStr));
2787  ParsesOk(String.format("%s INSERT ON DATABASE foo %s myRole", formatStr));
2788  ParsesOk(String.format("%s INSERT ON URI 'foo' %s myRole", formatStr));
2789 
2790  ParsesOk(String.format("%s SELECT ON TABLE foo %s myRole", formatStr));
2791  ParsesOk(String.format("%s SELECT ON DATABASE foo %s myRole", formatStr));
2792  ParsesOk(String.format("%s SELECT ON URI 'foo' %s myRole", formatStr));
2793 
2794  // Server scope does not accept a name.
2795  ParsesOk(String.format("%s ALL ON SERVER %s myRole", formatStr));
2796  ParsesOk(String.format("%s INSERT ON SERVER %s myRole", formatStr));
2797  ParsesOk(String.format("%s SELECT ON SERVER %s myRole", formatStr));
2798 
2799  // URIs are string literals
2800  ParserError(String.format("%s ALL ON URI foo %s myRole", formatStr));
2801  ParserError(String.format("%s ALL ON DATABASE 'foo' %s myRole", formatStr));
2802  ParserError(String.format("%s ALL ON TABLE 'foo' %s myRole", formatStr));
2803 
2804  // No object name (only works for SERVER scope)
2805  ParserError(String.format("GRANT ALL ON TABLE FROM myrole", formatStr));
2806  ParserError(String.format("GRANT ALL ON DATABASE FROM myrole", formatStr));
2807  ParserError(String.format("GRANT ALL ON URI FROM myrole", formatStr));
2808 
2809  // No role specified
2810  ParserError(String.format("%s ALL ON TABLE foo %s", formatStr));
2811  // Invalid privilege
2812  ParserError(String.format("%s FAKE ON TABLE foo %s myRole", formatStr));
2813  }
2814  ParsesOk("GRANT ALL ON TABLE foo TO myRole WITH GRANT OPTION");
2815  ParsesOk("GRANT ALL ON DATABASE foo TO myRole WITH GRANT OPTION");
2816  ParsesOk("GRANT ALL ON SERVER TO myRole WITH GRANT OPTION");
2817  ParsesOk("GRANT ALL ON URI '/abc/' TO myRole WITH GRANT OPTION");
2818  ParserError("GRANT ALL ON TABLE foo TO myRole WITH GRANT");
2819  ParserError("GRANT ALL ON TABLE foo TO myRole WITH");
2820  ParserError("GRANT ALL ON TABLE foo TO ROLE");
2821  ParserError("REVOKE ALL ON TABLE foo TO ROLE");
2822 
2823  ParsesOk("REVOKE GRANT OPTION FOR ALL ON TABLE foo FROM myRole");
2824  ParsesOk("REVOKE GRANT OPTION FOR ALL ON DATABASE foo FROM myRole");
2825  ParsesOk("REVOKE GRANT OPTION FOR ALL ON SERVER FROM myRole");
2826  ParsesOk("REVOKE GRANT OPTION FOR ALL ON URI '/abc/' FROM myRole");
2827  ParserError("REVOKE GRANT OPTION ALL ON URI '/abc/' FROM myRole");
2828  ParserError("REVOKE GRANT ALL ON URI '/abc/' FROM myRole");
2829 
2830  ParserError("ALL ON TABLE foo TO myrole");
2831  ParserError("ALL ON TABLE foo FROM myrole");
2832 
2833  ParserError("GRANT ALL ON TABLE foo FROM myrole");
2834  ParserError("REVOKE ALL ON TABLE foo TO myrole");
2835  }
2836 
2837  @Test
2838  public void TestShowRoles() {
2839  ParsesOk("SHOW ROLES");
2840  ParsesOk("SHOW CURRENT ROLES");
2841  ParsesOk("SHOW ROLE GRANT GROUP myGroup");
2842  ParserError("SHOW ROLES blah");
2843  ParserError("SHOW ROLE GRANT GROUP");
2844  ParserError("SHOW CURRENT");
2845  ParserError("SHOW ROLE");
2846  ParserError("SHOW");
2847  }
2848 
2849  @Test
2850  public void TestShowGrantRole() {
2851  // Show all grants on a role
2852  ParsesOk("SHOW GRANT ROLE foo");
2853 
2854  // Show grants on a specific object
2855  ParsesOk("SHOW GRANT ROLE foo ON SERVER");
2856  ParsesOk("SHOW GRANT ROLE foo ON DATABASE foo");
2857  ParsesOk("SHOW GRANT ROLE foo ON TABLE foo");
2858  ParsesOk("SHOW GRANT ROLE foo ON TABLE foo.bar");
2859  ParsesOk("SHOW GRANT ROLE foo ON URI '/abc/123'");
2860 
2861  ParserError("SHOW GRANT ROLE");
2862  ParserError("SHOW GRANT ROLE foo ON SERVER foo");
2863  ParserError("SHOW GRANT ROLE foo ON DATABASE");
2864  ParserError("SHOW GRANT ROLE foo ON TABLE");
2865  ParserError("SHOW GRANT ROLE foo ON URI abc");
2866  }
2867 
2868  @Test
2869  public void TestComputeStats() {
2870  ParsesOk("COMPUTE STATS functional.alltypes");
2871  ParserError("COMPUTE functional.alltypes");
2872  ParserError("COMPUTE STATS ON functional.alltypes");
2873  ParserError("COMPUTE STATS");
2874  }
2875 
2876  @Test
2878  ParsesOk("COMPUTE INCREMENTAL STATS functional.alltypes");
2879  ParserError("COMPUTE INCREMENTAL functional.alltypes");
2880 
2881  ParsesOk(
2882  "COMPUTE INCREMENTAL STATS functional.alltypes PARTITION(month=10, year=2010)");
2883  // No dynamic partition specs
2884  ParserError("COMPUTE INCREMENTAL STATS functional.alltypes PARTITION(month, year)");
2885 
2886  ParserError("COMPUTE INCREMENTAL STATS");
2887 
2888  ParsesOk("DROP INCREMENTAL STATS functional.alltypes PARTITION(month=10, year=2010)");
2889  ParserError("DROP INCREMENTAL STATS functional.alltypes PARTITION(month, year)");
2890  ParserError("DROP INCREMENTAL STATS functional.alltypes");
2891  }
2892 
2893  @Test
2894  public void TestSemiColon() {
2895  ParserError(";", "Syntax error");
2896  ParsesOk("SELECT 1;");
2897  ParsesOk(" SELECT 1 ; ");
2898  ParsesOk(" SELECT 1 ; ");
2899  ParserError("SELECT 1; SELECT 2;",
2900  "Syntax error in line 1:\n" +
2901  "SELECT 1; SELECT 2;\n" +
2902  " ^\n" +
2903  "Encountered: SELECT\n" +
2904  "Expected");
2905  ParsesOk("SELECT 1;;;");
2906  ParsesOk("SELECT 1 FROM functional.alltypestiny WHERE 1 = (SELECT 1);");
2907  ParserError("SELECT 1 FROM functional.alltypestiny WHERE 1 = (SELECT 1;)",
2908  "Syntax error");
2909  ParserError("SELECT 1 FROM functional.alltypestiny WHERE 1 = (SELECT 1;);",
2910  "Syntax error");
2911  ParsesOk("CREATE TABLE functional.test_table (col INT);");
2912  ParsesOk("DESCRIBE functional.alltypes;");
2913  ParsesOk("SET num_nodes=1;");
2914  }
2915 }
void TestInsertHints(String stmt, String...expectedHints)
void ParserError(String stmt, String expectedErrorString)
Definition: ParserTest.java:81
void TestSelectListHints(String stmt, String...expectedHints)
public< C extends Expr > Object ParsesOk(String selectStmtSql, Class< C > cl)
Definition: ParserTest.java:62
uint64_t Test(T *ht, const ProbeTuple *input, uint64_t num_tuples)
void TypeDefsError(String...typeDefs)
void TestJoinHints(String stmt, String...expectedHints)
void testLiteralTruthValues(String andStr, String orStr, String notStr)
void TypeDefsParseOk(String...typeDefs)
void testCompoundPredicates(String andStr, String orStr, String notStr)