为啥我不能在动态 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'怎么办? 示例 #3NLS_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 语句中使用绑定变量?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能在 python 中获取 sql 语句?

为啥我不能准备这个 sql 语句来设置 auto_increment?

java中sql语句为啥不能出现 * ?

mybatis在传参时,为啥#能够有效的防止sql注入

为啥我们不能从 sql 调用过程

SQL语句中的别名为啥不能用啊