DB2: No authorized routine named "EBCDIC_CHR" of type "FUNCTION" having compatible arguments was found - db2

When I try to create a defined function to convert hex to string in DB2, I encountered the following problem:
SQL ERROR[42884]: No authorized routine named "EBCDIC_CHR" of type "FUNCTION" having compatible arguments was found..SQLCODE=-440,SQLSTATE=42884,DRIVER=4.19.66
The details of code is as follows:
CREATE FUNCTION My_HEX2EBCDIC (I_STRING VARCHAR(50)) RETURNS VARCHAR(50)
BEGIN
DECLARE v_hex1 char(1);
DECLARE v_hex2 char(1);
DECLARE v_int INTEGER;
DECLARE v_start INTEGER;
DECLARE v_string varchar(50);
SET v_start = 1;
SET v_string = '';
WHILE v_start < length(I_string) DO
SET v_hex1 = substr(i_string,v_start,1);
SET v_hex2 = substr(i_string,v_start+1,1);
SET v_int = (locate(v_hex1,'0123456789ABCDEF') - 1 ) * 16 + locate(v_hex2,'0123456789ABCDEF') - 1 ;
set v_string = v_string || EBCDIC_CHR(v_int); // error
SET v_Start = v_Start + 2;
END WHILE;
return v_String;
END
I don't know why, and how can I solve it!
Please help me,Thanks!

There is no such function as DB2 for Z/OS EBCDIC_CHR among Db2 for LUW scalar functions.
DB2 for Z/OS and DB2 for LUW are different products with slightly different sets of built-in functions.
The easiest way to resolve achieve your goal is to create a generic java UDF.
public class Convert
{
public static byte[] char2byte(String str, String enc) throws java.io.UnsupportedEncodingException
{
return str.getBytes(enc);
}
public static String byte2char(byte[] b, String enc) throws java.io.UnsupportedEncodingException
{
return new String(b, enc);
}
}
Compile the Convert.java file with the following contents and place the Convert.class file to the ~db2instance/sqllib/function directory, make it readable for the ~db2instance/sqllib/adm/.fenced file owner (db2 fenced user).
Create a couple of java UDF using this class:
create function byte2char(bytes varchar(32672) for bit data, enc varchar(16))
RETURNS varchar(32672)
LANGUAGE JAVA
EXTERNAL NAME 'Convert.byte2char'
DETERMINISTIC
FENCED THREADSAFE
NO SQL
NOT NULL CALL
NO EXTERNAL ACTION
ALLOW PARALLEL
PARAMETER STYLE JAVA;
create function char2byte(str varchar(32672), enc varchar(16))
RETURNS varchar(32672) for bit data
LANGUAGE JAVA
EXTERNAL NAME 'Convert.char2byte'
DETERMINISTIC
FENCED THREADSAFE
NO SQL
NOT NULL CALL
NO EXTERNAL ACTION
ALLOW PARALLEL
PARAMETER STYLE JAVA;
Seems, that the hex string representation you provided is for one of the 1381, 1383 or 1386 codepages?
If yes, then try this:
VALUES BYTE2CHAR(HEXTORAW('D6A7B8B6503031'), 'IBM-1381')

Related

Can anybody please assist with syntax in a function in postgresql (from mysql)

I am trying to create the following function in PostgreSQL but get the following error. This is from a MySQL procedure that I need to convert to PostgreSQL. I am failing to convert the syntax to PostgreSQL. I am a beginner in PostgreSQL. Please assist me.
CREATE OR REPLACE FUNCTION public.usp_failed_analyze4()
RETURNS TABLE(status varchar) as
$BODY$
SET #maxdate = (SELECT MAX(analyzetime) FROM wp_analyze_history);
SET #maxdateint = (SELECT DATEDIFF(NOW() ,MAX(analyzetime)) FROM wp_analyze_history);
SET #STATUS = SELECT Status from wp_analyze_history WHERE Status NOT IN ('OK','Table is already up to date','The Analyze task DID NOT run!') AND analyzetime = #maxdate);
SET #STATUSNOTRUN = 'The Analyze task DID NOT run!';
IF #maxdateint > 7
THEN SELECT #STATUSNOTRUN;
ELSE SELECT #STATUS as "";
$BODY$
LANGUAGE sql;
error: ERROR: syntax error at or near "#"
Position: 109
It's hard to tell what you want as you tried to copy the MySQL 1:1.
However, there are several problems in your code:
language sql does not have variables or IF statements. You need to use PL/pgSQL (language plpgsql)
PL/pgSQL requires a declare block to declare all variables and the actual code needs a begin ... end; block as well.
You can use SET for assignment
To store the result of a single row query in a variable use select ... into ... from
The character # is invalid in an SQL identifier and can't be used for variable names (which follow the rules of SQL identifiers). In Postgres it's a common habit to prefix variable with something to avoid ambiguity with column names. I use l_ for local variables (but that's completely a personal preference)
You don't seem to want to return multiple rows, but a single value. So you don't need returns table
To return something from a function, use return not select
Putting that all together it should look something like this:
CREATE OR REPLACE FUNCTION usp_failed_analyze4()
RETURNS varchar -- return a single value
AS
$BODY$
declare
l_maxdate timestamp;
l_maxdatediff interval;
l_status text;
l_statusnotrun text;
begin
select MAX(analyzetime), current_timestamp - MAX(analyzetime)
into l_maxdate, l_maxdatediff
FROM wp_analyze_history;
SELECT Status
into l_status
from wp_analyze_history
WHERE Status NOT IN ('OK','Table is already up to date','The Analyze task DID NOT run!')
AND analyzetime = l_maxdate;
l_statusnotrun := 'The Analyze task DID NOT run!';
IF l_maxdatediff > interval '7 days'
THEN
return l_statusnotrun;
ELSE
return ''; -- strings are enclosed in single quotes in SQL
end if;
end;
$BODY$
LANGUAGE plpgsql;
There is still room for a lot of optimization, but this matches your initial code as much as possible.

Create Redshift UDF with default Parameters

I am trying to create a Redshift UDF with function Parameters as below:
create or replace function function1(srctimezone VARCHAR,desttimezone VARCHAR,flag = 'nr') returns datetime
The last Parameter would be a defualt Parameter, i.e if user does not pass any value, it should take 'nr' by default. But I am not able to create function with default parameters. Any suggestions if Redshfit does / does not allow function creation with default Parameters. If it does, then what will be the correct syntax for the same?
In Redshift, you can create a Python UDF with an arbitrary number of arguments but you have to pass the same number of arguments when you execute the function. The workaround for optional parameters would be passing nulls and setting the parameter to the default value at the beginning of the function body similar to this:
create function f_optional_test(a int, b int)
returns int
stable as $$
if b==None:
return 999 # set default
else:
return b
$$ language plpythonu;
select f_optional_test(1,2); -- returns 2
select f_optional_test(1,null); -- returns 999
Also, you can create multiple functions with the same name but different number of parameters, so the function that is selected for execution will be picked up by the database engine based on the number of parameters and their data type:
create function f_optional_test(a int)
returns int
stable as $$
return 999 # default for b
$$ language plpythonu;
select f_optional_test(1,2); -- returns 2
select f_optional_test(1); -- returns 999
It's up to you to choose whether you'd like to have a single function at the expense of passing nulls for default parameters or have optional parameters at the expense of maintaining two versions of the same function if there is one optional parameter (with more optional parameters and their variable order it's more complicated and the first option is obviously better).
You can do:
CREATE OR REPLACE FUNCTION public.emulate_optional_arg(env_name varchar, optional varchar)
RETURNS varchar
LANGUAGE sql
IMMUTABLE
AS $$
SELECT $1 || ', ' || $2
$$
;
CREATE OR REPLACE FUNCTION public.emulate_optional_arg(env_name varchar)
RETURNS varchar
LANGUAGE sql
IMMUTABLE
AS $$
SELECT public.emulate_optional_arg($1,'default_value_here')
$$
;
SELECT public.emulate_optional_arg('dev');
/*
emulate_optional_arg |
-----------------------|
dev, default_value_here|
*/
SELECT public.emulate_optional_arg('dev','newvalue');
/*
emulate_optional_arg|
--------------------|
dev, newvalue |
*/

npgsql does not recognize function parameter type

I use Npgsql 2.2.5 with EntityFramework 6.1.3 database first and extended context to call some server functions one of them gives this error:
"ERROR: 42883: function insert_chempair(integer, unknown) does not exist"
ErrorSql:
select * from insert_chempair(((50066)),(('C1(=O)C(c2ccccc2)(CC)C(=O)NC(=O)N1')))
With Code:
public int AddChemPair(int cas,string smilesstr)
{
return this.Database.SqlQuery<int>("select * from insert_chempair(#p0,#p1)",(object)cas,(object)smilesstr).First();
}
Googling suggested to use typed paremeters i`ve changed object params to NpgsqlParameter types but the eror is not much different :
BaseMessage "function insert_chempair(integer, text) does not exist" string
Using SQLManagemnet studio i`m able to execute the function.
CREATE FUNCTION insert_chem_pair(new_cas integer,new_smiles text) RETURNS integer
LANGUAGE plpgsql STRICT
AS $$
DECLARE new_id integer;
DECLARE new_smiles_id integer;
BEGIN
select * into new_smiles_id from insert_smiles(new_smiles);
select id into new_id from chempair where cas=new_cas and smiles_id=new_smiles_id;
if( new_id is NULL) then
insert into chempair(cas,smiles_id) values(new_cas,new_smiles_id) returning chempair.id into new_id;
end if;
RETURN new_id;
END;
$$;
Am i doing something wrong.
The devil is in details:
Function is defined like this insert_chem_pair
but i call
insert_chempair
It seems DST affected me.

PLPython & CAST composite data type in Postgresql

I am writing a stored procedure in PlPython with a user defined type. I know Plpython does not support user defined types, so, I have created a CAST for the user defined type. Still I keep getting an error when I call plpy.prepare. I am not sure if I am using the CAST incorrectly - the example code is below:
#User Defined Type - person
CREATE TYPE person As( name character varying(50), state character(2));
#Table definition using 'person'
CREATE TABLE manager As(id integer, mgr person)
#CAST for person
CREATE OR REPLACE FUNCTION person_to_text(person) RETURNS text AS 'SELECT ROW($1.*)::text' LANGUAGE SQL;
CREATE CAST (cv_person as text) WITH FUNCTION person_to_text(person)
#PlPython procedure
CREATE OR REPLACE FUNCTION load_portfolio_assoc (name text, state text) RETURNS integer AS $$
mgr_str ="('"+name+"','"+state+"')"
insert_qry = 'Insert into manager (mgr) values($1)'
value_type = ['text']
qry = plpy.prepare(insert_qry,value_type)
rv = plpy.execute(qry, [mgr_str])
return 1
$$ LANGUAGE plpython3u;
An update :
Plpython accepts the query when it is written as follows with the user defined type specified with the variable in this format $1:: and stops throwing composite type not supported exceptions,
insert_qry = 'Insert into manager (mgr) values($1::person)'
value_type = ['text']
At the end, I really didn't have to do any extra casting operation on the database. It worked just by tweaking the variable as above.

Declare variable of composite type in PostgreSQL using %TYPE

Question: How can I declare a variable of the same type a parameter in a stored function?
The simple answer is use %TYPE, this works:
CREATE OR REPLACE FUNCTION test_function_1(param1 text)
RETURNS integer AS
$BODY$
DECLARE
myVariable param1%TYPE;
BEGIN
return 1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
But the problem is when param1 is a composite type:
CREATE TYPE comp_type as
(
field1 text
)
CREATE OR REPLACE FUNCTION test_function_2(param1 comp_type)
RETURNS integer AS
$BODY$
DECLARE
myVariable param1%TYPE;
BEGIN
return 1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
This doesn't work:
ERROR: type comp_type does not exist [SQL State=42704]
So how can I do when param1 is a composite type?
(Note: Just myVariable comp_type is not a good option because my function is slightly more complex.)
Edited:
I had a mistake on copy&paste, the real error is:
ERROR: invalid type name "param1%TYPE"
Position: 130 [SQL State=42601]
And using param1%ROWTYPE the error is:
ERROR: relation "param1" does not exist
Where: compilation of PL/pgSQL function "test_function_2" near line 3 [SQL State=42P01]
Use %ROWTYPE in that case.
Simple case
Tests by A.H. and DavidEG have shown this won't work. Interesting problem!
You could try a workaround. As long as your definition is like the example you can simply resort to
CREATE FUNCTION test(param1 comp_type)
RETURNS integer
LANGUAGE plpgsql VOLATILE AS
$func$
DECLARE
myvar comp_type;
BEGIN
RETURN 1;
END
$func$;
But your real problem is probably not as simple?
The real problem
As expected, the real problem turns out to be more complex: a polymorphic input type.
Workaround for that scenario was harder, but should work flawlessly:
CREATE FUNCTION test(param1 anyelement, OUT a integer, OUT myvar anyelement)
RETURNS record
LANGUAGE plpgsql VOLATILE AS
$func$
BEGIN
myvar := $1; -- myvar has the required type now.
-- do stuff with myvar.
myvar := NULL; -- reset if you don't want to output ..
a := 1;
END;
$func$;
Call:
SELECT a FROM test('("foo")'::comp_type); -- just retrieve a, ignore myvar
See full output:
SELECT * FROM test('("foo")'::comp_type);
Note for Postgres 9.0+
There has been a crucial update in Postgres 9.0. The release notes:
Allow input parameters to be assigned values within PL/pgSQL functions
(Steve Prentice)
Formerly, input parameters were treated as being declared CONST, so
the function's code could not change their values. This restriction
has been removed to simplify porting of functions from other DBMSes
that do not impose the equivalent restriction. An input parameter now
acts like a local variable initialized to the passed-in value.
In addition to my workaround, you can (ab)use input variables directly now.
Dynamic field names
See:
How to clone a RECORD in PostgreSQL
How to set value of composite variable field using dynamic SQL