I have some code I'm trying to fix and a function is used within a CallableStatement but it seems that said function is called in a particular instance where a Schema of the Database becomes the entire 'see-able' database for the function.
Let me explain :
My database (in PostgreSQL) has multiple projects (schemas) such as i2b2test_project or i2b2test_project2. Each of these projects has an architecture of multiple tables, such as visit_dimension, patient_dimension, etc..
Now, if I want to reference the visit_dimension table from a i2b2test_project, I need to use i2b2test_project.visit_dimension, as any logical SQL syntax would suggest.
The problem is that, in the code (which I'll include below), a CallableStatement is used to execute a function (plain old load-table-from-temp-table function). This function references the architecture mentioned above as if only one project exists, as the database. In other words, instead of referencing i2b2test_project.visit_dimension, it only references visit_dimension.
I haven't found a way to execute a function in some sort of 'separated instance' of the database and as a result, the function can not be used in a plain SQL statement inside a DB terminal, errors such as visit_dimension table does not exist etc..
So I ask : Does the call statement (which indeed seems to reference the schema) allow for such a 'separated instance' of the database ? And is there a way to do so with a plain SQL statement ?
Code :
CallableStatement callStmt = conn.prepareCall("{call "
+ this.getDbSchemaName()
+ "INSERT_ENCOUNTERVISIT_FROMTEMP(?,?,?)}");
callStmt.setString(1, tempTableName);
callStmt.setInt(2, uploadId);
callStmt.registerOutParameter(3, java.sql.Types.VARCHAR);
callStmt.execute();
Related
During looking into the performance in my app, I noticed that for each object creation via JPA, framework calls T4CConnection.prepareStatement method in the Oracle JDBC driver (ojdbc8 19.3.0.0), code is constantly getting the table description via T4CConnection.doDescribeTable(), even if all inserts are for the same table. The retrieval of the table description takes around 20% longer then real insert statement execution. Can it be somehow tuned? Do you know what is the purpose to call table description every time for each insert, shouldn't it be cached for systems that schema does not change frequently?
Unfortunately it is hard to extract the code sample as it at framework level.
Stack is JPA, Hikari, OJDBC.
In general JPA saveAll method calls following:
com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement
com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate
PrepareStatement from Hikari internally calls a driver classes, where in my case it is: oracle.jdbc.driver.PhysicalConnection.prepareStatement()
Couldn't find the exact source code, but main concept is same as here https://github.com/mikesmithjr/ora-jdbc-source/blob/master/OracleJDBC/src/oracle/jdbc/driver/PhysicalConnection.java
Simplified code:
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
(...) //check if insert statment
AutoKeyInfo info = new AutoKeyInfo(sql, columnNames);
doDescribeTable(info); <-- table describe occurs here, pretty slow
OraclePreparedStatement pstmt = (OraclePreparedStatement) prepareStatement(newSql); <-- in prepareStatement i can benefot from the cache
return pstmt;
}
I am working on an application using Java, Eclipse, and Spring. We have an Oracle database that we are connecting to using JDBC.
Currently the application is using adhoc queries in the application to the database. Most of these were done by people working on the project before I came along. I have decided that using stored procedures is a better way of going. Decouple for another layer of abstraction. Not having to send the sql statement every time so less bandwidth and faster transactions. Oracle can optimize them unlike with the adhoc ones. Changes to them can occur without needing to be recompiled as long as inputs and outputs dont change. All that wonderful stuff.
The adhoc queries frequently get back multiple rows and are using the interface rowMapper and mapRow
return jdbcTemplate.query(sql, new adhoc_mapper1());
class adhoc_mapper1 implements RowMapper<List<String>> {
public List<String> mapRow(ResultSet rs, int arg1) throws SQLException{
ArrayList<String> arr1 = new ArrayList<String>();
arr1.add(rs.getString("OUT_POSITION_ID"));
arr1.add(rs.getString("OUT_POSITION_TITLE_EN"));
return arr1;
}
}
Adhoc Query in Spring
SELECT HR.POSITION_ID, HR.POSITION_TITLE_EN, HR.POSITION_TITLE_FR, HR.SECURITY_ID, HR.GROUP_NAME, HR.GROUP_LEVEL, HR.POSITION_IS_ACTIVE
FROM HR_POSITION HR JOIN DRILL_POSITION DP ON (HR.POSITION_ID = DP.POSITION_ID)
WHERE DP.TYPEVALUE = RECORD_TYPE;
Called Procedure in Oracle
CREATE OR REPLACE PROCEDURE DOCSADM.DRILL_RECORD_POSITION (
RECORD_TYPE IN VARCHAR2,
OUT_POSITION_ID OUT VARCHAR2,
OUT_POSITION_TITLE_EN OUT VARCHAR2,
OUT_POSITION_TITLE_FR OUT VARCHAR2,
OUT_SECURITY_ID OUT VARCHAR2,
OUT_GROUP_NAME OUT VARCHAR2,
OUT_GROUP_LEVEL OUT VARCHAR2,
OUT_POSITION_IS_ACTIVE OUT VARCHAR2
) AS
BEGIN
SELECT HR.POSITION_ID, HR.POSITION_TITLE_EN, HR.POSITION_TITLE_FR, HR.SECURITY_ID, HR.GROUP_NAME, HR.GROUP_LEVEL, HR.POSITION_IS_ACTIVE
INTO OUT_POSITION_ID, OUT_POSITION_TITLE_EN, OUT_POSITION_TITLE_FR, OUT_SECURITY_ID, OUT_GROUP_NAME, OUT_GROUP_LEVEL, OUT_POSITION_IS_ACTIVE
FROM HR_POSITION HR JOIN DRILL_POSITION DP ON (HR.POSITION_ID = DP.POSITION_ID) WHERE DP.TYPEVALUE = RECORD_TYPE;
END DRILL_RECORD_POSITION;
As you can see, the procedure returns multiple rows. I had asked a question about how to view the output from the procedure in Oracle but was not successful.
As the project is not using called procedures I have no examples in the code base to work back from. One of my coworkers involved in a different project has used them and was kind enough to show me their example, which regrettably was not helpful because it only called a procedure and had no returns. Their overall design also appears different. But I saw that they were using SimpleJdbcCall so I started looking online to use that.
Good examples online that I failed to get working.
I found examples that were doing what I needed to do, but not quite how I was expecting.
This example goes along the lines of what I was expecting to see and use, except that it only takes a single row as the result and I wasn't able to figure out how to alter the mapping to accept multiple rows.
This example however does use a procedure that returns multiple rows, but it uses ParameterizedBeanPropertyRowMapper and passes in a class.
This example has several ways of doing these calls but are all single row returns, but the answers comments do suggest that its easy to expand for multiple rows. But again I was unable to get it working.
I am not wanting to create a class for every procedure or family of procedures. Most of the queries end up displaying the information in a table, so I have been using a 2d object to hold and then display the data. It has been very convenient so far. I am fine with creating a mapping for each procedure as it needs to be done (unless there is a better way?), but I do not want to create a class for every procedure (and sometimes the mapper as well).
I have 150 lines of failed code attempts which I have not included to keep the question shorter. If they would help then I can include them.
TL;DR
I want to call a stored procedure in Oracle from Spring which has multiple rows being returned. I would like to use just the calling function, which either uses the RowMapper method of mapping, or an in function mapping. I want to avoid using class structures of data if possible. I am expecting/hoping it to look and get used like the first code block.
There is a basic error with my methodology for this. The way in which I was attempting to return multiple rows is wrong. As pointed out by someone in my linked question. So the ways that I was attempting to access it were also wrong. When I limited the return to a single row the following was successful.
First the imports
import java.sql.Connection;
import java.sql.CallableStatement;
Then the call
final String procedureCall = "{call DRILL_RECORD_POSITION(?, ?, ?, ?, ?, ?, ?, ?)}";
try (Connection connection = jdbcTemplate.getDataSource().getConnection();)
{
ArrayList<String> inner = new ArrayList<String>();
CallableStatement callableSt = connection.prepareCall(procedureCall);
callableSt.setString(1, "D");
callableSt.registerOutParameter(2, Types.VARCHAR);
callableSt.registerOutParameter(3, Types.VARCHAR);
callableSt.registerOutParameter(4, Types.VARCHAR);
callableSt.registerOutParameter(5, Types.VARCHAR);
callableSt.registerOutParameter(6, Types.VARCHAR);
callableSt.registerOutParameter(7, Types.VARCHAR);
callableSt.registerOutParameter(8, Types.VARCHAR);
//Call Stored Procedure
callableSt.executeUpdate();
for (int i=2; i<9; i++)
{
System.out.println(callableSt.getString(i));
}
}catch (SQLException e) {
e.printStackTrace();
}
Note that I am using the try with resources so I do not have to worry about closing the connection.
Other mistakes I made during this was not having enough ? in the String which was leading to invalid column index errors. I then made the mistake of trying to get the information before I actually executed the call.
I am working on the web application project developed using java. In my working project,
i have the requirement like i need to create the database dynamically after the user has been registered.I had done that approach.
But, now i want to call one stored procedure that is available in another schema(Master DB).The stored procedures contains tables. Now, i want to call that procedure in dynamically created DB.
I have written the code like following, can anybody help me to know what's wrong in this code,
Connection c1 = DriverManager.getConnection(URL, USER, PASSWORD);
java.sql.CallableStatement cstmt=null;
System.out.println("Invoking the stored procedure from subscription DB........");
String callSP="{call masterdb.createCorporateDBProc()};";
cstmt= c1.prepareCall(callSP);
cstmt.execute();
java.sql.CallableStatement cstmt=null;
try {
System.out.println("Invoking the stored procedure from subscription DB........");
String callSP="{call subscription.createCorporateDBProc()}";
cstmt = c1.prepareCall(callSP);
int r = cstmt.executeUpdate();
System.out.println("SP created"+r);
System.out.println("SP invoked and executed successfully in corporate DB....");
} catch(com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException e){
e.printStackTrace();
cstmt.close();
c1.close();
}
See javadoc for Statement:
http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#executeUpdate%28java.lang.String%29
Returns:
either (1) the row count for SQL Data Manipulation Language (DML) statements or (2) 0 for SQL statements that return nothing
This means that execute for procedure will return 0. Check your database as well, if the call was successful.
I have an Java application running on a Weblogic Server and Connecting to Oracle 11g DB server.
In the application i make a call to a DB Procedure and pass a parameter to it which communicates and calls multiple other procedures.
When i test the Procedure independently, it works perfectly and as expected.
The issue comes when i call the Procedure from Java Application.
The Procedure gives an error:
ORA-06508: PL/SQL: could not find program unit being called
The Backtrace leads to a call to a procedure that exists in another Schema and has a synonym in my current schema.
Please help if anybody else has faced the same issue or a similar one.
Edit#1:
Sample Code for Calling DB Proc
CallableStatement cstmt = null;
private Connection dbConn = null;
HashMap hashMap = new HashMap();
hashMap.put(DBDRIVER, driverType);
hashMap.put(USERID, userName);
hashMap.put(PASSWORD, password);
hashMap.put(SID, dbName);
hashMap.put(IPADDRESS, intDBServer);
hashMap.put(PORT, dbPort);
dbConn = (Connection)cmmObj.connect(hashMap);
cstmt = dbConn.prepareCall(queryToRun);
cstmt.setString(1, ReqId);
cstmt.executeUpdate();
Proc Call is { call Proc_CALL(?) }
It sounds to me as though your synonym is the wrong way round - the calling schema needs a synonym for the called procedure + permissions to execute.
I have probably found the issue. Although it seams weird to hear it but it seems to work:
The system i was working on has 3 Schema in connection.
One is the Staging Schema from which all the calls are made.
Second is the Main Schema to which calls were made. The Called Procedure existed in this Schema.
The third is another schema where a procedure existed that was being called from Main Schema Procedure.
Simplified:
StageSchema.Caller(Synonym)-->>
MainSchema.Proc_Call(Procedure)-->>
CoSchema.insideCall(Procedure).
The Grants to the CoSchema were available to the Main Schema, but not to the Stage Schema.
Although as per theory if Any Procedure is being granted to a schema then all inside calls to any other procedures should not matter.
but in this case when i gave the grant to Stage Schema, then everything seemed to work perfectly.
If any one has a solution to this then please share the reason for the same.
I am creating and testing a stored procedure through remote using JUnit , my user name is test and this is my code,
String sql = "create procedure test.firstProc3 AS select GETDATE()";
cursor.execute(sql);
cursor.executeQuery("firstProc3");
ANd to drop the procedure:
String dropSQL = "DROP PROCEDURE test.firstProc3";
cursor.execute(dropSQL);
Since the Drop Procedure is not working, I am unable to run the same SP for the second time ( new session) My error is:
There is already an object named 'firstProc3' in the database.
When I gave sp_help on the server side,
the table had the row with the value
firstProc3 test stored procedure
However when I give
DROP PROCEDURE test.firstProc3 in the Query analyzer, the row is getting deleted from the table.
What could be the issue in trying to do the same operation through Junit?
Are there any permissions to be set?
PS - the user test has the db_ddladmin enabled.
I managed to finally solve the problem by using the following :
declare #object_id int
select #object_id = object_id('test.firstProc5')
EXEC sp_MSdrop_object #object_id
GO
This is removing the data from the table too.And I am able to successfully run the Testcase multiple times !
Thanks for your help :)
The link I referred to is here, hope it helps someone:
http://www.mssqlcity.com/Articles/Undoc/SQL2000UndocSP.htm
Based upon the error message, I doubt it is a permissions issue. It looks like your cursor object is running the create again when you're trying to drop, or you're never really dropping the proc before running your unit test again, or the tests are running out of logical order in some fashion. Can you instantiate a new cursor object and try the drop with that, or verify the SQL being run against the database using profiler or some debug output?
Beyond that, I would be curious to see if changing your SQL commands to check for proc existence makes the error go away (not that this is the right answer):
if object_id('test.firstProc3') is null begin
-- Dynamic SQL because create must be first in a batch
exec ('create procedure test.firstProc3 as select getdate()')
end
if object_id('test.firstProc3') is not null begin
drop procedure test.firstProc3
end
Maybe something small, and maybe it is even not the case, but have you tried to use escaping in your drop statement?
something like
drop procedure [test].[firstProc3]
I can remember that i had an issue with this when i called a drop table from c# code...