Oracle Forms 中 PL/SQL 布尔变量的评估

16

假设我在Oracle表单中的PL/SQL块中有一个BOOLEAN变量:

DECLARE
  is_viewable BOOLEAN;
BEGIN
  is_viewable := ...;

  IF NOT is_viewable THEN
    raise_my_error(); // pseudo-code
  END IF;
END;

通过使用调试器逐步执行代码,我确定raise_my_error()从来没有被调用。为了澄清:

  • raise_my_error()不会被调用,如果is_viewable = TRUE
  • raise_my_error()不会被调用,如果is_viewable = FALSE

初始测试表明,这种行为仅限于在Oracle Forms内运行的PL/SQL代码,而不是直接在数据库内运行的PL/SQL代码(尽管我可能错了)。

我可以通过将is_viewableFALSE进行显式比较来避免这种情况:

IF is_viewable = FALSE THEN
  raise_my_error();
END IF;

我仍然好奇为什么NOT is_viewable从未计算为TRUE

更新:看起来我的调试器没有显示正确的值,这个问题已经无效了。对此混淆感到抱歉。


【友情提醒】作为有经验的用户,我猜您可能只是忘记接受答案(dcp或Jeffrey的)。 - Alexander Malakhov
@AlexanderMalakhov:我曾多次想要接受一个答案,但问题似乎现在已经无法回答了,因为代码似乎正在正确运行。除非我弄错了,否则两个答案都无法解释为什么 NOT is_viewable 总是会评估为 FALSE(无论 is_viewable 的值如何),而 is_viewable = FALSE 将根据 is_viewable 的值评估为 TRUEFALSE。由于问题已经停止发生,我无法验证任何答案。 :( - Adam Paynter
明白了。我曾经有一个类似的问题(关于“没有正确答案,无法验证”),链接在这里:http://stackoverflow.com/questions/2233856/oracle-forms-6i-crashes-with-0xc0000005-at-start-after-installing-patch-19。由于几乎没有人会回答我的问题,我决定接受*最有帮助的*(而不是正确的)答案,以此来奖励那位花费时间和精力的人,并且让我的问题不再悬而未决。当然,我完全没有问题,如果有人不遵循我的策略(尤其是因为你显然为SO社区做出了巨大的贡献)。 - Alexander Malakhov
6个回答

19

我们可以在SQLPlus中进行测试,以查看每种情况(true,false,null)发生了什么:

set serveroutput on

declare
  true_value boolean := true;
  false_value boolean := false;
  null_value boolean;
begin

    if not true_value then  --Should not pass
      dbms_output.put_line('True Value');
    end if;

    if not false_value then --Should pass
      dbms_output.put_line('False Value');
    end if;

    if null_value is null then --Just to make sure it is null
      dbms_output.put_line('Null Value is Null');
    end if;

    if not null_value then --Should not pass
      dbms_output.put_line('Null Value');
    end if;
end;
/

这会产生:

SQL> set serveroutput on
SQL>
SQL> declare
  2    true_value boolean := true;
  3    false_value boolean := false;
  4    null_value boolean;
  5  begin
  6
  7      if not true_value then  --Should not pass
  8        dbms_output.put_line('True Value');
  9      end if;
 10
 11      if not false_value then --Should pass
 12        dbms_output.put_line('False Value');
 13      end if;
 14
 15      if null_value is null then --Just to make sure it is null
 16        dbms_output.put_line('Null Value is Null');
 17      end if;
 18
 19      if not null_value then --Should not pass
 20        dbms_output.put_line('Null Value');
 21      end if;
 22  end;
 23  /
False Value
Null Value is Null

PL/SQL procedure successfully completed.

SQL>

因此,唯一可能产生您期望输出的代码路径是如果进入条件语句的值为false。如果这不是您所看到或期望的结果,则必须在您的过程中或作为副作用发生了其他事情。


讲解得很清楚.. 谢谢 - emphywork

5

NOT is_viewable的值为TRUE只有当is_viewable的值为FALSE时。

在您的情况下,is_viewable可能被设置为NULL; 可能Forms调试器在这种情况下显示“FALSE”,导致混淆。

请尝试使用以下代码:

IF NOT is_viewable THEN 
   raise_my_error();
ELSIF is_viewable IS NULL THEN
   raise_another_error();
END IF;

4

变量被设定为什么值?请注意,如果该值为null,则该代码块将永远不会执行。我不确定这是否是您的问题,但以下是一个示例:

DECLARE
is_viewable BOOLEAN;
BEGIN
  IF NOT is_viewable
  THEN
      /* this won't execute */
      dbms_output.put_line('nope');
  END IF;
  IF is_viewable
  THEN
      /* neither will this */
      dbms_output.put_line('nope');
  END IF;
END;

当然,我不知道Oracle Forms是如何进行区别处理的,但也许它以某种方式将变量设置为null?

谢谢你的提示!我已经理解了NULL值的问题。然而,我已经通过调试器观察到了is_viewable设置为TRUEis_viewable设置为FALSE时的行为。说实话,我还没有尝试过将其设置为NULL会发生什么...我怀疑这不会对情况有太大帮助。 - Adam Paynter

2

当声明is_viewable时,您必须设置一个初始值。在声明BOOLEAN时,Oracle不会设置默认值。在声明时设置BOOLEAN的值,将其值设置在块内部可能并不总是最佳选择。如果您正在创建一个函数并且该块失败,则可能会返回一个没有值的函数,但如果在块外声明并且有异常处理程序,则会捕获和处理错误。以此方式设置块始终是一种良好的实践。

DECLARE 
    bTest BOOLEAN := FALSE;

BEGIN

--in your test check for the most likely thing that would happen 
--if bTest would in most instances evaluate to be FALSE then that should be your check

  IF NOT bTest THEN


   MESSAGE('True Passed');

  ELSE 

   MESSAGE('False Passed');


  END IF;

--in the event that an exception occurs or the block fails
--the function would still return a value

EXCEPTION WHEN NO_DATA_FOUND THEN
     bTest := FALSE;

WHEN OTHERS THEN
      bTest := FALSE;


END 

1

尝试这个看看它是否有所改变:

IF is_viewable THEN
    NULL;
ELSE
    raise_my_error();
END IF;

1
值得一提的是,这段代码可能隐藏了一个错误。例如,myBool := (sum1 = sum2),其中 sum1=0sum2 是空值。人们可能希望这个结果是 True 而不是空值。 - Alexander Malakhov

1

Forms的版本是多少?
我刚在Forms Builder 6i中尝试了以下代码,它按预期工作。

DECLARE
    bTest BOOLEAN;
BEGIN
   bTest := FALSE;
    IF NOT bTest THEN
        MESSAGE('NOT FALSE passed'); 
        PAUSE;
    END IF;

    bTest := TRUE;
    IF bTest THEN
        MESSAGE('TRUE passed'); 
        PAUSE;
    END IF;

    bTest := NULL;
    IF bTest OR (NOT bTest) THEN
        MESSAGE('You will never see this message'); 
        PAUSE;
    END IF;
END;

这在你的环境中能正常工作吗? 编辑:示例中添加了 null。

是的,表单版本会很有用。还有Oracle客户端的版本和数据库的版本。旧版本的表单有自己的PL/SQL解释器,可能会影响您。 - Jim Hudson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接