Estou tentando criar um clob a partir de uma seqüência de caracteres> 4000 caracteres (fornecida na variável de ligação file_data) a ser usada em um predicado Oracle SELECT abaixo:
myQuery=
select *
from dcr_mols
WHERE flexmatch(ctab,:file_data,'MATCH=ALL')=1;
Se eu adicionar TO_CLOB () round file_data, ele falha no infame limite do Oracle 4k para um varchar (é bom para <4k strings). O erro (no SQL Developer) é:
ORA-01460: unimplemented or unreasonable conversion requested
01460. 00000 - "unimplemented or unreasonable conversion requested"
FYI A função flexmatch é usada para pesquisar moléculas e é descrita aqui: http://help.accelrysonline.com/ulm/onelab/1.0/content/ulm_pdfs/direct/developers/direct_2016_developersguide.pdf
A função em si é um pouco complicada, mas a essência é que o segundo parâmetro precisa ser um clob. Portanto, minha pergunta é como converter uma variável Java bind bind_variable de mais de 4000 caracteres em um clob em sql (ou Java).
Eu tentei o método abaixo (que funciona ao inserir clobs) em Java (Spring boot 2) usando:
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", fileDataStr,Types.CLOB);
jdbcNamedParameterTemplate.query(myQuery,parameters,…
Esse método deve funcionar, mas falha com um erro de flexmatch convergido, que é o FYI:
SQL state [99999]; error code [29902]; ORA-29902: error in executing ODCIIndexStart() routine\nORA-20100:
MDL-0203: Unable to read from CLOB (csfrm=1, csid=873):
ORA-22922: nonexistent LOB value\nMDL-0021: Unable to copy LOB to string\nMDL-1051: Molstructure search query is not a valid molecule\nMDL-0976:
Molecule index search initialization failed\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 329\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 309\n; nested exception is java.sql.SQLException:
ORA-29902: error in executing ODCIIndexStart() routine\nORA-20100: MDL-0203: Unable to read from CLOB (csfrm=1, csid=873):
ORA-22922: nonexistent LOB value\nMDL-0021: Unable to copy LOB to string\nMDL-1051: Molstructure search query is not a valid molecule\nMDL-0976:
Molecule index search initialization failed\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 329\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 309\n"
Observe que estou usando o SpringBoot 2, mas não consigo obter nenhum método usando um OracleConnection (obtido do meu objeto Spring NamedParametersJdbcTemplate) para funcionar (mesmo em clobs <4k), por isso suspeito que fiz algo estúpido. Eu tentei:
@Autowired
NamedParameterJdbcTemplate jdbcNamedParameterTemplate;
OracleConnection conn = this.jdbcNamedParameterTemplate.getJdbcTemplate().getDataSource().getConnection().unwrap(OracleConnection.class);
Clob myClob = conn.createClob();
myClob.setString( 1, fileDataStr);
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", myClob,Types.CLOB);
application.properties:
spring.datasource.url=jdbc:oracle:thin:@//${ORA_HOST}:${ORA_PORT}/${ORA_SID}
spring.datasource.username=${ORA_USER}
spring.datasource.password=${ORA_PASS}
Observe que funciona bem se eu for para o ensino médio e usar uma conexão sem mola, além de um PreparedStatement, que possui um método setClob ():
OracleDataSource ods = new OracleDataSource();
String url ="jdbc:oracle:thin:@//" + ORA_HOST +":"+ORA_PORT +"/"+ORA_SID;
ods.setURL(url);
ods.setUser(user);
ods.setPassword(passwd);
Connection conn = ods.getConnection();
Clob myClob=conn.createClob();
PreparedStatement ps = conn.prepareStatement("select dcr_number from dcr_mols WHERE flexmatch(ctab,?,'MATCH=ALL')=1");
myClob.setString(1,myMol);
ps.setClob(1,myClob);
ResultSet rs =ps.executeQuery();
Mas eu preferiria uma solução Spring 2 em Java ou Sql. Qualquer ajuda, sugestões apreciadas.
flexmatch()
função? Eu gostaria de ver a necessidade disso. Sinceramente, nunca usei grandes valores como parâmetros naWHERE
cláusula. Eu os useiINSERT
e os recuperei usandoSELECT
. Seu caso é diferente.Respostas:
Transmita-o. Você não pode simplesmente colar um valor enorme em uma instrução SQL.
Você precisará:
INSERT
instrução (usando EMPTY_BLOB ()? ... não me lembro).Essa é a maneira padrão de lidar com dados massivos no Oracle. Muitos exemplos por aí.
A recuperação de dados (
BLOB
eCLOB
tipos) massivos funciona da mesma maneira. Basta usar InputStreams nesse caso.fonte
Lendo a documentação da API "BIOVIA Direct", há um exemplo interessante na página 27, trecho mostrado abaixo:
Ele usa um CLOB já carregado . Portanto, acho que uma solução suficientemente decente seria carregar o CLOB em uma tabela sua (ou pré-carregá-los todos com antecedência) e depois usá-los.
Etapa 1 - Carregue seu CLOB em uma tabela:
E use seu código Java para executar a inserção CLOB (provavelmente usando fluxos), como mostrado em outra resposta (muitos exemplos na Internet). Por exemplo, insira seu conteúdo de dados mol com ID =
123
.Etapa 2 - Execute sua consulta usando o arquivo mol já carregado:
Você pode definir o
:id
parâmetro para123
usar o arquivo carregado anteriormente (ou qualquer outro).fonte
Você pode chamar sua função antiga como esta. crie uma classe para manipular o ResultSet
e chame sua consulta usando o JdbcTemplate no seu método
fonte
Eu tive que voltar a usar um PreparedStatement, mas aprimorei um pouco a implementação normal obtendo a conexão do Spring e usando o apache commons BeanListHandler para mapear o ResultSet para um objeto List
fonte
Você pode declarar fileDataStr como CLOB usando con, que é a conexão
e depois use como abaixo
Além disso, se você estiver usando o SID em vez do nome do serviço na cadeia de conexão, tente alterar o arquivo de propriedades como abaixo
fonte