前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Calcite parser config介绍

Calcite parser config介绍

作者头像
skyyws
发布2022-11-21 09:58:57
2.3K0
发布2022-11-21 09:58:57
举报
文章被收录于专栏:skyyws的技术专栏

Calcite针对SQL parse提供了很多的配置项,可以针对不同的SQL方言进行解析。相关的配置项都存储在SqlParser.Config这个结构中,常见的用法如下所示:

代码语言:javascript
复制
SqlParser.Config config = SqlParser.config();
String sql = xxx;
SqlParser sqlParser = SqlParser.create(sql, config);
SqlNode sqlNode = sqlParser.parseStmt();

最终,我们就可以将一个字符串的sql,转换成一个SqlNode,这是一个Calcite中抽象语法树的代码标识。而这个config()就是Calcite默认提供的一个配置集合,如下所示:

代码语言:javascript
复制
public static Config config() {
  return Config.DEFAULT;
}

/** Default configuration. */
Config DEFAULT = ImmutableBeans.create(Config.class)
    .withLex(Lex.ORACLE)
    .withIdentifierMaxLength(DEFAULT_IDENTIFIER_MAX_LENGTH)
    .withConformance(SqlConformanceEnum.DEFAULT)
    .withParserFactory(SqlParserImpl.FACTORY);

可以看到,Calcite默认设置了四个属性,除了这四个,还有其他的属性也可以设置,下面我们就看一下常用的一些配置项。

引用标识符

相关的结构如下所示:

代码语言:javascript
复制
/** Syntax for quoting identifiers in SQL statements. */
public enum Quoting {
  /** Quote identifiers in double-quotes. For example, {@code "my id"}. */
  DOUBLE_QUOTE("\""),

  /** Quote identifiers in back-quotes. For example, {@code `my id`}. */
  BACK_TICK("`"),

  /** Quote identifiers in brackets. For example, {@code [my id]}. */
  BRACKET("[");

  public String string;

  Quoting(String string) {
    this.string = string;
  }
}

使用方法如下所示:

代码语言:javascript
复制
SqlParser.Config config = SqlParser.config().withQuoting(Quoting.BACK_TICK)

此时,我们就可以针对列名、表名等,使用反引号包围起来,如下所示:

代码语言:javascript
复制
select `c1` from `t`
select `c1` as `id` from t
select c1,`sum`(c2) from t group by c1

上面的三种值,分别表示双引号、反引号和括号。因此,如果我们设置quoting为BACK_TICK,那么使用双引号则会报错,如下所示:

代码语言:javascript
复制
select "c1" from "t"
select c1 as "id" from t
select c1,"sum"(c2) from t group by c1

标识符大小写转换

相关的结构如下所示:

代码语言:javascript
复制
/** Policy for converting case of identifiers before storing them.
 *
 * <p>A database often has policies for quoted versus unquoted identifiers.
 * For example, Oracle converts unquoted identifiers to upper-case, but
 * quoted identifiers are unchanged.</p> */
public enum Casing {
  /** The case of identifiers is not changed. */
  UNCHANGED,

  /** Identifiers are converted to upper-case. */
  TO_UPPER,

  /** Identifiers are converted to lower-case. */
  TO_LOWER
}

这是针对引用标识符可以设置是否进行大小写转换,通过SqlParser.Config的两个方法可以进行设置,如下所示:

代码语言:javascript
复制
//针对使用了引用标识符包围的列、表名等,进行大小写转换
Config withQuotedCasing(Casing casing);
//针对没有引用标识符包围的列、表名等,进行大小写转换
Config withUnquotedCasing(Casing casing);

我们看如下所示的例子:

代码语言:javascript
复制
SqlParser.Config config = SqlParser.config()
  .withQuoting(Quoting.BACK_TICK)
  .withQuotedCasing(Casing.UNCHANGED)
  .withUnquotedCasing(Casing.TO_UPPER);
 
String sql = "select `Col1`,sum(col2) from t group by Col1";
SqlParser sqlParser = SqlParser.create(sql, config);
SqlNode sqlNode = sqlParser.parseQuery();
System.out.println(sqlNode.toString());

最终输出的SQL如下所示:

代码语言:javascript
复制
SELECT `Col1`, SUM(`COL2`)
FROM `T`
GROUP BY `COL1`

可以看到,被反引号包围的Col1保持了大小写不变,而没有标识符包围的col2和Col1则都被转换成了大写。

字符常量值格式

格式如下所示:

代码语言:javascript
复制
/** Styles of character literal.
 *
 * @see Lex#charLiteralStyles */
public enum CharLiteralStyle {
  /** Standard character literal. Enclosed in single quotes, using single quotes
   * to escape. Example: {@code 'Won''t'}. */
  STANDARD,
  /** Single-quoted character literal with backslash escapes, as in BigQuery.
   * Example: {@code 'Won\'t'}. */
  BQ_SINGLE,
  /** Double-quoted character literal with backslash escapes, as in BigQuery.
   * Example: {@code "Won\'t"}. */
  BQ_DOUBLE
}

这里指的主要就是字符串的格式,包括转义字符,例如STANDARD的格式就是单引号包围,如果字符串包含单引号,则使用单引号进行转移,如下所示:

代码语言:javascript
复制
// Config配置如下:
SqlParser.config().withCharLiteralStyles(ImmutableSet.of(CharLiteralStyle.STANDARD))
// 解析成功
select 'I''m super man'
// 解析失败
select 'I\'m super man'
select "I''m super man"

而BQ_SINGLE和BQ_DOUBLE分别表示使用单引号和双引号来包围字符串,但是转义符号用的则是反斜杠,这两种格式是BigQuery的语法。

其他配置

除了上述的配置项,SqlParser.Config还提供了一些额外的配置,如下所示:

代码语言:javascript
复制
// 匹配时,大小写是否敏感
Config withCaseSensitive(boolean caseSensitive);
// 标识符最大长度
Config withIdentifierMaxLength(int identifierMaxLength);

使用模板进行配置

语法特性Lex

Calcite针对当前主流的一些方言,构造了专门的模板,我们可以使用这些模板快速创建对应的config,如下所示:

代码语言:javascript
复制
public enum Lex {
  BIG_QUERY(Quoting.BACK_TICK, Casing.UNCHANGED, Casing.UNCHANGED, true,
      CharLiteralStyle.BQ_SINGLE, CharLiteralStyle.BQ_DOUBLE),
      
  ORACLE(Quoting.DOUBLE_QUOTE, Casing.TO_UPPER, Casing.UNCHANGED, true,
      CharLiteralStyle.STANDARD),
  // 省略其余部分代码

这里设置的配置项就是我们上面提到的几种,例如我们要创建BigQuery的语法,可以这样使用:

代码语言:javascript
复制
SqlParser.Config config = SqlParser.config().withLex(Lex.BIG_QUERY);
SqlConformance

除了上面提到的Lex,还有一个与之搭配使用的变量就是SqlConformanceEnum,这个枚举里面定义了一系列的SQL行为模式,例如是否支持group by alias,group by ordinal等,如下所示:

代码语言:javascript
复制
public boolean isGroupByAlias() {
  switch (this) {
  case BABEL:
  case LENIENT:
  case BIG_QUERY:
  case MYSQL_5:
    return true;
  default:
    return false;
  }
}

这个枚举里面也定义了一系列的常用方言的SQL行为,如下所示:

代码语言:javascript
复制
public enum SqlConformanceEnum implements SqlConformance {
  DEFAULT,
  LENIENT,
  BABEL,
  // 省略其余部分代码

因此,我们通常就可以结合上面的Lex来使用,如下所示:

代码语言:javascript
复制
SqlParser.Config config = SqlParser.config()
  .withLex(Lex.BIG_QUERY)
  .withConformance(SqlConformanceEnum.BIG_QUERY);

小结

基本到这里Calcite得parser config的配置就基本已经设置介绍完了。通过上面的介绍我们可以发现,Calcite提供了比较多的配置项组合,可以解析不同的SQL方言,还是很强大的。除了parse,Calcite还有一个unparse的过程,可以将RelNode转换成不同方言的sql,后续有时间再做介绍。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引用标识符
  • 标识符大小写转换
  • 字符常量值格式
  • 其他配置
  • 使用模板进行配置
    • 语法特性Lex
      • SqlConformance
      • 小结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档