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

时间:2011-02-22 22:50:14

标签: sql sql-server-2005 stored-procedures localization

我们正致力于使我们的应用程序100%可本地化,我们大部分都在那里。但是,我们偶尔会发现一个英文字符串仍然在存储过程中硬编码。 (顺便说一下,我们在SQL Server 2005上。)我们有数千个存储过程,因此手动浏览它们是不切实际的。我正在尝试考虑自动搜索的最准确方法。

现在,我知道没有办法搜索“英文”字符串 - 但是搜索由单引号限制的字符串,可能还有20多个字符长,应该将其中的大部分字符冲洗掉。足以满足我们的目的。但我也期待存储过程的评论中有很多误报。

那你怎么看待这个? SMO会让我在存储过程中将SQL与其中的注释区分开来吗?我是否必须使用OBJECT_DEFINITION()并开始破解一些可怕的正则表达式?

提前非常感谢,伙计们。

2 个答案:

答案 0 :(得分:4)

另一个想法:Microsoft使用Visual Studio提供了一个可以解析SQL的程序集。我用过它,使用起来相当简单。您可以使用它来解析存储过程的文本;它可以返回语句中各种标记的列表,包括标记的类型。因此,它应该能够帮助您区分您可能感兴趣的文本字符串与评论的一部分,并且可以忽略。这里有更多详细信息:http://blogs.msdn.com/b/gertd/archive/2008/08/21/getting-to-the-crown-jewels.aspx

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

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

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);
                            }
                        }
                    }
                }

            }
        }
    }
}

答案 1 :(得分:2)

我们通过在不同的语言/区域设置中创建SQL Server并运行我们的sp来解决由此产生的问题,并注意哪些是破坏的。

这可能不是最优雅的解决方案,但由于我们支持的地点设置有限,我们能够快速完成。