我正在使用第三方库在数据库PgBulkInsert中进行批量插入。它需要插入通常需要30分钟并在30秒内执行的插入内容。我们注意到超时会导致磁盘使用率泄漏,但是我们发现执行table reindex似乎可以纠正此问题。我正在尝试使用我的JPA实体管理器执行本机更新。以下代码有效,但包含潜在的SQL注入漏洞。
@Stateless
public class ReindexService {
@PersistenceContext(unitName = "my-ds")
private EntityManager em;
public void reindexTable(String table) {
String queryStr = "REINDEX TABLE " + table;
Query query = em.createNativeQuery(queryStr);
query.executeUpdate();
}
}
当我传递字符串“ alert”以索引警报表时,它会产生以下SQL输出
/* dynamic native SQL query */ REINDEX TABLE alert
当我尝试使用位置参数时,会产生SQL错误
String queryStr = "REINDEX TABLE ?";
Query query = em.createNativeQuery(queryStr);
query.setParameter(1, table);
query.executeUpdate();
这将产生以下错误输出
/* dynamic native SQL query */ REINDEX TABLE ?
SQL Error: 0, SQLState: 42601
ERROR: syntax error at or near "$1"
Position: 46
[尝试使用名称参数时出现类似错误
String queryStr = "REINDEX TABLE :table";
Query query = em.createNativeQuery(queryStr);
query.setParameter("table", table);
query.executeUpdate();
这将产生相同的错误
/* dynamic native SQL query */ REINDEX TABLE ?
SQL Error: 0, SQLState: 42601
ERROR: syntax error at or near "$1"
Position: 46
有人知道如何使用我的实体管理器以不添加SQL注入漏洞的方式调用本地Postgresql重新索引表命令吗?我正在使用Hibernate 5.3.6.Final,但希望使用非实现特定的解决方案。
我也尝试访问Connection并执行JDBC调用,这似乎给出了错误
final Session session = //get session from entity manager
session.doWork(conn -> {
try (PreparedStatement stmt = conn.prepareCall(REINDEX TABLE ?)) {
stmt.setString(1, table);
stmt.execute();
}
});
产生与上述相同的错误
SQL Error: 0, SQLState: 42601
ERROR: syntax error at or near "$1"
Position: 15
标识符不能作为参数传递。如果您不希望表名来自用户输入(听起来有些奇怪),则可以尝试使用要重新索引的所有表的枚举,然后将枚举值传递给服务(仅连接字符串) )。
如果您确实希望表名来自不受信任的来源,则可以尝试将标识符括在双引号中并转义现有的双引号。
PostgreSQL中还有一个函数quote_ident,可用于正确引用标识符。因此,您可以创建一个存储过程,该存储过程从JPA代码中获取常规参数,并使用quote_ident和EXECUTE构造的查询。