Uploaded image for project: 'Calcite'
  1. Calcite
  2. CALCITE-4802

Babel parser doesn't parse IF(condition, then, else) statements

    XMLWordPrintableJSON

Details

    Description

      Following my email on Calcite's dev mailing list, julianhyde told me to open an issue as there is likely a bug in Babel's parser regarding IF statements.

       

      You can find the email with this title: Error parsing DATE("2021-01-01") for BigQuery using Calcite

       

      The symptoms are the following:

      • If I use SqlParserImpl.FACTORY, most statements work but DATE(string) fails, likely because it's a reserved keyword, as Julian pointed out in the mail thread. Statements such as IF(cond, then, else) work, as well as other dialect-specific functions such as CURRENT_DATETIME() [Bigquery].
      • If I use SqlBabelParserImpl.FACTORY, it will work for parsing DATE(string), it also works for dialect-specific functions, but it doesn't work for IF(cond, then, else).

       

      Here is a table to sum it up:

       

       

      Test Normal parser Babel
      1+(2*4) as foo SUCCESS SUCCESS
      CURRENT_DATE() SUCCESS SUCCESS
      CURRENT_DATETIME() SUCCESS SUCCESS
      DATE_FROM_UNIX(123456) SUCCESS SUCCESS
      IF(TRUE, 1, 2) SUCCESS FAILURE
      DATE("2021-01-01") FAILURE SUCCESS

       

       

      Here is the code I use to check:

       

       

      package test.Test;
      
      import org.apache.calcite.config.Lex;
      import org.apache.calcite.sql.SqlNode;
      import org.apache.calcite.sql.parser.SqlParseException;
      import org.apache.calcite.sql.parser.SqlParser;
      import org.apache.calcite.sql.parser.babel.SqlBabelParserImpl;
      import org.apache.calcite.sql.parser.impl.SqlParserImpl;
      import org.apache.calcite.sql.validate.SqlConformanceEnum;
      import org.apache.calcite.tools.FrameworkConfig;
      import org.apache.calcite.tools.Frameworks;
      import org.apache.calcite.tools.Planner;
      
      import java.util.HashMap;
      import java.util.Map;
      
      public class Test {
          public static void main(String[] args) {
              SqlParser.Config sqlParserConfigBabel = SqlParser.config().DEFAULT
                      .withLex(Lex.BIG_QUERY)
                      .withConformance(SqlConformanceEnum.BIG_QUERY)
                      .withParserFactory(SqlBabelParserImpl.FACTORY);
      
              SqlParser.Config sqlParserConfigNotBabel = SqlParser.config().DEFAULT
                      .withLex(Lex.BIG_QUERY)
                      .withConformance(SqlConformanceEnum.BIG_QUERY)
                      .withParserFactory(SqlParserImpl.FACTORY);
      
              Map<String, SqlParser.Config> parserConfigs = new HashMap<String, SqlParser.Config>();
              parserConfigs.put("With babel", sqlParserConfigBabel);
              parserConfigs.put("Without babel", sqlParserConfigNotBabel);
      
              String[] testSqlFragments = {
                      "1+(2*4) as foo",
                      "CURRENT_DATE()",
                      "CURRENT_DATETIME()",
                      "DATE_FROM_UNIX(123456)",
                      "IF(TRUE, 1, 2)",
                      "DATE('2021-01-01')",
              };
      
              for (String sqlFragment : testSqlFragments) {
                  String query = "SELECT " + sqlFragment;
                  System.out.println("Trying to parse : " + query);
      
                  for (var config : parserConfigs.entrySet()) {
                      System.out.print(config.getKey() + " : ");
                      try {
                          FrameworkConfig frameworkConfig = Frameworks.newConfigBuilder()
                                  .parserConfig(config.getValue())
                                  .build();
                          Planner planner = Frameworks.getPlanner(frameworkConfig);
                          SqlNode node = planner.parse(query);
                          System.out.println("SUCCESS");
                      } catch (SqlParseException e) {
                          System.out.println("ERROR");
                      }
                  }
              }
          }
      }
      
      

       

       

      And here is the output of that code:

       

      Trying to parse : SELECT 1+(2*4) as foo
      Without babel : SUCCESS
      With babel : SUCCESS
      Trying to parse : SELECT CURRENT_DATE()
      Without babel : SUCCESS
      With babel : SUCCESS
      Trying to parse : SELECT CURRENT_DATETIME()
      Without babel : SUCCESS
      With babel : SUCCESS
      Trying to parse : SELECT DATE_FROM_UNIX(123456)
      Without babel : SUCCESS
      With babel : SUCCESS
      Trying to parse : SELECT IF(TRUE, 1, 2)
      Without babel : SUCCESS
      With babel : ERROR
      Trying to parse : SELECT DATE('2021-01-01')
      Without babel : ERROR
      With babel : SUCCESS
      
      Process finished with exit code 0
      

       

       

      Please tell me if I can be of any help on this issue, or if it's too deep into the project and a newcomer can't solve this.

       

      Have a great day

      Attachments

        Issue Links

          Activity

            People

              jiajunbernoulli Jiajun Xie
              ftecmartineau Florent Martineau
              Votes:
              1 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 40m
                  40m