フューチャー技術ブログ

新しいSQLフォーマッターであるuroboroSQL-fmtをリリースしました

コアテクノロジーグループの山田です。

先日、新しいSQLフォーマッターであるuroboroSQL-fmtをリリースしました 🎉
このツールは弊社が公開しているPostgreSQL向けのSQLコーディング規約に基づき、SQL文をフォーマットするツールです。

弊社でのSQLフォーマッター開発の取り組み

元々弊社ではuroboroSQL Formatter(以下uroboroSQL Formatterを旧版、uroboroSQL-fmtを新版と呼ぶ)というSQLフォーマッターを公開していました。旧版は

  • 字句解析して得られたトークンを基にフォーマットするという設計になっていたため、SELECT句のエイリアス補完といった文法を考慮する必要のある機能の追加が困難
  • Pythonで書かれておりVSCodeの拡張機能として動作させるのが難しい

という課題を抱えており、それを解消するため新たなSQLフォーマッターを開発していました。

ANTLR+TypeScriptによるSQLフォーマッターの開発

Engineer Camp2020でANTLRとTypeScriptによるSQLフォーマッターを開発しました。インターンシップ中にSQLがフォーマットできるようになり、この方向性で旧版が抱えていた課題は解決できそうに思えましたが、SQLの構文解析が著しく遅いという問題点がありました。弊社太田がANTLRのJavaScript runtimeの不具合を発見し、かなり高速化されたものの実用的な速さにはならなかったこともありANTLRを用いたSQLフォーマッターの開発はストップしました。

インターンシップで行ったことについては以下の記事をご覧ください。

RustによるSQLフォーマッターの開発

旧版の課題を解決しつつ十分な速さでフォーマット可能なSQLフォーマッターを開発するため、Engineer Camp2022でRustによるSQLフォーマッターの開発を開始しました。インターンシップ終了時点で簡単なSQLのフォーマットが可能になり、その後もアルバイトとしてSQLフォーマッター開発に参画していただき、旧版のフォーマッターでは実現できなかったSELECT句のエイリアス補完等の機能、vscode拡張化wasm化を実現しリリースに至りました。

インターンシップで行ったことや開発の過程で調査したことは以下の記事をご覧ください。

旧版と新版の比較

処理時間比較

新しく開発したSQLフォーマッターでは処理時間が大幅に向上しています!
巨大なSQLファイルと小さなSQLファイルをフォーマットしたときの処理時間を比較しました。
内容によってフォーマットにかかる時間は変わって変わるため、あくまで一例ですが概ね5-500倍ほど性能改善しています。

旧版 新版
3985行のINSERT-SELECT文 1m53.651s 0m0.194s
6行のSELECT文 0m0.357s 0m0.054s

機能比較

字句解析ベースから構文解析ベースになったことで、下記のような構文を意識した補完やauto fixができるようになっています。

カラムのAS補完
フォーマット前
SELECT
COLUMN1 COL1
FROM
TBL
フォーマット後
SELECT
COLUMN1 AS COL1
FROM
TBL
カラムエイリアス補完
フォーマット前
SELECT
COL1
FROM
TAB1
フォーマット後
SELECT
COL1 AS COL1
FROM
TAB1
長い関数呼出の折返し
フォーマット前
select
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong(
short_func(
param1
, param2
)
, param2
) as func_col
, t.col1
from
tbl t
where
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong(param1,param2) = case when t.col2 = 1 then 'pattern1' else 'default' end
フォーマット後

max_char_per_lineの設定は関数呼出の長さの上限を表し、デフォルトが50になっています。

この例ではlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglongは50文字超のため変数ごとに折返され、short_funcは引数入れても50文字以内のためワンライン化されています。

where句にあってもいい感じに折り返され、横スクロールが発生しにくいようになっています。

longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglongは50文字超のため変数ごとに折返され、short_funcは引数入れても50文字以内のためワンライン化されています。

where句にあってもいい感じに折り返され、横スクロールが発生しにくいようになっています。

select
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong(
short_func(param1, param2)
, param2
) as func_col
, t.col1 as col1
from
tbl t
where
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong(
param1
, param2
) =
case
when
t.col2 = 1
then
'pattern1'
else
'default'
end
新旧の機能比較

その他新旧の機能比較は下記です。

テーブルのAS除去::によるキャストをCASTに変換などPostgreSQL限定構文は等価の標準SQLに変換する機能を入れています。

旧版 新版
対応SQL 全て PostgreSQL
タブサイズの設定 o o
予約語識別子の変換 大文字化、小文字化 大文字化、小文字化、変換なし
エイリアス補完 - o
outer補完 - o
カラムのAS補完 - o
テーブルのAS除去 - o
バインドパラメータの余計な空白除去 - o
冗長な空白除去 - o
1行の最大長指定 - o
SQL ID補完
::によるキャストをCASTに変換 - o
<>を!=に変換 - o
ディレクトリ内のファイルを一括フォーマット o -
予約語をファイルで指定 o -
vscode拡張 - o
wasm - o
eclipse plugin o -
IntelliJ plugin o -
SublimeText3 plugin o -
exe版 o -
2way-sql uroborosqldoma uroborosqlgo-twowaysqldoma
選択範囲フォーマット - o vscode拡張版のみ
  • PostgreSQL以外のSQLには対応していないため、PostgreSQL以外のSQLのフォーマットには旧版の使用をお勧めしています。
  • eclipse pluginとexe版は現在は用意できていないのですが、将来的には作成する予定です!

使い方

方法1:wasm版を試してみる

wasm版はこちらのデモでお試しできます。
使い方についてはデモページ内の説明をご参照ください。

wasm版の実行イメージ
wasm版フォーマットデモ.gif

方法2:vscode拡張として使用する

  1. まず、他の拡張機能と同様にuroborosql-fmt - Visual Studio Marketplaceをvscodeにインストールしてください。
  2. settings.jsonに以下の設定を入れてください
    {
    "[sql]": {
    "editor.defaultFormatter": "Future.uroborosql-fmt"
    }
    }
  3. SQLファイルを開き、コマンドパレットからFormat Documentか、format sqlを実行してください
    format sqlでは選択範囲のフォーマットをサポートしています
フォーマットの設定方法

フォーマットの各種設定を記載したファイルのパスを指定することができます。
指定されなかった場合にはデフォルトのパスにある ./.uroborosqlfmtrc.json を読み込みます。
設定ファイルが存在しなかった場合、デフォルト値でフォーマットされます。
※ 現状は設定ファイルのパスしかできませんが、個々の設定の変更もvscodeの設定画面から出来るようにする予定です。

設定ファイルは以下のような内容です。
個々の設定についてはuroborosql-fmt - Visual Studio Marketplaceをご参照ください。

{
"debug": false,
"tab_size": 4,
"complement_alias": true,
"trim_bind_param": false,
"keyword_case": "preserve",
"identifier_case": "preserve",
"max_char_per_line": 50,
"complement_outer_keyword": true,
"complement_column_as_keyword": true,
"remove_table_as_keyword": true,
"remove_redundant_nest": true,
"complement_sql_id": true,
"convert_double_colon_cast": false,
"unify_not_equal": true
}
vscode拡張版の実行イメージ
vscode版フォーマットデモ.gif

方法3:cliで使用する

  1. Rustの環境を構築
  2. cargo install --git https://github.com/future-architect/uroborosql-fmturoborosql-fmt-cli をインストール
  3. uroborosql-fmt-cli input.sqlinput.sql をフォーマットした結果が標準出力に出力されます。uroborosql-fmt-cli input.sql result.sql のように第2引数を渡すと、第2引数で指定したファイルにフォーマット結果が格納されます

チーム開発で使用する場合

  1. .vscode/settings.json を作成し、以下のようにuroborosql-fmt.configurationFilePathの設定を記載してください
    {
    "uroborosql-fmt.configurationFilePath": "./.uroborosqlfmtrc.json"
    }
  2. チームで使用したいフォーマットの設定を.uroborosqlfmtrc.jsonに記載し、リポジトリ直下に配置してください

最後に

まだまだ枯れておらずフォーマットできないことも多いです。元のSQLを壊していないか検証するロジックは入っていますが、意図しない変更が入っていないか確認お願いします。不具合や要望等ございましたらお気軽にissueやPRいただければと思います。

※ ライセンスはBSLですが競合会社含め開発環境での利用は自由ですので、お気軽に使用ください