This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit a9f0fc052877b925fd5eccb19b39268f15fc0a03
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sun Jun 28 16:49:13 2026 -0400

    Immutable ParameterBindings, new BatchParameterBinding
---
 .../crypto/batch/CryptoBatchTranslator.java        |  5 +-
 .../transformer/DefaultBindingsTransformer.java    |  5 +-
 .../transformer/DefaultTransformerFactory.java     | 10 ++--
 .../crypto/transformer/TransformerFactory.java     |  4 +-
 .../merge/token/DefaultValueForNullProvider.java   |  5 +-
 .../cayenne/dbsync/merge/token/ValueForNullIT.java |  2 +-
 .../org/apache/cayenne/velocity/BindDirective.java | 12 ++--
 .../cayenne/velocity/BindEqualDirective.java       |  6 +-
 .../cayenne/velocity/BindNotEqualDirective.java    |  6 +-
 .../cayenne/velocity/BindObjectEqualDirective.java |  8 +--
 .../velocity/BindObjectNotEqualDirective.java      |  6 +-
 .../VelocitySQLTemplateTranslatorTest.java         |  4 +-
 .../apache/cayenne/access/jdbc/SelectAction.java   |  4 +-
 .../access/sqlbuilder/sqltree/ValueNode.java       |  8 ++-
 .../access/translator/ParameterBinding.java        | 70 +---------------------
 .../translator/batch/BaseBatchTranslator.java      | 12 ++--
 ...slatedBatch.java => BatchParameterBinding.java} | 16 ++---
 .../access/translator/batch/BatchRowBinder.java    |  7 +--
 .../translator/batch/DeleteBatchTranslator.java    | 12 ++--
 .../translator/batch/InsertBatchTranslator.java    |  7 ++-
 .../batch/SoftDeleteBatchTranslator.java           | 30 ++++------
 .../access/translator/batch/TranslatedBatch.java   |  8 +--
 .../translator/batch/UpdateBatchTranslator.java    | 11 ++--
 .../procedure/DefaultProcedureTranslator.java      |  6 +-
 .../access/translator/sqltemplate/Context.java     |  6 +-
 .../translator/sqltemplate/directive/Bind.java     |  7 +--
 .../sqltemplate/directive/BindEqual.java           |  5 +-
 .../sqltemplate/directive/BindNotEqual.java        |  5 +-
 .../sqltemplate/directive/BindObjectEqual.java     |  7 +--
 .../sqltemplate/directive/BindObjectNotEqual.java  |  5 +-
 .../java/org/apache/cayenne/dba/JdbcAdapter.java   | 14 ++---
 .../org/apache/cayenne/dba/db2/DB2Adapter.java     |  4 +-
 .../org/apache/cayenne/dba/derby/DerbyAdapter.java |  4 +-
 .../apache/cayenne/dba/ingres/IngresAdapter.java   |  4 +-
 .../apache/cayenne/dba/oracle/OracleAdapter.java   |  6 +-
 .../cayenne/dba/postgres/PostgresSelectAction.java |  2 +-
 .../cayenne/dba/sqlserver/SQLServerAdapter.java    |  8 +--
 .../apache/cayenne/dba/sybase/SybaseAdapter.java   |  8 +--
 .../cayenne/log/CompactSlf4jJdbcEventLogger.java   | 12 ++--
 .../apache/cayenne/log/Slf4jJdbcEventLogger.java   | 12 ++--
 .../select/DefaultObjectSelectTranslatorIT.java    |  4 +-
 .../DefaultSQLTemplateTranslatorTest.java          |  4 +-
 .../sqltemplate/parser/SQLTemplateParserTest.java  |  4 +-
 .../log/CompactSlf4jJdbcEventLoggerTest.java       |  4 +-
 44 files changed, 159 insertions(+), 230 deletions(-)

diff --git 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/batch/CryptoBatchTranslator.java
 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/batch/CryptoBatchTranslator.java
index c27423bcd..ff494b4c0 100644
--- 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/batch/CryptoBatchTranslator.java
+++ 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/batch/CryptoBatchTranslator.java
@@ -19,6 +19,7 @@
 package org.apache.cayenne.crypto.batch;
 
 import org.apache.cayenne.access.translator.ParameterBinding;
+import org.apache.cayenne.access.translator.batch.BatchParameterBinding;
 import org.apache.cayenne.access.translator.batch.BatchTranslator;
 import org.apache.cayenne.access.translator.batch.TranslatedBatch;
 import org.apache.cayenne.crypto.transformer.BindingsTransformer;
@@ -55,11 +56,11 @@ public class CryptoBatchTranslator<T extends BatchQuery> 
implements BatchTransla
     }
 
     private static ParameterBinding[] transform(
-            ParameterBinding[] bindings,
+            BatchParameterBinding[] template,
             BatchQueryRow row,
             TranslatedBatch translated,
             BindingsTransformer encryptor) {
-        ParameterBinding[] updated = translated.binder().bind(bindings, row);
+        ParameterBinding[] updated = translated.binder().bind(template, row);
         encryptor.transform(updated);
         return updated;
     }
diff --git 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultBindingsTransformer.java
 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultBindingsTransformer.java
index d3fade7bd..1f7b9be25 100644
--- 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultBindingsTransformer.java
+++ 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultBindingsTransformer.java
@@ -51,13 +51,14 @@ public class DefaultBindingsTransformer implements 
BindingsTransformer {
 
         for (int i = 0; i < len; i++) {
             ParameterBinding b = bindings[positions[i]];
-            Object transformed = transformers[i].encrypt(encryptor, 
b.getValue());
+            Object transformed = transformers[i].encrypt(encryptor, b.value());
 
             ExtendedType extendedType = transformed != null
                     ? extendedTypeMap.getRegisteredType(transformed.getClass())
                     : extendedTypeMap.getDefaultType();
 
-            b.reset(b.getStatementPosition(), transformed, extendedType);
+            bindings[positions[i]] = new ParameterBinding(b.jdbcType(), 
b.scale(), b.attribute(),
+                    b.statementPosition(), transformed, extendedType);
         }
     }
 
diff --git 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultTransformerFactory.java
 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultTransformerFactory.java
index 1d76f5097..39067dfc2 100644
--- 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultTransformerFactory.java
+++ 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/DefaultTransformerFactory.java
@@ -19,7 +19,7 @@
 package org.apache.cayenne.crypto.transformer;
 
 import org.apache.cayenne.access.jdbc.ColumnDescriptor;
-import org.apache.cayenne.access.translator.ParameterBinding;
+import org.apache.cayenne.access.translator.batch.BatchParameterBinding;
 import org.apache.cayenne.access.types.ExtendedTypeMap;
 import org.apache.cayenne.crypto.map.ColumnMapper;
 import org.apache.cayenne.crypto.transformer.bytes.BytesTransformerFactory;
@@ -91,13 +91,13 @@ public class DefaultTransformerFactory implements 
TransformerFactory {
     }
 
     @Override
-    public BindingsTransformer encryptor(ParameterBinding[] bindings, 
ExtendedTypeMap extendedTypeMap) {
+    public BindingsTransformer encryptor(BatchParameterBinding[] bindings, 
ExtendedTypeMap extendedTypeMap) {
         int len = bindings.length;
         List<Integer> cryptoColumns = null;
 
         for (int i = 0; i < len; i++) {
 
-            DbAttribute a = bindings[i].getAttribute();
+            DbAttribute a = bindings[i].attribute();
             if (columnMapper.isEncrypted(a)) {
 
                 if (cryptoColumns == null) {
@@ -116,9 +116,9 @@ public class DefaultTransformerFactory implements 
TransformerFactory {
 
             for (int i = 0; i < dlen; i++) {
                 int pos = cryptoColumns.get(i);
-                ParameterBinding b = bindings[pos];
+                BatchParameterBinding b = bindings[pos];
                 positions[i] = pos;
-                transformers[i] = 
transformerFactory.encryptor(b.getAttribute());
+                transformers[i] = transformerFactory.encryptor(b.attribute());
             }
 
             return new DefaultBindingsTransformer(positions, transformers, 
bytesTransformerFactory.encryptor(), extendedTypeMap);
diff --git 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/TransformerFactory.java
 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/TransformerFactory.java
index a2eade242..d277b33ed 100644
--- 
a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/TransformerFactory.java
+++ 
b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/TransformerFactory.java
@@ -19,7 +19,7 @@
 package org.apache.cayenne.crypto.transformer;
 
 import org.apache.cayenne.access.jdbc.ColumnDescriptor;
-import org.apache.cayenne.access.translator.ParameterBinding;
+import org.apache.cayenne.access.translator.batch.BatchParameterBinding;
 import org.apache.cayenne.access.types.ExtendedTypeMap;
 
 /**
@@ -30,7 +30,7 @@ import org.apache.cayenne.access.types.ExtendedTypeMap;
  */
 public interface TransformerFactory {
 
-    BindingsTransformer encryptor(ParameterBinding[] bindings, ExtendedTypeMap 
extendedTypeMap);
+    BindingsTransformer encryptor(BatchParameterBinding[] bindings, 
ExtendedTypeMap extendedTypeMap);
 
     MapTransformer decryptor(ColumnDescriptor[] columns, Object sampleRow);
 }
diff --git 
a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/token/DefaultValueForNullProvider.java
 
b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/token/DefaultValueForNullProvider.java
index 5f77227cf..848e31540 100644
--- 
a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/token/DefaultValueForNullProvider.java
+++ 
b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/token/DefaultValueForNullProvider.java
@@ -35,8 +35,7 @@ public class DefaultValueForNullProvider implements 
ValueForNullProvider {
     public void set(DbEntity entity, DbAttribute column, Object value, int 
type) {
         // the binding is only ever read for its value (inlined into the 
UPDATE below), never bound to a
         // statement, so the position is irrelevant here
-        ParameterBinding binding = new ParameterBinding(type, 
column.getAttributePrecision())
-                .reset(1, value, null);
+        ParameterBinding binding = new ParameterBinding(type, 
column.getAttributePrecision(), null, 1, value, null);
         values.put(createKey(entity, column), binding);
     }
 
@@ -52,7 +51,7 @@ public class DefaultValueForNullProvider implements 
ValueForNullProvider {
 
         // TODO: change things so it is possible to use prepared statements 
here
         return Collections.singletonList("UPDATE " + 
entity.getFullyQualifiedName()
-                + " SET " + column.getName() + "='" + value.getValue() + "' 
WHERE " + column.getName() + " IS NULL");
+                + " SET " + column.getName() + "='" + value.value() + "' WHERE 
" + column.getName() + " IS NULL");
     }
 
     public boolean hasValueFor(DbEntity entity, DbAttribute column) {
diff --git 
a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/ValueForNullIT.java
 
b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/ValueForNullIT.java
index 0d3d615d7..74dc582f6 100644
--- 
a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/ValueForNullIT.java
+++ 
b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/token/ValueForNullIT.java
@@ -105,7 +105,7 @@ public class ValueForNullIT extends MergeCase {
                 int type = column.getType();
                 switch (type) {
                     case Types.VARCHAR:
-                        return new ParameterBinding(type, -1).reset(1, 
DEFAULT_VALUE_STRING, null);
+                        return new ParameterBinding(type, -1, null, 1, 
DEFAULT_VALUE_STRING, null);
                     default:
                         throw new AssertionError("should not get here");
                 }
diff --git 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindDirective.java 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindDirective.java
index 2c2b3d438..99c727553 100644
--- 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindDirective.java
+++ 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindDirective.java
@@ -133,7 +133,7 @@ public class BindDirective extends Directive {
                                        + ") at line " + node.getLine() + ", 
column " + node.getColumn());
                }
 
-               render(context, writer, new 
ParameterBinding(preferredBindingType(context, jdbcType), scale), value);
+               render(context, writer, preferredBindingType(context, 
jdbcType), scale, value);
        }
 
        /**
@@ -149,10 +149,10 @@ public class BindDirective extends Directive {
                return (DbAdapter) 
context.getInternalUserContext().get(VelocitySQLTemplateTranslator.ADAPTER_KEY);
        }
 
-       protected void render(InternalContextAdapter context, Writer writer, 
ParameterBinding binding, Object value)
+       protected void render(InternalContextAdapter context, Writer writer, 
int jdbcType, int scale, Object value)
                        throws IOException {
 
-               bind(context, binding, value);
+               bind(context, jdbcType, scale, value);
                writer.write('?');
        }
 
@@ -163,7 +163,7 @@ public class BindDirective extends Directive {
        /**
         * Adds value to the list of bindings in the context.
         */
-       protected void bind(InternalContextAdapter context, ParameterBinding 
binding, Object value) {
+       protected void bind(InternalContextAdapter context, int jdbcType, int 
scale, Object value) {
 
                @SuppressWarnings("unchecked")
                Collection<ParameterBinding> bindings = 
(Collection<ParameterBinding>)
@@ -172,8 +172,8 @@ public class BindDirective extends Directive {
                if (bindings != null) {
                        // a binding's statement position is its 1-based 
ordinal among the bound parameters; the
                        // ExtendedType is resolved from the value via the 
adapter
-                       binding.reset(bindings.size() + 1, value, 
extendedType(context, value));
-                       bindings.add(binding);
+                       bindings.add(new ParameterBinding(jdbcType, scale, null,
+                                       bindings.size() + 1, value, 
extendedType(context, value)));
                }
        }
 
diff --git 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindEqualDirective.java
 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindEqualDirective.java
index af8916d47..a36a9c94f 100644
--- 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindEqualDirective.java
+++ 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindEqualDirective.java
@@ -22,7 +22,6 @@ package org.apache.cayenne.velocity;
 import java.io.IOException;
 import java.io.Writer;
 
-import org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.velocity.context.InternalContextAdapter;
 
 /**
@@ -43,12 +42,13 @@ public class BindEqualDirective extends BindDirective {
     protected void render(
         InternalContextAdapter context,
         Writer writer,
-        ParameterBinding binding,
+        int jdbcType,
+        int scale,
         Object value)
         throws IOException {
 
         if (value != null) {
-            bind(context, binding, value);
+            bind(context, jdbcType, scale, value);
             writer.write("= ?");
         }
         else {
diff --git 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindNotEqualDirective.java
 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindNotEqualDirective.java
index f25bf7992..8590c15ec 100644
--- 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindNotEqualDirective.java
+++ 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindNotEqualDirective.java
@@ -22,7 +22,6 @@ package org.apache.cayenne.velocity;
 import java.io.IOException;
 import java.io.Writer;
 
-import org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.velocity.context.InternalContextAdapter;
 
 /**
@@ -43,11 +42,12 @@ public class BindNotEqualDirective extends BindDirective {
     protected void render(
             InternalContextAdapter context,
             Writer writer,
-            ParameterBinding binding,
+            int jdbcType,
+            int scale,
             Object value) throws IOException {
 
         if (value != null) {
-            bind(context, binding, value);
+            bind(context, jdbcType, scale, value);
             writer.write("<> ?");
         }
         else {
diff --git 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindObjectEqualDirective.java
 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindObjectEqualDirective.java
index 9662cb710..9659cc2db 100644
--- 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindObjectEqualDirective.java
+++ 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindObjectEqualDirective.java
@@ -27,7 +27,6 @@ import java.util.Map;
 
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
-import org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.velocity.context.InternalContextAdapter;
 import org.apache.velocity.exception.MethodInvocationException;
@@ -94,7 +93,7 @@ public class BindObjectEqualDirective extends BindDirective {
 
             renderColumn(context, writer, sqlColumnsArray[i], i);
             writer.write(' ');
-            render(context, writer, new 
ParameterBinding(preferredBindingType(context, jdbcType), -1), value);
+            render(context, writer, preferredBindingType(context, jdbcType), 
-1, value);
         }
 
         return true;
@@ -151,11 +150,12 @@ public class BindObjectEqualDirective extends 
BindDirective {
     protected void render(
             InternalContextAdapter context,
             Writer writer,
-            ParameterBinding binding,
+            int jdbcType,
+            int scale,
             Object value) throws IOException {
 
         if (value != null) {
-            bind(context, binding, value);
+            bind(context, jdbcType, scale, value);
             writer.write("= ?");
         }
         else {
diff --git 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindObjectNotEqualDirective.java
 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindObjectNotEqualDirective.java
index 70afc50ff..73e501d58 100644
--- 
a/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindObjectNotEqualDirective.java
+++ 
b/cayenne-velocity/src/main/java/org/apache/cayenne/velocity/BindObjectNotEqualDirective.java
@@ -21,7 +21,6 @@ package org.apache.cayenne.velocity;
 import java.io.IOException;
 import java.io.Writer;
 
-import org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.velocity.context.InternalContextAdapter;
 
 /**
@@ -57,11 +56,12 @@ public class BindObjectNotEqualDirective extends 
BindObjectEqualDirective {
     protected void render(
             InternalContextAdapter context,
             Writer writer,
-            ParameterBinding binding,
+            int jdbcType,
+            int scale,
             Object value) throws IOException {
 
         if (value != null) {
-            bind(context, binding, value);
+            bind(context, jdbcType, scale, value);
             writer.write("<> ?");
         }
         else {
diff --git 
a/cayenne-velocity/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateTranslatorTest.java
 
b/cayenne-velocity/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateTranslatorTest.java
index ae96a6e18..82770ab51 100644
--- 
a/cayenne-velocity/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateTranslatorTest.java
+++ 
b/cayenne-velocity/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateTranslatorTest.java
@@ -240,11 +240,11 @@ public class VelocitySQLTemplateTranslatorTest {
 
        private void assertBindingValue(Object expectedValue, Object binding) {
                assertTrue(binding instanceof ParameterBinding, "Not a 
binding!");
-               assertEquals(expectedValue, ((ParameterBinding) 
binding).getValue());
+               assertEquals(expectedValue, ((ParameterBinding) 
binding).value());
        }
 
        private void assertBindingType(Integer expectedType, Object binding) {
                assertTrue(binding instanceof ParameterBinding, "Not a 
binding!");
-               assertEquals(expectedType, ((ParameterBinding) 
binding).getJdbcType());
+               assertEquals(expectedType, ((ParameterBinding) 
binding).jdbcType());
        }
 }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java 
b/cayenne/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
index 1414cb3da..f960bc8bb 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/jdbc/SelectAction.java
@@ -79,8 +79,8 @@ public class SelectAction extends BaseSQLAction {
             // processing (qualifier can't map parameters to DbAttributes
             // and therefore only supports standard java types now) hence, a
             // special moronic case here:
-            if (b.getAttribute() == null) {
-                statement.setObject(b.getStatementPosition(), b.getValue());
+            if (b.attribute() == null) {
+                statement.setObject(b.statementPosition(), b.value());
             } else {
                 adapter.bindParameter(statement, b);
             }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValueNode.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValueNode.java
index 2e442e414..c8f3038da 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValueNode.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/ValueNode.java
@@ -133,11 +133,13 @@ public class ValueNode extends Node {
 
         // 'attribute' is only a type hint and may be absent (e.g. function 
arguments and other
         // literals not bound to a column); fall back to deriving the JDBC 
type from the value
+        int statementPosition = context.getBindings().size() + 1;
         ParameterBinding binding = (attribute != null)
-                ? new 
ParameterBinding(context.getAdapter().preferredBindingType(attribute.getType()),
 attribute.getScale(), attribute)
-                : new 
ParameterBinding(context.getAdapter().preferredBindingType(TypesMapping.getSqlTypeByJava(value.getClass())),
 -1);
+                ? new 
ParameterBinding(context.getAdapter().preferredBindingType(attribute.getType()),
+                        attribute.getScale(), attribute, statementPosition, 
value, extendedType)
+                : new 
ParameterBinding(context.getAdapter().preferredBindingType(TypesMapping.getSqlTypeByJava(value.getClass())),
+                        -1, null, statementPosition, value, extendedType);
 
-        binding.reset(context.getBindings().size() + 1, value, extendedType);
         context.getBindings().add(binding);
     }
 
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/ParameterBinding.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/ParameterBinding.java
index b4fc6869b..492db5da7 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/ParameterBinding.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/ParameterBinding.java
@@ -22,74 +22,10 @@ import org.apache.cayenne.access.types.ExtendedType;
 import org.apache.cayenne.map.DbAttribute;
 
 /**
- * Describes a single PreparedStatement parameter binding. Partially mutable
+ * Describes a single immutable PreparedStatement parameter binding.
  *
  * @since 4.0
  */
-public class ParameterBinding<T> {
-
-    private final DbAttribute attribute;
-    private final int jdbcType;
-    private final int scale;
-
-    private T value;
-    private int statementPosition;
-    private ExtendedType<T> extendedType;
-
-    /**
-     * @since 5.0
-     */
-    public ParameterBinding(int jdbcType, int scale) {
-        this(jdbcType, scale, null);
-    }
-
-    /**
-     * @since 5.0
-     */
-    public ParameterBinding(int jdbcType, int scale, DbAttribute attribute) {
-        this.attribute = attribute;
-        this.jdbcType = jdbcType;
-        this.scale = scale;
-
-        this.statementPosition = -1;
-    }
-
-    /**
-     * Sets the value, statement position and {@link ExtendedType} of the 
binding.
-     *
-     * @since 5.0
-     */
-    public ParameterBinding<T> reset(int statementPosition, T value, 
ExtendedType<T> extendedType) {
-        this.statementPosition = statementPosition;
-        this.value = value;
-        this.extendedType = extendedType;
-        return this;
-    }
-
-    public T getValue() {
-        return value;
-    }
-
-    public int getStatementPosition() {
-        return statementPosition;
-    }
-
-    public ExtendedType<T> getExtendedType() {
-        return extendedType;
-    }
-
-    public int getJdbcType() {
-        return jdbcType;
-    }
-
-    public int getScale() {
-        return scale;
-    }
-
-    /**
-     * @since 5.0
-     */
-    public DbAttribute getAttribute() {
-        return attribute;
-    }
+public record ParameterBinding<T>(int jdbcType, int scale, DbAttribute 
attribute,
+                                  int statementPosition, T value, 
ExtendedType<T> extendedType) {
 }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BaseBatchTranslator.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BaseBatchTranslator.java
index b13db6c7f..d1ac0677a 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BaseBatchTranslator.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BaseBatchTranslator.java
@@ -44,20 +44,22 @@ public abstract class BaseBatchTranslator<T extends 
BatchQuery> implements Batch
         BatchTranslatorContext<T> context = new 
BatchTranslatorContext<>(query, adapter);
 
         String sql = createSql(context);
-        ParameterBinding[] bindings = createBindings(context);
+        BatchParameterBinding[] bindings = createBindings(context);
 
-        return new TranslatedBatch(sql, bindings, (b, row) -> 
updateBindings(context, b, row));
+        return new TranslatedBatch(sql, bindings, (template, row) -> 
updateBindings(context, template, row));
     }
 
     protected abstract String createSql(BatchTranslatorContext<T> context);
 
-    protected ParameterBinding[] createBindings(BatchTranslatorContext<T> 
context) {
-        return context.getBindings().toArray(new ParameterBinding[0]);
+    protected BatchParameterBinding[] createBindings(BatchTranslatorContext<T> 
context) {
+        return context.getBindings().stream()
+                .map(b -> new BatchParameterBinding(b.jdbcType(), b.scale(), 
b.attribute()))
+                .toArray(BatchParameterBinding[]::new);
     }
 
     protected abstract ParameterBinding[] updateBindings(
             BatchTranslatorContext<T> context,
-            ParameterBinding[] bindings,
+            BatchParameterBinding[] template,
             BatchQueryRow row);
 
     protected String doTranslate(BatchTranslatorContext<T> context, 
NodeBuilder nodeBuilder) {
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/TranslatedBatch.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BatchParameterBinding.java
similarity index 61%
copy from 
cayenne/src/main/java/org/apache/cayenne/access/translator/batch/TranslatedBatch.java
copy to 
cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BatchParameterBinding.java
index 4c81af7b2..c0b0184b4 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/TranslatedBatch.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BatchParameterBinding.java
@@ -20,21 +20,21 @@
 package org.apache.cayenne.access.translator.batch;
 
 import org.apache.cayenne.access.translator.ParameterBinding;
-import org.apache.cayenne.query.BatchQueryRow;
+import org.apache.cayenne.access.types.ExtendedType;
+import org.apache.cayenne.map.DbAttribute;
 
 /**
- * An immutable result of translating a batch query: the SQL String shared by 
all rows of the batch,
- * the widest possible array of parameter bindings, and a stateless {@link 
BatchRowBinder} that applies
- * a single row's state to those bindings.
+ * An immutable per-batch parameter binding template, carrying only the static 
column metadata shared by all
+ * rows of a batch. A per-row {@link ParameterBinding} is produced by {@link 
#bind(int, Object, ExtendedType)}.
  *
  * @since 5.0
  */
-public record TranslatedBatch(String sql, ParameterBinding[] bindings, 
BatchRowBinder binder) {
+public record BatchParameterBinding(int jdbcType, int scale, DbAttribute 
attribute) {
 
     /**
-     * Applies the given row's state to the binding template, returning the 
(reused) bindings array.
+     * Resolves this per-batch template into a per-row {@link 
ParameterBinding}.
      */
-    public ParameterBinding[] updateBindings(BatchQueryRow row) {
-        return binder.bind(bindings, row);
+    public <T> ParameterBinding<T> bind(int statementPosition, T value, 
ExtendedType<T> extendedType) {
+        return new ParameterBinding<>(jdbcType, scale, attribute, 
statementPosition, value, extendedType);
     }
 }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BatchRowBinder.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BatchRowBinder.java
index f0f8a3329..e72e31e64 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BatchRowBinder.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/BatchRowBinder.java
@@ -23,14 +23,13 @@ import 
org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.cayenne.query.BatchQueryRow;
 
 /**
- * A stateless strategy that populates a batch query's binding template with 
the values of a single
- * {@link BatchQueryRow}. The same template array is reused for every row, so 
the returned array is the
- * one passed in, only with the per-row state applied.
+ * A stateless strategy that resolves a batch query's binding templates 
against the values of a single
+ * {@link BatchQueryRow}, returning a fresh array of per-row {@link 
ParameterBinding}s.
  *
  * @since 5.0
  */
 @FunctionalInterface
 public interface BatchRowBinder {
 
-    ParameterBinding[] bind(ParameterBinding[] bindings, BatchQueryRow row);
+    ParameterBinding[] bind(BatchParameterBinding[] template, BatchQueryRow 
row);
 }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java
index 830a3e7af..ce53b24d6 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/DeleteBatchTranslator.java
@@ -48,25 +48,27 @@ public class DeleteBatchTranslator extends 
BaseBatchTranslator<DeleteBatchQuery>
     @Override
     protected ParameterBinding[] updateBindings(
             BatchTranslatorContext<DeleteBatchQuery> context,
-            ParameterBinding[] bindings,
+            BatchParameterBinding[] template,
             BatchQueryRow row) {
 
         DeleteBatchQuery deleteBatch = context.getQuery();
+        ParameterBinding[] bindings = new ParameterBinding[template.length];
         for (int i = 0, position = 0; i < 
deleteBatch.getDbAttributes().size(); i++) {
-            position = updateBinding(context, bindings, row.getValue(i), 
position);
+            position = updateBinding(context, template, bindings, 
row.getValue(i), position);
         }
         return bindings;
     }
 
     protected int updateBinding(
             BatchTranslatorContext<DeleteBatchQuery> context,
+            BatchParameterBinding[] template,
             ParameterBinding[] bindings,
             Object value, int position) {
-        
+
         // skip null attributes... they are translated as "IS NULL"
         if (value != null) {
-            ExtendedType<?> extendedType = 
context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass());
-            bindings[position].reset(++position, value, extendedType);
+            ExtendedType extendedType = 
context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass());
+            bindings[position] = template[position].bind(++position, value, 
extendedType);
         }
         return position;
     }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java
index f67545e26..8c926d66a 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/InsertBatchTranslator.java
@@ -54,8 +54,9 @@ public class InsertBatchTranslator extends 
BaseBatchTranslator<InsertBatchQuery>
 
     @Override
     protected ParameterBinding[] 
updateBindings(BatchTranslatorContext<InsertBatchQuery> context,
-                                                ParameterBinding[] bindings, 
BatchQueryRow row) {
+                                                BatchParameterBinding[] 
template, BatchQueryRow row) {
         InsertBatchQuery query = context.getQuery();
+        ParameterBinding[] bindings = new ParameterBinding[template.length];
         int i=0;
         int j=0;
         for(DbAttribute attribute : query.getDbAttributes()) {
@@ -65,10 +66,10 @@ public class InsertBatchTranslator extends 
BaseBatchTranslator<InsertBatchQuery>
             }
 
             Object value = row.getValue(i++);
-            ExtendedType<?> extendedType = value != null
+            ExtendedType extendedType = value != null
                     ? 
context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass())
                     : context.getAdapter().getExtendedTypes().getDefaultType();
-            bindings[j].reset(++j, value, extendedType);
+            bindings[j] = template[j].bind(++j, value, extendedType);
         }
         return bindings;
     }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java
index ced812e00..1f7a9963f 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslator.java
@@ -75,33 +75,25 @@ public class SoftDeleteBatchTranslator extends 
DeleteBatchTranslator {
         return doTranslate(context, updateBuilder);
     }
 
-    @Override
-    protected ParameterBinding[] 
createBindings(BatchTranslatorContext<DeleteBatchQuery> context) {
-        ParameterBinding[] bindings = super.createBindings(context);
-        if (isHardDelete(context.getQuery())) {
-            return bindings;
-        }
-
-        // the 'deleted' flag is the first binding and stays constant across 
all rows of the batch
-        DbAttribute deleteAttribute = 
context.getQuery().getDbEntity().getAttribute(deletedFieldName);
-        String typeName = TypesMapping.getJavaBySqlType(deleteAttribute);
-        ExtendedType<?> extendedType = 
context.getAdapter().getExtendedTypes().getRegisteredType(typeName);
-        bindings[0].reset(1, true, extendedType);
-
-        return bindings;
-    }
-
     @Override
     protected ParameterBinding[] 
updateBindings(BatchTranslatorContext<DeleteBatchQuery> context,
-                                                ParameterBinding[] bindings, 
BatchQueryRow row) {
+                                                BatchParameterBinding[] 
template, BatchQueryRow row) {
         DeleteBatchQuery deleteBatch = context.getQuery();
         if (isHardDelete(deleteBatch)) {
-            return super.updateBindings(context, bindings, row);
+            return super.updateBindings(context, template, row);
         }
 
+        ParameterBinding[] bindings = new ParameterBinding[template.length];
+
+        // the 'deleted' flag is the first binding and stays constant across 
all rows of the batch
+        DbAttribute deleteAttribute = 
deleteBatch.getDbEntity().getAttribute(deletedFieldName);
+        String typeName = TypesMapping.getJavaBySqlType(deleteAttribute);
+        ExtendedType extendedType = 
context.getAdapter().getExtendedTypes().getRegisteredType(typeName);
+        bindings[0] = template[0].bind(1, Boolean.TRUE, extendedType);
+
         // bindings[0] holds the constant 'deleted' flag, so qualifier values 
start at position 1
         for(int i=0, position=1; i<deleteBatch.getDbAttributes().size(); i++) {
-            position = updateBinding(context, bindings, row.getValue(i), 
position);
+            position = updateBinding(context, template, bindings, 
row.getValue(i), position);
         }
 
         return bindings;
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/TranslatedBatch.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/TranslatedBatch.java
index 4c81af7b2..1a2d8ba4c 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/TranslatedBatch.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/TranslatedBatch.java
@@ -24,15 +24,15 @@ import org.apache.cayenne.query.BatchQueryRow;
 
 /**
  * An immutable result of translating a batch query: the SQL String shared by 
all rows of the batch,
- * the widest possible array of parameter bindings, and a stateless {@link 
BatchRowBinder} that applies
- * a single row's state to those bindings.
+ * the widest possible array of per-batch binding templates, and a stateless 
{@link BatchRowBinder} that
+ * resolves a single row's state into per-row bindings.
  *
  * @since 5.0
  */
-public record TranslatedBatch(String sql, ParameterBinding[] bindings, 
BatchRowBinder binder) {
+public record TranslatedBatch(String sql, BatchParameterBinding[] bindings, 
BatchRowBinder binder) {
 
     /**
-     * Applies the given row's state to the binding template, returning the 
(reused) bindings array.
+     * Resolves the given row's state against the binding templates, returning 
a fresh per-row bindings array.
      */
     public ParameterBinding[] updateBindings(BatchQueryRow row) {
         return binder.bind(bindings, row);
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java
index 7adf35a0a..b565d9fb6 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/batch/UpdateBatchTranslator.java
@@ -55,17 +55,18 @@ public class UpdateBatchTranslator extends 
BaseBatchTranslator<UpdateBatchQuery>
 
     @Override
     protected ParameterBinding[] 
updateBindings(BatchTranslatorContext<UpdateBatchQuery> context,
-                                                ParameterBinding[] bindings, 
BatchQueryRow row) {
+                                                BatchParameterBinding[] 
template, BatchQueryRow row) {
         UpdateBatchQuery updateBatch = context.getQuery();
+        ParameterBinding[] bindings = new ParameterBinding[template.length];
 
         int i = 0;
         int j = 0;
         for(; i < updateBatch.getUpdatedAttributes().size(); i++) {
             Object value = row.getValue(i);
-            ExtendedType<?> extendedType = value == null
+            ExtendedType extendedType = value == null
                 ? context.getAdapter().getExtendedTypes().getDefaultType()
                 : 
context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass());
-            bindings[j].reset(++j, value, extendedType);
+            bindings[j] = template[j].bind(++j, value, extendedType);
         }
 
         for(DbAttribute attribute : updateBatch.getQualifierAttributes()) {
@@ -74,8 +75,8 @@ public class UpdateBatchTranslator extends 
BaseBatchTranslator<UpdateBatchQuery>
                 continue;
             }
             Object value = row.getValue(i);
-            ExtendedType<?> extendedType = 
context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass());
-            bindings[j].reset(++j, value, extendedType);
+            ExtendedType extendedType = 
context.getAdapter().getExtendedTypes().getRegisteredType(value.getClass());
+            bindings[j] = template[j].bind(++j, value, extendedType);
             i++;
         }
         return bindings;
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/DefaultProcedureTranslator.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/DefaultProcedureTranslator.java
index d4ebc13c3..dbc423bf2 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/DefaultProcedureTranslator.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/DefaultProcedureTranslator.java
@@ -81,7 +81,7 @@ public class DefaultProcedureTranslator implements 
ProcedureTranslator {
 
         // match values with parameters in the correct order, assuming a 
missing value is NULL
         if (param.getDirection() == ProcedureParameter.OUT_PARAMETER) {
-            return new ParameterBinding(param.getType(), 
param.getPrecision()).reset(position, OUT_PARAM, null);
+            return new ParameterBinding(param.getType(), param.getPrecision(), 
null, position, OUT_PARAM, null);
         }
 
         Object value = queryValues.get(param.getName());
@@ -89,8 +89,8 @@ public class DefaultProcedureTranslator implements 
ProcedureTranslator {
                 ? 
adapter.getExtendedTypes().getRegisteredType(value.getClass())
                 : adapter.getExtendedTypes().getDefaultType();
 
-        return new 
ParameterBinding(adapter.preferredBindingType(param.getType()), 
param.getPrecision())
-                .reset(position, value, extendedType);
+        return new 
ParameterBinding(adapter.preferredBindingType(param.getType()), 
param.getPrecision(), null,
+                position, value, extendedType);
     }
 
     /**
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/Context.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/Context.java
index 53d5a71ee..6b038f182 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/Context.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/Context.java
@@ -122,14 +122,14 @@ public class Context {
         return null;
     }
 
-    public void addParameterBinding(ParameterBinding binding, Object value) {
+    public void addParameterBinding(int jdbcType, int scale, Object value) {
         if(parameterBindings == null) {
             parameterBindings = new ArrayList<>();
         }
         // a binding's statement position is its 1-based ordinal among the 
bound parameters; the
         // ExtendedType is resolved from the value via the adapter
-        binding.reset(parameterBindings.size() + 1, value, 
extendedType(value));
-        parameterBindings.add(binding);
+        parameterBindings.add(new ParameterBinding(jdbcType, scale, null,
+                parameterBindings.size() + 1, value, extendedType(value)));
     }
 
     private ExtendedType<?> extendedType(Object value) {
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/Bind.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/Bind.java
index 63f1b8e67..763bfb2b7 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/Bind.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/Bind.java
@@ -22,7 +22,6 @@ package 
org.apache.cayenne.access.translator.sqltemplate.directive;
 import java.util.Collection;
 import java.util.Iterator;
 
-import org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.access.translator.sqltemplate.Context;
 import org.apache.cayenne.access.translator.sqltemplate.parser.ASTExpression;
@@ -67,11 +66,11 @@ public class Bind implements Directive {
             jdbcType = TypesMapping.getSqlTypeByName(TypesMapping.SQL_NULL);
         }
 
-        processBinding(context, new 
ParameterBinding(context.preferredBindingType(jdbcType), scale), value);
+        processBinding(context, context.preferredBindingType(jdbcType), scale, 
value);
     }
 
-    protected void processBinding(Context context, ParameterBinding binding, 
Object value) {
-        context.addParameterBinding(binding, value);
+    protected void processBinding(Context context, int jdbcType, int scale, 
Object value) {
+        context.addParameterBinding(jdbcType, scale, value);
         context.getBuilder().append('?');
     }
 }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindEqual.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindEqual.java
index 38ce70428..249d50e0f 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindEqual.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindEqual.java
@@ -19,7 +19,6 @@
 
 package org.apache.cayenne.access.translator.sqltemplate.directive;
 
-import org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.cayenne.access.translator.sqltemplate.Context;
 
 /**
@@ -30,9 +29,9 @@ public class BindEqual extends Bind {
     public static final BindEqual INSTANCE = new BindEqual();
 
     @Override
-    protected void processBinding(Context context, ParameterBinding binding, 
Object value) {
+    protected void processBinding(Context context, int jdbcType, int scale, 
Object value) {
         if (value != null) {
-            context.addParameterBinding(binding, value);
+            context.addParameterBinding(jdbcType, scale, value);
             context.getBuilder().append("= ?");
         } else {
             context.getBuilder().append("IS NULL");
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindNotEqual.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindNotEqual.java
index 723d0436e..74c4fe692 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindNotEqual.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindNotEqual.java
@@ -19,7 +19,6 @@
 
 package org.apache.cayenne.access.translator.sqltemplate.directive;
 
-import org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.cayenne.access.translator.sqltemplate.Context;
 
 /**
@@ -30,9 +29,9 @@ public class BindNotEqual extends Bind {
     public static final BindNotEqual INSTANCE = new BindNotEqual();
 
     @Override
-    protected void processBinding(Context context, ParameterBinding binding, 
Object value) {
+    protected void processBinding(Context context, int jdbcType, int scale, 
Object value) {
         if (value != null) {
-            context.addParameterBinding(binding, value);
+            context.addParameterBinding(jdbcType, scale, value);
             context.getBuilder().append("<> ?");
         } else {
             context.getBuilder().append("IS NOT NULL");
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindObjectEqual.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindObjectEqual.java
index 2aaddc190..b6be96506 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindObjectEqual.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindObjectEqual.java
@@ -27,7 +27,6 @@ import java.util.Map;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
-import org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.access.translator.sqltemplate.Context;
 import org.apache.cayenne.access.translator.sqltemplate.parser.ASTExpression;
@@ -81,7 +80,7 @@ public class BindObjectEqual implements Directive {
             int jdbcType = (value != null) ? 
TypesMapping.getSqlTypeByJava(value.getClass()) : Types.INTEGER;
 
             renderColumn(context, sqlColumnsArray[i], i);
-            render(context, new 
ParameterBinding(context.preferredBindingType(jdbcType), -1), value);
+            render(context, context.preferredBindingType(jdbcType), -1, value);
         }
     }
 
@@ -93,9 +92,9 @@ public class BindObjectEqual implements Directive {
         context.getBuilder().append(columnName).append(' ');
     }
 
-    protected void render(Context context, ParameterBinding binding, Object 
value) {
+    protected void render(Context context, int jdbcType, int scale, Object 
value) {
         if (value != null) {
-            context.addParameterBinding(binding, value);
+            context.addParameterBinding(jdbcType, scale, value);
             context.getBuilder().append("= ?");
         } else {
             context.getBuilder().append("IS NULL");
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindObjectNotEqual.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindObjectNotEqual.java
index fbf3cc847..ef646dd2c 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindObjectNotEqual.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/sqltemplate/directive/BindObjectNotEqual.java
@@ -19,7 +19,6 @@
 
 package org.apache.cayenne.access.translator.sqltemplate.directive;
 
-import org.apache.cayenne.access.translator.ParameterBinding;
 import org.apache.cayenne.access.translator.sqltemplate.Context;
 
 /**
@@ -39,9 +38,9 @@ public class BindObjectNotEqual extends BindObjectEqual {
     }
 
     @Override
-    protected void render(Context context, ParameterBinding binding, Object 
value) {
+    protected void render(Context context, int jdbcType, int scale, Object 
value) {
         if (value != null) {
-            context.addParameterBinding(binding, value);
+            context.addParameterBinding(jdbcType, scale, value);
             context.getBuilder().append("<> ?");
         } else {
             context.getBuilder().append("IS NOT NULL");
diff --git a/cayenne/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java
index 32d39552a..8ae5d25b1 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java
@@ -625,14 +625,14 @@ public class JdbcAdapter implements DbAdapter {
     @Override
     public void bindParameter(PreparedStatement statement, ParameterBinding 
binding) throws Exception {
 
-        if (binding.getValue() == null) {
-            statement.setNull(binding.getStatementPosition(), 
binding.getJdbcType());
+        if (binding.value() == null) {
+            statement.setNull(binding.statementPosition(), binding.jdbcType());
         } else {
-            binding.getExtendedType().setJdbcObject(statement,
-                    binding.getValue(),
-                    binding.getStatementPosition(),
-                    binding.getJdbcType(),
-                    binding.getScale());
+            binding.extendedType().setJdbcObject(statement,
+                    binding.value(),
+                    binding.statementPosition(),
+                    binding.jdbcType(),
+                    binding.scale());
         }
     }
 
diff --git a/cayenne/src/main/java/org/apache/cayenne/dba/db2/DB2Adapter.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/db2/DB2Adapter.java
index 39b425a2d..32cd4a7b5 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/db2/DB2Adapter.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/db2/DB2Adapter.java
@@ -191,8 +191,8 @@ public class DB2Adapter extends JdbcAdapter {
 
     @Override
     public void bindParameter(PreparedStatement statement, ParameterBinding 
binding) throws Exception {
-        if (binding.getValue() == null && (binding.getJdbcType() == 0 || 
binding.getJdbcType() == Types.BOOLEAN)) {
-            statement.setNull(binding.getStatementPosition(), Types.VARCHAR);
+        if (binding.value() == null && (binding.jdbcType() == 0 || 
binding.jdbcType() == Types.BOOLEAN)) {
+            statement.setNull(binding.statementPosition(), Types.VARCHAR);
         } else {
             super.bindParameter(statement, binding);
         }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/dba/derby/DerbyAdapter.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/derby/DerbyAdapter.java
index c43c09bd2..eb501c233 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/derby/DerbyAdapter.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/derby/DerbyAdapter.java
@@ -219,8 +219,8 @@ public class DerbyAdapter extends JdbcAdapter {
             PreparedStatement statement,
             ParameterBinding binding) throws SQLException, Exception {
 
-        if (binding.getValue() == null && binding.getJdbcType() == 0) {
-            statement.setNull(binding.getStatementPosition(), Types.VARCHAR);
+        if (binding.value() == null && binding.jdbcType() == 0) {
+            statement.setNull(binding.statementPosition(), Types.VARCHAR);
         } else {
             super.bindParameter(statement, binding);
         }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/dba/ingres/IngresAdapter.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/ingres/IngresAdapter.java
index 3c09248fb..01186b61e 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/ingres/IngresAdapter.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/ingres/IngresAdapter.java
@@ -118,8 +118,8 @@ public class IngresAdapter extends JdbcAdapter {
     @Override
     public void bindParameter(PreparedStatement statement, ParameterBinding 
binding) throws Exception {
 
-        if (binding.getValue() == null && (binding.getJdbcType() == 
Types.BIT)) {
-            statement.setNull(binding.getStatementPosition(), Types.SMALLINT);
+        if (binding.value() == null && (binding.jdbcType() == Types.BIT)) {
+            statement.setNull(binding.statementPosition(), Types.SMALLINT);
         } else {
             super.bindParameter(statement, binding);
         }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java
index 3dd44c372..273b1e872 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/oracle/OracleAdapter.java
@@ -266,10 +266,10 @@ public class OracleAdapter extends JdbcAdapter {
         // Oracle doesn't support BOOLEAN even when binding NULL, so have to
         // intercept
         // NULL Boolean here, as super doesn't pass it through ExtendedType...
-        if (binding.getValue() == null && binding.getJdbcType() == 
Types.BOOLEAN) {
+        if (binding.value() == null && binding.jdbcType() == Types.BOOLEAN) {
             ExtendedType typeProcessor = 
getExtendedTypes().getRegisteredType(Boolean.class);
-            typeProcessor.setJdbcObject(statement, binding.getValue(), 
binding.getStatementPosition(), binding
-                    .getJdbcType(), binding.getScale());
+            typeProcessor.setJdbcObject(statement, binding.value(), 
binding.statementPosition(), binding
+                    .jdbcType(), binding.scale());
         } else {
             super.bindParameter(statement, binding);
         }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/dba/postgres/PostgresSelectAction.java
 
b/cayenne/src/main/java/org/apache/cayenne/dba/postgres/PostgresSelectAction.java
index e7993a564..3be731f71 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/dba/postgres/PostgresSelectAction.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/dba/postgres/PostgresSelectAction.java
@@ -81,7 +81,7 @@ class PostgresSelectAction extends SelectAction {
                }
                // a large object bound as a parameter (e.g. in a qualifier) 
also needs a transaction
                for (ParameterBinding binding : translated.bindings()) {
-                       if (isLargeObject(binding.getJdbcType())) {
+                       if (isLargeObject(binding.jdbcType())) {
                                return true;
                        }
                }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
index fb627cb89..e1712ffd7 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
@@ -141,13 +141,13 @@ public class SQLServerAdapter extends JdbcAdapter {
     public void bindParameter(PreparedStatement statement, ParameterBinding 
binding) throws Exception {
 
         // SQL Server driver doesn't like CLOBs and BLOBs as parameters
-        if (binding.getValue() == null) {
-            int jdbcType = switch (binding.getJdbcType()) {
+        if (binding.value() == null) {
+            int jdbcType = switch (binding.jdbcType()) {
                 case Types.CLOB, 0 -> Types.VARCHAR;
                 case Types.BLOB -> Types.VARBINARY;
-                default -> binding.getJdbcType();
+                default -> binding.jdbcType();
             };
-            statement.setNull(binding.getStatementPosition(), jdbcType);
+            statement.setNull(binding.statementPosition(), jdbcType);
         } else {
             super.bindParameter(statement, binding);
         }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/dba/sybase/SybaseAdapter.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/sybase/SybaseAdapter.java
index fecddc056..17d250abd 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/sybase/SybaseAdapter.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/sybase/SybaseAdapter.java
@@ -146,13 +146,13 @@ public class SybaseAdapter extends JdbcAdapter {
     public void bindParameter(PreparedStatement statement, ParameterBinding 
binding) throws Exception {
 
         // Sybase driver doesn't like CLOBs and BLOBs as parameters
-        if (binding.getValue() == null) {
-            int jdbcType = switch (binding.getJdbcType()) {
+        if (binding.value() == null) {
+            int jdbcType = switch (binding.jdbcType()) {
                 case Types.CLOB, 0 -> Types.VARCHAR;
                 case Types.BLOB -> Types.VARBINARY;
-                default -> binding.getJdbcType();
+                default -> binding.jdbcType();
             };
-            statement.setNull(binding.getStatementPosition(), jdbcType);
+            statement.setNull(binding.statementPosition(), jdbcType);
         } else {
             super.bindParameter(statement, binding);
         }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/log/CompactSlf4jJdbcEventLogger.java 
b/cayenne/src/main/java/org/apache/cayenne/log/CompactSlf4jJdbcEventLogger.java
index c28c37f97..8606ee5a3 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/log/CompactSlf4jJdbcEventLogger.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/log/CompactSlf4jJdbcEventLogger.java
@@ -112,19 +112,19 @@ public class CompactSlf4jJdbcEventLogger extends 
Slf4jJdbcEventLogger {
         String key = null;
         String value;
         for (ParameterBinding b : bindings) {
-            DbAttribute attribute = b.getAttribute();
+            DbAttribute attribute = b.attribute();
             if (attribute != null) {
                 key = attribute.getName();
             }
 
-            if (b.getExtendedType() != null) {
-                value = b.getExtendedType().toString(b.getValue());
-            } else if (b.getValue() == null) {
+            if (b.extendedType() != null) {
+                value = b.extendedType().toString(b.value());
+            } else if (b.value() == null) {
                 value = "NULL";
             } else {
-                value = b.getValue().getClass().getName() +
+                value = b.value().getClass().getName() +
                         "@" +
-                        System.identityHashCode(b.getValue());
+                        System.identityHashCode(b.value());
             }
 
             List<String> objects = bindingsMap.computeIfAbsent(key, k -> new 
ArrayList<>());
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/log/Slf4jJdbcEventLogger.java 
b/cayenne/src/main/java/org/apache/cayenne/log/Slf4jJdbcEventLogger.java
index 0b62d1a32..322ce5705 100644
--- a/cayenne/src/main/java/org/apache/cayenne/log/Slf4jJdbcEventLogger.java
+++ b/cayenne/src/main/java/org/apache/cayenne/log/Slf4jJdbcEventLogger.java
@@ -110,7 +110,7 @@ public class Slf4jJdbcEventLogger implements 
JdbcEventLogger {
 
                                buffer.append(j++);
 
-                               DbAttribute attribute = b.getAttribute();
+                               DbAttribute attribute = b.attribute();
                                if (attribute != null) {
                                        buffer.append("->");
                                        buffer.append(attribute.getName());
@@ -118,14 +118,14 @@ public class Slf4jJdbcEventLogger implements 
JdbcEventLogger {
 
                                buffer.append(":");
 
-                               if (b.getExtendedType() != null) {
-                                       
buffer.append(b.getExtendedType().toString(b.getValue()));
-                               } else if(b.getValue() == null) {
+                               if (b.extendedType() != null) {
+                                       
buffer.append(b.extendedType().toString(b.value()));
+                               } else if(b.value() == null) {
                                    buffer.append("NULL");
                 } else {
-                                       
buffer.append(b.getValue().getClass().getName())
+                                       
buffer.append(b.value().getClass().getName())
                             .append("@")
-                            .append(System.identityHashCode(b.getValue()));
+                            .append(System.identityHashCode(b.value()));
                                }
                        }
 
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/translator/select/DefaultObjectSelectTranslatorIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/translator/select/DefaultObjectSelectTranslatorIT.java
index bdea314f4..e53b927a4 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/access/translator/select/DefaultObjectSelectTranslatorIT.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/translator/select/DefaultObjectSelectTranslatorIT.java
@@ -72,8 +72,8 @@ public class DefaultObjectSelectTranslatorIT {
         assertTrue(sql.indexOf("WHERE") > sql.indexOf("JOIN PAINTING t1"));
 
         assertEquals(2, translator.bindings().length);
-        assertEquals("ARTIST_NAME", 
translator.bindings()[0].getAttribute().getName());
-        assertEquals("PAINTING_TITLE", 
translator.bindings()[1].getAttribute().getName());
+        assertEquals("ARTIST_NAME", 
translator.bindings()[0].attribute().getName());
+        assertEquals("PAINTING_TITLE", 
translator.bindings()[1].attribute().getName());
 
         assertEquals(3, translator.resultColumns().length);
         assertEquals("ARTIST_NAME", 
translator.resultColumns()[0].dataRowKey());
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/translator/sqltemplate/DefaultSQLTemplateTranslatorTest.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/translator/sqltemplate/DefaultSQLTemplateTranslatorTest.java
index 79e27c3e2..33351bb88 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/access/translator/sqltemplate/DefaultSQLTemplateTranslatorTest.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/translator/sqltemplate/DefaultSQLTemplateTranslatorTest.java
@@ -236,12 +236,12 @@ public class DefaultSQLTemplateTranslatorTest {
 
     private void assertBindingValue(Object expectedValue, Object binding) {
         assertTrue(binding instanceof ParameterBinding, "Not a binding!");
-        assertEquals(expectedValue, ((ParameterBinding) binding).getValue());
+        assertEquals(expectedValue, ((ParameterBinding) binding).value());
     }
 
     private void assertBindingType(Integer expectedType, Object binding) {
         assertTrue(binding instanceof ParameterBinding, "Not a binding!");
-        assertEquals(expectedType, ((ParameterBinding) binding).getJdbcType());
+        assertEquals(expectedType, ((ParameterBinding) binding).jdbcType());
     }
 
 }
\ No newline at end of file
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/translator/sqltemplate/parser/SQLTemplateParserTest.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/translator/sqltemplate/parser/SQLTemplateParserTest.java
index 8121d768f..a7e713635 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/access/translator/sqltemplate/parser/SQLTemplateParserTest.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/translator/sqltemplate/parser/SQLTemplateParserTest.java
@@ -96,7 +96,7 @@ public class SQLTemplateParserTest {
         String sql = parseString(template, context);
         assertEquals("SELECT  ?  FROM a", sql);
         assertEquals(1, context.getParameterBindings().length);
-        assertEquals("var", context.getParameterBindings()[0].getValue());
+        assertEquals("var", context.getParameterBindings()[0].value());
     }
 
     @Test
@@ -129,7 +129,7 @@ public class SQLTemplateParserTest {
                 "     \tAND \n" +
                 "COLUMN2 ?\n\n", sql);
         assertEquals(2, context.getParameterBindings().length);
-        assertEquals("aaaa", context.getParameterBindings()[0].getValue());
+        assertEquals("aaaa", context.getParameterBindings()[0].value());
     }
 
     @Test
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/log/CompactSlf4jJdbcEventLoggerTest.java
 
b/cayenne/src/test/java/org/apache/cayenne/log/CompactSlf4jJdbcEventLoggerTest.java
index f78db4021..210d0363e 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/log/CompactSlf4jJdbcEventLoggerTest.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/log/CompactSlf4jJdbcEventLoggerTest.java
@@ -111,8 +111,6 @@ public class CompactSlf4jJdbcEventLoggerTest {
 
     private ParameterBinding createBinding(String name, int position, Object 
object, ExtendedType type){
         DbAttribute attribute = new DbAttribute(name);
-        ParameterBinding binding = new ParameterBinding(attribute.getType(), 
-1, attribute);
-        binding.reset(position, object, type);
-        return binding;
+        return new ParameterBinding(attribute.getType(), -1, attribute, 
position, object, type);
     }
 }

Reply via email to