首页 > 解决方案 > CREATE USER 和 CREATE ROLE as PreparedStatement with ? 占位符

问题描述

我正在尝试以CREATE USER允许使用参数的方式从 Java 代码中针对 HSQLDB 数据库发出语句。

但是,以下行:

connection.prepareStatement("CREATE USER ? PASSWORD ?;");

抛出异常:

java.sql.SQLSyntaxErrorException: unexpected token: ? in statement [CREATE USER ? PASSWORD ?;]
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCPreparedStatement.<init>(Unknown Source)
    at org.hsqldb.jdbc.JDBCConnection.prepareStatement(Unknown Source)
    at (somewhere in my code)

同样的情况发生在

connection.prepareStatement("CREATE ROLE ?;");

当然,我可以?通过将值直接粘贴到语句中来组装不带 的字符串,尽管这会为 SQL 注入带来一些可能性。

所以我想知道为什么占位符不起作用。这些声明是否完全支持它们?还是我错过了其他东西?

标签: jdbcparametersprepared-statement

解决方案


一般来说,数据库只允许在 DML 中使用参数,而不是在 DDL 中。而在 DML 中,它只允许用于values。在 and 的情况下CREATE USERCREATE ROLE您不处理值(至少不是用户名或角色名),因此这些参数化是不可能的。这类似于不允许在 select 语句中使用表名或列名的参数。

理论上,像密码这样的东西CREATE PASSWORD是一个值并且可以参数化,但实际上这是不可能的(至少,我不知道),因为所有 DDL 都被处理为不可参数化。

作为一种针对 SQL 注入的次要保护形式,自 JDBC 4.3(在 Java 9 中引入)以来,您可以使用Statement.enquoteIdentifier引用标识符以及Statement.enquoteLiteral密码等文字。这些方法有一个默认实现,但是如果您使用的是带有非标准标识符引号的平台(例如 MySQL),那么您必须确保它实际上被覆盖(在当前版本的 MySQL Connector/ 中不是这种情况) J阿法伊克)。


推荐阅读