はじめに
2018年からサーバーリプレース作業(Windows Server 2008R2 → Windows Server 2016)でデータベースを Oracle 11g から PostgreSQL 9.6 に移行作業をしました。
PostgreSQL 9.6 のサポート終了期限が 2021年11月となっているため、PostgreSQL 12 に移行する準備を進めています。
最新のPostgreSQL 13 にしないのは、現時点(2021/04/18)で某N社のサポートがPostgreSQL 12 までだからです。
バージョン | 初期リリース日 | サポート終了期限 |
---|---|---|
13 | 2020年09月 | 2025年11月 |
12 | 2019年10月 | 2024年11月 |
11 | 2018年10月 | 2023年11月 |
10 | 2017年10月 | 2022年11月 |
9.6 | 2016年09月 | 2021年11月 |
SQLの構文解析
20近くの既存アプリケーションのSQLを抜き出して、PostgreSQL 9.6とPostgreSQL 12で性能検証をする必要があります。1000近くのSQLがあるため、プログラムを組んで自動で性能検証をしたいと考えました。
自動でやるためには、登録・更新・削除するデータをDB上から抜き出し、該当のSQLに抽出条件や登録・更新データのパラメーターとして当てはめて実行したいのです。
当初は正規表現を多様してSQLを解析しようと考えていたのですが、他言語でSQL文を構文解析するという記事を見つけて、それならC#版でも似たようなのがあるだろうと、NuGetで見つけたのが「TSQL Parser」になります。
.NET Fiddleの紹介
オンライン上でC#のコードを簡単に試せる「.NET Fiddle」を初めて使用してみました。
他のC#オンラインエディタと違って、NuGet Packageを指定することで「TSQL.Parser」を使用できます。
ソースコード
using System;
using TSQL;
using TSQL.Statements;
using TSQL.Tokens;
using System.Collections.Generic;
namespace TSQLParserExample
{
public class ParseRule
{
public string Field {get;set;}
public string Operator {get;set;}
public string FieldValue {get;set;}
public string SearchOperator { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
TSQLSelectStatement select = TSQLStatementReader.ParseStatements(@"
SELECT id, name
FROM hoge h
WHERE h.id = @id AND h.name = '@name'
")[0] as TSQLSelectStatement;
List<ParseRule> rules = new List<ParseRule>();
if (select.Where != null)
{
Console.WriteLine("WHERE:");
ParseRule ruleValue = new ParseRule();
foreach (TSQLToken token in select.Where.Tokens)
{
string tokenType = token.Type.ToString();
string tokenText = token.Text;
switch(tokenType)
{
case "Keyword":
if(string.IsNullOrEmpty(ruleValue.SearchOperator))
{
ruleValue.SearchOperator = tokenText;
}
else
{
ruleValue.Operator = tokenText;
}
break;
case "Identifier":
ruleValue.Field = tokenText;
break;
case "Variable":
case "StringLiteral":
case "NumericLiteral":
ruleValue.FieldValue = tokenText;
if(!string.IsNullOrEmpty(ruleValue.SearchOperator) && ruleValue.SearchOperator.Equals("WHERE"))
{
ruleValue.SearchOperator = "AND";
}
rules.Add(ruleValue);
ruleValue = new ParseRule();
break;
default:
break;
}
}
for(var i = 0; i < rules.Count; i++)
{
var rule1 = rules[i];
Console.WriteLine("\t Field: " + rule1.Field + "\t Operator: " + rule1.Operator + " \t SearchOperator: " + rule1.SearchOperator + "\t Value: " + rule1.FieldValue);
}
}
}
}
}
結果
ちなみにまだ研究中です。
PostgreSQLのNpgsqlのプレースホルダーは「: (コロン)」なのですが、TSQL Parserで変数として認識させるなら「@」に置き換えるとか必要かも知れません。
WHERE:
Field: id Operator: SearchOperator: AND Value: @id
Field: name Operator: SearchOperator: AND Value: '@name'
最後に
実は開発はこれからなので、何か気付いたことがあれば追記していきます。
【2022/08/08追記】
応用編を書きました。