HSQLDB 意外令牌:?

Posted

技术标签:

【中文标题】HSQLDB 意外令牌:?【英文标题】:HSQLDB unexpected token:? 【发布时间】:2017-02-14 09:26:45 【问题描述】:

我有一个使用 HSQLDB 的 JAVAFX 项目。在尝试设置表的 SOURCE 时,我得到一个我认为我理解的异常,但由于我无法修复它,我想我不明白它。 我的 SQL 是:

DROP TABLE temp IF EXISTS;
CREATE TEXT TABLE temp(text_data LONGVARCHAR(10000));
SET TABLE temp SOURCE ?;
INSERT INTO log(typ, json) SELECT SUBSTRING(text_data, 3, LOCATE('"', text_data, 3)-3),text_data FROM temp WHERE text_data <> '';
DROP TABLE temp IF EXISTS;

多个语句在这里对我不起作用,现在这应该不是问题。我将上面的 sql 拆分为字符串的 ArrayList,每一行都是一个元素。所以我得到了这个 Java 代码:

s = c.createStatement();
for (String sql : sqls) 
  System.out.println("sql: " + sql);
  if (sql.contains("?")) 
    System.out.println("in ? part");
    PreparedStatement ps = c.prepareStatement(sql);

    ps.setString(1, path.toUri().toString() + ";encoding=UTF-8;ignore_first=false;fs=\\n\\r");
    System.out.println("ps prepared" + ps.toString());
    ps.execute();
   else 
    s.execute(sql);
  

我的应用程序在PreparedStatement ps = c.prepareStatement(sql); 行失败,但有以下异常:

java.sql.SQLSyntaxErrorException: unexpected token: ? in statement [SET TABLE temp SOURCE ?;]
    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 myfile in the line I pointed out above
    at anotherofmyfiles
    at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.hsqldb.HsqlException: unexpected token: ?
    at org.hsqldb.error.Error.parseError(Unknown Source)
    at org.hsqldb.ParserBase.unexpectedToken(Unknown Source)
    at org.hsqldb.ParserBase.checkIsValue(Unknown Source)
    at org.hsqldb.ParserBase.readQuotedString(Unknown Source)
    at org.hsqldb.ParserCommand.compileTableSource(Unknown Source)
    at org.hsqldb.ParserCommand.compileSetTable(Unknown Source)
    at org.hsqldb.ParserCommand.compileSet(Unknown Source)
    at org.hsqldb.ParserCommand.compilePart(Unknown Source)
    at org.hsqldb.ParserCommand.compileStatement(Unknown Source)
    at org.hsqldb.Session.compileStatement(Unknown Source)
    at org.hsqldb.StatementManager.compile(Unknown Source)
    at org.hsqldb.Session.execute(Unknown Source)
    ... 7 more

之前有这个输出:

sql: DROP TABLE temp IF EXISTS;
sql: CREATE TEXT TABLE temp(text_data LONGVARCHAR(10000));
sql: SET TABLE temp SOURCE ?;
in ? part

我知道ps.setString(1, path.toUri().toString() + ";encoding=UTF-8;ignore_first=false;fs=\\n\\r"); 在语义上可能不完全正确,但在语法上它应该可以工作,并且由于错误在此之前它不应该是导致此错误的原因。当我在没有该行的情况下运行应用程序时,会发生同样的错误。

所以我的问题是:SET TABLE temp SOURCE ?; 有什么问题?为什么我不能将它用作 Java 中的 PreparedStatement?正如我从documentation 了解到的,语法是SET TABLE &lt;tablename&gt; SOURCE &lt;quoted_filename_and_options&gt;,其中&lt;quoted_filename_and_options&gt; 是一个字符串。我不能用 Java 准备吗?

【问题讨论】:

【参考方案1】:

PreparedStatements 被发送到底层 SQL 引擎进行编译。允许使用参数的位置取决于驱动程序和引擎。通常它们只在非常特定的地方受到支持,否则无法真正编译语句。

考虑一个只包含“?”的 PreparedStatement,并提供一个参数:

 ps.setString(1, "SELECT * FROM myTable");

无法编译,因此被拒绝。

因此,大多数 SQL 数据库仅支持 INSERT/UPDATE/SELECTS 中通常会出现简单值的位置的参数。它们不能用于字段名、表名等。

【讨论】:

这是一个很好的观点,谢谢。我想我会将此标记为答案,因为您回答了我的问题。您对如何将表的 SOURCE 设置为参数有什么建议吗? 好吧,你自己替换? 的明显方法是可行的,但可能会让你容易受到 SQL 注入攻击,具体取决于该字符串的来源。您必须首先清理输入以确保它不能用于此类目的。通常这样做的方法是严格限制您可以使用正则表达式放在那里的内容。

以上是关于HSQLDB 意外令牌:?的主要内容,如果未能解决你的问题,请参考以下文章

HSQL 触发意外令牌 NEW

HSQL - 意外的令牌:语句中的 PROCEDURE

使用列名作为 inteval expr 时,hsqldb 的 date_add 函数中出现意外标记

HSQLDB 在触发器中声明行

解析错误:意外的令牌,预期的“,”和语法错误:意外的令牌'['[重复]

休眠错误消息:意外令牌:NULLS(脚本文件行中的错误:13 意外令牌:NULLS)