Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2887,6 +2887,7 @@ private Map<String, Object> 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);

Expand Down Expand Up @@ -2955,6 +2956,7 @@ private Map<Long, Map<Integer, Map<String, Object>>> 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();
Expand Down Expand Up @@ -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 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude:

Name and javadoc describe the wrong thing. prepareThreshold=0 stops pgjdbc from using a named server-side prepared statement, along with its cached result description. It doesn't really "disable plan caching." Something like useUnnamedStatement or disableServerPrepare would keep a future Oracle or SQL Server override from implementing the wrong behaviour. The existing // do not cache this statement comment above each call now means two different things.

I had to look it up to see what prepareThreshold did, but specifies the limit where if the driver uses a client-side preparedStatement threshold number of times, then it creates a server-side prepared statement to use for future calls. Setting it to 0 instructs the client to not create the server-side prepare.

// nop for most drivers
}

protected void close(Statement statement) {
try {
DbUtils.close(statement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*/
Comment on lines +1 to +8

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chore: fix file header


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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both Claude and Gemini suggested adding this guard for safety against a non-pgjdbc driver.

Suggested change
statement.unwrap(PGStatement.class).setPrepareThreshold(0);
if (statement.isWrapperFor(PGStatement.class)) {
statement.unwrap(PGStatement.class).setPrepareThreshold(0);
}

}

}
Loading