我试图通过sql文件在sqlplus中执行以下代码:
connect sys/knl_test7 as sysdba
grant sysdba to user1 identified by user1;
grant sysoper to user2 identified by user2;
variable c number;
begin
:c := dbms_sql.open_cursor;
for i in 3 .. 98 loop
dbms_sql.parse(:c, 'grant sysdba to user'||to_char(i)||' identified by user'||to_char(i), dbms_sql.v7);
dbms_lock.sleep(5);
end loop;
dbms_sql.close_cursor(:c);
tkzpwfsync.check_condition('(select count(username) from v$pwfile_users where username like ''USER%'')=98');
end;
/但是,在运行脚本之后,我将得到以下错误:
begin
*
ERROR at line 1:
ORA-00905 missing keywordcheck_condition过程如下所示,它基本上验证所提供的条件是否为真。
create or replace package tkzpwfsync is
procedure check_condition(condition varchar2);
end;
/
show errors
create or replace package body tkzpwfsync is
procedure check_condition(condition varchar2) is
x integer;
c number;
begin
x := 0;
c := dbms_sql.open_cursor;
dbms_sql.parse(c,'select 1 into x from dual where '||condition,dbms_sql.v7);
if (x!=1) then raise_application_error(-20001,'Condition '||condition||' is not met.'); end if;
dbms_sql.close_cursor(c);
end;
end;
/
show errors
create public synonym tkzpwfsync for tkzpwfsync;
grant execute on tkzpwfsync to public;发布于 2016-04-28 15:10:49
问题不在于您在匿名块中显示的动态SQL --如果使用dbms_sql可以使用execute immediate,但这两种方法都是有效的(如果不常见的话)。而且它也与SQL*Plus绑定变量声明或用法无关,尽管如此,使用本地PL/SQL变量而不是客户端绑定变量(就像在过程中那样)更常见,因为不需要在匿名块之外知道c的值。但这两种方法都是可行的。
问题在于您调用tkzpwfsync.wait()。您传递的字符串被用作另一个动态查询的一部分,而抛出ORA-00905的是生成的查询。
在您的过程中,您的块获得了比您已经显示的更多的错误细节:
begin
*
ERROR at line 1:
ORA-00905: missing keyword
ORA-06512: at "SYS.DBMS_SQL", line 1199
ORA-06512: at "SCHEMA.TKZPWFSYNC.WAIT", line 7
ORA-06512: at line 8wait()过程试图解析SQL语句:
select 1 into x from dual
where (select count(username) from v$pwfile_users where username like 'USER%')=98into x是PL/SQL结构,而不是SQL的一部分。如果直接运行它,您将看到相同的ORA-00905错误,因为它将'into‘作为列别名,然后不知道如何处理'x':
select 1 into x from dual
where (select count(username) from v$pwfile_users where username like 'USER%')=98;
Error report -
SQL Error: ORA-00905: missing keyword
00905. 00000 - "missing keyword"实际上,您也没有执行查询- 执行DDL吗? (因此您在匿名块中的授权可以工作),但是不执行DML。如果满足了,那么它将得到一个ORA-01403,如果条件不满足;在这里使用聚合更安全,所以您总是得到一行返回。
您可以修改该过程以执行以下操作:
dbms_sql.parse(c,'select count(*) from dual where '||condition,dbms_sql.v7);
dbms_sql.define_column(c, 1, x);
r := dbms_sql.execute(c);因此,它变成:
procedure wait(condition varchar2) is
x integer;
c number;
r integer;
begin
c := dbms_sql.open_cursor;
dbms_sql.parse(c,'select count(*) from dual where '||condition,dbms_sql.v7);
dbms_sql.define_column(c, 1, x);
r := dbms_sql.execute(c);
if dbms_sql.fetch_rows(c) > 0 then
dbms_sql.column_value(c, 1, x);
end if;
if (x!=1) then
raise_application_error(-20001,'Condition '||condition||' is not met.');
end if;
dbms_sql.close_cursor(c);
end;
/这现在起作用了,如果条件不满足,就会抛出ORA-20001。
如@Mottor所示,在这里使用execute immediate也更简单:
procedure wait(condition varchar2) is
x integer;
begin
execute immediate 'select count(*) from dual where '||condition into x;
if (x!=1) then
raise_application_error(-20001,'Condition '||condition||' is not met.');
end if;
end;
/..。但是,也许您希望使用dbms_sql.v7而不是本机执行是有原因的。
但是,我不确定等待是否真的是必要的;在创建用户时,条目将被添加到该视图中,因此在进行调用之前它们都将存在。对于带有修改后的过程名的检查(而不是等待)来说,这更有意义,但仍然不确定它是否有必要--如果计数不匹配,那么就会因为授权失败而引发错误,或者您已经拥有了SYSDBA特权的用户。所以计数会更高。只是看起来不太有用。(我甚至不会问你为什么需要98个SYSDBA用户;希望你只是在做实验,但如果是这样的话,我会使用一个不那么危险的角色)。
发布于 2016-04-28 08:08:06
尝尝这个。希望能帮上忙。
connect sys/knl_test7@DB_NAME as sysdba
grant sysdba to user1 identified by user1;
grant sysoper to user2 identified by user2;
SET SQLBL ON;
SET DEFINE OFF;
BEGIN
FOR i IN 3 .. 98
LOOP
EXECUTE IMMEDIATE 'grant sysdba to user'||TO_CHAR(i)||' identified by "user'||TO_CHAR(i)||'"';
dbms_lock.sleep(5);
END LOOP;
tkzpwfsync.wait('(select count(username) from v$pwfile_users where username like ''USER%'')=98');
END;
/发布于 2016-04-29 08:04:16
使用问汤姆查看dbms_sql.parse示例
你不能选择..。变成..。在动态sql中。您只需选择并绑定输出列。
下面是“立即执行”:
CREATE OR REPLACE PACKAGE BODY POINT_NET.tkzpwfsync
IS
PROCEDURE wait (condition VARCHAR2)
IS
x INTEGER;
BEGIN
x := 0;
EXECUTE IMMEDIATE 'select count(*) from dual where ' || condition INTO x;
IF (x != 1) THEN
raise_application_error (-20001, 'Condition ' || condition || ' is not met.');
END IF;
END;
END;
/只需说明,此程序不等待,只检查条件。
https://stackoverflow.com/questions/36908560
复制相似问题