How does Oracle VARRAY represent data in Java terms? - java

Slightly broad question here, but here goes
I'm trying to call an Oracle stored procedure, which returns a VARRAY which is of constructed from a ROWTYPE on one of my tables. For simplicity, lets say this table looks like the following :
MY_TABLE
ID VALUE
-----------
1 John
2 Dave
so I will call a SP that returns the following VARRAY type :
CREATE OR REPLACE TYPE param_array is VARRAY(100) OF MY_TABLE%ROWTYPE;
According to the Oracle Documentation, you can extract this as an array, but my question is : what will the type of the array be, is it an array of Strings, name/value paired strings etc?
I'm creating some Java code that will take data out of this array, but I'm not sure which format it will be, such as 1, John OR 1=John or 1,John
Any ideas?

From the docs:
SQL>CREATE OR REPLACE TYPE EMPARRAY is VARRAY(20) OF VARCHAR2(30)
SQL>/
Then create the following function that returns a VARRAY.
CREATE OR REPLACE FUNCTION getEmpArray RETURN EMPARRAY
AS
l_data EmpArray := EmpArray();
CURSOR c_emp IS SELECT ename FROM EMP;
BEGIN
FOR emp_rec IN c_emp LOOP
l_data.extend;
l_data(l_data.count) := emp_rec.ename;
END LOOP;
RETURN l_data;
END;
It will return an array of strings (VARCHARs) max length 30
it returns emparray which is declared as a varray of varchars (strings)

Related

SQL - Convert pipelined function to a java stored procedure/function

I've got the following types (A row type and a table of that kind of row):
CREATE TYPE t_tf_row AS OBJECT (
id NUMBER,
description VARCHAR2(50)
);
/
CREATE TYPE t_tf_tab IS TABLE OF t_tf_row;
/
And the following pipelined function which returns information for that kind of table (for this example it just prints a basic iteration).
CREATE OR REPLACE FUNCTION get_tab_ptf (p_rows IN NUMBER) RETURN t_tf_tab PIPELINED AS
BEGIN
FOR i IN 1 .. p_rows LOOP
PIPE ROW(t_tf_row(i, 'Description for ' || i));
END LOOP;
RETURN;
END;
/
Instead of using a pipelined function with its definition like above, I want to use a java stored procedure that does the exact same thing. How can I achieve the same output from this?
I want to be able to call the java stored procedure/function just like the following:
SELECT *
FROM TABLE(get_tab_ptf(10))
ORDER BY id DESC;
Thanks
PS: This question is meant for learning purposes only.

How to call a pl/SQL functuion having array as an argument using SQL

I have a SQL function named as IP_ELEARN_PERSON.F_GET_PERSON(int, string, array).
Now I want to run this function directly from sql developer and I am trying to execute this function like this --
select IP_ELEARN_PERSON.F_GET_PERSON(32433,'SOURCED',('ALL')) from dual;
Now the problem is when I am trying to execute this funtion I am getting the following errror --
ORA-06553: PLS-306: wrong number or types of arguments in call to 'F_GET_PERSON'
06553. 00000 - "PLS-%s: %s"
*Cause:
*Action:
Error at Line: 3 Column: 8
We were calling this function from java by using setArray method of the CallableStatment like this--
cstmt.setArray(4, new ObtainSqlArrayFromJava().returnSqlArray(
underlyingConn, roles));
So my doubt is, is the way I used to mention the array in the query right?
I went through many Stack Overflow posts but no where any thing was written for arrays as an argument.
CREATE TYPE string_list IS TABLE OF VARCHAR2(100);
/
CREATE FUNCTION F_GET_PERSON (
id INT,
type VARCHAR2,
array string_list
) RETURN INT
AS
BEGIN
RETURN 0;
END;
/
SELECT F_GET_PERSON( 1, 'SOURCED', string_list( 'ALL' ) )
FROM DUAL;
If you want some java code for passing an array as a bind variable to a PreparedStatement then you can look at my answer here. You should be able to easily adapt it to a CallableStatement.
As stated here:
http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS00501
Oracle supports the following collections types: associative array, VARRAY (variable-size array), and nested table.
You'll need to properly initialize the collection before passing it to the function.

Modifying PLSQL function to return multiple rows from same column

I am a beginner PLSQL user, and I have what might be a rather simple question.
I have created the following SQL Function, which returns the created date of the process whose corporate ID matches the corporate ID that I have given it. I have this connected to my JDBC, and it returns values just fine.
However, I just realized I overlooked an important issue--it's entirely possible that more than one process will have a corporate ID that matches the ID value I've inputted, and in cases like that I will need to be able to access all of the created date values where the IDs return a match.
CREATE OR REPLACE FUNCTION FUNCTION_1(
c_id IN INT)
RETURN INT
AS
p_date process.date_created%TYPE;
BEGIN
SELECT process.date_created
FROM PROCESS
WHERE process.corporate_id = c_id
ORDER BY process.corporate_id;
RETURN p_id;
END FUNCTION_1;
/
Is there a way that I can modify my function to return multiple rows from the same column, and then call that function to return some sort of array using JDBC? Or, if that isn't possible, is there a way I can return what I need using PLSQL procedures or just plain SQL combined with JDBC? I've looked through other questions here, but none seemed to be about quite what I need to know.
Thanks to anyone who can help!
you need make some changes in your function. on java side it will be simple select
you need change type of your function from int to collection
read about the table functions here Table Functions
user oracle table() function to convert result of your function to table
it let you use your function in queries. read more about the syntax here: Table Collections: Examples
here the example how to call your function from java:
select t.column_value as process_id
from table(FUNCTION_1(1)) t
--result
PROCESS_ID
1 1
2 2
--we need create new type - table of integers
CREATE OR REPLACE TYPE t_process_ids IS TABLE OF int;
--and make changes in function
CREATE OR REPLACE FUNCTION FUNCTION_1(
c_id IN INT)
RETURN t_process_ids
AS
l_ids t_process_ids := t_process_ids();
BEGIN
--here I populated result of select into the local variables
SELECT process.id
bulk collect into l_ids
FROM PROCESS
WHERE process.corporate_id = c_id
ORDER BY process.corporate_id;
--return the local var
return l_ids;
END FUNCTION_1;
--the script that I used for testing
create table process(id int, corporate_id int, date_created date);
insert into process values(1, 1, sysdate);
insert into process values(2, 1, sysdate);
insert into process values(3, 2, sysdate);

Why some strings are not inserted into PostgreSQL table from java?

What could be the reason that some strings are not inserted into PostgreSQL table from Java?
This happens after an update of source of data from API v1 to API v2. The inserted data structure is almost the same, float values are inserted, but some strings are not. And without any error: the fields are just empty.
It is probably some escape character but I'm not able to figure out which one. And how to fix it as well. The string length is about 6k characters and its PostgreSQL representation is text.
Here is the stored procedure:
CREATE OR REPLACE FUNCTION add_data_string(in_ts bigint, in_ids integer[], in_string_values text[])
RETURNS integer AS
$BODY$
DECLARE
tmp_id integer;
tmp_index integer;
BEGIN
tmp_index := 0;
FOREACH tmp_id IN ARRAY in_ids LOOP
tmp_index := tmp_index +1;
INSERT INTO data (ts, id, string_value) VALUES (in_ts, tmp_id, in_string_values[tmp_index]);
END LOOP;
RETURN tmp_index;
END;
The strings are passed into the procedure like this:
cs.setArray(3, con.createArrayOf("varchar", (String[]) values));
There is one more thing: if the stored procedure is modified, for the sake of debug, that only first five characters of the string are inserted, e.g. like this:
INSERT INTO data (ts, id, string_value) VALUES (in_ts, tmp_id, substring(0, 5, in_string_values[tmp_index]));
the first five characters are inserted as expected.
Check the in_ids and in_string_values arrays before you pass them to PostgreSQL. My guess is that their sizes do not match (the string_values array probably has a few extra empty string values you do not expect) like this
ids string_values
1 "string that makes it to the database"
2 "" //unexpected empty string
"string which does not get inserted in the database"
The problem is in pgAdmin III which for some strange reason does show empty fields for strings longer than 3640 characters even though the value Max. characters per column is set to 4096.

What Java library can map a PostgreSQL array literal to a Java array or list?

What third-party Java class library is available to map a PostgreSQL array literal string to a Java array or list of strings?
For example, suppose I wish to convert a PostgreSQL array literal string such as
{ A, B, C }
into the equivalent Java List<String> or Array<String> that contains { "A", "B", "C" }. Does the the PostgreSQL JDBC driver have a class method to perform this conversion?
Why would you want to parse array string literals in Java, when you can just get a java.sql.Array from PgJDBC and call getArray() on it to get the native Java array directly?
Parsing array literals in Java seems like an unnecessarily complicated approach.
Since you're getting the values as array literals from hstore, I'd say that you have a bit of a data model design problem since hstore really only stores string values so storing array literals is a wee bit ugly. I can understand that there might be circumstances where it's desirable though, at least until Pg gets improved json support.
In that case I'd let PostgreSQL parse the array literals for you. Given setup:
regress=# CREATE EXTENSION hstore;
CREATE EXTENSION
regress=# CREATE TABLE hstoretest ( test hstore );
CREATE TABLE
regress=# INSERT INTO hstoretest(test) VALUES ( hstore( ARRAY['a', 'b'], ARRAY[ ARRAY[1,2,3]::text, ARRAY[9,8,7]::text ] ) );
INSERT 0 1
regress=# INSERT INTO hstoretest(test) VALUES ( hstore( ARRAY['a', 'b'], ARRAY[ ARRAY[11,12,13]::text, ARRAY[99,88,77]::text ] ) );
INSERT 0 1
regress=# SELECT * FROM hstoretest ;
test
--------------------------------------
"a"=>"{1,2,3}", "b"=>"{9,8,7}"
"a"=>"{11,12,13}", "b"=>"{99,88,77}"
(2 rows)
You could let Pg expand and parse the array literals for you with something like:
regress=# SELECT k, fetchval(test,k)::integer[] FROM (SELECT test, skeys(test) AS k FROM hstoretest) withkeys;
k | fetchval
---+------------
a | {11,12,13}
b | {99,88,77}
a | {1,2,3}
b | {9,8,7}
(4 rows)
You may need more or less complicated variants depending on whether you're fetching just one hstore field or many fields, whether all your values are arrays of the same type or not, etc. In some cases you'll need to do individual SQL calls to unpack values.
Yes, it has. Take a look at: http://www.postgresql.org/message-id/49107A7D.3050206#gmail.com. Also there is an interesting article here. That article has a comment linking to an interesting project on GitHub (sproc-spring-mapper).
For whom needs to parse array value from logical replication(pgoutput):
In such situation, it's so good/familiar/high-performance to use the sql way in Craig Ringer's answer, so I wrote a Class to parse it.

Categories