开发者

No short-circuit OR with an Oracle function?

开发者 https://www.devze.com 2023-04-01 03:36 出处:网络
To allow an Super User/Admin to log in to my system, I am running (a larger version of) this query: Select *

To allow an Super User/Admin to log in to my system, I am running (a larger version of) this query:

Select *
  From mytable
 Where (:id = 'Admin' Or :id = mytable.id);

If I pass a user id I get all the data for that user; if I pass the string 'Admin' I get all the data. This works because Oracle's OR is a short-circuit operator.

However, if I make 'Admin' a package constant and get it with a function, like this

Select *
  From mytable
 Where (:id = mypackage.GetAdminConstant Or :id = myt开发者_开发百科able.id);

I get ORA-01722: invalid number when I pass 'Admin'.

Why does OR lose its short-circuit aspect when I introduce a function?


It doesn't lose the short-circuit aspect. But SQL is not a procedural language, and there is no guarantee of the order of evaluation of multiple predicates.

In C, if you write a || b, you know that a will be evaluated first, then b will be evaluated only if necessary.

In SQL, if you write a OR b, you know only that either a or b will be evaluated first, and that the other expression (at least in Oracle) will be evaluated only if necessary.

Looking at the execution plan for the two queries may give some indication of the order of evaluation, or it may not.

I would guess that, in your first case, Oracle can see that the first expression will have the same value for every row, so evaluates it first. When you change to the second case, Oracle now sees a function that could have different results each time it is evaluated, so it will have to check each row, so it tries to do the simple equality check on a column before doing the function call.

I wonder if you would get different results if you marked the function DETERMINISTIC so Oracle would know that it is essentially a constant.


Better use 2 bind variables.

Select *
  From mytable
 Where (:admin = 'Admin' Or (:admin is null and :id = mytable.id));
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号