识别TSql110Parser解析树中的T-SQL保留/词法词

本文关键字:保留 T-SQL 词法 TSql110Parser 识别 | 更新日期: 2023-09-27 18:06:27

我使用TSql110Parser列出特定T-SQL过程(最终包括所有模块)中的Identifier和QuotedIdentifier令牌。任务是组装每个模块中使用的列及其表的列表,以便我们可以在脚本的基础上识别数据库中过时的列、表和模块。

我已经验证了我的数据库中没有用户对象使用当前定义的T-SQL保留字作为对象名。

问题:是否有一种方法来检测标识符何时是T-SQL词典的一部分?也就是说,从tree.ScriptTokenStream[idx]中包含的信息,可以确定tree.ScriptTokenStream[idx].Text是否是一个T-SQL词汇词吗?保留字似乎都有一个' tree.ScriptTokenStream[idx]。TokenType'不是"Identifier"的东西,所以它们已经被排除在外了。我想要消除的单词是像"NOCOUNT","VARCHAR","LTRIM"answers"RTRIM"这样的单词,它们都具有TokenType"Identifier"。

相关附加问题:此列表当前输出到控制台。在SQL Server CLR中将令牌输出重路由为crlf分隔的文本有什么提示吗?

我是一个完全的c#新手,但已经编码了很长时间,所以你能提供的任何帮助都需要从c#语法的角度来看是相当低级的,请。

我的环境是SQL Server 2008R2/c# in VS10/. net 4.5.2。

感谢您的关注和帮助。

程序如下:

  // Program.cs
  // Cloned and kludged from Program.cs, found in the BasicUsage project, available from the Samples download link in 
  //   http://blogs.msdn.com/b/arvindsh/archive/2013/11/06/slides-and-samples-for-my-sql-pass-scriptdom-talk.aspx
  //
  // See also: http://michaeljswart.com/2014/04/removing-comments-from-sql/
  // 
  // The page that VS10 "Help" should reference instead of the useless one it does:
  // https://msdn.microsoft.com/en-us/library/kx37x362(v=vs.100).aspx

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.IO;
  using Microsoft.SqlServer.TransactSql.ScriptDom;
  namespace BasicUsage
  {
      class Program
      {
          static void Main(string[] args)
          {
              // before proceeding, add a reference to the ScriptDom assembly
              IList<ParseError> errors = null;
              //TextReader rdr = new StreamReader(@"C:'ScriptDom'SampleProc.sql");
              TextReader rdr = new StreamReader(@"C:'ScriptDom'pTestProc.sql");
              // pass the reader to the scriptdom
              TSql110Parser parser = new TSql110Parser(true);
              TSqlFragment tree = parser.Parse(rdr, out errors);
              // some placeholders to avoid typing!
              foreach (ParseError err in errors)
              {
                  Console.WriteLine(err.Message);
              }
              string strtokentype ;
              string strtokentext ;
              int strtokentextlen ;
              int tokencount;
              int identifiercount = 0;
              tokencount = tree.ScriptTokenStream.Count;  // 249
              Console.WriteLine(tree.ScriptTokenStream.Count);
              Console.WriteLine("====== Listing only Identifiers ======");
              // walk through the tokens
              int idx = 0;
              for (idx=0; idx < tokencount; idx++ )  // remember: zero-based arrays here.
              {
                  //if (String.Equals(tree.ScriptTokenStream[idx].TokenType, "QuotedIdentifier", StringComparison.OrdinalIgnoreCase) = true ||
                  //    String.Equals(tree.ScriptTokenStream[idx].TokenType, "Identifier", StringComparison.OrdinalIgnoreCase) = true)
                  // Make string ops easier by doing the conversion only once, and operating on a string basis thereafter.
                  strtokentype = Convert.ToString(tree.ScriptTokenStream[idx].TokenType);

                  // if it's a quoted identifier, remove the first and last character, e.g. "[Rate]" becomes "Rate".
                  if (strtokentype == "QuotedIdentifier" ||
                      strtokentype == "Identifier"
                     )
                  {
                      identifiercount++;
                      // do the conversion first,
                      strtokentext =  Convert.ToString(tree.ScriptTokenStream[idx].Text);
                      // then extract the meaningful part if needed.
                      if (strtokentype == "QuotedIdentifier")
                      {
                          strtokentextlen = strtokentext.Length - 2;
                          strtokentext = strtokentext.Substring(1, strtokentextlen);
                      }
                      else
                      {
                          strtokentype = "      Identifier";  // Provide leading spaces to clean up the output text for a nicer presentation.
                      }
                      Console.Write("[" + idx + "] = " + strtokentype);
                      Console.WriteLine("  " + strtokentext);
                      Console.WriteLine();
                  }
              };
              Console.WriteLine();
              Console.WriteLine(identifiercount + "  Identifiers found.");
              Console.WriteLine();
              rdr.Dispose();  // Set breakpoint here so console remains visible during development
          }
      }
  }

识别TSql110Parser解析树中的T-SQL保留/词法词

结果是,我所问的MVP的共识是,真的没有一个全面的T-SQL关键字列表可用。

但是,在安装SSMS时创建了包含许多关键字的XML文件。该文件保存在您的机器上
   ,C:'Program Files (x86)'Microsoft SQL Server'120'Tools'Binn'ManagementStudio'SqlToolsData'1033'SqlCommonObjects.xml

这些,加上保留词(参见上面问题中的链接)组成了一个超过600个不同的词的列表[ODBC和未来使用的词包括],这些词对T-SQL有或可能有"特殊意义"。

作为题外话:请注意关键字与保留字的区别在于关键字可以合法地(如果不明智的话)用于创建有效的DDL,例如
,,,,,CREATE TABLE varchar(varchar varchar NOT NULL)
完全有效,但是有点混淆。