为啥我不能在动态 SQL 的 DDL/SCL 语句中使用绑定变量?
Posted
技术标签:
【中文标题】为啥我不能在动态 SQL 的 DDL/SCL 语句中使用绑定变量?【英文标题】:Why cannot I use bind variables in DDL/SCL statements in dynamic SQL?为什么我不能在动态 SQL 的 DDL/SCL 语句中使用绑定变量? 【发布时间】:2014-10-18 18:51:58 【问题描述】:我正在尝试使用绑定变量在动态 SQL 中执行 SQL 命令:
-- this procedure is a part of PL/SQL package Test_Pkg
PROCEDURE Set_Nls_Calendar(calendar_ IN VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE
'ALTER SESSION
SET NLS_CALENDAR = :cal'
USING IN calendar_;
END Set_Nls_Calendar;
然后在客户端,我尝试调用该过程:
Test_Pkg.Set_Nls_Calendar('Thai Buddha');
但这就是我ORA-02248: invalid option for ALTER SESSION
。
我的问题是:为什么我不能在动态 SQL 的 DDL/SCL 语句中使用绑定变量?
【问题讨论】:
【参考方案1】:DDL 语句中不允许绑定变量。所以下面的语句会报错:
示例 #1:DDL 语句。会导致ORA-01027: bind variables not allowed for data definition operations
EXECUTE IMMEDIATE
'CREATE TABLE dummy_table ( dummy_column NUMBER DEFAULT :def_val )'
USING 42;
示例 #2:DDL 语句。会导致ORA-00904: : invalid identifier
EXECUTE IMMEDIATE
'CREATE TABLE dummy_table ( :col_name NUMBER )'
USING var_col_name;
示例 #3:SCL 语句。会导致ORA-02248: invalid option for ALTER SESSION
EXECUTE IMMEDIATE
'ALTER SESSION SET NLS_CALENDAR = :cal'
USING var_calendar_option;
问题
要了解为什么会发生这种情况,我们需要查看How Dynamic SQL Statements Are Processed。
通常,应用程序会提示用户输入 SQL 语句的文本和语句中使用的主变量的值。然后 Oracle 解析 SQL 语句。也就是说,Oracle 检查 SQL 语句以确保它遵循语法规则并且 引用有效的数据库对象。解析还涉及检查数据库访问权限1、保留所需资源以及找到最佳访问路径。
1回答者添加的重点
请注意,解析步骤发生在将任何变量绑定到动态语句之前。如果您检查上述四个示例,您会发现解析器无法在不知道绑定变量的值的情况下保证这些动态 SQL 语句的语法有效性。
示例 #1:解析器无法判断绑定值是否有效。如果程序员写的不是USING 42
,而是USING 'forty-two'
,该怎么办?
示例 #2:解析器无法判断 :col_name
是否是有效的列名。如果绑定的列名是'identifier_that_well_exceeds_thirty_character_identifier_limit'
怎么办?
示例 #3:NLS_CALENDAR
的值内置在常量中(对于给定的 Oracle 版本?)。解析器无法判断绑定变量是否具有有效值。
所以答案是不能在动态SQL中绑定表名、列名等模式元素。你也不能绑定内置常量。
解决方案
实现动态引用架构元素/常量的唯一方法是在动态 SQL 语句中使用字符串连接。
示例 #1:
EXECUTE IMMEDIATE
'CREATE TABLE dummy_table ( dummy_column NUMBER DEFAULT ' || to_char(42) || ')';
示例 #2:
EXECUTE IMMEDIATE
'CREATE TABLE dummy_table (' || var_col_name || ' NUMBER )';
示例 #3:
EXECUTE IMMEDIATE
'ALTER SESSION SET NLS_CALENDAR = ''' || var_calendar_option || '''';
【讨论】:
非常好。汤姆在这里也讨论了这个asktom.oracle.com/pls/apex/… 我需要使用用户提供的密码进行ALTER USER
,但是字符串连接会引入SQL注入攻击。
@RayCheng:你显然需要清理用户输入。以上是关于为啥我不能在动态 SQL 的 DDL/SCL 语句中使用绑定变量?的主要内容,如果未能解决你的问题,请参考以下文章