无效的 SQL 类型:sqlKind = UNINITIALIZED - PLSQL 错误
Posted
技术标签:
【中文标题】无效的 SQL 类型:sqlKind = UNINITIALIZED - PLSQL 错误【英文标题】:Invalid SQL type: sqlKind = UNINITIALIZED - PLSQL Error 【发布时间】:2015-04-15 22:24:12 【问题描述】:我只是想阻止用户在没有 WHERE 子句的情况下运行 UPDATE 语句。我在下面提供了我的 PLSQL
create or replace PROCEDURE secure_update(update_query IN varchar2)
IS
msg varchar2(30000);
flag char(1);
qry varchar2(30000);
BEGIN
IF upper(update_query) LIKE 'UPDATE%SET%WHERE%=%' THEN
flag := '1';
ELSE
flag := '0';
END IF;
IF (flag = '1') THEN
--qry := update_query;
execute immediate update_query into msg;
END IF;
dbms_output.put_line(msg);
END;
这就是我的执行方式
EXEC secure_update
('
UPDATE dummy_table
SET col1 = ''whatever''
WHERE pk = ''1234''
')
我不断收到这条消息:
无效的 SQL 类型:sqlKind = UNINITIALIZED
您能帮我找出解决此错误的方法吗?
【问题讨论】:
使用dynamic sql
时,尝试将varchar值放在两个引号''whatever''
我的意思是使用''
作为'
除了您看到的错误、不平衡的单引号以及 exec
必须在一行之外,我不确定您的目标。如果您想检查 where
子句以使调用者无法一次更新所有记录,那么是什么阻止他们执行 where 1=1
之类的操作?
这个 plsql 用于实验目的。我目前不考虑安全性
不相关但是:为什么不使用真正的boolean
来表示flag
变量?
@AlexPoole:单行所需的 exec 是 SQL*Plus 的限制。并非所有 SQL 客户端都有相同的限制。
【参考方案1】:
这可行,请查看更改,不要在立即执行中使用 into 子句
create or replace PROCEDURE secure_update(update_query IN varchar2)
IS
msg varchar2(30000);
flag char(1);
qry varchar2(30000);
BEGIN
IF upper(update_query) LIKE 'UPDATE%SET%WHERE%=%' THEN
flag := '1';
dbms_output.put_line('updated succesfully');
ELSE
flag := '0';
dbms_output.put_line('no where clause in update');
END IF;
IF (flag = '1') THEN
--qry := update_query;
execute immediate update_query ;
END IF;
END;
如果您想在更新中使用 varchar,请参阅此
SCOTT@research 16-APR-15> select * from test2;
A B
----- -----
a b
code to execute procedure :
declare
lsql varchar2(100):= 'update test2 set a=''z'' where b=''b'' ';
begin
secure_update(lsql);
end;
output: updated succesfully
SCOTT@research 16-APR-15> select * from test2;
A B
----- -----
z b
declare
lsql varchar2(100):= 'update test2 set a=''z''';
begin
secure_update(lsql);
end;
output
no where clause in update
另一个例子
SCOTT@research 16-APR-15> select * from test1;
VAL1 VAL2 VAL3
---------- ---------- ----------
2 2 4
3 2 4
123 2 3
42 3
SCOTT@research 16-APR-15> exec secure_update('update test1 set val1=555 where val1=2');
updated succesfully
PL/SQL procedure successfully completed.
SCOTT@research 16-APR-15> select * from test1;
VAL1 VAL2 VAL3
---------- ---------- ----------
555 2 4
3 2 4
123 2 3
42 3
SCOTT@research 16-APR-15> exec secure_update('update test1 set val1=555');
no where clause in update
PL/SQL procedure successfully completed.
【讨论】:
【参考方案2】:SQL Developer(和 SQL*Plus,但可能不是其他客户端!)需要 exec
命令位于一行。您没有显示从该调用中得到的较早错误:
EXEC secure_update
Error report -
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'SECURE_UPDATE'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Error starting at line : 25 in command -
('
UPDATE dummy_table
SET col1 = ''whatever''
WHERE pk = ''1234''
')
Error at Command Line : 25 Column : 2
Error report -
SQL Error: Invalid SQL type: sqlKind = UNINITIALIZED
调用过程时不带参数,因为在同一行中没有参数与实际的exec
,因此您从该行得到 PLS-00306。然后其余的被解释为一个单独的命令,它会得到你报告的“invalid SQL type”错误。 (即在 SQL Developer 中;在 SQL*Plus 中,第一部分的 PLS-00306 相同,其余部分为 ORA-00928: missing SELECT keyword
)。
您可以将整个语句移到一行中:
EXEC secure_update ('UPDATE dummy_table SET col1 = ''whatever'' WHERE pk = ''1234''');
或者使用显式匿名块而不是 exec
速记:
BEGIN
secure_update
('UPDATE dummy_table
SET col1 = ''whatever''
WHERE pk = ''1234''
');
dbms_output.put_line('after');
END;
/
还请注意,无论如何我都必须将UPDATE
向上移动一行,因为您的检查不允许在命令开头使用任何空格(包括换行符)。您的程序中的into msg
没有做任何事情,但似乎没有引起问题;如果您想查看更新了多少行,请改用execute immediate
之后的 SQL%ROWCOUNT。
【讨论】:
【参考方案3】:UPDATE
语句不应该被执行 into
任何东西,它应该被执行。此代码演示了错误,尽管错误消息与您发布的略有不同。
create table dummy_table(col1 varchar2(100), pk number);
declare
msg varchar2(30000);
begin
execute immediate q'[
UPDATE dummy_table
SET col1 = 'whatever'
WHERE pk = '1234'
]' into msg;
end;
/
ORA-01007: variable not in select list
ORA-06512: at line 4
删除into msg
即可。此外,替代引用机制用于避免转义引号。
【讨论】:
顺便问一下,您是否正在尝试构建一个通用程序来处理任何类型的动态 SQL 语句?如果是这样,您可能需要做很多工作。仅仅弄清楚它是什么类型的陈述并获得适当的反馈信息是很复杂的。我正在开发这样的系统here。它需要几周时间才能准备好,但它可能会让您了解这项任务的难度。以上是关于无效的 SQL 类型:sqlKind = UNINITIALIZED - PLSQL 错误的主要内容,如果未能解决你的问题,请参考以下文章
Spring PreparedStatementCallback; SQL 无效列类型 Oracle 的未分类 SQLException