Foro sobre Java SE > Problema insertar clob con setObject entre dos tablas de esquemas diferentes y de bd diferentes
Hola!
Primero comentar que trabajo con oracle 11g version 11.2.0.3 y el ojdbc6.jar con java 6.0.
El problema con el que me encuentro es el siguiente:
Quiero pasar los datos de una tabla tab1 de un usuario1 de la base datos bd1 a una tabla tab2 de un usuario usuario2 de la base de datos bd2. Las tablas tienen los mismos campos y tienes definidos algunos campos como clob.
Entonces mi "programilla" funciona perfectamente si las tablas tab1 y tab2 son del mismo usuario o de usuarios distintos pero dentro de la misma base de datos, en el momento lo ejecuto para dos usuarios de bases de datos diferentes da un mensaje d'error.
// Aquí creo la sentencia insert de la tabla StringBuffer insertum=new StringBuffer("insert into termes_primaria ("); for(int k=0; k < cols; k++) { insertum.append(columnNames[k]); if(k < cols-1)insertum.append(","); } insertum.append(") values ("); for(int k=0; k < cols; k++) { insertum.append("?"); if(k < cols-1)insertum.append(","); } insertum.append(")"); System.out.println("insert... "+insertum);
// leer datos de la tabla origen y insertarlos en la de destino PreparedStatement aDesti=cproduccio.prepareStatement(insertum.toString()); int conta=0; while(rsFont.next()) { for(int k=0; k < cols; k++) { columnValues[k] = rsFont.getObject(columnNames[k]); if ( rsFont.wasNull() ) aDesti.setNull(k+1, tipus[k]); else aDesti.setObject(k+1, columnValues[k]); } System.out.println("Conta:"+conta); aDesti.executeUpdate(); aDesti.clearParameters(); conta++; }
aDesti.close(); rsFont.close(); st.close(); cproduccio.commit(); cproduccio.close(); cdev.close(); System.out.println("Hi han "+conta);
El programa solo funciona si las conexiones cdev i cproduccio se corresponden con la misma base de datos aunque sea de usuarios diferentes. Si són de diferentes base de tos deja de funcionar y además para mas inri, oracle devueve el siguiente error:
java.sql.SQLSyntaxErrorException: ORA-00942: la tabla o vista no existe
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445) at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396) at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:879) at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450) at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192) at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531) at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207) at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1044) at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1329) at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584) at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3665) at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1352) at provesmeves.ProvesMeves.main(ProvesMeves.java:83)
Además, probando cosas el error està en el setObject() cuando el objecto que paso como parametro es un clob, ya que cambie el trozo de codigo por este:
PreparedStatement aDesti=cproduccio.prepareStatement(insertum.toString()); int conta=0; while(rsFont.next()) {
Y ahora ya funcionaba cuando las dos conexiones, cdev y cproduccio era de diferentes bases de datos.
Sólo se nos ocurre algo parecido a esto:
Dado que están definidas en la interfaz PreparedStatment las llamadas setObject, la ejecución sólo debería fallar, en mi opinión, (en algún lugar de la secuencia de llamadas) para:
a. conexión mal configurada b. inyectar un objeto que no se corresponde (que no se puede convertir) en la columna correspondiente al índice del parámetro c. utilizar un índice de columna incorrecto d. utilizar una expresión sql no correcto o que hace referencia a una tabla inexistente
Ninguna de estas cosas ocurre en el ejemplo que falla (utilizando dos conexiones)
Parece que el CLOB contiene información de conexión de origen y que se utiliza de alguna manera en la conexión de destino, en la implementación que ha hecho Oracle de esta interfaz.
Esto me parece del todo incorrecto, entre otras cosas por que la información de la conexión de destino está implícita en el objeto PreparedStatemt de destino: este comportamiento es tan absurdo como sería el del caso hipotético de obtener un String de una tabla de una cierta conexión y que al llamar al SetObject correspondiente a un PreparedStatement asociado a otro conexión utilizara la table y conexión del objeto original, en cuanto lo que habíamos obtenido es el valor de una columna de una tabla de una bd, simplemente .
Este comportamiento hace que el código funcione si la conexión de origen y destino es la misma pero no si es diferente.
Lo que tampoco es aceptable es el mensaje de la excepción, java.sql.SQLSyntaxErrorException: ORA-00 942: la tabla o vista no existe, por razones obvias.
Hola!
Primero comentar que trabajo con oracle 11g version 11.2.0.3 y el ojdbc6.jar con java 6.0.
El problema con el que me encuentro es el siguiente:
Quiero pasar los datos de una tabla tab1 de un usuario1 de la base datos bd1 a una tabla tab2 de un usuario usuario2 de la base de datos bd2. Las tablas tienen los mismos campos y tienes definidos algunos campos como clob.
Entonces mi "programilla" funciona perfectamente si las tablas tab1 y tab2 son del mismo usuario o de usuarios distintos pero dentro de la misma base de datos, en el momento lo ejecuto para dos usuarios de bases de datos diferentes da un mensaje d'error.
El programa en cuestion és:
public class ProvesMeves
{
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
try
{
// java.sql.Connection cdev = java.sql.DriverManager.getConnection("jdbc:oracle:thin:user1/*****@racestad.idescat.local:1521/bdintern.idescat.local");
java.sql.Connection cdev = java.sql.DriverManager.getConnection("jdbc:oracle:thin:user1/*****@10.116.2.159:1521/destad.idescat.local");
// java.sql.Connection cdev = java.sql.DriverManager.getConnection("jdbc:oracle:thin:cataleg/cataleg@10.116.2.157:1521/bdestcat.idescat.local");
cdev.setReadOnly(true);
java.sql.Connection cproduccio = java.sql.DriverManager.getConnection("jdbc:oracle:thin:rep/rep1966@racestad.idescat.local:1521/bdintern.idescat.local");
// java.sql.Connection cproduccio = java.sql.DriverManager.getConnection("jdbc:oracle:thin:user2/******@10.116.2.159:1521/destad.idescat.local");
// java.sql.Connection cproduccio = java.sql.DriverManager.getConnection("jdbc:oracle:thin:user2/****+@10.116.2.157:1521/bdestcat.idescat.local");
cproduccio.setAutoCommit(false);
java.sql.Statement st=cdev.createStatement();
java.sql.ResultSet rsFont=st.executeQuery("select * from termes_primaria");
ResultSetMetaData meta=rsFont.getMetaData();
int cols=meta.getColumnCount();
String[] columnNames=new String[cols];
Object[] columnValues=new Object[cols];
int[] tipus=new int[cols];
for(int k=0; k < cols; k++ )
{
columnNames[k]=meta.getColumnName(k+1);
tipus[k]=meta.getColumnType(k+1);
}
// Aquí creo la sentencia insert de la tabla
StringBuffer insertum=new StringBuffer("insert into termes_primaria (");
for(int k=0; k < cols; k++)
{
insertum.append(columnNames[k]);
if(k < cols-1)insertum.append(",");
}
insertum.append(") values (");
for(int k=0; k < cols; k++)
{
insertum.append("?");
if(k < cols-1)insertum.append(",");
}
insertum.append(")");
System.out.println("insert... "+insertum);
// leer datos de la tabla origen y insertarlos en la de destino
PreparedStatement aDesti=cproduccio.prepareStatement(insertum.toString());
int conta=0;
while(rsFont.next())
{
for(int k=0; k < cols; k++)
{
columnValues[k] = rsFont.getObject(columnNames[k]);
if ( rsFont.wasNull() ) aDesti.setNull(k+1, tipus[k]);
else aDesti.setObject(k+1, columnValues[k]);
}
System.out.println("Conta:"+conta);
aDesti.executeUpdate();
aDesti.clearParameters();
conta++;
}
aDesti.close();
rsFont.close();
st.close();
cproduccio.commit();
cproduccio.close();
cdev.close();
System.out.println("Hi han "+conta);
}
catch(Exception e)
{
e.printStackTrace(System.out);
}
}
}
El programa solo funciona si las conexiones cdev i cproduccio se corresponden con la misma base de datos aunque sea de usuarios diferentes. Si són de diferentes base de tos deja de funcionar y además para mas inri, oracle devueve el siguiente error:
java.sql.SQLSyntaxErrorException: ORA-00942: la tabla o vista no existe
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:879)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1044)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1329)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3665)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1352)
at provesmeves.ProvesMeves.main(ProvesMeves.java:83)
Además, probando cosas el error està en el setObject() cuando el objecto que paso como parametro es un clob, ya que cambie el trozo de codigo por este:
PreparedStatement aDesti=cproduccio.prepareStatement(insertum.toString());
int conta=0;
while(rsFont.next())
{
for(int k=0; k < cols; k++)
{
columnValues[k] = rsFont.getObject(columnNames[k]);
if ( rsFont.wasNull() ) aDesti.setNull(k+1, tipus[k]);
else
{
if ( tipus[k] != 2005 ) aDesti.setObject(k+1, columnValues[k]);
else
{
Clob clob = (Clob) columnValues[k];
aDesti.setClob(k+1, clob.getCharacterStream());
}
}
}
System.out.println("Conta:"+conta);
aDesti.executeUpdate();
aDesti.clearParameters();
conta++;
}
Y ahora ya funcionaba cuando las dos conexiones, cdev y cproduccio era de diferentes bases de datos.
Sólo se nos ocurre algo parecido a esto:
Dado que están definidas en la interfaz PreparedStatment las llamadas setObject, la ejecución sólo debería fallar, en mi opinión, (en algún lugar de la secuencia de llamadas) para:
a. conexión mal configurada
b. inyectar un objeto que no se corresponde (que no se puede convertir) en la columna correspondiente al índice del parámetro
c. utilizar un índice de columna incorrecto
d. utilizar una expresión sql no correcto o que hace referencia a una tabla inexistente
Ninguna de estas cosas ocurre en el ejemplo que falla (utilizando dos conexiones)
Parece que el CLOB contiene información de conexión de origen y que se utiliza de alguna manera en la conexión de destino, en la implementación que ha hecho Oracle de esta interfaz.
Esto me parece del todo incorrecto, entre otras cosas por que la información de la conexión de destino está implícita en el objeto PreparedStatemt de destino: este comportamiento es tan absurdo como sería el del caso hipotético de obtener un String de una tabla de una cierta conexión y que al llamar al SetObject correspondiente a un PreparedStatement asociado a otro conexión utilizara la table y conexión del objeto original, en cuanto lo que habíamos obtenido es el valor de una columna de una tabla de una bd, simplemente .
Este comportamiento hace que el código funcione si la conexión de origen y destino es la misma pero no si es diferente.
Lo que tampoco es aceptable es el mensaje de la excepción, java.sql.SQLSyntaxErrorException: ORA-00 942: la tabla o vista no existe, por razones obvias.
Si alguien quiere aportar algo
saludos y gracias,
Miguel