Oracle PL/SQL 语句抛出错误
Posted
技术标签:
【中文标题】Oracle PL/SQL 语句抛出错误【英文标题】:Oracle PL/SQL statement throwing errors 【发布时间】:2011-11-09 16:59:00 【问题描述】:我通过 ADO 将以下 PL/SQL 发送到远程 oracle 11gr2 服务器。 它的目的是检查用户是否存在。然后,如果确实如此,则终止其所有连接。最后它丢弃了用户。
DECLARE
i INTEGER;
BEGIN
select count(1) into i from dba_users where username='<schema>';
if i=0 THEN
FOR c IN (SELECT s.sid,s.serial# FROM v$session s WHERE s.username = '<schema>') LOOP
EXECUTE IMMEDIATE 'alter system kill session ''' ||c.sid || ',' || c.serial# || '''';
END LOOP;
drop user <schema> Cascade;
END IF;
END;
经过多次调整后我收到的错误消息仍然是:
错误:[Microsoft][Oracle 的 ODBC 驱动程序][Oracle]ORA-06550:第 1 行, 第 286 列:PLS-00103:预期时遇到符号“DROP” 以下之一:
( begin case declare else elsif end exit for goto if loop mod null pragma raise return select update while with
它不喜欢在 IF 语句中放置 drop 的语法。有谁知道让这个运行正常吗?
编辑: 需要明确的是,我通常不会以这种方式执行此语句。但由于环境原因,这是唯一可行的方法,不会造成任何安全风险。我知道我违反了几乎所有的良好做法,但这次是必要的!
【问题讨论】:
我强烈建议您在存储过程中执行此操作。这将完成几件事:1) 您将从问题中删除 jet 解析器并让 Oracle 在内部处理它。 2)您可以构造 SP,使其简单地返回 1 或 0 作为成功/失败,从而拒绝任何注入尝试。此外,请注意 Ollie 的建议并使用绑定参数来进一步保护任何 sql 事务。 @wave:另外,使用count(1)
比使用count(*)
没有优势。此外,SQL 解析引擎无论如何都会将您的count(1)
更改为count(*)
。请参阅 Tom Kyte 的许多关于此的文章:Select Count(1): How it works
【参考方案1】:
您不能直接在 PL/SQL 中发出 DDL(即 DROP)语句,您需要使用动态 SQL 运行 DROP 语句。
实现这一点的最简单方法是使用EXECUTE IMMEDIATE
语句(与您已经将它用于ALTER SESSION
命令的方式类似):
http://download.oracle.com/docs/cd/B12037_01/appdev.101/b10807/13_elems017.htm
DECLARE
i INTEGER;
BEGIN
SELECT COUNT( 1 )
INTO i
FROM dba_users
WHERE username = '<schema>';
IF i = 0
THEN
FOR c IN ( SELECT s.sid,
s.serial#
FROM v$session s
WHERE s.username = '<schema>' )
LOOP
EXECUTE IMMEDIATE 'alter system kill session ''' ||
c.sid || ',' || c.serial# || '''';
END LOOP;
EXECUTE IMMEDIATE 'DROP USER :username CASCADE'
USING '<schema>';
END IF;
END;
顺便说一句,您可能希望考虑使用绑定变量而不是连接动态 SQL 中的值,因为它可以提高性能,尤其是在循环中。
例如
EXECUTE IMMEDIATE 'alter system kill session '':sid'','':serial'''
USING c.sid,
c.serial#;
希望对你有帮助...
【讨论】:
您不能在 DDL 中使用绑定变量,因此您不能以这种方式参数化ALTER SYSTEM
或 DROP USER
命令。您必须连接用户名。您可能希望使用DBMS_ASSERT.SCHEMA_NAME
函数来验证传入的用户名是一个简单的模式名称,以防止 SQL 注入攻击,此外还要执行诸如记录调用和验证用户名是否合理(即您不这样做)之类的操作。不希望有人意外删除 Oracle 提供的帐户)
您不能在 DDL 中使用绑定变量(即 alter system
和 drop user
)。
这在摆脱绑定部分后起到了作用。非常感谢。
啊,是的,我在想什么。您不能对 DDL 使用绑定变量。对不起,当我发布答案时,我正冲出门。答案的原则是正确的,为绑定变量红鲱鱼道歉。 Justin 是正确的,您仍然应该使用 DBMS_ASSET 包来保护您的过程免受 SQL 注入。以上是关于Oracle PL/SQL 语句抛出错误的主要内容,如果未能解决你的问题,请参考以下文章
ORACLE:错误错误(6,3):PL/SQL:SQL 语句被忽略和错误(8,3):PL/SQL:ORA-00933:SQL 命令未在过程中正确结束