Oracle STANDARD_HASH not available in PLSQL? - oracle

I'm trying to use STANDARD_HASH Oracle (12c) function in PL/SQL but seems not available:
SQL> exec dbms_output.put_line(STANDARD_HASH('test'));
BEGIN dbms_output.put_line(STANDARD_HASH('test')); END;
*
ERROR at line 1:
ORA-06550: line 1, column 28:
PLS-00201: identifier 'STANDARD_HASH' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
From sql is working just fine:
SQL> select STANDARD_HASH('test') from dual;
STANDARD_HASH('TEST')
----------------------------------------
A94A8FE5CCB19BA61C4C0873D391E987982FBBD3
Why? What is the best way to implement the STANDARD_HASH in PLSQL?
Regards

Seems like it isn't yet a part of PL/SQL in 12c.
As a workaround, use SELECT INTO in PL/SQL:
SQL> set serveroutput on
SQL> DECLARE
2 str VARCHAR2(40);
3 BEGIN
4 SELECT STANDARD_HASH('test') INTO str FROM dual;
5 dbms_output.put_line(str);
6 END;
7 /
A94A8FE5CCB19BA61C4C0873D391E987982FBBD3
PL/SQL procedure successfully completed.
SQL>
I would suggest to create a function, and use it whenever you need it in PL/SQL.
For example,
SQL> CREATE OR REPLACE FUNCTION STANDARD_HASH_OUTPUT(str IN VARCHAR2)
2 RETURN VARCHAR2
3 AS
4 op VARCHAR2(40);
5 BEGIN
6 SELECT STANDARD_HASH(str) INTO op FROM dual;
7 RETURN op;
8 END;
9 /
Function created.
Call the function directly in PL/SQL block:
SQL> BEGIN
2 dbms_output.put_line(STANDARD_HASH_OUTPUT('test'));
3 END;
4 /
A94A8FE5CCB19BA61C4C0873D391E987982FBBD3
PL/SQL procedure successfully completed.
SQL>

For text, STANDARD_HASH is the same as DBMS_CRYPTO.HASH with SHA1:
begin
dbms_output.put_line(dbms_crypto.hash(cast('test' as clob), dbms_crypto.hash_sh1));
end;
/
Output:
A94A8FE5CCB19BA61C4C0873D391E987982FBBD3
For other data types, it's not documented how they are passed to the hash function.

standard hash allows you to specify hash algorithm. Algorithms are SHA1, SHA256, SHA384, SHA512, and MD5. If you omit this argument, then SHA1 is used.
To get a more familiar GUID than sys_guid provides:
LOWER (CAST (standard_hash (SYS_GUID (), 'MD5') AS VARCHAR2 (40)))
I've tested on 20.5 million records with no collisions...

Related

How to call stored procedure with only OUT parameter?

I have created a stored procedure in Oracle 11g:
CREATE OR REPLACE PROCEDURE greetings(cnt OUT VARCHAR2)
AS
BEGIN
SELECT COUNT(*)
INTO cnt
FROM SYS.all_tables;
END greetings;
but I am unable to call it.
I have tried the following code snippets:
EXEC GREETINGS();
EXEC GREETINGS;
CALL GREETINGS;
The procedure requires one parameter, so - provide it.
SQL> CREATE OR REPLACE PROCEDURE greetings(cnt OUT VARCHAR2)
2 AS
3 BEGIN
4 SELECT COUNT(*)
5 INTO cnt
6 FROM SYS.all_tables;
7 END greetings;
8 /
Procedure created.
One option, which works everywhere, is to use an anonymous PL/SQL block:
SQL> set serveroutput on
SQL> declare
2 l_cnt number;
3 begin
4 greetings(l_cnt);
5 dbms_output.put_line(l_cnt);
6 end;
7 /
87
PL/SQL procedure successfully completed.
Another one works in SQL*Plus (or any other tool which is capable of simulating it):
SQL> var l_cnt number;
SQL> exec greetings(:l_cnt);
PL/SQL procedure successfully completed.
SQL> print l_cnt;
L_CNT
----------
87
Regarding the call example, this is explained in EXECUTE recognizes a stored procedure, CALL does not. It's not obvious from the syntax documentation but it does require brackets, so it is (rather unhelpfully) rejecting the whole thing and giving the impression that greetings is the problem, when actually it is not:
SQL> call greetings;
call greetings
*
ERROR at line 1:
ORA-06576: not a valid function or procedure name
while using the mandatory brackets gets you the real issue:
SQL> call greetings();
call greetings()
*
ERROR at line 1:
ORA-06553: PLS-306: wrong number or types of arguments in call to 'GREETINGS'
As others have pointed out, you are missing the parameter.
SQL> var n number
SQL>
SQL> call greetings(:n);
Call completed.
SQL> print :n
N
----------
134
execute is just a handy SQL*Plus shortcut for the PL/SQL block begin xxx; end; which is less fussy about brackets and gives the same error message with or without them.
(variable and print are SQL*Plus commands and may not be supported in other environments.)
There's no problem with the procedure body. You can call like this :
SQL> var nmr number;
SQL> exec greetings(:nmr);
PL/SQL procedure successfully completed
nmr
------------------------------------------
306 -- > <a numeric value returns in string format>
Oracle doesn't care assigning a numeric value to a string. The execution prints the result directly, but whenever you want you can recall that value of variable(nmr) again, and print as
SQL> print nmr
nmr
---------
306

when try to excure procedure it said compliation error in oracle?

I try to write select procedure in oracle.but it compile success, when I try to execute it given error.
set serveroutput on;
CREATE OR REPLACE PROCEDURE retrieve_decrypt(
custid in NUMBER,
column_name in VARCHAR2,
test_value OUT VARCHAR2
)
AS
BEGIN
-- enc_dec.decrypt(column_name,password) into test_value from employees where custid=5;
COMMIT;
END;
/
set serveroutput on;
EXEC retrieve_decrypt(5,'creditcardno');
the error says ,
This is your procedure:
SQL> create or replace procedure retrieve_decrypt
2 (custid in number,
3 column_name in varchar2,
4 test_value out varchar2
5 )
6 as
7 begin
8 -- your code goes here
9 null;
10 end;
11 /
Procedure created.
SQL>
This is how you call it (and get the error):
SQL> exec retrieve_decrypt(5, 'creditcardno');
BEGIN retrieve_decrypt(5, 'creditcardno'); END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'RETRIEVE_DECRYPT'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL>
The cause of the error is:
the procedure contains 3 parameters:
2 of them are IN - you provided their values
1 of them is OUT - you didn't provide it and got the error
Here's what you should have done: as the 3rd parameter is OUT, you'll have to DECLARE it:
SQL> declare
2 l_out varchar2(20);
3 begin
4 retrieve_decrypt(5, 'creditcardno', l_out);
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
EXEC you used is a SQL*Plus command so it might not work everywhere; DECLARE-BEGIN-END block will so I'd suggest you use it.
Alternatively, in SQL*Plus, it could be rewritten as
SQL> var l_out varchar2
SQL>
SQL> exec retrieve_decrypt(5, 'creditcardno', :l_out);
PL/SQL procedure successfully completed.
SQL>
but - once again - you'd better use DECLARE-BEGIN-END PL/SQL block.
The initial error is:
wrong number or types of arguments in call to 'RETRIEVE_DECRYPT'
The procedure requires 3 parameters. You are only passing 2 (or apparently only 1, in the attempt that generated the error message shown).
Why do you also see the message "Usually a PL/SQL compilation error"? The EXEC command in SQLPlus creates a PL/SQL block containing the text you provide, and sends that to Oracle for execution. Oracle attempts to compile that PL/SQL block (just like it compiles the procedure when you create it). In this case, the compilation fails because of the mismatch in the number of arguments.

What Causes the Numeric Overflow in this PL/SQL Function?

I can run this command on Oracle 10.2 without problem:
SQL> select instr(unistr('foo'), chr(4050596145)) as hazit from dual;
HAZIT
----------
0
So I tried to encapsulate it into a function:
CREATE OR REPLACE FUNCTION hazit(string IN VARCHAR2) RETURN INTEGER
AS
BEGIN
RETURN instr(unistr(string), chr(4050596145));
END;
/
Function created.
But I get a numeric overflow error when I try to use it:
SQL> select hazit('foo') FROM DUAL;
select hazit('foo') FROM DUAL
*
ERROR at line 1:
ORA-01426: numeric overflow
ORA-06512: at "DWHEELER.HAZIT", line 4
What gives?
I don't have an explanation but this seems to work:
CREATE OR REPLACE FUNCTION hazit(string IN VARCHAR2) RETURN NUMBER IS
i number;
BEGIN
select instr(unistr(string), chr(4050596145))
into i from dual;
return i;
END;
/
Here is a fiddle

MD5 in Oracle (DBMS_OBFUSCATION_TOOLKIT.MD5)

I'm trying to compose a function to obtain MD5 hashes from bits I've gathered here and there. I want to obtain the lower-case hexadecimal representation of the hash. I have this so far:
CREATE OR REPLACE FUNCTION MD5 (
CADENA IN VARCHAR2
) RETURN DBMS_OBFUSCATION_TOOLKIT.VARCHAR2_CHECKSUM
AS
BEGIN
RETURN LOWER(
RAWTOHEX(
UTL_RAW.CAST_TO_RAW(
DBMS_OBFUSCATION_TOOLKIT.MD5(INPUT_STRING => CADENA)
)
)
);
END;
I'm not sure about the return type of the function. DBMS_OBFUSCATION_TOOLKIT.VARCHAR2_CHECKSUM looks like the appropriate choice and as far as I can tell it works as expected but the package definition for dbms_obfuscation_toolkit as displayed by SQL Developer shows this:
SUBTYPE varchar2_checksum IS VARCHAR2(16);
The output has 32 characters so I must be doing something wrong. My questions:
What's the correct type for the RETURN statement?
Am I doing unnecessary conversions to calculate the hash?
Here you go:
create or replace function getMD5(
in_string in varchar2)
return varchar2
as
cln_md5raw raw(2000);
out_raw raw(16);
begin
cln_md5raw := utl_raw.cast_to_raw(in_string);
dbms_obfuscation_toolkit.md5(input=>cln_md5raw,checksum=>out_raw);
-- return hex version (32 length)
return rawtohex(out_raw);
end;
The 32 length is because it is a hex representation of the raw(16) value. Or, modify above to output the raw version and store the raw in a RAW column (less space used, but you'll be doing future rawtohex and hextoraw conversions, believe me).
Cheers
It's a peculiarity of Oracle PL/SQL that stored procedure parameters and function return types cannot be limited. That is, we cannot have a procedure with a signature like this:
SQL> create or replace procedure my_proc (p1 in varchar2(30))
2 is
3 begin
4 null;
5 end;
6 /
Warning: Procedure created with compilation errors.
SQL> show error
Errors for PROCEDURE MY_PROC:
LINE/COL ERROR
-------- -----------------------------------------------------------------
1/34 PLS-00103: Encountered the symbol "(" when expecting one of the
following:
:= . ) , # % default character
The symbol ":=" was substituted for "(" to continue.
SQL> create or replace procedure my_proc (p1 in varchar2)
2 is
3 begin
4 null;
5 end;
6 /
Procedure created.
SQL>
Sure we can define the procedure's parameter using a SUBTYPE but Oracle will ignore it. Same goes for function return types...
SQL> create or replace package my_subtypes as
2 subtype ltd_string is varchar2(30);
3 end;
4 /
Package created.
SQL> create or replace function my_func return my_subtypes.ltd_string
2 is
3 begin
4 return lpad('a', 4000, 'a');
5 end;
6 /
Function created.
SQL> select length(my_func) from dual
2 /
LENGTH(MY_FUNC)
---------------
4000
SQL>
The only way of limiting parameters and return types is to declare variables using subtypes within the stored procedure. Use the variables within the package, and assign them to the OUT paramters (or RETURN the variable for functions).
Which is a long-winded way of saying, you can use DBMS_OBFUSCATION_TOOLKIT.VARCHAR2_CHECKSUM in your code confident that it won't prevent your function returning 32 characters.
However, it will confuse developers who will lookup the SUBTYPE declaration. In the worst case these people will use the subtype to declare their own working variables with the following tragic result:
SQL> declare
2 v my_subtypes.ltd_string;
3 begin
4 v := my_func;
5 end;
6 /
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 4
SQL>
So, it is better not to use an inappropriate subtype. Instead declare your own.

Create Oracle procedure error - declare custom type

I'm attempting to create a procedure in Oracle Express Server (Application Express 2.1.0.00.39) using the web interface.
This is the SQL I'm running via the SQL Commands option in the web interface
CREATE OR REPLACE PROCEDURE my_procedure (listOfNumbers num_list,
v_value varchar2)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE my_table
SET my_column = v_value
WHERE my_row_id IN (SELECT column_value
FROM TABLE(listOfNumbers));
COMMIT;
END;
UPDATE:
Changed SELECT column_value FROM TABLE to SELECT column_value FROM TABLE(listOfNumbers) but now I get the following error:
PLS-00201: identifier 'num_list' must
be declared
UPDATE 2:
Here is how I created my type:
CREATE OR REPLACE TYPE "num_list" as table of NUMBER(38,1)
/
Seems the error is being caused on the parameter declaration line:
(listOfNumbers num_list, v_value varchar2)
Below is the object details as displayed by the Oracle Database Express Edition web interface.
Try ...TABLE(CAST(listOfNumbers AS num_list)).
The SQL parser simply sees a bind placeholder in place of listOfNumbers, and since it's a custom type you need to tell it what type it is.
This will only work if num_list has been defined as a type in the schema, not just declared as a type in a PL/SQL block.
Your code works - providing the array type has been declared correctly (see below). As you are still having a problem I suspect that is where you are going wrong. But you need to post the code you are using to create the NUM_LIST type in order for us to correct it.
My test data:
SQL> select * from my_table
2 /
MY_COLUMN MY_ROW_ID
-------------------- ----------
APC 1
XYZ 2
JFK 3
SQL>
In order to use a type in a SQL statement we must create it as a SQL object:
SQL> create type num_list as table of number;
2 /
Type created.
SQL>
SQL>
SQL> create or replace procedure my_procedure
2 (listofnumbers num_list,
3 v_value varchar2)
4 is
5 begin
6
7 update my_table
8 set my_column = v_value
9 where my_row_id in (select column_value
10 from table(listofnumbers));
11
12 end;
13 /
Procedure created.
SQL>
Executing the procedure:
SQL> declare
2 n num_list := num_list(1,3);
3 begin
4 my_procedure (n , 'FOX IN SOCKS');
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
And lo!
SQL> select * from my_table
2 /
MY_COLUMN MY_ROW_ID
-------------------- ----------
FOX IN SOCKS 1
XYZ 2
FOX IN SOCKS 3
SQL>
Apparently I was creating the type with quotes around the name:
The following didn't work:
CREATE OR REPLACE TYPE "NUMBER_T" as table of NUMBER(38,1)
When I did it without the quotes and then created the procedure, it was able to recognize it.
The following did work:
CREATE OR REPLACE TYPE NUMBER_T as table of NUMBER(38,1)
I'm not sure why, but it worked.

Resources