正则表达式提取sql语句的@参数名,顺便修正subsonic的一个bug

        subsonic的InlineQuery非常好用,用于执行参数的Sql语句,防止被注入,其运行机制类似我之前写的《借用.net framework的string.Fromat(...),实现一个执行参数化SQL的方法》,都是先提前sql语句中的参数名,再根据参数名和传入的值动态构造Command.

贴一个官方的使用InlineQuery的示例:

Northwind.ProductCollection products=
   
new InlineQuery()
    .ExecuteAsCollection
<Northwind.ProductCollection>
    (
"SELECT productID from products WHERE productid=@productid"1);

 

 

        今天用InlineQuery执行带参数的SQl语句时候,发现subsonic分析sql参数的一个bug,跟踪进入subsonic的源代码,发现其解析sql语句的参数是这样解析的:

private static List<string> ParseParameters(string sql)
{
     List<string> result = new List<string>();
     Regex paramReg = new Regex(@"@\w*");
     MatchCollection matches = paramReg.Matches(String.Concat(sql, " "));
     foreach(Match m in matches)
          result.Add(m.Value);
     return result;
}
注意看第三行,Regex paramReg = new Regex(@"@\w*"),它的其他机制是用正则表达式分组匹配,例如有以下sql语句:
SELECT * FROM students WHERE fname=@name;
SELECT @@ROWCOUNT
提取的时候连@@ROWCOUNT这样的变量都会被提取出来,

显然这不是我们想要的,我们想要的结果是,只提取@name这个参数名,这显然是不能满足要求的,真则表达式@"@\w*"未免处理得太草率了,还好开源的东西有源码好修改,最好花了10分钟时间(真是惭愧啊,好久没有用这玩意了)写正则表达式:([^@@](?<p>@\w+))|(?<p>^@\w+)

最后修改的代码如下:

private static List<string> ParseParameters(string sql)
{
     List<string> result = new List<string>();
     //Regex paramReg = new Regex(@"@\w*");
     //2009-2-29 修正正则表达式匹配参数时,Sql中包括@@rowcount之类的变量的情况,不应该算作参数
     Regex paramReg = new Regex(@"[^@@](?<p>@\w+)");
     MatchCollection matches = paramReg.Matches(String.Concat(sql, " "));
     foreach(Match m in matches)
          result.Add(m.Groups["p"].Value);
     return result;
}
 
各位如果还有简单点的写法,请留言告知这下,谢谢。
posted @ 2009-02-28 21:10  代码乱了  阅读(3387)  评论(7编辑  收藏