2016-05-18 2 views
1

SQL文でカラム名を変更してテーブル名だけを変更する簡単なアプリケーションを実装しています。ステートメントはStringとして渡され、変更されたステートメントもStringとして返されます。データベース接続は必要ありません。apache calciteはテーブル名とカラム名を区別する

これを達成するために、Apache CalciteのSQLパーサーを使用しています。私はSqlNodeにSQL文字列を解析し、SqlNodeと名前を変更したSqlVisitorを受け入れ、SqlNode.toSqlString()を使用してStringにすべてを書き戻します。

問題は、SqlVisitorを受け入れる間に、解析されたSqlNodeオブジェクトの列と表の違いをわかりません。両方ともSqlIdentifierと表され、同じSqlKindを有する。したがって、SqlVisitorSqlIdentifierにアクセスしているときは、それが列であろうとテーブルであろうと名前を変更します。例えば

private String changeNames(String str) throws SqlParseException { 
    SqlShuttle visitor = new SqlShuttle() { 
     private String rename(String str) { 
      return str + "-test"; 
     } 

     @Override 
     public SqlNode visit(SqlIdentifier identifier) { 
      SqlIdentifier output = new SqlIdentifier(rename(identifier.getSimple()), identifier.getCollation(), identifier.getParserPosition()); 
      return output; 
     } 
    }; 

    SqlParser.ConfigBuilder configBuilder = SqlParser.configBuilder(); 
    configBuilder.setLex(Lex.MYSQL); 
    SqlParser.Config config = configBuilder.build(); 

    SqlParser parser = SqlParser.create(str, config); 
    SqlNode parsedStatement = parser.parseQuery(str); 
    SqlNode outputNode = parsedStatement.accept(visitor); 

    return outputNode.toSqlString(SqlDialect.DUMMY).getSql(); 
} 

SELECT name, address, age FROM mytablename WHERE age = 23 AND name = 'John' 

SqlIdentifierが列または表で与えられた場合にはどのように私は言うことができる?

SELECT `name-test`, `address-test`, `age-test` FROM `mytablename-test` WHERE `age-test` = 23 AND `name-test` = 'John' 

に変更されますか

答えて

1

識別子をテーブルと列に解決し、その型を調べるには、Calciteのバリデーター(SqlValidator)を使用する必要があります。バリデータは、パーサを意図的に作成しなかったのに対し、FROM句のエイリアスをサブクエリで見ることができるかどうかなど、SQL名前解決規則を理解しています。

バリデータの2つの重要な概念は、有効範囲(SqlValidatorScope)と名前空間(SqlValidatorNamespace)です。

スコープは、識別子を解決しようとしているところです。たとえば、クエリのSELECT句にあるとします。または、特定のサブクエリのWHERE句で指定します。異なるスコープの異なる表と列のコレクションを見ることができます。 GROUP BY句とORDER BY句でも異なるスコープがあります。

名前空間は、表のように見え、列のリストを持つものです。これは、FROM句のサブクエリ、つまりテーブルである可能性があります。スコープ内にいる場合は、テーブルエイリアスを検索し、名前空間を取得してから、それが持つ列を調べることができます。

SqlShuttleのバリアントが正確にわかっていて、識別子をテーブル参照と列参照に展開する必要がある場合に便利です。残念ながら、誰もそのようなことをまだ構築していません。

+0

SqlScopedShuttleはどうなっていますか? –

+0

SqlScopedShuttleは便利なように聞こえますが、それほど多くは行いません。これは、ツリーに再帰的にASTノード(SqlNode)のスタックを保持します。 SQLスコープ規則については何も知らない。 –

0

私はちょっとcalcitesqlParserを使用したことがあります。いくつかのスニペットは以下に掲載されています。

public void convertSelect(SqlSelect root) { 
    convertFrom(root.getFrom()); 
    convertWhere(root.getWhere()); 
    } 

    public void convertFrom(SqlNode from) { 
    if (from instanceof SqlJoin) { 
     convertFromOfJoinExpression((SqlJoin)from); 
    } 
    } 

    public String extractTableFromJoinNode(SqlNode jnn) { 
    if (jnn instanceof SqlBasicCall) { 
     SqlBasicCall asExp = (SqlBasicCall)jnn; 
     if (asExp.getKind().equals(SqlKind.AS)) { 
     extractTableFromJoinNodeAsExpression(asExp); 
     } 
    } 
    return "SomeTableAlias"; 
    } 

一般的に、あなたはfrom文でtableを取得します。 selectcolumnsが表示されます。

最後に、calciteは、多くの最適化ルールを適用してクエリを最適化することを専門としています。必要なもの(カラム/テーブル名の変換)によっては、calciteが最適ではないかもしれません。

関連する問題