Hola a todos, estoy teniendo problemas con un código que ataca a una base de datos Oracle.
El tema es que los usuarios que rellenan los campos de una base de datos, estan de alguna forma metiendo caracteres extraños en la base de datos que luego cuando enviamos por el webservice no se reconocen correctamente. El caracter en si es una especie de apostrofe o comilla simple, pero no es tal.
El código hex del caracter es el 0x91, 0x92, 0x93 y 0x94.
El problema es que no podemos lanzar una query de update, porque los campos Clobs hay alguno que ocupa muchisimos caracteres y la Oracle nos dice que el buffer no tiene tanto tamaño para almacenar datos. Así que la opcion que hemos pensado es usar una utilidad Java que se encargue de obtener el texto del Clob , haga el replace, y actualice la base de datos con el nuevo texto.
A la funcion, le pasamos una tabla (string->nombreTabla) y el resultado de la query sobre esta tabla, y por cada campo de ese ResultSet detecta si es un CLOB o un VARCHAR2/CHAR y aplica la funcion de limpiaCaracteres. (previamente ya hemos puesto solo los campos en la SELECT que sean CLOB/VARCHAR2/CHAR). El problema que me da es que la primera row la hace correctamente, pero a la segunda falla.
El error que suelta Java (por culpa de la Oracle es):
RESULTSET ROWS == 793 ## COLS == 31
## ROWID: [AALYTiAAFAAABlkAAA] TABLA: [gsbtas01] > Commit ##
## ROWID: [AALYTiAAFAAABlnAAB] TABLA: [gsbtas01] > Failure ## Fallo al cargar datos en el campo CAT_PREVIS
## ERROR: Se ejecuto Rollback
-------------- STACKTRACE INIT -------------
java.sql.SQLException: ORA-22990: LOB locators cannot span transactions
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:283)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:278)
at oracle.jdbc.driver.T4C8TTILob.receiveReply(T4C8TTILob.java:930)
at oracle.jdbc.driver.T4C8TTIClob.write(T4C8TTIClob.java:435)
at oracle.jdbc.driver.T4CConnection.putChars(T4CConnection.java:2666)
at oracle.sql.CLOB.putChars(CLOB.java:433)
at oracle.sql.CLOB.setString(CLOB.java:910)
at utilitat.UtilitatCaractersExtranys.actualizaRegistrosEnTabla(UtilitatCaractersExtranys.java:267)
at utilitat.UtilitatCaractersExtranys.execute(UtilitatCaractersExtranys.java:355)
at utilitat.UtilitatCaractersExtranys.main(UtilitatCaractersExtranys.java:60)
-------------- STACKTRACE END --------------
platform@eSecretary:/usr/local/zonas/zona_autentica$ java utilitat.UtilitatCaractersExtranys
spoiler private void actualizaRegistrosEnTabla(String tabla, ResultSet cursor) throws Exception {
int rows = this.getNumRegistres(cursor);
int cols = cursor.getMetaData().getColumnCount();
System.out.println("\n\tRESULTSET ROWS == " + rows + " ## COLS == " + cols);
String update = "";
String columns_for_update;
Clob clob = null;
if (cols > 1) {
// Posicionamos el cursor al principio del resultset (pointer -> fantasma_init)
cursor.beforeFirst();
columns_for_update = "";
// Por cada row en el ResultSet
update = "UPDATE " + tabla + " SET $$FIELDS$$ WHERE rowid = '$$ROWID$$'";
// For para los campos que tenemos que actualizar
// i = 2 , porque no nos interesa el rowid , pero es que las columnas de resultset comienzan por 1!!!! de ahi 1 + rowid = 2
for (int i = 2; i <= cols; i++) {
columns_for_update += cursor.getMetaData().getColumnName(i) + " = ? ";
if ((i + 1) <= cols) {
columns_for_update += ", ";
}
}
update = update.replace("$$FIELDS$$", columns_for_update);
String field_value = "";
String field_name = "";
while (cursor.next()) {
// Preparamos UPDATE
String rowid = cursor.getString("ROWID");
String update_for_rowid = update.replace("$$ROWID$$", rowid); // Copiamos la query y le asignamos su rowid!
try {
this.conOrcl.setAutoCommit(false);
PreparedStatement stmt = conOrcl.prepareStatement(update_for_rowid, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); // Creamos el statement para el registro
// Añadiremos al statement los campos
for (int i = 2; i <= cols; i++) {
int posicionEnStatement = i - 1;
field_value = "";
field_name = cursor.getMetaData().getColumnName(i);
int fieldType = cursor.getMetaData().getColumnType(i);
switch (fieldType) {
case Types.CLOB:
clob = cursor.getClob(i);
if (clob != null) {
field_value = clob.getSubString(1, (int) clob.length());
field_value = this.limpiaCaractersEstranys(field_value);
}
clob.setString(1, field_value);
stmt.setClob(posicionEnStatement, clob);
break;
case Types.CHAR:
case Types.VARCHAR:
// VARCHAR2 o CHAR
field_value = cursor.getString(i);
field_value = this.limpiaCaractersEstranys(this.cleanNullString(field_value));
stmt.setString(posicionEnStatement, field_value);
break;
default:
System.out.println("TIPO DE COLUMNA NO ESPERADO PARA EL CAMPO " + cursor.getMetaData().getColumnName(i) + " :\n");
System.out.println("ID [" + cursor.getMetaData().getColumnType(i) + "] TIPO = " + cursor.getMetaData().getColumnTypeName(i));
// Si se quiere admitir otro tipo de dato, entonces añadelo al SWITCH!
throw new Exception("Tipo de campo no soportado! Si quieres soportarlo añadelo en el switch!\n");
}
}
// Una vez ya hemos mapeado los valores a sus campos, entonces ejecutamos el update
stmt.execute();
this.conOrcl.commit();
System.out.println("## ROWID: [" + rowid + "] TABLA: [" + tabla + "] > Commit ##");
} catch (Exception e) {
this.conOrcl.rollback();
System.out.println("## ROWID: [" + rowid + "] TABLA: [" + tabla + "] > Failure ## Fallo al cargar datos en el campo " + field_name);
System.out.println("## ERROR: Se ejecuto Rollback ");
System.out.println("-------------- STACKTRACE INIT -------------");
e.printStackTrace();
System.out.println("-------------- STACKTRACE END --------------\n");
System.exit(-1);
}
}
this.conOrcl.setAutoCommit(true);
} else {
System.out.println("\n\tERROR: El numero de columnas para tabla " + tabla + " no es mayor a 1 --> COLS: " + cols + " - Skipping");
}
}
private String cleanNullString(String str) {
String retorno = "";
if (str == null) {
return retorno;
}
if (str.equalsIgnoreCase("null")) {
return retorno;
}
if (str.equalsIgnoreCase("(null)")) {
return retorno;
}
retorno = str.trim();
return retorno;
}