将DDL与SELECT混合使用时,“错误:缓存计划不得更改结果类型”

时间:2015-12-09 14:12:37

标签: java sql postgresql jdbc

我正在通过JDBC遇到一个有趣的PostgreSQL问题(还没有在JDBC之外再现它)我得到了

  

“错误:缓存计划不得更改结果类型”

重现此问题的最简单方法是使用以下代码:

Connection c = getConnection();
c.setAutoCommit(true);
List<String> statements = Arrays.asList(
    "create table t(a int)",
    "select * from t",
    "alter table t add b int",
    "select * from t",
    "alter table t add c int",
    "select * from t",
    "alter table t add d int",
    "select * from t",
    "alter table t add e int",
    "select * from t",
    "alter table t add f int",
    "select * from t"
);

for (String statement : statements)
    try (PreparedStatement s = c.prepareStatement(statement)) {
        System.out.println(s);
        s.execute();
    }

以下代码工作正常的事实导致我假设这是JDBC驱动程序中的一个非常微妙的错误(注意,我只是删除了批处理中的第六个DDL语句):

Connection c = getConnection();
c.setAutoCommit(true);
List<String> statements = Arrays.asList(
    "create table t(a int)",
    "select * from t",
    "alter table t add b int",
    "select * from t",
    "alter table t add c int",
    "select * from t",
    "alter table t add d int",
    "select * from t",
    "alter table t add e int",
    "select * from t"
);

for (String statement : statements)
    try (PreparedStatement s = c.prepareStatement(statement)) {
        System.out.println(s);
        s.execute();
    }

似乎通过DISCARD ALL放弃所有缓存的计划应该有效,但这会让事情变得更糟:

Connection c = getConnection();
c.setAutoCommit(true);
List<String> statements = Arrays.asList(
    "create table t(a int)",
    "select * from t",
    "alter table t add b int",
    "select * from t",
    "alter table t add c int",
    "select * from t",
    "alter table t add d int",
    "select * from t",
    "alter table t add e int",
    "select * from t",
    "alter table t add f int",
    "discard all",
    "select * from t"
);

for (String statement : statements)
    try (PreparedStatement s = c.prepareStatement(statement)) {
        System.out.println(s);
        s.execute();
    }

I'm running into another error message

  

“错误:准备好的陈述”S_1“不存在”

有没有人知道解决方法?还是记录这个bug的指针?有趣的是,它似乎与default prepare threshold of 5

有关

2 个答案:

答案 0 :(得分:5)

这似乎与PostgreSQL's PREPARE_THRESHOLD, which defaults to 5 for the JDBC driver有关。

将其设置为零将解决/解决此特定问题:

 ((PGConnection) connection).setPrepareThreshold(0);

More info is also available in this stack overflow question

答案 1 :(得分:2)

禁用预准备语句太过激烈,无法解决此问题。您现在可以通过在pgjdbc连接设置上设置autosave=conservative来解决具体问题,请参阅:https://stackoverflow.com/a/48536394/924597