为什么会出现 "ORA-00933: SQL command not properly ended" 错误(立即执行)?
Why do I get "ORA-00933: SQL command not properly ended" error ( execute immediate )?
我创建了一个函数,它使用动态 sql:
create function check_ref_value
(
table_name varchar2,
code_value number,
code_name varchar2
) return number is
l_query varchar2(32000 char);
l_res number;
begin
l_query := '
select sign(count(1))
into :l_res
from '|| table_name ||'
where '|| code_name ||' = :code_value
';
execute immediate l_query
using in code_value, out l_res;
return l_res;
end;
但是当我尝试使用它时出现异常“ORA-00933:SQL 命令未正确结束”
这段代码有什么问题?
您可以使用 EXECUTE IMMEDIATE ... INTO ... USING ...
获取 return 值并使用 DBMS_ASSERT
在 SQL 注入尝试的情况下引发错误:
create function check_ref_value
(
table_name varchar2,
code_value number,
code_name varchar2
) return number is
l_query varchar2(32000 char);
l_res number;
begin
l_query := 'select sign(count(1))'
|| ' from ' || DBMS_ASSERT.SIMPLE_SQL_NAME(table_name)
|| ' where ' || DBMS_ASSERT.SIMPLE_SQL_NAME(code_name)
|| ' = :code_value';
execute immediate l_query INTO l_res USING code_value;
return l_res;
end;
/
其中,对于示例数据:
CREATE TABLE abc (a, b, c) AS
SELECT 1, 42, 3.14159 FROM DUAL;
然后:
SELECT CHECK_REF_VALUE('abc', 42, 'b') AS chk FROM DUAL;
输出:
CHK
1
并且:
SELECT CHECK_REF_VALUE('abc', 42, '1 = 1 OR b') AS chk FROM DUAL;
引发异常:
ORA-44003: invalid SQL name
ORA-06512: at "SYS.DBMS_ASSERT", line 160
ORA-06512: at "FIDDLE_UVOFONEFDEHGDQJELQJL.CHECK_REF_VALUE", line 10
关于你的问题:
What is wrong with this code?
使用 SELECT ... INTO
仅在 PL/SQL 块中的 SQL 语句中有效,当您 运行 通过 EXECUTE IMMEDIATE
语句时,它在SQL 范围而不是 PL/SQL 范围。
您可以通过将动态代码包装在 BEGIN .. END
PL/SQL 匿名块中来修复它(并反转 USING
子句中绑定参数的顺序):
create function check_ref_value
(
table_name varchar2,
code_value number,
code_name varchar2
) return number is
l_query varchar2(32000 char);
l_res number;
begin
l_query := '
BEGIN
select sign(count(1))
into :l_res
from '|| DBMS_ASSERT.SIMPLE_SQL_NAME(table_name) ||'
where '|| DBMS_ASSERT.SIMPLE_SQL_NAME(code_name) ||' = :code_value;
END;
';
execute immediate l_query
using out l_res, in code_value;
return l_res;
end;
/
(但是,仅使用 EXECUTE IMMEDIATE ... INTO ... USING ...
的解决方案有点复杂。)
db<>fiddle here
我创建了一个函数,它使用动态 sql:
create function check_ref_value
(
table_name varchar2,
code_value number,
code_name varchar2
) return number is
l_query varchar2(32000 char);
l_res number;
begin
l_query := '
select sign(count(1))
into :l_res
from '|| table_name ||'
where '|| code_name ||' = :code_value
';
execute immediate l_query
using in code_value, out l_res;
return l_res;
end;
但是当我尝试使用它时出现异常“ORA-00933:SQL 命令未正确结束” 这段代码有什么问题?
您可以使用 EXECUTE IMMEDIATE ... INTO ... USING ...
获取 return 值并使用 DBMS_ASSERT
在 SQL 注入尝试的情况下引发错误:
create function check_ref_value
(
table_name varchar2,
code_value number,
code_name varchar2
) return number is
l_query varchar2(32000 char);
l_res number;
begin
l_query := 'select sign(count(1))'
|| ' from ' || DBMS_ASSERT.SIMPLE_SQL_NAME(table_name)
|| ' where ' || DBMS_ASSERT.SIMPLE_SQL_NAME(code_name)
|| ' = :code_value';
execute immediate l_query INTO l_res USING code_value;
return l_res;
end;
/
其中,对于示例数据:
CREATE TABLE abc (a, b, c) AS
SELECT 1, 42, 3.14159 FROM DUAL;
然后:
SELECT CHECK_REF_VALUE('abc', 42, 'b') AS chk FROM DUAL;
输出:
CHK 1
并且:
SELECT CHECK_REF_VALUE('abc', 42, '1 = 1 OR b') AS chk FROM DUAL;
引发异常:
ORA-44003: invalid SQL name ORA-06512: at "SYS.DBMS_ASSERT", line 160 ORA-06512: at "FIDDLE_UVOFONEFDEHGDQJELQJL.CHECK_REF_VALUE", line 10
关于你的问题:
What is wrong with this code?
使用 SELECT ... INTO
仅在 PL/SQL 块中的 SQL 语句中有效,当您 运行 通过 EXECUTE IMMEDIATE
语句时,它在SQL 范围而不是 PL/SQL 范围。
您可以通过将动态代码包装在 BEGIN .. END
PL/SQL 匿名块中来修复它(并反转 USING
子句中绑定参数的顺序):
create function check_ref_value
(
table_name varchar2,
code_value number,
code_name varchar2
) return number is
l_query varchar2(32000 char);
l_res number;
begin
l_query := '
BEGIN
select sign(count(1))
into :l_res
from '|| DBMS_ASSERT.SIMPLE_SQL_NAME(table_name) ||'
where '|| DBMS_ASSERT.SIMPLE_SQL_NAME(code_name) ||' = :code_value;
END;
';
execute immediate l_query
using out l_res, in code_value;
return l_res;
end;
/
(但是,仅使用 EXECUTE IMMEDIATE ... INTO ... USING ...
的解决方案有点复杂。)
db<>fiddle here