How can I convert an integer variable in PLSQL to pass to a boolean procedure parameter? - oracle

I am writing unit tests for an existing procedure which has boolean parameters. As the tests run, they will store the associated parameter values in a table. I want to use variables for setting the parameter columns in the table and to pass to the procedure. Is there a way to go from an integer (what I'll set in my table) to the procedure (which requires boolean values)?
I've tried passing 1/0 values and the strings "TRUE" and "FALSE" to the procedure. I've tried making my table use a boolean datatype for the relevant columns. I've tried CASTing. I've tried using a SELECT INTO with CASE statement to set a different boolean-type variable based on the value of the integer-type variable.
CREATE TABLE UNIT_TEST_RESULTS (
case VARCHAR2(50)
,includeLines NUMBER(1) --this will hold the value of i_includeLines below
,result VARCHAR2(4)
);
CREATE OR REPLACE PROCEDURE X_UNIT_TEST AS
i_includeLines NUMBER(1)
BEGIN
i_includeLines:=0;
X_THING_TO_TEST(includeLinesBool=>i_includeLines);
/*...analyze output...*/
INSERT INTO UNIT_TEST_RESULTS(case,includeLines,result)
VALUES ('test',i_includeLines,'fail'); COMMIT;
END X_UNIT_TEST;

I'd probably do something like
i_includeLines NUMBER(1)
b_includeLines boolean;
BEGIN
i_includeLines:=0;
b_includeLines := (case i_includeLines when 1 then true else false end);
X_THING_TO_TEST(includeLinesBool=>b_includeLines);
or
b_includeLines boolean;
i_includeLines integer;
BEGIN
b_includeLines:= false;
X_THING_TO_TEST(includeLinesBool=>b_includeLines);
/*...analyze output...*/
i_includeLines := case when b_includeLines = true then 1 else 0 end;
INSERT INTO UNIT_TEST_RESULTS(case,includeLines,result)
VALUES ('test',i_includeLines,'fail');
COMMIT;
Obviously, either of these case statements could (and should) get encapsulated into a function assuming you are going to call them regularly.
I would suggest that you not use the reserved word case for a column name-- that's going to bite you at some point. I'm also not a fan of the Hungarian notation for variable names but that's more of a religious debate...

There is no implicit conversion from numbers or strings to Boolean, but a simple true/false expression like i_includeLines = 1 evaluates to Boolean true if i_includeLines has the value 1, so you could call your procedure like this:
x_thing_to_test(includeLinesBool => i_includeLines = 1);
That will pass true if i_includeLines is 1, false if it is not 1, else null.
If you need to treat null as false then you'll need a case/coalesce/nvl or similar expression.

There's no Boolean in your code so - here's how I understood the question:
You have a procedure which accepts parameter that is Boolean:
SQL> create or replace procedure p_test
2 (par_bool in boolean)
3 is
4 begin
5 null;
6 end;
7 /
Procedure created.
SQL>
You want to call it; there's some number variable (l_int in my example) and you'd want to convert it to Boolean and pass as such to the p_test procedure. Here's how:
SQL> declare
2 l_int integer := 1;
3 begin
4 p_test(case when l_int = 1 then true else false end);
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>

Related

oracle function not displaying results

I am very new to this so it might sound basic, however i want create a function that takes two input parameter , (a primary key and a numeric value) and does a calculation to compare if the input numeric value (v_priceWantToInsert) is greater than maximum value in the column of the table and returns the result as true or false.
here is the code :
CREATE OR REPLACE FUNCTION PRICE_CHECK(v_productID IN VARCHAR2, v_priceWantToInsert in NUMBER)
RETURN VARCHAR2
IS
RETURN BOOLEAN AS
v_Bool BOOLEAN;
v_MAXPRICE NUMBER;
BEGIN
SELECT
MAX(B.BIDPRICE) INTO v_MAXPRICE
FROM
PRICEBID B
WHERE B.PRODUCTID = v_productID;
IF (v_MAXPRICE > v_priceWantToInsert) THEN
v_Bool := FALSE;
ELSE
v_Bool := TRUE;
END IF;
END PRICE_CHECK;
DECLARE
var1 VARCHAR2(100);
BEGIN
var1 := case when PRICE_CHECK('P00001',45) then 'true' else 'false' end;
DBMS_OUTPUT.PUT_LINE('It is: ' || var1);
END;
however my code is showing an error that object is invalid AND Usually a PL/SQL compilation error.I am open to any solution as long as it gives me a true or false value.
There are some moments I see in the code:
Missing string's length in DECLARE part. Oracle requires to specify variable's length when it is a "stringy" type, like VARCHAR or CHAR. Limit is 32767:
var1 VARCHAR2(100); -- might be up to 32767
In the function you are using variable v_MAXPRICE which is not defined. It must be done between IS and BEGIN parts of the function's defintion. I think this is how it should look like:
IS
v_MAXPRICE number;
BEGIN
There is another moment you have in your code after you've updated the question
RETURN VARCHAR2
IS
RETURN BOOLEAN AS
v_Bool BOOLEAN;
v_MAXPRICE NUMBER;
Having 2 returns is wrong, replace it with
RETURN BOOLEAN
IS
v_Bool BOOLEAN;
v_MAXPRICE NUMBER;
and since it is a function and has to return something you need to add
return v_bool
after "end if"
I thnk the last part is the anonimous block
first of all, your function returns boolean into var1 which is defined as a varchar2. This is wrong as Oracle can't convert booleans to string and it needs help with that.
try that out:
var1 := case when PRICE_CHECK('P00001',45) then 'true' else 'false' end;

The compiler ignores NOCOPY in these cases

I read about IN OUT and NOCOPY. Then I encountered NOCOPY use cases but I was not able to get it. Can anybody explain these with examples? Thanks in advance.
The actual parameter must be implicitly converted to the data type of the formal parameter.
The actual parameter is the element of a collection.
The actual parameter is a scalar variable with the NOT NULL constraint.
The actual parameter is a scalar numeric variable with a range, size, scale, or precision constraint.
The actual and formal parameters are records, one or both was declared with %ROWTYPE or %TYPE, and constraints on corresponding fields differ.
The actual and formal parameters are records, the actual parameter was declared (implicitly) as the index of a cursor FOR LOOP statement, and constraints on corresponding fields differ.
The subprogram is invoked through a database link or as an external subprogram.
The basic principle is that PL/SQL will honour the NOCOPY directive as long as the value we pass can be used as provided, without transformation, and is addressable by the called program. The scenarios you list are circumstances where this is not the cases. I must admit a couple of these examples made me think, so this is a worthwhile exercise.
The first four examples call this toy procedure.
create or replace procedure tst2 (p1 in out nocopy t34%rowtype) is
begin
p1.id := 42;
end;
/
Case 1: The actual parameter must be implicitly converted to the data type of the formal parameter.
declare
n varchar2(3) := '23';
begin
tst(n);
dbms_output.put_line(n);
end;
/
Case 2: The actual parameter is the element of a collection.
declare
nt sys.odcinumberlist := sys.odcinumberlist(17,23,69);
begin
tst(nt(2));
dbms_output.put_line(to_char(nt(2)));
end;
/
Case 3: The actual parameter is a scalar variable with the NOT NULL constraint.
declare
n number not null := 23;
begin
tst(n);
dbms_output.put_line(to_char(n));
end;
/
Case 4: The actual parameter is a scalar numeric variable with a range, size, scale, or precision constraint.
declare
n number(5,2) := 23;
begin
tst(n);
dbms_output.put_line(to_char(n));
end;
/
The next example uses this table ...
create table t34 (id number not null, col1 date not null)
/
...and toy procedure:
create or replace procedure tst2 (p1 in out nocopy t34%rowtype) is
begin
p1.id := 42;
end;
/
Case 5 : The actual and formal parameters are records, one or both was declared with %ROWTYPE or %TYPE, and constraints on corresponding fields differ.
declare
type r34 is record (id number, dt date);
r r34;
begin
r.id := 23;
r.dt := to_date(null); --trunc(sysdate);
tst2(r);
dbms_output.put_line(to_char(r.id));
end;
/
The next example uses this package spec...
create or replace package pkg is
type r34 is record (id number, dt date);
end;
/
...and toy procedure:
create or replace procedure tst3 (p1 in out nocopy pkg.r34) is
begin
p1.id := p1.id + 10;
end;
/
Case 6: The actual and formal parameters are records, the actual parameter was declared (implicitly) as the index of a cursor FOR LOOP statement, and constraints on corresponding fields differ.
begin
for j in ( select * from t34) loop
tst3(j);
dbms_output.put_line(to_char(j.id));
end loop;
end;
/
The last example uses a remote version of the first procedure.
Case 7: The subprogram is invoked through a database link or as an external subprogram.
declare
n number := 23;
begin
tst#remote_db(n);
dbms_output.put_line(to_char(n));
end;
/
There are working demos of the first six cases on db<>fiddle here.

Can I know the number of parameters passed in stored procedure in Oracle PL/SQL

I have a stored procedure in a Oracle Database that receives 3 parameters.
I know that I call it with 1 to 3 parameters but it's possible to know inside itself how many arguments are the defaults or are really passed?
For example:
dummy(1) some keyword say me "1"
dummy(1,2,3) say me "3"
I ask this because I worked with Informix 4GL and I could use "NARGS" to know the number of arguments that I receive.
The short answer is no.. there is not an equivalent to NARGS or "C"s argc.
if you are using null default values you could manually count the number of arguments that do no equal the default value.. but that wont tell you if you explicitly pass the default value as a parameter.
i can think of 2 solutions.
1. user overloaded procedures .. ie
procedure a (p_1 number);
procedure a (p_1 number, p_2 number);
procedure a (p_1 number, p_2 number, p_3 number);
then in the bodies you would "know" by which one you are in.
option 2. pass a varray/plsql table as a single argument but then actually passing the arguments becomes problematic.
create or replace package x
is
type an_arg is record ( n number, v varchar2(2000), d date);
type args is table of an_arg;
procedure a(argv args);
end;
/
create or replace package body x
is
procedure a(argv args)
is
begin
dbms_output.put_line('i was passed '||argv.count||' arguments');
end;
end;
/
Similar to ShoeLace's answer, I think counting the number of parameters that do not equal the default of each parameter would work.
The key to this is to give each parameter a nonsensical default value. Like '~#dummee_v#1u3#~' maybe. Anything you are confident will never actually be passed in. This way you don't have to worry about somebody passing in a parameter value that equals the default value.
So:
create procedure p1 (id1 varchar2 default '~#dummee_v#1u3#~', id2 varchar2 default '~#dummee_v#1u3#~') is
lParamCount number := 0;
lDummyParamValue varchar2 := '~#dummee_v#1u3#~';
begin
if id1 <> lDummyParamValue then lParamCount := lParamCount + 1;
if id2 <> lDummyParamValue then lParamCount := lParamCount + 1;
end p1;

Receiving error during compile test of procedure

I've written a short procedure when a donor id is input it checks for active pledge based on status field (NUMBER for data type 10 is active, 20 is complete) and is making monthly payments and return boolean value True if all conditions are met and False if not. Before adding the DBMS output it would compile fine but I get error PLS-00306:wrong number or types of arguments in call"
Was feeling pretty good about solving this on my own but not sure where my mistakes are. Also looking for explanation (commented in code) about exception handlers. Thanks in advance for comments and teaching points!
My code:
CREATE OR REPLACE PROCEDURE DDPAY_SP
(donor_id IN NUMBER, active_pl OUT BOOLEAN)
IS
pay_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO pay_count
FROM dd_pledge
WHERE iddonor = donor_id AND
idstatus = 10 AND
paymonths > 1;
IF pay_count > 1 THEN
active_pl := TRUE;
ELSE active_pl := FALSE;
END IF;
DBMS_OUTPUT.PUT_LINE('Active Pledge and paymonths: ' || active_pl);
/* want to add exception but don't understand how to choose
the handler for blocks of code that are not the Oracle defined
exceptions--Can someone explain better than book I have? I know
code should be:
EXCEPTION
WHEN .....
DBMS_OUTPUT.PUT_LINE(' '); */
END;
DBMS_OUTPUT.PUT_LINE('Active Pledge and paymonths: ' || active_pl);
You cannot pass a BOOLEAN to DBMS_OUTPUT. You could only pass string arguments, i.e. VARCHAR2 datatype.
This is the reason you get the following error:
PLS-00306:wrong number or types of arguments in call"
Ideally, you would not want any DBMS_OUTPUT to be sent to your client, since you are using an OUT parameter, that would suffice.
If you really want to print the boolean value, then you must convert it into VARCHAR2 datatype.
For example,
SQL> set serveroutput on
SQL> DECLARE
2 var_bool BOOLEAN;
3 BEGIN
4 var_bool := TRUE;
5 dbms_output.put_line('Status = '||
6 CASE
7 WHEN var_bool THEN
8 'TRUE'
9 ELSE
10 'FALSE'
11 END);
12 END;
13 /
Status = TRUE
PL/SQL procedure successfully completed.
SQL>

"Boolean" parameter for Oracle stored procedure

I'm aware that Oracle does not have a boolean type to use for parameters, and am currently taking in a NUMBER type which would have 1/0 for True/False (instead of the 'Y'/'N' CHAR(1) approach).
I'm not a very advanced Oracle programmer, but after doing some digging and reading some ASKTOM posts, it seems like you can restrict a field using a format for the column like:
MyBool NUMBER(1) CHECK (MyBool IN (0,1))
Is there a way to apply the same sort of a check constraint to an input parameter to a stored procedure? I'd like to restrict the possible inputs to 0 or 1, rather than checking for it explicitly after receiving the input.
You can use Booleans as parameters to stored procedures:
procedure p (p_bool in boolean) is...
However you cannot use Booleans in SQL, e.g. select statements:
select my_function(TRUE) from dual; -- NOT allowed
For a number parameter there is no way to declaratively add a "check constraint" to it, you would have to code some validation e.g.
procedure p (p_num in number) is
begin
if p_num not in (0,1) then
raise_application_error(-20001,'p_num out of range');
end if;
...
Yes and no.
You can do..
create or replace package t_bool is
subtype t_bool_num IS PLS_INTEGER RANGE 0..1;
function f_test (i_bool_num t_bool_num) return varchar2;
end t_bool;
/
create or replace package body t_bool is
function f_test (i_bool_num t_bool_num) return varchar2 is
begin
if i_bool_num = 0 then
return 'false';
elsif i_bool_num = 1 then
return 'true';
elsif i_bool_num is null then
return 'null';
else
return to_char(i_bool_num);
end if;
end;
end t_bool;
/
The good news is that, if you do
exec dbms_output.put_line(t_bool.f_test(5));
it reports an error.
The bad news is that if you do
select t_bool.f_test(5) from dual;
then you don't get an error

Resources