読者です 読者をやめる 読者になる 読者になる

SQL Server のバージョン毎の TSqlParser

相変わらずの ScriptDom ネタです。
パーサーとジェネレーターには、それぞれ SQL Server 2000, 2005, 2008, 2012 と 4つのバージョンがあります。

パーサーは、
TSqlParser クラス (Microsoft.SqlServer.TransactSql.ScriptDom) が基底クラスで、
TSql80Parser, TSql90Parser, TSql100Parser, TSql110Parser が、
ジェネレーターは、
SqlScriptGenerator クラス (Microsoft.SqlServer.TransactSql.ScriptDom) が基底クラスで、
Sql80ScriptGenerator, Sql90ScriptGenerator, Sql100ScriptGenerator, Sql110ScriptGenerator があります。


ジェネレーターは、使ってみた感じ各バージョンによってどんな差異があるのかイマイチわかりませんでした。
パーサーのほうは、違いがあったのでここで紹介してみます。


TSql80Parser クラス (Microsoft.SqlServer.TransactSql.ScriptDom)SQL Server 2000 用のパーサーです。
2000 用ですので、こんなクエリはエラーになります。

using Microsoft.SqlServer.TransactSql.ScriptDom;
using System;
using System.Collections.Generic;
using System.IO;

class Program {
  static void Main(string[] args) {
    var parser = new TSql80Parser(false);
    IList<ParseError> errors;
    using (var reader = new StringReader(@"select top (10) id from Table1")) {
      parser.Parse(reader, out errors);
    }
    foreach (var e in errors) {
      Console.WriteLine("{0} 行目 {1} 文字目 {2}", e.Line, e.Column, e.Message);
    }
    Console.ReadKey();
  }
}


続いて、TSql90Parser クラス (Microsoft.SqlServer.TransactSql.ScriptDom)SQL Server 2005 用のパーサーです。

using Microsoft.SqlServer.TransactSql.ScriptDom;
using System;
using System.Collections.Generic;
using System.IO;

class Program {
  static void Main(string[] args) {
    var parser = new TSql90Parser(false);
    IList<ParseError> errors;
    using (var reader = new StringReader(@"select top (10) id from Table1")) {
      parser.Parse(reader, out errors);
    }
    Console.WriteLine(errors.Count == 0 ? "エラー無" : "エラー有");
    using (var reader = new StringReader(@"declare @Id int = 10")) {
      parser.Parse(reader, out errors);
    }
    foreach (var e in errors) {
      Console.WriteLine("{0} 行目 {1} 文字目 {2}", e.Line, e.Column, e.Message);
    }
    Console.ReadKey();
  }
}


2000 でエラーだったクエリはエラーでは無くなりましたが、変数宣言と同時の代入クエリはエラーになりました。
TSql100Parser クラス (Microsoft.SqlServer.TransactSql.ScriptDom)SQL Server 2008 用のパーサーです。

using Microsoft.SqlServer.TransactSql.ScriptDom;
using System;
using System.Collections.Generic;
using System.IO;

class Program {
  static void Main(string[] args) {
    var parser = new TSql100Parser(false);
    IList<ParseError> errors;
    using (var reader = new StringReader(@"select top (10) id from Table1")) {
      parser.Parse(reader, out errors);
    }
    Console.WriteLine(errors.Count == 0 ? "エラー無" : "エラー有");
    using (var reader = new StringReader(@"declare @Id int = 10")) {
      parser.Parse(reader, out errors);
    }
    Console.WriteLine(errors.Count == 0 ? "エラー無" : "エラー有");
    using (var reader = new StringReader(@"execute sp_lock with result sets (
  ( [セッション] int, 
    [データベース] int, 
    [オブジェクト] int, 
    [インデックス] int, 
    [型] char, 
    [リソース] char, 
    [モード] char, 
    [状態] char )
)")) {
      parser.Parse(reader, out errors);
    }
    foreach (var e in errors) {
      Console.WriteLine("{0} 行目 {1} 文字目 {2}", e.Line, e.Column, e.Message);
    }
    Console.ReadKey();
  }
}


2005 でエラーだったクエリは、エラーではなくなりました。
が、2012 から追加された EXECUTE - WITH RESULT SETS ではエラーが出ています。
最後は、TSql110Parser クラス (Microsoft.SqlServer.TransactSql.ScriptDom) SQL Server 2012 用のパーサーです。

using Microsoft.SqlServer.TransactSql.ScriptDom;
using System;
using System.Collections.Generic;
using System.IO;

class Program {
  static void Main(string[] args) {
    var parser = new TSql110Parser(false);
    IList<ParseError> errors;
    using (var reader = new StringReader(@"select top (10) id from Table1")) {
      parser.Parse(reader, out errors);
    }
    Console.WriteLine(errors.Count == 0 ? "エラー無" : "エラー有");
    using (var reader = new StringReader(@"declare @Id int = 10")) {
      parser.Parse(reader, out errors);
    }
    Console.WriteLine(errors.Count == 0 ? "エラー無" : "エラー有");
    using (var reader = new StringReader(@"execute sp_lock with result sets (
  ( [セッション] int, 
    [データベース] int, 
	[オブジェクト] int, 
	[インデックス] int, 
	[型] char, 
	[リソース] char, 
	[モード] char, 
	[状態] char )
)")) {
      parser.Parse(reader, out errors);
    }
    Console.WriteLine(errors.Count == 0 ? "エラー無" : "エラー有");
    Console.ReadKey();
  }
}


全部のクエリでエラーが出ませんね!
SQL Server のバージョン毎にパーサーがあるので、バージョン間の移行や他DBからの移行の際に使えるかも?!