无效的 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 错误的主要内容,如果未能解决你的问题,请参考以下文章

SQL 无效的对象名称“地址类型”

PL/SQL 函数返回类型整数:无效标识符

Spring PreparedStatementCallback; SQL 无效列类型 Oracle 的未分类 SQLException

SQL 参数数据类型 int 对 charindex 函数的参数 1 无效

ORACLE SQL - 创建表时数据类型无效

在sql数据库中,我用聚合函数sum,为啥显示操作数据类型varchar对于sum运算符无效啊?