admin

如何最好地在SQL Server存储过程中找到硬编码的英语字符串?

sql

我们正在努力使我们的应用程序100%可本地化,并且我们大部分都在那儿。但是,有时我们会发现仍然在存储过程中对英语字符串进行了硬编码。(顺便说一下,我们使用的是SQL
Server2005。)我们有成千上万的存储过程,因此手动进行存储是不切实际的。我正在尝试考虑自动搜索的最准确方法。

现在,我知道没有办法搜索“英语”字符串-
但是,搜索以单引号和大约20个以上的字符为界的字符串应该可以将大部分内容清除掉。对于我们的目的而言已经足够好了。但是在存储过程的注释中,我也期待很多错误的肯定。

那么您将如何处理呢?SMO是否可以让我从存储过程中的注释中挑出SQL?我是否必须使用OBJECT_DEFINITION()并开始破解一些令人恐惧的正则表达式?

各位,请多多关照。


阅读 152

收藏
2021-07-01

共1个答案

admin

另一个想法:Microsoft通过Visual
Studio提供了可以解析SQL的程序集。我已经用过了,而且使用起来很简单。您也许可以使用它来解析存储过程的文本;它可以返回语句中各种标记的列表,包括标记的类型。因此,它应该能够帮助您区分您可能会感兴趣的文本字符串与注释中哪些内容可以忽略。

基本上,从.NET,您将打开与数据库的连接,并查询syscomments以获取存储过程的文本。您将遍历每个过程,并使用这些解析器对其进行解析。然后,您将使用Sql100ScriptGenerator从解析的文本中获取标记,遍历标记并查找其类型为ASCII或Unicode字符串文字的标记。对于那些字符串,请检查它们的长度以查看其长度是否超过20,如果是20,则将这些字符串和proc标记为需要进一步检查。

我玩了一下,这是一个 非常 原始的示例来说明基本原理:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Data.Schema;
using Microsoft.Data.Schema.ScriptDom;
using Microsoft.Data.Schema.ScriptDom.Sql;

namespace FindHardCodedStrings
{
    class Program
    {
        static void Main(string[] args)
        {
            using (SqlConnection conn = new SqlConnection())
            {
                SqlConnectionStringBuilder bldr = new SqlConnectionStringBuilder();
                bldr.DataSource = "localhost\\sqlexpress";
                bldr.InitialCatalog = "msdb";
                bldr.IntegratedSecurity = true;

                conn.ConnectionString = bldr.ConnectionString;

                SqlCommand cmd = conn.CreateCommand();
                cmd.CommandType = System.Data.CommandType.Text;
                cmd.CommandText = "select [text] from syscomments";

                SqlDataAdapter da = new SqlDataAdapter(cmd);
                DataSet ds = new DataSet();
                da.Fill(ds);

                TSql100Parser parser = new TSql100Parser(false);
                Sql100ScriptGenerator gen = new Sql100ScriptGenerator();
                gen.Options.SqlVersion = SqlVersion.Sql100;

                foreach (DataRow proc in ds.Tables[0].Rows)
                {
                    string txt = proc[0].ToString();
                    using (System.IO.TextReader sr = new System.IO.StringReader(txt))
                    {
                        IList<ParseError> errs;
                        IScriptFragment frag = parser.Parse(sr, out errs);

                        if (null == frag)
                            continue;

                        IList<TSqlParserToken> tokens = gen.GenerateTokens((TSqlFragment)frag);

                        foreach (TSqlParserToken token in tokens)
                        {
                            if (token.TokenType == TSqlTokenType.UnicodeStringLiteral || token.TokenType == TSqlTokenType.AsciiStringLiteral)
                            {
                                if (token.Text.Length >= 20)
                                    Console.WriteLine("String found: " + token.Text);
                            }
                        }
                    }
                }

            }
        }
    }
}
2021-07-01