"READ" constant in PLSQL - oracle

I found the following PL/SQL code but I am unable to find it as a valid constant declaration from Oracle documentation.
Can anyone explain me what this means?
create or replace package file_security authid current_user is
READ constant pls_integer := 1;
WRITE constant pls_integer := 2;
EXEC constant pls_integer := 4;
procedure grant_permission(
p_file_path in varchar2,
p_grantee in varchar2,
p_permission in pls_integer
);
end file_security;

The package declares three constants (called READ, WRITE and EXEC) and a function, which would supposedly accept a binary mask of those constants as its third parameter.
None of those words are reserved in Oracle, they "have a special meaning to Oracle but are not reserved words and so can be redefined"

Related

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.

How to convert pls_number to varchar2 in oracle?

I tried to convert pls_integer to varchar2 using to_char but it is not working.
I also tried pls_integer to number and number to varchar2 using to_number and to_char methods, but that also not working. I am getting an error :
Pls00306 - wrong number or types of arguments in call 'to_number'.
Can you please help.
There's no need to do anything special just assign. Oracle allows implicit data type conversion between pls_integer and varchar2. See table 3-10 at the bottom of this page
declare
l_number pls_integer;
l_varchar varchar2(1);
begin
l_number := 8;
l_varchar := l_number;
end;

What does PLS stand for in PLS_INTEGER?

There's other data types in PL/SQL like BINARY_INTEGER. What does the PLS add in PLS_INTEGER? I was told that it stands for PL/SQL, but why would it be named that?
I doubt there is any deep rationale for using "PLS" in "PLS_INTEGER". When this datatype was added, it was a more efficient implementation of the "original" BINARY_INTEGER datatype. And a new name was needed.
Both of those types and other related subtypes have a constrained set of values compared to INTEGER. You can see this in the STANDARD package, in which the types are defined:
subtype BINARY_INTEGER is INTEGER range '-2147483647'..2147483647;
subtype NATURAL is BINARY_INTEGER range 0..2147483647;
subtype NATURALN is NATURAL not null;
subtype POSITIVE is BINARY_INTEGER range 1..2147483647;
subtype POSITIVEN is POSITIVE not null;
subtype SIGNTYPE is BINARY_INTEGER range '-1'..1; -- for SIGN functions
subtype pls_integer is binary_integer;

Is there a way to get the PL/SQL maximum pls_integer?

Is there a way to determine the maximum possible value of a pls_integer either by a language predefined constant or a function? I can find the maximum on the internet (2^31 - 1 = 2,147,483,647), but I don't want to hard code it.
Cheers :)
I don't think this is possible. Why? Because it is not needed - PLS_INTEGER's maximal value is due to its maximal size - 4 bytes (and it is a signed datatype).
What is more, as stated in documentation about PL/SQL datatypes, PLS_INTEGER is actually a BINARY_INTEGER. Look at the definition of PLS_INTEGER in the Oracle's STANDARD package:
subtype pls_integer is binary_integer;
And then take a look at the definition of BINARY_INTEGER:
subtype BINARY_INTEGER is INTEGER range '-2147483647'..2147483647;
Nowhere in the STANDARD package header can you find a constant which holds the maximal value of those datatypes.
I don't think there is any constant that you can use; however, if it is so vital not to hard code any values, you can calculate the maximum value with the method given below.
This solution is based on the assumption that the maximum value would be in the form of 2^b-1 where b is the number of bits.
This is the function you can use:
CREATE FUNCTION MAX_PLS_INTEGER_SIZE RETURN PLS_INTEGER AS
p PLS_INTEGER;
b NUMBER;
BEGIN
b := 0;
WHILE TRUE LOOP
BEGIN
p := POWER(2, b)-1;
b := b + 1;
EXCEPTION WHEN OTHERS THEN
EXIT;
END;
END LOOP;
RETURN p;
end;
After you create the function, you can test it:
SELECT MAX_PLS_INTEGER_SIZE FROM DUAL;
Result:
MAX_PLS_INTEGER_SIZE
--------------------
2147483647

What's the difference between pls_integer and binary_integer?

I've inherited some code which is going to be the base for some additional work. Looking at the stored procs, I see quite a lot of associative-arrays.
Some of these are indexed by binary_integers, some by pls_integers. Are there any differences between the two?
I had a look at the documentation, but apart from this line:
The PL/SQL data types PLS_INTEGER and BINARY_INTEGER are identical. For simplicity, this document uses PLS_INTEGER to mean both PLS_INTEGER and BINARY_INTEGER.
I couldn't find any difference between the two. So what's the difference? Are both around for historical/compatibility reasons?
I'm using Oracle 10gR2
Historical reasons. They used to be different before 10g:
On 8i and 9i, PLS_INTEGER was noticeably faster than BINARY_INTEGER.
When it comes to declaring and manipulating integers, Oracle offers lots of options, including:
INTEGER - defined in the STANDARD package as a subtype of NUMBER, this datatype is implemented in a completely platform-independent fashion, which means that anything you do with NUMBER or INTEGER variables should work the same regardless of the hardware on which the database is installed.
BINARY_INTEGER - defined in the STANDARD package as a subtype of INTEGER. Variables declared as BINARY_INTEGER can be assigned values between -231+1 .. 231-1, aka -2,147,483,647 to 2,147,483,647. Prior to Oracle9i Database Release 2, BINARY_INTEGER was the only indexing datatype allowed for associative arrays (aka, index-by tables), as in:
TYPE my_array_t IS TABLE OF VARCHAR2(100)
INDEX BY BINARY_INTEGER
PLS_INTEGER - defined in the STANDARD package as a subtype of BINARY_INTEGER. Variables declared as PLS_INTEGER can be assigned values between -231+1 .. 231-1, aka -2,147,483,647 to 2,147,483,647. PLS_INTEGER operations use machine arithmetic, so they are generally faster than NUMBER and INTEGER operations. Also, prior to Oracle Database 10g, they are faster than BINARY_INTEGER. In Oracle Database 10g, however, BINARY_INTEGER and PLS_INTEGER are now identical and can be used interchangeably.
binary_integer and pls_integer both are same. Both are PL/SQL datatypes with range -2,147,648,467 to 2,147,648,467.
Compared to integer and binary_integer pls_integer very fast in excution. Because pls_intger operates on machine arithmetic and binary_integer operes on library arithmetic.
pls_integer comes from oracle10g.
binary_integer allows indexing integer for assocative arrays prior to oracle9i.
Clear example:
SET TIMING ON
declare
num integer := 0;
incr integer := 1;
limit integer := 100000000;
begin
while num < limit loop
num := num + incr;
end loop;
end;
PL/SQL procedure successfully completed.
Elapsed: 00:00:20.23
ex:2
declare
num binary_integer := 0;
incr binary_integer := 1;
limit binary_integer := 100000000;
begin
while num < limit loop
num := num + incr;
end loop;
end;
/
PL/SQL procedure successfully completed.
Elapsed: 00:00:05.81
ex:3
declare
num pls_integer := 0;
incr pls_integer := 1;
limit pls_integer := 100000000;
begin
while num < limit loop
num := num + incr;
end loop;
end;
/
Another difference between pls_integer and binary_integer is that when calculations involving a pls_integer overflow the PL/SQL engine will raise a run time exception. But, calculations involving a binary_integer will not raise an exception even if there is an overflow.

Resources