背景
VSCodeマクロでsql-formatterライブラリを使ったSQL整形機能を実装する際、8方言対応やオプション選択は素直に実装できましたが、Oracle PL/SQL特有の区切り文字/だけは後処理が必要でした。
1. sql-formatterはオプション指定だけで方言対応が完結する
import { format } from 'sql-formatter';
const formattedSql = format(sql, {
language: 'mysql', // MySQL/PostgreSQL/tsql/plsql/db2/redshift等
keywordCase: 'upper', // upper/lower/preserve
tabWidth: 2,
useTabs: false,
linesBetweenQueries: 2
});
languageオプションを切り替えるだけで、MySQLのバッククォート記法やPostgreSQLの型キャスト(::)、SQL Serverの[]識別子などをそれぞれ正しく解釈してくれます。1つのライブラリで8方言をカバーできるのは実務上かなり便利です。
2. Oracle PL/SQLの/は整形後に行末へくっついてしまう
-- 期待する出力
BEGIN
INSERT INTO users (id, name) VALUES (1, 'Test');
COMMIT;
END;
/
-- sql-formatterの実際の出力(/が行末にくっつく)
END; /
Oracle SQL*Plusでは、PL/SQLブロックの終端を示す/が独立した行にないと正しく認識されません。しかしsql-formatterはこの区切り文字の意味を理解していないため、直前のトークンと同じ行に整形してしまいます。
3. 正規表現による後処理で解決
function postProcessSlashSeparator(sql: string): string {
// 行末のスラッシュの前に改行を挿入
return sql.replace(/\s+\/\s*$/gm, '\n/');
}
format()の出力に対して、行末の空白+/というパターンを\n/に置換する後処理を1つ追加するだけで解決します。gmフラグ(グローバル+複数行)を指定することで、複数のPL/SQLブロックが含まれる場合でもすべての/区切りに対応できます。ライブラリ側の制約を、ライブラリを改造せず後処理1関数で吸収した形です。
4. パースエラー時は原因を特定できるメッセージを出す
if (error.message && error.message.includes('Parse error')) {
const message =
'SQL整形に失敗しました。\n\n' +
'原因:SQLとして認識できない文字が含まれています。\n' +
'(例:△、●、■などの記号、不正なSQL構文)\n\n' +
'対処法:\n' +
'1. SQL以外のテキストやコメントを削除してください\n' +
'2. 特殊文字(△など)を削除してください';
vscode.window.showErrorMessage(message, { modal: true });
}
sql-formatterのパースエラーはメッセージがそっけないため、エラーメッセージにParse errorという文字列が含まれるかで判定し、日本語での原因説明と対処法を独自にラップして表示しています。ログから抽出したSQLには全角記号(△や●)が混入していることが多く、この分岐が実務でも頻繁に役立ちました。
まとめ
ライブラリの対応範囲外(Oracle固有の/区切り)を正規表現の後処理1つで補う設計と、パースエラーメッセージの日本語ラップ、この2点が実務で使えるSQL整形ツールにする上でのポイントでした。8方言・インデント幅の選択肢を含む完全なコードは元記事にまとめています。