[Meio resolvido] Erro a executar via código Java um bloco anônimo em um script sql!

11 respostas
andersonrc

Olá pessoal.

Estou com problemas ao executar via código Java, um bloco anônimo em arquivo sql.

É o seguinte: já testei via aplicação Java, para que seja feito um insert em uma tabela, a partir de um script sql e deu certo. Agora estou tendo problemas caso eu tente executar via aplicação Java, um script sql que tenha um bloco anônimo.

Eu já coloquei pra executar esse bloco anônimo no SQL Developer e funcionou perfeitamente. Mas, como devo executar apenas via código Java, peguei o código desse bloco anônimo e coloquei em uma única linha no script sql

Tá dando essa excessão aqui

Exception: ORA-06550: linha 1, coluna 455:
PLS-00103: Encontrado o símbolo "end-of-file" quando um dos seguintes símbolos era esperado:

   ; <um identificador>
   <um identificador delimitado por aspas duplas>
O símbolo ";" foi substituído por "end-of-file" para continuar.


Script SQL executado com sucesso!
java.sql.SQLException: ORA-06550: linha 1, coluna 455:
PLS-00103: Encontrado o símbolo "end-of-file" quando um dos seguintes símbolos era esperado:

Alguém sabe como posso resolver isso? Se eu consegui fazer um insert, então porque um bloco anônimo não dá certo?

Abaixo o script que funcionou no SQL Developer

BEGIN
	FOR C IN (SELECT CODCATEGORIA FROM CATEGORIA WHERE CODCATEGORIA = ? )
	LOOP
		FOR L IN (SELECT CODLIVRO COD FROM LIVRO WHERE CODCATEGORIA = C.CODCATEGORIA)
		LOOP
			FOR E IN (SELECT CODEMPRESTIMO FROM EMPRESTIMO WHERE CODLIVRO = L.COD)
			LOOP
				DELETE EMPRESTIMO WHERE CODLIVRO = L.COD;
			END LOOP;
			
			DELETE LIVRO WHERE CODLIVRO = L.COD;
		END LOOP;
	
		DELETE CATEGORIA WHERE CODCATEGORIA = C.CODCATEGORIA;
		
		COMMIT;
		
	END LOOP;
END;

E abaixo, o mesmo script, em uma única linha que está sendo chamado no arquivo sql.

BEGIN 	FOR C IN (SELECT CODCATEGORIA FROM CATEGORIA WHERE CODCATEGORIA = 2 ) 	LOOP 		FOR L IN (SELECT CODLIVRO COD FROM LIVRO WHERE CODCATEGORIA = C.CODCATEGORIA) 		LOOP 			FOR E IN (SELECT CODEMPRESTIMO FROM EMPRESTIMO WHERE CODLIVRO = L.COD) 			LOOP 				DELETE EMPRESTIMO WHERE CODLIVRO = L.COD; 			END LOOP; 			 			DELETE LIVRO WHERE CODLIVRO = L.COD; 		END LOOP; 	 		DELETE CATEGORIA WHERE CODCATEGORIA = C.CODCATEGORIA; 		 		COMMIT; 		 	END LOOP; END;

11 Respostas

julianosts

andersonnrc blz?

Seu codigo esta assim mesmo? td em maisuculas?

Posta teu codigo todo, fica melhor para ajudar voce…

abs

andersonrc

julianosts:
andersonnrc blz?

Seu codigo esta assim mesmo? td em maisuculas?

Posta teu codigo todo, fica melhor para ajudar voce…

abs

Oi julianosts, tudo certo.

O código está todo em maiúsculo sim.

Abaixo o método que executa o script. O método executarScriptsInsercao eu não fiz, ele está sendo chamado de um jar

public void executeSQL(String arquivo) {

		String caminhoDatasetPrimario;
		try {
			caminhoDatasetPrimario = inf.getFilePrecondicao(arquivo);
			this.schema.executarScriptsInsercao(caminhoDatasetPrimario, inf.getPath());
		} catch (FileNotFoundException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		} catch (IOException e) {
			e.getMessage();
		}	

	}
public class LeitorDados {
	
	private LoadProperties prop = new LoadProperties();

        public String getFilePrecondicao(String file) throws FileNotFoundException, IOException{
		String caminho = this.getClass().getResource(prop.getProperties("preCondicao") + file + ".sql").getFile();
		return caminho;
	}
}
public class LoadProperties {

	public String getProperties(String chave) throws FileNotFoundException, IOException{
		
		Properties properties = new Properties();
		properties.load(new InputStreamReader(this.getClass().getResourceAsStream("/propriedades.properties")));
		return properties.getProperty(chave);
	}
	
}
A

e o código desse método executarScriptsInsercao, tem como vc postar?

andersonrc

Cara, eu vou atrás desse código, pq só me passaram o jar. Não tenho ele aqui.

andersonrc

Usei o Java Decompiler pra ver o código do .class

Acho que o problema está no fato de haver essa verificação aqui if (linha1.trim().endsWith(";")) Em um comando DML como tem uma única vírgula em um linha, não há problema, mas como o código que tenho aqui é um bloco anônimo, com várias vírgulas em uma única linha não funciona.

protected ArrayList<String> extrairScriptsSqlArquivo(File f)
	    throws IOException
	  {
	    ArrayList scripts = new ArrayList();
	    FileReader fr = new FileReader(f);
	    BufferedReader buffReader = new BufferedReader(fr);

	    String comando = "";
	    String linha;
	    while ((linha = buffReader.readLine()) != null)
	    {
	      String linha1 = null;
	      if (linha1.trim().endsWith(";")) {
	        comando = comando + " " + linha1.substring(0, linha1.lastIndexOf(';'));
	        scripts.add(comando);

	        comando = "";
	      } else {
	        comando = comando + linha1.trim();
	      }
	    }

	    fr.close();
	    return scripts;
	  }
andersonrc

Tentei fazer uma alteração. Como o bloco anônimo contém 25 vírgulas, coloquei um contador. Se for igual a 25, deveria extrair o sql do script e adicionar no comando, mas, ele nem chega a passar daqui if (linha1.trim().endsWith(";")) {

protected ArrayList&lt;String&gt; extrairScriptsSqlArquivo(File f)
	    throws IOException
	  {
	    ArrayList scripts = new ArrayList();
	    FileReader fr = new FileReader(f);
	    BufferedReader buffReader = new BufferedReader(fr);

	    String comando = "";
	    String linha;
	    while ((linha = buffReader.readLine()) != null)
	    {
	      String linha1 = null;
	      if (linha1.trim().endsWith(";")) {
	    	  int count = 0;
	    	  if (linha1.equals(";")) {
	    		  count++;
	    	  }
	    	  if (count == 25) {
	        comando = comando + " " + linha1.substring(0, linha1.lastIndexOf(';'));
	        scripts.add(comando);
	        comando = "";
	    	  }
	      } else {
	        comando = comando + linha1.trim();
	      }
	    }

	    fr.close();
	    return scripts;
	  }
A

Mas então… dentro do loop você tem na linha 13:

Não importa quantas vezes o loop executar… o teste da linha 14 sempre vai dar false, não é? e no restante do código… nada muda o valor dessa variável linha1… acho que precisa rever isso aí, mano…

andersonrc

Não tô saindo do lugar. Tô pensando em estudar alguma classe, e eu mesmo criar um método para que a partir de um arquivo sql, não apenas um comando DML, como tbm um bloco anônimo possa ser executado via aplicação Java. A classe StringBuilder resolveria meu problema? E como eu trataria essa questão de ter várias vírgulas em uma única linha?

A

StringBuilder por si só não é o suficiente, porque basicamente, substituiria uma concatenação de Strings que se faz assim:

String a = "uma coisa"; a = a + "alguma outra coisa";
por

StringBuilder a = new StringBuilder("uma coisa"); a.append("alguma outra coisa");

Seu problema está em outro lugar. A classe que você tinha inicialmente suportava uma sequência de disparos de inserts, e agora você precisa enviar um bloco de execução de comando, tentando usar a mesma classe.

Havia um furo na lógica do último código correto? não conseguiu contornar isso? Ainda acho possível consertar isso… continue postando seus códigos e com certeza uma hora a solução aparece. ou dê uma olhada vê se ajuda:
http://www.javadocexamples.com/java/sql/Statement/addBatch(String%20sql).html

andersonrc

ADEMILTON:
StringBuilder por si só não é o suficiente, porque basicamente, substituiria uma concatenação de Strings que se faz assim:

String a = "uma coisa"; a = a + "alguma outra coisa";
por

StringBuilder a = new StringBuilder("uma coisa"); a.append("alguma outra coisa");

Seu problema está em outro lugar. A classe que você tinha inicialmente suportava uma sequência de disparos de inserts, e agora você precisa enviar um bloco de execução de comando, tentando usar a mesma classe.

Havia um furo na lógica do último código correto? não conseguiu contornar isso? Ainda acho possível consertar isso… continue postando seus códigos e com certeza uma hora a solução aparece. ou dê uma olhada vê se ajuda:
http://www.javadocexamples.com/java/sql/Statement/addBatch(String%20sql).html

Valeu pela ajuda ADEMILTON, mas a forma que consegui resolver foi não usando mais um bloco anônimo, e sim criando uma procedure no Oracle, e depois eu só faço executar a procedure na classe Java

CallableStatement cs = connection.getConnection().prepareCall("{ call exclui_categoria(?) }");

Pelo que eu pude ver, e tentar, não é possível deixar um bloco anônimo ou um procedimento em uma única linha de arquivo com vários pontos e vírgulas, para que esse código seja lido via Java.

A

Acredito que não precisava criar uma stored procedure para isso.

Neste link há um exemplo de como fazer: http://dbaspot.com/oracle-server/383427-help-how-call-pl-sql-anonymous-block-java.html

Provavelmente no código antigo ele estava preparado para executar uma série de comandos (INSERTS) diferentes.
Isso é diferente de executar um bloco inteiro de uma vez.

E para executar o bloco você também não precisa se preocupar com os ;
Jogue tudo numa String e execute de uma vez.

Criado 12 de janeiro de 2012
Ultima resposta 14 de jan. de 2012
Respostas 11
Participantes 4