[Resolvido] Enviar parametro com nome de tabela para PreparedStatement

Olá pessoal,

  Possuo um PreparedStetement onde gostaria de passar como parâmetro o nome da tabela que vou usar.

Ex.

public void executa( String tabela ){
    stmt= con.prepareStatement("select * from ? a, produto p where a.id = p.id );
    stmt.setString( 1, tabela );
    ...
    ..
    .

Porém, quando executo pego uma exception, identificando o erro:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '‘tbhist_1’ a, produto p …

Mas se eu substituir o ‘?’ do preparedStatement e colocar o nome da tabela na mão, funciona. Só não funciona quando eu passo por parâmetro. Já dei um system.out na String do parametro e ela está saindo exatamente igual como escrevo na mão.

Alguem sabe o que pode ser ???

Nomes de tabelas e colunas não podem ser passados via “?” em PreparedStatement, apenas valores - embora não haja alguma limitação na especificação do JDBC que eu saiba, há essa limitação nos próprios bancos de dados (porque uma boa parte dos bancos de dados implementa nativa ou semi-nativamente a parte de PreparedStatements. E é por isso que para muitos bancos não é possível obter a string SQL equivalente ao PreparedStatement com os parâmetros, pelo simples motivo que essa string nunca chega a ser montada; o próprio banco recebe os parâmetros, nem chega a montar a string SQL.

Então se precisar mudar nome de tabela ou coluna, precisa ser via montagem da String mesmo, não como parâmetro “?”.

Valeu pela dica. Fiz toda query dentro de uma string sem utilizar o set do PreparedStatement.

:slight_smile:

Tópico antigo, mas se alguém pesquisar pelo google e chegar aqui, não faça a loucura descrita acima.

Se você setar parâmetros usando concatenação de strings, seu código SQL ficará vulnerável a SQL Injection, ou seja, podem digitar um comando em um campo de texto para apagar registros, tabelas ou até mesmo o próprio banco. Existem métodos específicos que fazem esse tratamento na classe PreparedStatement. O problema ao tentar passar o nome de uma tabela como parâmetro é que o método setString coloca apóstrofos (chamados de aspas simples) na string. O método getNextId(String tabela) da classe abaixo retorna o valor do Auto_increment de qualquer tabela do banco, recebendo o nome da tabela como parâmetro e setando na consulta com o método setString(). Reparem que a consulta sql tem que ter apóstrofos no nome da tabela, o que torna o método setString aplicável.

SQL
SHOW TABLE STATUS LIKE ‘nome_da_tabela’

package util;

import java.sql.Connection;
import conexao.ConnectionFactory;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

public abstract class NextId {
    
    private static Connection conexao;
    
    static {
        try {
            conexao = ConnectionFactory.getConnection();
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(NextId.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public static Long getNextId(String tabela) { 
        String sql = "SHOW TABLE STATUS LIKE ?";
        Long nextId = null;
        
        try {
            PreparedStatement stmt = conexao.prepareStatement(sql);
            stmt.setString(1, tabela);
            ResultSet rs = stmt.executeQuery();          
            
            while(rs.next()) {
                nextId = rs.getLong("Auto_increment");
            }
            
            rs.close();
            stmt.close();       
        } catch (SQLException ex) {
            JOptionPane.showMessageDialog(null, ex);
            Logger.getLogger(NextId.class.getName()).log(Level.SEVERE, null, ex);
        }
            
        return nextId;
    }    
}