Hi all.
According to the JDBC-spec. the returned Array
from con.createArrayOf
should bee call free()
on after usage.
Lacking this results in:
2022.03.10 18:32:49:793 [PG-JDBC I/O (1)] [TTUF] [] [] ERROR com.impossibl.shadow.io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
Created at:
com.impossibl.shadow.io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:402)
com.impossibl.shadow.io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:187)
com.impossibl.shadow.io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:178)
com.impossibl.shadow.io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:115)
com.impossibl.shadow.io.netty.buffer.ByteBufUtil.writeUtf8(ByteBufUtil.java:623)
com.impossibl.postgres.jdbc.PGBuffersArray.encode(PGBuffersArray.java:126)
com.impossibl.postgres.jdbc.PGBuffersArray.encode(PGBuffersArray.java:110)
com.impossibl.postgres.jdbc.PGBuffersArray.encode(PGBuffersArray.java:92)
com.impossibl.postgres.jdbc.PGDirectConnection.createArrayOf(PGDirectConnection.java:1230)
com.zaxxer.hikari.pool.HikariProxyConnection.createArrayOf(HikariProxyConnection.java)
org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.createArray(DatabasePlatform.java:3444)
org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.createArray(DatabasePlatform.java:3415)
org.eclipse.persistence.mappings.structures.ObjectRelationalDataTypeDescriptor.buildFieldValueFromDirectValues(ObjectRelationalDataTypeDescriptor.java:112)
org.eclipse.persistence.mappings.foundation.AbstractCompositeDirectCollectionMapping.writeFromObjectIntoRow(AbstractCompositeDirectCollectionMapping.java:625)
…using the pgjdbc-ng JDBC-driver for PostgreSQL.
createArray()
is called here in ObjectRelationalDataTypeDescriptor:
@Override
public Object buildFieldValueFromDirectValues(Vector directValues, String elementDataTypeName, AbstractSession session) throws DatabaseException {
Object[] fields = Helper.arrayFromVector(directValues);
try {
((DatabaseAccessor)session.getAccessor()).incrementCallCount(session);
java.sql.Connection connection = ((DatabaseAccessor)session.getAccessor()).getConnection();
return session.getPlatform().createArray(elementDataTypeName, fields, session,connection);
} catch (java.sql.SQLException ex) {
throw DatabaseException.sqlException(ex, session, false);
} finally {
((DatabaseAccessor)session.getAccessor()).decrementCallCount();
}
}
And that value is used here in AbstractCompositeDirectCollectionMapping:
@Override
public void writeFromObjectIntoRow(Object object, AbstractRecord row, AbstractSession session, WriteType writeType) {
if (this.isReadOnly()) {
return;
}
Object attributeValue = this.getAttributeValueFromObject(object);
if (attributeValue == null) {
row.put(this.getField(), null);
return;
}
ContainerPolicy cp = this.getContainerPolicy();
Vector elements = new Vector(cp.sizeFor(attributeValue));
for (Object iter = cp.iteratorFor(attributeValue); cp.hasNext(iter);) {
Object element = cp.next(iter, session);
if (this.getValueConverter() != null) {
element = getValueConverter().convertObjectValueToDataValue(element, session);
}
if (element != null) {
elements.addElement(element);
}
}
Object fieldValue = null;
if (!elements.isEmpty()) {
fieldValue = this.getDescriptor().buildFieldValueFromDirectValues(elements, elementDataTypeName, session);
}
row.put(this.getField(), fieldValue);
}
There should be a:
if (fieldValue != null && fieldValue instanceof java.sql.Array) {
((java.sql.Array) fieldValue).free();
}
at the end of that method, and other usages of DatabasePlatform.createArray
--
Andreas Joseph Krogh
CTO / Partner - Visena AS
Mobile: +47 909 56 963