正则表达式提取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);
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; }
各位如果还有简单点的写法,请留言告知这下,谢谢。