Oracle JDBC callable statement and getMetadata count - oracle

Let's say I have a pl/sql like below:
final Connection c = DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:XE", "system", "manager");
String plsql = "" +
" declare " +
" p_id varchar2(20) := null; " +
" l_rc sys_refcursor;" +
" begin " +
" p_id := ?; " +
" ? := 'input parameter was = ' || p_id;" +
" open l_rc for " +
" select 1a id, 'hello' name from dual " +
" union " +
" select 2a, 'peter' from dual; " +
" ? := l_rc;" +
" end;";
CallableStatement cs = c.prepareCall(plsql);
cs.setString(1, "12345");
cs.registerOutParameter(2, Types.VARCHAR);
cs.registerOutParameter(3, OracleTypes.CURSOR);
cs.execute();
Everything's fine here but how can I get a metadat.getColumnCount() from this?
What I would like to achive?
Instead of:
ResultSet cursorResultSet = (ResultSet) cs.getObject(3);
while (cursorResultSet.next ())
{
System.out.println (cursorResultSet.getString(1) + " " + cursorResultSet.getString(2));
}
I would like to find metadata count and print all values for one record in a loop like:
//pseudo code
int x = callablestatement.metadata.count();
String myRecord='';
while (cursorResultSet.next ()){
for(int i=1; i<=x; i++){
myRecord= myRecord+ " " + cursorResultSet.getString(i);
}
}

To obtain the number of columns in the result set, you need to use
cursorResultSet.getMetaData().getColumnCount()

Related

convert string to base64 in oracle database

Hello I'm converting a string {"view": 1, "date": "2020-10-13", "cuit": 30000000007, "ptoVta": 10, "tipoCmp": 1, "nroCmp": 94, " amount ": 12100," currency ":" DOL "," ctz ": 65," tipoDocRec ": 80," nroDocRec ": 20000000001," tipoCodAut ":" E "," codAut ": 70417054367476} to base64 with the following function
CREATE OR REPLACE function CRISOL.returnsbase64 (ptext varchar2) RETURN VARCHAR2 IS
vResult varchar2 (1000);
BEGIN
--Create encoded value
vResult: = '';
vResult: = utl_encode.text_encode (ptext, 'WE8ISO8859P1', UTL_ENCODE.BASE64);
- dbms_output.put_line (vResult);
return vResult;
EXCEPTION
WHEN OTHERS
THEN
RAISE_APPLICATION_ERROR (
-20800,
'Problems in the function returnsbase64 when converting:' || ptext || ' Error; '|| SQLERRM,
TRUE);
END;
turns it well
e78idmVyIjoxLCJmZWNoYSI6IjIwMjAtMTAtMTMiLCJjdWl0IjozMDAwMDAwMDAw
NywicHRvVnRhIjoxMCwidGlwb0NtcCI6MSwibnJvQ21wIjo5NCwiaW1wb3J0ZSI6
MTIxMDAsIm1vbmVkYSI6IkRPTCIsImN0eiI6NjUsInRpcG9Eb2NSZWMiOjgwLCJu
cm9Eb2NSZWMiOjIwMDAwMDAwMDAxLCJ0aXBvQ29kQXV0IjoiRSIsImNvZEF1dCI6
NzA0MTcwNTQzNjc0NzZ9
but I need you to not have line breaks
Is there any solution?
The comment by #WernfriedDomscheit is right, the line breaks are ignored; but if you are dealing with an application that wants it as one nice long string, just do something like this, using the regexp_replace function to change carriage returns and line feeds to null:
regexp_replace
(
utl_encode.text_encode (ptext, 'WE8ISO8859P1', UTL_ENCODE.BASE64)
, chr(10) || '|' || chr(13)
, null
)

Output parameter is empty when calling Oracle package procedure using Oracle ADO in VBScript

I need to call Oracle package procedure from VBScript (from PowerDesigner app). It is 64-bit application so i am using Oracle 64-bit ODBC driver (Oracle client 12.1.0.2).
The job should be done with following code, which runs without any error but output values are empty:
Const ORAUser = "****"
Const ORAPass = "****"
Const ORASchema = "****"
Const ORAInst = "****"
Const ORADRV = "Oracle in OraClient12Home1"
Const ADO_CMD_STORED_PROC = 4
Dim Conn, ConnString, CmdStoredProc
Set Conn = CreateObject("ADODB.Connection")
ConnString = "Driver={" + ORADRV + "};Dbq=" + ORAInst + ";Uid=" + ORAUser + ";Pwd=" + ORAPass + ";"
Conn.Open ConnString
Set CmdStoredProc = CreateObject("ADODB.Command")
With CmdStoredProc
Set .ActiveConnection = Conn
.CommandText = ORASchema & ".PDLOCKS_ADMIN.VBS_TEST"
.CommandType = ADO_CMD_STORED_PROC
.Parameters.Append CmdStoredProc.CreateParameter("i_input_num", 5, 1, 0, 1)
.Parameters.Append CmdStoredProc.CreateParameter("i_input_vchar", 200, 1, 4000, "1")
.Parameters.Append CmdStoredProc.CreateParameter("o_output_num", 5, 2, 0)
.Parameters.Append CmdStoredProc.CreateParameter("o_output_vchar", 200, 2, 4000)
.Execute
Output .Parameters("o_output_num").Value ' EMPTY :-(
Output .Parameters(2) ' EMPTY :-(
End With
Conn.Close
Set Conn = Nothing
Set CmdStoredProc = Nothing
In Oracle database package procedure is everything processed correctly and input and output parameters are saved into table TEST:
PROCEDURE VBS_TEST (
i_input_num in number
,i_input_vchar in varchar2
,o_output_num out number
,o_output_vchar out varchar2
)
IS
BEGIN
insert into test values (to_char(i_input_num) || i_input_vchar);
o_output_num := i_input_num + 1;
o_output_vchar := i_input_vchar || '1';
insert into test values (to_char(o_output_num) || o_output_vchar);
commit;
END;

Oracle JDBC call PL/SQL procedure with input parameter a table of records

I am trying to call the following pl/sql procedure from JDBC.
create or replace PACKAGE test AS
type testrec_r is record (
val1 number,
val2 varchar2(100)
);
type testarr_t is table of testrec_r index by binary_integer;
function test_func(i_data in testarr_t, o_sum out number, o_totallength out number) return number;
END test;
This is how I tried to invoke it, but without success:
StructDescriptor recDescriptor = StructDescriptor.createDescriptor("test.testrec_r", conn);
STRUCT[] RECORDS_ARRAY = new STRUCT[2];
for (int i = 0; i < 2; i++) {
STRUCT oracle_record = new STRUCT(recDescriptor, conn, new
Object[] {i, "test"});
RECORDS_ARRAY[i] = oracle_record;
}
CallableStatement stmt = conn.prepareCall("{ call TEST.TEST_FUNC(?, ?, ?) }");
ArrayDescriptor arrayDescriptor = ArrayDescriptor.createDescriptor("TEST.TESTARR_T", conn);
ARRAY oracle_array = new ARRAY(arrayDescriptor, conn, RECORDS_ARRAY);
// Bind the input record
stmt.setArray(1, oracle_array);
stmt.registerOutParameter(2, Types.NUMERIC);
stmt.registerOutParameter(3, Types.NUMERIC);
stmt.executeUpdate();
double out1 = stmt.getDouble(2);
double out2 = stmt.getDouble(3);
return new Object[] { out1, out2 };
I just have read that oracle jdbc does not support pl/sql struct types. So, this fails with "invalid name pattern: test.testrec_r"
How can I call this procedure from Java? Ideally would be to only use a java libray/API, but as this seems almost imposible, which is the best workaround to wrap the pl/sql package in simple sql call and to invoke it?
P.S I am using Spring JDBCTemplate for database connection.
You cannot use PL/SQL types because they known to PL/SQL alone (since 12c this is no more strictly true - see UPD). Also any type created within a package is not visible by java directly.
You should create a SQL type at schema level. SQL types are visible to all and usable by all.
create or replace and compile java source named "ArrayOfRecTest" as
import java.io.*;
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.driver.*;
public class ArrayOfRecTest
{
public static void passArrayOfRec() throws SQLException
{
Connection conn = new OracleDriver().defaultConnection();
StructDescriptor sd = StructDescriptor.createDescriptor("MYREC_TYPE", conn);
ArrayDescriptor ad = ArrayDescriptor.createDescriptor("MYRECARR_TYPE", conn);
STRUCT[] recarr = new STRUCT[2];
for (int i = 0; i < 2; i++) { recarr[i] = new STRUCT(sd, conn, new Object[] {i+1, "value " + (i+1)}); }
ARRAY oracle_array = new ARRAY(ad, conn, recarr);
CallableStatement stmt = conn.prepareCall("{ ? = call testpkg.showArrOfRec(?, ?, ?) }");
stmt.registerOutParameter(1, Types.INTEGER);
stmt.setObject(2, oracle_array);
stmt.registerOutParameter(3, Types.INTEGER);
stmt.registerOutParameter(4, Types.INTEGER);
stmt.execute();
int sizeofArr = stmt.getInt(1);
int total = stmt.getInt(3);
int totalLength = stmt.getInt(4);
System.out.println("passArrayOfRec(total,len)=(" + total + "," + totalLength + ") " + sizeofArr + " records were shown");
}
}
/
create or replace force type myrec_type as object( id number, value varchar2(100));
/
create or replace type myrecarr_type as table of myrec_type;
/
create or replace package testpkg as
procedure passArrayOfRec as language java name 'ArrayOfRecTest.passArrayOfRec()' ;
function showArrOfRec(ra myrecarr_type, total out number, totallength out number) return number;
end testpkg;
/
create or replace package body testpkg as
--OP stuff
type testrec_r is record (val1 number, val2 varchar2(100));
type testarr_t is table of testrec_r index by binary_integer;
function test_func(data in testarr_t, total out number, totallength out number) return number is
begin
<<for_each>> for i in data.first..data.last loop
dbms_output.put_line('data(' || i || ')[val1,val2]=[' || data(i).val1 || ',' || data(i).val2 || ']');
total := nvl(total,0) + data(i).val1;
totallength := nvl(totallength,0) + length(data(i).val2);
end loop for_each;
return data.count;
end test_func;
--end OP stuff
function showArrOfRec(ra myrecarr_type, total out number, totallength out number) return number is
data testarr_t;
begin
for i in ra.first..ra.last loop data(i).val1 := ra(i).id; data(i).val2 := ra(i).value; end loop;
return test_func(data, total, totalLength);
end showArrOfRec;
end testpkg;
/
exec testpkg.passArrayOfRec;
Output:
data(1)[val1,val2]=[1,value 1]
data(2)[val1,val2]=[2,value 2]
passArrayOfRec(total,len)=(3,14) 2 records were shown
UPD New in 12cR1: Using PL/SQL Types

TSql (sql server 2005) query running slow

The following query is running slow. for one value in memberid, there are multiple entries in memberid0, memberid1........ memberid9. Therefore each statement is effecting multiple row updates. Ofcourse the table size is in MBs
Declare #memberName nvarchar(250)
Declare #memberID bigint
Declare #dimId int
Declare #levelId int
Declare #newName nvarchar(250)
Declare #updateSQL1 nvarchar(500)
Declare #updateSQL2 nvarchar(500)
Declare #cursorStmt nvarchar(300)
Declare #custCounter bigint
Declare #prodCounter bigint
Declare #regCounter bigint
Declare #memberCounter int
SET #custCounter = 1
SET #prodCounter = 1
SET #regCounter = 1
SET #memberCounter = 0
BEGIN TRANSACTION
While #memberCounter < 3
Begin
Set #cursorStmt = 'Declare memberCursor CURSOR
FOR Select name, memberid, dimensionId, levelNumber from member' + CAST(#memberCounter as NVARCHAR(1)) + ' where memberID <> 0 order by memberid'
print #cursorStmt
exec sp_executesql #cursorStmt
OPEN memberCursor
FETCH NEXT FROM memberCursor INTO #memberName, #memberId, #dimId, #levelId
WHILE ##FETCH_STATUS = 0
BEGIN
IF #dimId = 0
BEGIN
SET #newName = 'Customer_' + CAST(#custCounter AS NVARCHAR(10)) + '_LEVEL_' + CAST(#levelId AS NVARCHAR(10))
SET #custCounter = #custCounter + 1
END
else if #dimId = 1
BEGIN
SET #newName = 'Product_' + CAST(#prodCounter AS NVARCHAR(10)) + '_LEVEL_' + CAST(#levelId AS NVARCHAR(10))
SET #prodCounter = #prodCounter + 1
END
else if #dimId = 2
BEGIN
SET #newName = 'Region_' + CAST(#regCounter AS NVARCHAR(10)) + '_LEVEL_' + CAST(#levelId AS NVARCHAR(10))
SET #regCounter = #regCounter + 1
END
SET #updateSQL1 = 'Update Member' + CAST(#dimId AS NVARCHAR(5)) + ' set name = ''' + #newName + ''' where memberId = ' + CAST(#memberId AS NVARCHAR(10))
SET #updateSQL2 = 'Update Member' + CAST(#dimId AS NVARCHAR(5)) + ' set memberName' + CAST(#levelId-1 AS NVARCHAR(5)) + ' = ''' + #newName + ''' where memberId' + CAST(#levelId-1 AS NVARCHAR(5)) + ' = ' + CAST(#memberId AS NVARCHAR(10))
--print #updateSQL1
--print #updateSQL2
exec sp_executesql #updateSQL1
exec sp_executesql #updateSQL2
FETCH NEXT FROM memberCursor INTO #memberName, #memberId, #dimId, #levelId
END
CLOSE memberCursor
DEALLOCATE memberCursor
Set #memberCounter = #memberCounter + 1
END
I double marc_s says, but if you don't want to do that,
try creating a table which hold your Update statements and then execute them in a batch of minimum 10 updates per query.
Try to create two table to store two different kind of updates so in a batch, you can have only kind of update in minimum of 10 rows. I would like to update as many as I could in a single query.
Multiple updates in single SQL query is faster, see:
Why are batch inserts/updates faster? How do batch updates work?

Using PL/SQL how do you I get a file's contents in to a blob?

I have a file. I want to get its contents into a blob column in my oracle database or into a blob variable in my PL/SQL program. What is the best way to do that?
To do it entirely in PL/SQL, the file would need to be on the server, located in a directory which you'd need to define in the database. Create the following objects:
CREATE OR REPLACE DIRECTORY
BLOB_DIR
AS
'/oracle/base/lobs'
/
CREATE OR REPLACE PROCEDURE BLOB_LOAD
AS
lBlob BLOB;
lFile BFILE := BFILENAME('BLOB_DIR', 'filename');
BEGIN
INSERT INTO table (id, your_blob)
VALUES (xxx, empty_blob())
RETURNING your_blob INTO lBlob;
DBMS_LOB.OPEN(lFile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.OPEN(lBlob, DBMS_LOB.LOB_READWRITE);
DBMS_LOB.LOADFROMFILE(DEST_LOB => lBlob,
SRC_LOB => lFile,
AMOUNT => DBMS_LOB.GETLENGTH(lFile));
DBMS_LOB.CLOSE(lFile);
DBMS_LOB.CLOSE(lBlob);
COMMIT;
END;
/
Depends a bit on your environment. In Java you could do it something like this...
// Need as OracleConnection in mConnection
// Set an EMPTY_BLOB()
String update = "UPDATE tablename"+
" SET blob_column = EMPTY_BLOB()"+
" WHERE ID = "+id;
CallableStatement stmt = mConnection.prepareCall(update);
stmt.executeUpdate();
// Lock the row FOR UPDATE
String select = "BEGIN " +
" SELECT " + blob_column
" INTO ? " +
" FROM " + tablename +
" WHERE ID = '" + id + "'" +
" FOR UPDATE; " +
"END;";
stmt = mConnection.prepareCall(select);
stmt.registerOutParameter(1, java.sql.Types.BLOB);
stmt.executeUpdate();
BLOB blob = (BLOB) stmt.getBlob(1);
OutputStream bos = blob.setBinaryStream(0L);
FileInputStream fis = new FileInputStream(file);
// Code needed here to copy one stream to the other
fis.close();
bos.close();
stmt.close();
mConnection.commit();
But it really depends what environment / tools you're using. More info needed.

Resources