我们正致力于使我们的应用程序100%可本地化,我们大部分都在那里。但是,我们偶尔会发现一个英文字符串仍然在存储过程中硬编码。 (顺便说一下,我们在SQL Server 2005上。)我们有数千个存储过程,因此手动浏览它们是不切实际的。我正在尝试考虑自动搜索的最准确方法。
现在,我知道没有办法搜索“英文”字符串 - 但是搜索由单引号限制的字符串,可能还有20多个字符长,应该将其中的大部分字符冲洗掉。足以满足我们的目的。但我也期待存储过程的评论中有很多误报。
那你怎么看待这个? SMO会让我在存储过程中将SQL与其中的注释区分开来吗?我是否必须使用OBJECT_DEFINITION()并开始破解一些可怕的正则表达式?
提前非常感谢,伙计们。
答案 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来解决由此产生的问题,并注意哪些是破坏的。
这可能不是最优雅的解决方案,但由于我们支持的地点设置有限,我们能够快速完成。