Internal Error: Image is a collection image,expecting ADT with Oracle - oracle

I am trying to call a stored function on an oracle database with spring-jdbc.
This is the stored function I am trying to call:
FUNCTION GET_RESOURCE_LIST RETURN RESOURCE_TAB;
Next is the definition of resource_tab
TYPE RESOURCE_TAB AS TABLE OF TRESOURCE;
Next is the definition of tresource
TYPE TRESOURCE AS OBJECT(
RESOURCE_ID NUMBER(10,0),
RESOURCE_NAME VARCHAR2(100)
)
The calling code
final SimpleJdbcCall call = new SimpleJdbcCall(idmJdbcTemplate).withFunctionName("get_resource_list").declareParameters(new SqlOutParameter(
"RETURN", OracleTypes.STRUCT,
"RESOURCE_TAB",
new SqlReturnType() {
#Override
public Object getTypeValue(CallableStatement cs, int paramIndex, int sqlType, String typeName) throws SQLException {
final Struct s = (Struct)cs.getObject(paramIndex);
final Object[] attr = s.getAttributes();
return attr[1];
}
}));
call.compile();
final Collection<String> resources = call.executeFunction(Collection.class);
Last is the stack trace that I am receiving:
org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{? = call WVUID.IDM_REPO_MANUAL.GET_RESOURCE_LIST()}]; SQL state [99999]; error code [17001]; Internal Error: Image is a collection image,expecting ADT; nested exception is java.sql.SQLException: Internal Error: Image is a collection image,expecting ADT
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:969)
at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:1003)
Truncated. see log file for complete stacktrace
Caused By: java.sql.SQLException: Internal Error: Image is a collection image,expecting ADT
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:199)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:263)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:271)
Truncated. see log file for complete stacktrace
>
at org.springframework.jdbc.core.JdbcTemplate$5.doInCallableStatement(JdbcTemplate.java:1015)
at org.springframework.jdbc.core.JdbcTemplate$5.doInCallableStatement(JdbcTemplate.java:1)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:953)
... 62 more

I have the same problem, and I spent a day to fix it.
Thinking about error "Image is a collection image", instead of
OracleTypes.STRUCT it must be OracleTypes.ARRAY.
About your getTypeValue(...) method I can't say is it right or not, but I will show how parse the resultset (maybe it is and other way, please write it):
#Override
public Object getTypeValue(CallableStatement cs, int paramIndex,
int sqlType, String typeName) throws SQLException {
ARRAY struct = (ARRAY) cs.getObject(paramIndex);
ResultSet rs = struct.getResultSet();
while (rs.next()) {
Object rowIndex = rs.getObject(1);
oracle.sql.STRUCT row = (oracle.sql.STRUCT) rs.getObject(2);
if (row != null) {
Object[] cols = row.getAttributes();
System.out.print(rowIndex + ": ");
for (Object col : cols) {
System.out.print(col + " ");
}
System.out.println();
}
}
return "construct your data structure above and return here";
}
the another way is
#Override
public Object getTypeValue(CallableStatement cs, int paramIndex,
int sqlType, String typeName) throws SQLException {
ARRAY array = (ARRAY) cs.getObject(paramIndex);
Object[] rows = (Object[])array.getArray();
for(Object row : rows){
Object[] cols = ((oracle.sql.STRUCT)row).getAttributes();
for (Object col : cols) {
System.out.print(col + " ");
}
System.out.println();
}
return "construct your data structure above and return here";
}

The problem is with the declaration of the output parameter
final SimpleJdbcCall call = new SimpleJdbcCall(idmJdbcTemplate).withFunctionName("get_resource_list").declareParameters(new SqlOutParameter(
"RETURN", OracleTypes.STRUCT,
"RESOURCE_TAB",
new SqlReturnType() <etc>
The return type (TYPE RESOURCE_TAB AS TABLE OF TRESOURCE) is not a OracleTypes.STRUCT (that is reserved for Object Types) but an OracleTypes.ARRAY.

Related

hive UDF - convert StringObjectInspector to String

I am writing generic UDF. If I use UDF directly it works, however if I use UDF with other function (distinct, max, min) it's not even calling evaluate function.
I want to see what's happening and so trying to log the values. However need to understand how to convert StringObjectInspector to String.
Code
#Description(name = "Decrypt", value = "Decrypt the Given Column", extended = "SELECT Decrypt('Hello World!');")
public class Decrypt extends GenericUDF {
Logger logger = Logger.getLogger(getClass().getName());
PrimitiveObjectInspector col;
StringObjectInspector databaseName;
StringObjectInspector schemaName;
StringObjectInspector tableName;
StringObjectInspector colName;
#Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
System.out.println("****************************** initialize called ******************************");
logger.info("****************************** initialize called ******************************");
if (arguments.length != 5) {
throw new UDFArgumentLengthException("Decrypt only takes 4 arguments: T, String, String, String");
}
ObjectInspector colObject = arguments[0];
ObjectInspector databaseNameObject = arguments[1];
ObjectInspector schemaNameObject = arguments[2];
ObjectInspector tableNameObject = arguments[3];
ObjectInspector colNameNameObject = arguments[4];
if ( !(databaseNameObject instanceof StringObjectInspector) ||
!(schemaNameObject instanceof StringObjectInspector) ||
!(tableNameObject instanceof StringObjectInspector) ||
!(colNameNameObject instanceof StringObjectInspector)
) {
throw new UDFArgumentException("Error: databaseName, schemeName, tableName and ColName should be String");
}
this.col = (PrimitiveObjectInspector) colObject;
this.databaseName = (StringObjectInspector) databaseNameObject;
this.tableName = (StringObjectInspector) tableNameObject;
this.schemaName = (StringObjectInspector) schemaNameObject;
this.colName = (StringObjectInspector) colNameNameObject;
logger.info("****************************** initialize end ******************************");
logger.info(col.toString());
logger.info(col);
logger.info(databaseNameObject.toString());
logger.info(databaseNameObject);
logger.info(colName.toString());
logger.info(colName);
logger.info(colNameNameObject);
logger.info(colNameNameObject.toString());
return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
}
#Override
public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
System.out.println("******************** Decrypt ********************");
logger.info("******************** Decrypt ******************** ");
if(col.getPrimitiveJavaObject(deferredObjects[0].get()) == null){
return null;
}
String stringToDecrypt = col.getPrimitiveJavaObject(deferredObjects[0].get()).toString();
String database = databaseName.getPrimitiveJavaObject(deferredObjects[1].get());
String schema = schemaName.getPrimitiveJavaObject(deferredObjects[2].get());
String table = tableName.getPrimitiveJavaObject(deferredObjects[3].get());
String col = colName.getPrimitiveJavaObject(deferredObjects[4].get());
return new Text(AES.decrypt(stringToDecrypt, database, schema, table, col));
}
#Override
public String getDisplayString(String[] strings) {
return null;
}
}
Try getPrimitiveJavaObject method instead of toString, more details.
Another thought on your problem, check out optimization flags:
vectorization: hive.vectorized.execution, hive.vectorized.execution.enabled, hive.vectorized.execution.reduce.groupby.enabled
Cost-Based Optimization: hive.cbo.enable
predicate push down: hive.optimize.ppd
Check if those flags are enabled/disabled by typing set <option>, e.g., set hive.optimize.ppd;, in hive shell, and try to switch the value.

Hive UDF - Generic UDF for all Primitive Type

I am trying to implement the Hive UDF with Parameter and so I am extending GenericUDF class.
The problem is my UDF works find on String Datatype however it throws error if I run on other data types. I want UDF to run regardless of data type.
Would someone please let me know what's wrong with following code.
#Description(name = "Encrypt", value = "Encrypt the Given Column", extended = "SELECT Encrypt('Hello World!', 'Key');")
public class Encrypt extends GenericUDF {
StringObjectInspector key;
StringObjectInspector col;
#Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
if (arguments.length != 2) {
throw new UDFArgumentLengthException("Encrypt only takes 2 arguments: T, String");
}
ObjectInspector keyObject = arguments[1];
ObjectInspector colObject = arguments[0];
if (!(keyObject instanceof StringObjectInspector)) {
throw new UDFArgumentException("Error: Key Type is Not String");
}
this.key = (StringObjectInspector) keyObject;
this.col = (StringObjectInspector) colObject;
return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
}
#Override
public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
String keyString = key.getPrimitiveJavaObject(deferredObjects[1].get());
String colString = col.getPrimitiveJavaObject(deferredObjects[0].get());
return AES.encrypt(colString, keyString);
}
#Override
public String getDisplayString(String[] strings) {
return null;
}
}
Error
java.lang.ClassCastException: org.apache.hadoop.hive.serde2.objectinspector.primitive.JavaIntObjectInspector cannot be cast to org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector
I would suggest you to replace StringObjectInspector col with PrimitiveObjectInspector col and the corresponding cast this.col = (PrimitiveObjectInspector) colObject. Then there are two ways:
First is to process every possible Primitive type, like this
switch (((PrimitiveTypeInfo) colObject.getTypeInfo()).getPrimitiveCategory()) {
case BYTE:
case SHORT:
case INT:
case LONG:
case TIMESTAMP:
cast_long_type;
case FLOAT:
case DOUBLE:
cast_double_type;
case STRING:
everyting_is_fine;
case DECIMAL:
case BOOLEAN:
throw new UDFArgumentTypeException(0, "Unsupported yet");
default:
throw new UDFArgumentTypeException(0,
"Unsupported type");
}
}
Another way, is to use PrimitiveObjectInspectorUtils.getString method:
Object colObject = col.getPrimitiveJavaObject(deferredObjects[0].get());
String colString = PrimitiveObjectInspectorUtils.getString(colObject, key);
It just pseudocode like examples. Hope it helps.

ORA-00911: invalid character exception raised upon inserting records from variables

public class MainApp {
static final String JDBC_DRIVER="oracle.jdbc.driver.OracleDriver";
static final String DB_URL="jdbc:oracle:thin:#localhost";
static final String USER="system";
static final String PASS="system";
public static void main (String args[])
{
Connection conn=null;
Statement stmt=null;
try{
Class.forName(JDBC_DRIVER);
System.out.println("Connecting to Database.....");
conn=DriverManager.getConnection(DB_URL,USER,PASS);
System.out.println("Creating statement...");
stmt=conn.createStatement();
//stmt.executeUpdate("CREATE table Driver (phoneNumber number(10) primary key, licenseNumber number(5),driverName varchar(30),address varchar(10))");
//stmt.executeUpdate("INSERT into Driver values (9013105837,12347,'sunny','Delhi')");
String sql;
sql="SELECT phoneNumber,licenseNumber,driverName,address FROM Driver";
//insert a new record
Scanner sc = new Scanner(System.in);
System.out.println("Phone Number:");
long phone = sc.nextLong();
System.out.println("License Number:");
long license=sc.nextLong();
System.out.println("Name:");
String name = sc.next();
System.out.println("Address:");
String address = sc.next();
stmt.executeUpdate("INSERT into `Driver` values ("+phone+"," + license +",'" + name + "','" + address + "')");
//search by phone number(primary key)
//search by license number
ResultSet rs=stmt.executeQuery(sql);
while(rs.next())
{
long pn=rs.getLong("phoneNumber");
long ln=rs.getLong("licenseNumber");
String dn=rs.getString("driverName");
String add =rs.getString("address");
System.out.println("Phone Number:" +pn);
System.out.println("License Number:" +ln);
System.out.println("Name:" +dn);
System.out.println("Address:" +add);
System.out.println("--end of record--");
}
rs.close();
stmt.close();
conn.close();
}
catch(SQLException se){
se.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
System.out.println("Done!!");
}
}
}
I am able to insert static values with ease,but soon as I try to take the Input from the user,I get an exception.
OUTPUT
Connecting to Database.....
Creating statement...
Phone Number:
9013020737
License Number:
12349
Name:
rohit
Address:
dwarka
java.sql.SQLException: ORA-00911: invalid character
I cannot seem to figure out what invalid character I'm providing. Please help.I'm fairly new to jdbc, so please excuse me if the question seems too basic.
You should really be using prepareStatement to insert data. With your existing code, what happens if the user enters O'Reilly into the name input?
Try this instead:
PreparedStatement pst = conn.prepareStatement("insert into driver values (?,?,?,?)");
pst.setLong(1,phone);
pst.setLong(2,license);
pst.setString(3,name);
pst.setString(4,address);
pst.executeQuery();

null is entered when using prepared statement setcharacterstream h2 database

I am trying to add value into clob as give on h2 website using preparedstatement.setcharacterstream(arg,reader) null value is inserted in the database
Connection con=getConnection();
pstmnt=con.prepareStatement(sql);
int paramcounter=1;
for (Object object : param) {
if(paramcounter==1) {
int len=object.toString().length();
Reader rdr=new StringReader(object.toString());
pstmnt.setCharacterStream(1, rdr,len);;
}
else{
pstmnt.setObject(paramcounter, object);
}
paramcounter++;
}
int retvalue=pstmnt.executeUpdate();
closeConnection();
We don't really have enough information to clearly identify why you might be having difficulty, but the following code works for me:
package h2test;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.sql.*;
public class H2testMain {
public static void main(String[] args) {
Connection con = null;
try {
// create an in-memory database ("...mem:...")
con = DriverManager.getConnection("jdbc:h2:mem:");
Statement s = null;
try {
s = con.createStatement();
s.execute("CREATE TABLE Table1 (Column1 CLOB)");
InputStream is = new FileInputStream("C:/__tmp/MIME/stuff.txt");
Reader rdr = new InputStreamReader(is, StandardCharsets.ISO_8859_1);
PreparedStatement ps = con.prepareStatement(
"INSERT INTO Table1 (Column1) VALUES (?)");
ps.setCharacterStream(1, rdr);
ps.executeUpdate();
ResultSet rs = s.executeQuery(
"SELECT Column1 FROM Table1");
int rowNumber = 0;
while (rs.next()) {
String str = rs.getString("Column1");
System.out.println(
String.format(
"Row %d: CLOB is %d character(s) long.",
++rowNumber,
str.length()));
}
rs.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
It reads the text file
02/15/2014 10:55 358,785 stuff.txt
writes the file contents to a CLOB column in an H2 database, reads the data back from the database, and produces the following console output:
Row 1: CLOB is 358785 character(s) long.

inserting multiple data iteratively into a table in java database (derby) gives error

I've written a program that takes care of registration and each time i try to insert multiple new users at a time with different id it gives the error message:
java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL130217122630580' defined on 'STCEPARTICIPANTS'.
here is the action passed from a button WHICH instructs the data to be saved:
private void printsavebtnActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String query1= "insert into STCEPARTICIPANTS values("
+speno1tf.getText()+",'"+sname1tf.getText()+"','"
+fname1tf.getText()+"','"+uni1cb.getSelectedItem()
+"')";
String query2= "insert into STCEPARTICIPANTS values("
+speno1tf.getText()+",'"+sname1tf.getText()+"','"
+fname1tf.getText()+"','"+uni1cb.getSelectedItem()
+"')";
String query3= "insert into STCEPARTICIPANTS values("
+speno1tf.getText()+",'"+sname1tf.getText()+"','"
+fname1tf.getText()+"','"+uni1cb.getSelectedItem()
+"')";
String query4= "insert into STCEPARTICIPANTS values("
+speno1tf.getText()+",'"+sname1tf.getText()+"','"
+fname1tf.getText()+"','"+uni1cb.getSelectedItem()
+"')";
String [] queryarray= {query1,query2,query3,query4};
int speno1,speno2,speno3,speno4;
String task;
if(fname1tf.getText().equals("")||sname1tf.getText().equals("")||speno1tf.getText().equals("")
||uni1cb.getSelectedItem().equals("-")|| fname2tf.getText().equals("")||sname2tf.getText().equals("")||speno2tf.getText().equals("")
||uni2cb.getSelectedItem().equals("-") || fname3tf.getText().equals("")||sname3tf.getText().equals("")||speno3tf.getText().equals("")
||uni3cb.getSelectedItem().equals("-") || fname4tf.getText().equals("")||sname4tf.getText().equals("")||speno4tf.getText().equals("")
||uni4cb.getSelectedItem().equals("-") ){
JOptionPane.showMessageDialog(rootPane, "Please enter the fields marked '*'");
}
else {
try{
speno1=Integer.parseInt(speno1tf.getText());
speno2=Integer.parseInt(speno2tf.getText());
speno3=Integer.parseInt(speno3tf.getText());
speno4=Integer.parseInt(speno4tf.getText());
int [] taskit = {speno1,speno2,speno3,speno4};
for(int count2=0;count2<taskit.length;count2++){
task= "select * from STCEPARTICIPANTS where spe_number="+taskit[count2];
DBOptions.executeNonQuery(queryarray[count2]);
if(SearchData.searchSpeno(task)==true){
JOptionPane.showMessageDialog(rootPane, "Sorry, this member is already in the database./t Please go to Profile to renew of view membership details. Thank you!");
}
}
the class SearchData is given below:
public static boolean searchSpeno(String task){
String query =task;
ResultSet rs = DBOptions.executeSQLQuery(query);
if(rs!=null)
{
try
{
java.sql.ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
if(colCount > 0)
{
try
{
if(rs.next() && ! rs.getString("spe_number").equals(""))
{
return true;
}
else
{
return false;
}
}
catch(SQLException e)
{
JOptionPane.showMessageDialog(null, e,"Search Error", 3);
return false;
}
}
else
{
//JOptionPane.showMessageDialog(null, "Invalid Employee ID","Search Error", 3);
return false;
}
}
catch(SQLException ex)
{
//JOptionPane.showMessageDialog(null, ex.getMessage(),"Error Occured", 2);
return false;
}
}
else
{
return false;
}
}
}
}
the class DBOptions is :
public static boolean executeNonQuery(String sqlString)
{
try
{
Statement stmt = con.createStatement();
stmt.executeUpdate(sqlString);
JOptionPane.showMessageDialog(null,"success!");
return true;
//return the number of rows affected
}
catch(SQLException e)
{
//display error message
JOptionPane.showMessageDialog(null, e.getMessage()+"\nPlease Try Again","Non Query Execution Failure", 1);
e.printStackTrace();
return false;
}
}
public static ResultSet executeSQLQuery(String sqlQuery)
{
try
{
Statement stmt = con.createStatement();
return stmt.executeQuery(sqlQuery); //query successfully executed
}
catch(SQLException e)
{
//display error message
JOptionPane.showMessageDialog(null, e.getMessage()+"\nPlease Try Again","Query Execution Failure", 1);
return null; //sql query execution failed
}
}
}
Please, i have seen some problems like this and i have tried the different forms of solution but no head way. I need to get this ready for a mini project defense. I appreciate your response. Thank you.
How did you create the table? Can you paste the CREATE TABLE statement into your question?
Each row in your table must have a unique value for each column which is defined either as PRIMARY KEY or as UNIQUE, and Derby is enforcing that constraint.
Go back to your table definition, figure out for which columns you have specified either PRIMARY KEY or UNIQUE on the column, and then look at your program to figure out what values you are providing for those columns.
Then modify your program so that it provides a unique value for each such column.

Resources