我需要用旧的方式转换SQL,或者将参数插入到查询中,将参数替换为问号(?)并分别传递给查询处理程序-请参阅下面的“旧”和“新”示例。
我已经使用了各种参数和各种参数的SQL语句的顺序或1200条,我想将它们全部转换为新的of。
这是我必须为之创建一个自定义解析器的东西吗?还是有一些工具可以让我轻松地进行批量转换?
非参数化查询(又称旧查询)
$product = "widget";
$price = 10.00;
$sql = "SELECT description
FROM resource.product
WHERE
product.model = '" . db_input($product) . "'
and product.price = '" . db_input($price) . "'
";
$result = db_query($sql);参数化查询(又名新查询)
$product = "widget";
$price = 10.00;
$sql = "SELECT description
FROM resource.product
WHERE
product.model = ?
and product.price = ?
";
$result = db_param_query($sql, [$product, $price]);注意,下面4行中有两个块不同。
发布于 2016-10-12 04:13:28
你需要的是一个程序转换系统(PTS)。PTS是一种工具,可以将源代码解析为编译器数据结构(例如,抽象语法树或AST ),可以将转换应用到表示所需更改的AST,然后可以从修改后的AST重新生成有效的源代码。
良好的PTS将允许您指定使用语法转换的langauge,并允许您使用源到源重写规则对树进行代码修改,这些规则本质上是形式的:
**when** you see *this*, replace it by *that*, **if** condition(*this*)其中--和--即是使用正在转换的语言的语法编写的模式,并且条件可以检查匹配的模式以获得额外的约束。
在OP的例子中,我猜他使用的是PHP (telltales:"$“作为变量名的前缀,”。用于级联操作符)。因此,他需要一个好的PTS和一个精确的PHP语法。
在OP中,他有一个双重语法问题:他不仅希望转换将SQL字符串片段粘合在一起的PHP代码,而且还希望修改SQL字符串本身。可以说,他还需要PTS解析SQL字符串片段,然后应用同时修改PHP和SQL字符串的转换。如果我们假设SQL字符串总是由遗留程序通过串接字符串片段来组装,而这些片段总是表示参数之间的SQL块,那么我们就可以避免这个双重解析问题。
第二个问题是知道字符串表示SQL字符串片段。考虑以下代码:
$A=1; $B=10;
echo "SELECT number from '" . $A . "' to '" . $B . "'";这看起来非常像一个真正的select语句,但事实并非如此;我们不想对这段代码应用任何转换。通常,您无法知道组装的字符串实际上是SQL字符串,或者仅仅是看起来类似的字符串。我们将假设所有分别终止和以"'“开头的连接字符串都是SQL字符串。
我们的DMS软件重组工具包是一个PTS,可以解决这个问题;它甚至有一个可用的PHP语法。大约需要以下DMS重写规则:
rule fix_legacy_SQL_parameter_passing(s1: STRING, v, DOLLARVAR, s2:STRING):
expression -> expression=
" \s1 . db_input(\v) . \s2 "
-> " \concatenate3\(\allbutlastcharacter\(\s1\)\,"?"\
\allbutfirstcharacter\(\s2\)"
if last_character_is(s1,"'") and first_character_is(s2,"'");规则被命名为fix_legacy_SQL_parameter_passing,以使我们能够将它与我们可能拥有的许多其他规则区分开来。参数s1和s2表示匹配指定(非)终端类型的子树的元数据。表达式->表达式告诉DMS,规则仅适用于表达式。
这个模式是“\s1 . db_input( \v ) . \s2 ";"是一个元引号,它将DMS重写规则语法与PHP语法分隔开来。\s1、\v和\s2使用*来表示一个元可调,该模式实际上是这样写的:”如果您能够找到一个包含有变量名的dbinput函数作为参数的两个文字字符串的连接.“
遵循第二个->是该模式;它非常复杂,因为我们需要对匹配的字符串进行一些计算。为此,它使用了如下所写的元功能
\fnname\( arg1 \, arg2 \, ... \)通过匹配从绑定到模式变量的树中计算新树。注意*转义以区分元函数调用的元素和目标语言的语法。我希望我建议使用的一组元功能的用途是明确的;它们必须被编码为对此规则的自定义辅助支持。该规则以";“结尾。
应该清楚的是,此规则将SQL字符串补丁为"?“在构造的字符串中。
但是等等哦..。我们没有收集db_input变量。
我们可以这样做:隐藏累加器(这里没有显示,因为它看起来像魔法),或者笨拙,但更容易重写标记。
DMS的标记是一棵树,它包含我们希望它包含的任何内容;它通常表明我们打算做进一步的工作,我们需要更多的重写规则来完成这项工作。首先,我们介绍标记树的定义:
pattern accumulated_db_variable( vars:expression, computed:expression) :expression = TAG;这使得accumulated_db_variable成为这样一个标记,有两个子标记,第一个是变量名列表,第二个是任意表达式。
现在,我们修改上述规则:
rule fix_legacy_SQL_parameter_passing(s1: STRING, v, DOLLARVAR, s2:STRING):
expression -> expression=
" \s1 . db_input(\v) . \s2 "
-> " \accumulated_dbinputs\([\v]\,
\concatenate3\(\allbutlastcharacter\(\s1\)\,"?"\
\allbutfirstcharacter\(\s2\)\)"
if last_character_is(s1,"'") and first_character_is(s2,"'");此规则计算修改后的SQL字符串,但也计算在该字符串中找到的dbinput变量集,并将这一对树封装在标记中。坏消息是,我们现在在表达式的中间有标记;但是,我们可以编写额外的规则来消除这些标记,方法是在它们彼此接近时组合它们:
rule merge_accumulated_dbinputs(vars: element_list,
v: DOLLARVAR,
e: expression):
expression -> expression =
" \accumulated_dbinputs\([\vars]\,
\accumulated_db_inputs\([\v]\,e\)\)"
-> "\accumulated_dbinputs\([vars,v]\,\e)";我们需要一条规则将集合的变量移到OP建议的以下语句:
rule finalize_accumlated_dbinputs(lhs1: DOLLARVAR,
vars: element_list,
query: expression,
lhs2: DOLLARVAR)
statements -> statements =
" \lhs1 = \accumulated_dbinputs\([\vars],\query);
\lsh2 = db_param_query(\lhs1,[\vars]);如果他的代码具有比这更大的可变性,他可能需要编写额外的规则。
最后,我们需要将这组规则粘合在一起,并给它起一个名称:
ruleset fix_legacy_SQL { fix_legacy_SQL_parameter_passing,merge_accumulated_dbinputs,finalize_accumlated_dbinputs }
这样,我们就可以对一个文件调用DMS,并告诉它应用规则集直到耗尽为止。
这组规则应该做的是,通过一系列步骤将其转换为OP示例的预期输出:
$sql = "SELECT description
FROM resource.product
WHERE
product.model = '" . db_input($product) . "'
and product.price = '" . db_input($price) . "'
";
$result = db_query($sql);-> (“转换为”):
$sql = TAG_accumulated_dbinputs([$product],
"SELECT description
FROM resource.product
WHERE
product.model = ?
and product.price = '" . db_input($price) . "'
");
$result = db_query($sql);-> (“转换为”):
$sql = TAG_accumulated_dbinputs([$product],
TAG_accumulated_dbinputs([$price],
"SELECT description
FROM resource.product
WHERE
product.model = ?
and product.price = ?
"));
$result = db_query($sql);-> (“转换为”):
$sql = TAG_accumulated_dbinputs([$product,$price],
"SELECT description
FROM resource.product
WHERE
product.model = ?
and product.price = ?
");
$result = db_query($sql);-> (“转换为”):
$sql = "SELECT description
FROM resource.product
WHERE
product.model = ?
and product.price = ?
";
$result = db_param_query($sql,[$product,$price]);哇哦。未经测试,但我认为这是非常接近正确的。
https://stackoverflow.com/questions/39987521
复制相似问题