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

クエリが SQL Database でサポートされているかを ScriptDom で判定する(作成中)

SQL Database(旧SQL Azure) がサポートしていないクエリを、実際にクエリを実行せずに知りたいなーというのがきっかけです。

サポート状況はここらへんを見ています。
関数 (Azure SQL データベース)
構文やファンクション等のサポート状況が MSDNTechNet のドキュメントベースで提供されていますが、ドキュメント見ないと判断出来ないのはちょっと不便だなと。

で、ScriptDom を使って出来ないかな~と試してるところです。

こんな感じ。

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

namespace ScriptDom.SqlDatabase {
  public class SqlDatabaseVerifyVisitor : TSqlFragmentVisitor {
    public List<TSqlFragment> Errors { get; private set; }
    public SqlDatabaseVerifyVisitor() {
      Errors = new List<TSqlFragment>();
    }
    /// <summary>
    /// 行セット関数(Rowset Functions)
    /// </summary>
    /// <param name="node"></param>
    public override void Visit(TableReferenceWithAlias node) {
      if (node.IsUnsupport()) {
        Errors.Add(node);
      }
      base.Visit(node);
    }
    /// <summary>
    /// 構成関数(Configuration Functions)
    /// </summary>
    /// <param name="node"></param>
    public override void Visit(GlobalVariableExpression node) {
      if (node.IsUnsupport()) {
        Errors.Add(node);
      }
      base.Visit(node);
    }
    /// <summary>
    /// 分析関数(Analytic Functions)
    /// </summary>
    /// <param name="node"></param>
    public override void Visit(FunctionCall node) {
      if (node.IsUnsupport()) {
        Errors.Add(node);
      }
      base.Visit(node);
    } 
  }
}
using System;
using System.Collections.Generic;
using Microsoft.SqlServer.TransactSql.ScriptDom;

namespace ScriptDom.SqlDatabase {
  public static class Unsupports {
  /// <summary>
    /// 行セット関数(Rowset Functions)
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    public static bool IsUnsupport(this TableReferenceWithAlias node) {
      switch (node.GetType().Name) {
        case "FullTextTableReference": // CONTAINSTABLE/FREETEXTTABLE
        case "AdHocTableReference": // OPENDATASOURCE
        case "OpenQueryTableReference": // OPENQUERY
        case "OpenRowsetTableReference": // OPENROWSET
        case "OpenXmlTableReference": // OPENROWSET
          return true;
        default: return false;
      }
    }
    /// <summary>
    /// 構成関数(Configuration Functions)
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    public static bool IsUnsupport(this GlobalVariableExpression node) {
      switch (node.Name.ToUpper()) {
        case "@@MAX_CONNECTIONS":
        case "@@REMSERVER":
        case "@@SERVICENAME":
          return true;
        default: return false;
      }
    }
    /// <summary>
    /// 分析関数(Analytic Functions)
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    public static bool IsUnsupport(this FunctionCall node) {
      switch (node.FunctionName.Value.ToUpper()) {
        case "COME_DIST":
        case "FIRST_VALUE":
        case "LAG":
        case "LAST_VALUE":
        case "LEAD":
        case "PERCENTILE_CONT":
        case "PERCENTILE_DISC":
        case "PERCENT_RANK": 
          return true;
        default: return false;
      }
    }
  }
}

ただ今のところ自分で使う予定も無いので、最終どんな形で実行出来るようにするのか何も考えてないです。
.targets ファイルとか作って MSBuild にするのか、CUI な.exe にしてしまうのかどうしようかな~。