From 2ad11006573ab187c277973613367dda22c35d9d Mon Sep 17 00:00:00 2001 From: Mitch Gaffigan Date: Mon, 21 Sep 2026 00:08:34 -0500 Subject: [PATCH] Fix 500 after metadata schema changes Postgres would have intermittent 500 errors after a metadata column changed from one type to another. Fix that. Issue: https://github.com/OpenIntegrationEngine/engine/issues/458 Signed-off-by: Mitch Gaffigan --- .../donkey/server/data/jdbc/JdbcDao.java | 10 ++++++ .../data/jdbc/PostgresqlDaoFactory.java | 9 +++++ .../server/data/jdbc/PostgresqlJdbcDao.java | 35 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PostgresqlJdbcDao.java diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDao.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDao.java index 999b863f0c..ad4f748482 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDao.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDao.java @@ -2887,6 +2887,7 @@ private Map getMetaDataMap(String channelId, long messageId, int // do not cache this statement since metadata columns may be added/removed statement = connection.prepareStatement(querySource.getQuery("getMetaDataMap", values)); + disableServerSidePlanCache(statement); statement.setLong(1, messageId); statement.setInt(2, metaDataId); @@ -2955,6 +2956,7 @@ private Map>> getMetaDataMaps(String chan // do not cache this statement since metadata columns may be added/removed statement = connection.prepareStatement(querySource.getQuery("getMetaDataMapByMessageId", values)); + disableServerSidePlanCache(statement); resultSet = statement.executeQuery(); ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); @@ -3094,6 +3096,14 @@ PreparedStatement prepareStatement(String queryId, String channelId) throws SQLE return statementSource.getPreparedStatement(queryId, localChannelId); } + /** + * Stops the driver from caching a server-side plan for one statement where the schema may have + * changed from query to query. + */ + protected void disableServerSidePlanCache(PreparedStatement statement) throws SQLException { + // nop for most drivers + } + protected void close(Statement statement) { try { DbUtils.close(statement); diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PostgresqlDaoFactory.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PostgresqlDaoFactory.java index da72f47388..7e79b17982 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PostgresqlDaoFactory.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PostgresqlDaoFactory.java @@ -9,13 +9,17 @@ package com.mirth.connect.donkey.server.data.jdbc; +import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.mirth.connect.donkey.server.Donkey; +import com.mirth.connect.donkey.server.channel.Statistics; import com.mirth.connect.donkey.server.data.DonkeyDaoException; +import com.mirth.connect.donkey.server.data.StatisticsUpdater; import com.mirth.connect.donkey.util.SerializerProvider; public class PostgresqlDaoFactory extends JdbcDaoFactory { @@ -33,6 +37,11 @@ public JdbcDao getDao(SerializerProvider serializerProvider) { return dao; } + @Override + protected JdbcDao getDao(Donkey donkey, Connection connection, QuerySource querySource, PreparedStatementSource statementSource, SerializerProvider serializerProvider, boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData, boolean decryptData, StatisticsUpdater statisticsUpdater, Statistics currentStats, Statistics totalStats, String statsServerId) { + return new PostgresqlJdbcDao(donkey, connection, querySource, statementSource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId); + } + private String getAsyncCommitCommand(JdbcDao dao) { if (supported == null) { try { diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PostgresqlJdbcDao.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PostgresqlJdbcDao.java new file mode 100644 index 0000000000..07c272542e --- /dev/null +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PostgresqlJdbcDao.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) Mirth Corporation. All rights reserved. + * + * http://www.mirthcorp.com + * + * The software in this package is published under the terms of the MPL license a copy of which has + * been included with this distribution in the LICENSE.txt file. + */ + +package com.mirth.connect.donkey.server.data.jdbc; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import org.postgresql.PGStatement; + +import com.mirth.connect.donkey.server.Donkey; +import com.mirth.connect.donkey.server.channel.Statistics; +import com.mirth.connect.donkey.server.data.StatisticsUpdater; +import com.mirth.connect.donkey.util.SerializerProvider; + +public class PostgresqlJdbcDao extends JdbcDao { + + public PostgresqlJdbcDao(Donkey donkey, Connection connection, QuerySource querySource, PreparedStatementSource statementSource, SerializerProvider serializerProvider, boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData, boolean decryptData, StatisticsUpdater statisticsUpdater, Statistics currentStats, Statistics totalStats, String statsServerId) { + super(donkey, connection, querySource, statementSource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId); + } + + /** Excludes a statement from caching. Required when schema changes at runtime. */ + @Override + protected void disableServerSidePlanCache(PreparedStatement statement) throws SQLException { + statement.unwrap(PGStatement.class).setPrepareThreshold(0); + } + +}