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 178cd4b1e79cacf8cc5f9e007eab2075f228576e
Author: Andrus Adamchik <[email protected]>
AuthorDate: Fri Jul 3 16:55:05 2026 -0400

    Introducing CSParameter for translated stored procedures
---
 .../CSParameter.java}                              | 17 +++--
 .../cayenne/access/jdbc/ProcedureAction.java       | 12 +--
 .../procedure/DefaultProcedureTranslator.java      | 19 ++---
 .../translator/procedure/TranslatedProcedure.java  |  5 +-
 .../java/org/apache/cayenne/dba/AutoAdapter.java   |  7 ++
 .../java/org/apache/cayenne/dba/DbAdapter.java     |  9 +++
 .../java/org/apache/cayenne/dba/JdbcAdapter.java   | 32 ++++++--
 .../org/apache/cayenne/dba/db2/DB2Adapter.java     | 11 +--
 .../apache/cayenne/dba/db2/DB2ProcedureAction.java |  2 +-
 .../org/apache/cayenne/dba/derby/DerbyAdapter.java | 12 +--
 .../apache/cayenne/dba/ingres/IngresAdapter.java   | 12 +--
 .../cayenne/dba/mysql/MySQLProcedureAction.java    |  2 +-
 .../apache/cayenne/dba/oracle/OracleAdapter.java   | 21 ++----
 .../cayenne/dba/sqlserver/SQLServerAdapter.java    | 15 ++--
 .../dba/sqlserver/SQLServerProcedureAction.java    |  2 +-
 .../apache/cayenne/dba/sybase/SybaseAdapter.java   | 15 ++--
 .../org/apache/cayenne/log/JdbcEventLogger.java    |  6 ++
 .../apache/cayenne/log/NoopJdbcEventLogger.java    |  5 ++
 .../apache/cayenne/log/Slf4jJdbcEventLogger.java   | 87 +++++++++++++++-------
 19 files changed, 188 insertions(+), 103 deletions(-)

diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/TranslatedProcedure.java
 b/cayenne/src/main/java/org/apache/cayenne/access/jdbc/CSParameter.java
similarity index 70%
copy from 
cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/TranslatedProcedure.java
copy to cayenne/src/main/java/org/apache/cayenne/access/jdbc/CSParameter.java
index 66b08651f..56994423b 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/TranslatedProcedure.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/jdbc/CSParameter.java
@@ -16,16 +16,23 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
+package org.apache.cayenne.access.jdbc;
 
-package org.apache.cayenne.access.translator.procedure;
-
-import org.apache.cayenne.access.jdbc.PSParameter;
+import org.apache.cayenne.access.types.ExtendedType;
 import org.apache.cayenne.map.ProcedureParameter;
 
 /**
- * An immutable result of translating a {@link 
org.apache.cayenne.query.ProcedureQuery} to a stored procedure call.
+ * Describes a single immutable CallableStatement parameter binding, pairing a 
bound value with the
+ * {@link ProcedureParameter} that describes it.
  *
  * @since 5.0
  */
-public record TranslatedProcedure(String sql, PSParameter<?>[] bindings, 
ProcedureParameter[] callParams) {
+public record CSParameter<T>(
+        T value,
+        int psPosition,
+        int psType,
+        int psScale,
+        ExtendedType<T> binder,
+        ProcedureParameter param
+) {
 }
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/jdbc/ProcedureAction.java 
b/cayenne/src/main/java/org/apache/cayenne/access/jdbc/ProcedureAction.java
index 6befd015d..22ad8c1e5 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/jdbc/ProcedureAction.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/jdbc/ProcedureAction.java
@@ -73,7 +73,7 @@ public class ProcedureAction extends BaseSQLAction {
                TranslatedProcedure translated = 
dataNode.getProcedureTranslator()
                                .translate(query, dataNode.getAdapter(), 
dataNode.getEntityResolver());
 
-               dataNode.getJdbcEventLogger().logQuery(translated.sql(), 
translated.bindings());
+               dataNode.getJdbcEventLogger().logQuery(translated.sql(), 
translated.params());
 
                try (CallableStatement statement = 
connection.prepareCall(translated.sql())) {
                        initStatement(statement);
@@ -129,11 +129,11 @@ public class ProcedureAction extends BaseSQLAction {
         */
        protected void bindParameters(CallableStatement statement, 
TranslatedProcedure translated) throws Exception {
                DbAdapter adapter = dataNode.getAdapter();
-               ProcedureParameter[] callParams = translated.callParams();
-               PSParameter<?>[] bindings = translated.bindings();
+               CSParameter<?>[] params = translated.params();
 
-               for (int i = 0; i < callParams.length; i++) {
-                       ProcedureParameter param = callParams[i];
+               for (int i = 0; i < params.length; i++) {
+                       CSParameter<?> binding = params[i];
+                       ProcedureParameter param = binding.param();
 
                        if (param.isOutParam()) {
                                int precision = param.getPrecision();
@@ -145,7 +145,7 @@ public class ProcedureAction extends BaseSQLAction {
                        }
 
                        if (param.isInParameter()) {
-                               adapter.bindParameter(statement, bindings[i]);
+                               adapter.bindParameter(statement, binding);
                        }
                }
        }
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 1294ca38b..86743164f 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
@@ -19,7 +19,7 @@
 
 package org.apache.cayenne.access.translator.procedure;
 
-import org.apache.cayenne.access.jdbc.PSParameter;
+import org.apache.cayenne.access.jdbc.CSParameter;
 import org.apache.cayenne.access.types.ExtendedType;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.map.EntityResolver;
@@ -63,25 +63,25 @@ public class DefaultProcedureTranslator implements 
ProcedureTranslator {
         ProcedureParameter[] callParams = 
procedure.getCallParameters().toArray(new ProcedureParameter[0]);
         Map<String, ?> queryValues = query.getParameters();
 
-        PSParameter[] bindings = new PSParameter[callParams.length];
+        CSParameter<?>[] params = new CSParameter[callParams.length];
         for (int i = 0; i < callParams.length; i++) {
-            bindings[i] = createBinding(adapter, callParams[i], queryValues, i 
+ 1);
+            params[i] = createBinding(adapter, callParams[i], queryValues, i + 
1);
         }
 
         String sql = createSqlString(procedure, callParams.length);
-        return new TranslatedProcedure(sql, bindings, callParams);
+        return new TranslatedProcedure(sql, params);
     }
 
     /**
-     * Builds a {@link PSParameter} for a single call parameter. IN (and 
INOUT) parameters carry the actual value
+     * Builds a {@link CSParameter} for a single call parameter. IN (and 
INOUT) parameters carry the actual value
      * and its {@link ExtendedType}; pure OUT parameters carry an "[OUT]" 
marker value so that logging renders nicely.
      */
-    protected PSParameter<?> createBinding(DbAdapter adapter, 
ProcedureParameter param,
+    protected CSParameter<?> createBinding(DbAdapter adapter, 
ProcedureParameter param,
                                         Map<String, ?> queryValues, int 
position) {
 
         // match values with parameters in the correct order, assuming a 
missing value is NULL
         if (param.getDirection() == ProcedureParameter.OUT_PARAMETER) {
-            return new PSParameter<>(OUT_PARAM, position, param.getType(), 
param.getPrecision(), null, null);
+            return new CSParameter<>(OUT_PARAM, position, param.getType(), 
param.getPrecision(), null, param);
         }
 
         Object value = queryValues.get(param.getName());
@@ -89,8 +89,9 @@ public class DefaultProcedureTranslator implements 
ProcedureTranslator {
                 ? 
adapter.getExtendedTypes().getRegisteredType(value.getClass())
                 : adapter.getExtendedTypes().getDefaultType();
 
-        return new PSParameter<>(
-                value, position, 
adapter.preferredBindingType(param.getType()), param.getPrecision(), 
extendedType, null);
+        return new CSParameter<>(
+                value, position, 
adapter.preferredBindingType(param.getType()), param.getPrecision(), 
extendedType,
+                param);
     }
 
     /**
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/TranslatedProcedure.java
 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/TranslatedProcedure.java
index 66b08651f..1aca953c2 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/TranslatedProcedure.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/access/translator/procedure/TranslatedProcedure.java
@@ -19,13 +19,12 @@
 
 package org.apache.cayenne.access.translator.procedure;
 
-import org.apache.cayenne.access.jdbc.PSParameter;
-import org.apache.cayenne.map.ProcedureParameter;
+import org.apache.cayenne.access.jdbc.CSParameter;
 
 /**
  * An immutable result of translating a {@link 
org.apache.cayenne.query.ProcedureQuery} to a stored procedure call.
  *
  * @since 5.0
  */
-public record TranslatedProcedure(String sql, PSParameter<?>[] bindings, 
ProcedureParameter[] callParams) {
+public record TranslatedProcedure(String sql, CSParameter<?>[] params) {
 }
diff --git a/cayenne/src/main/java/org/apache/cayenne/dba/AutoAdapter.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
index cf18fbc03..1c32d5c8b 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/AutoAdapter.java
@@ -22,6 +22,7 @@ package org.apache.cayenne.dba;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
+import org.apache.cayenne.access.jdbc.CSParameter;
 import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslator;
 import org.apache.cayenne.access.translator.procedure.ProcedureTranslator;
@@ -38,6 +39,7 @@ import org.apache.cayenne.query.Select;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.SQLAction;
 
+import java.sql.CallableStatement;
 import java.sql.PreparedStatement;
 import java.util.Collection;
 import java.util.List;
@@ -243,6 +245,11 @@ public class AutoAdapter implements DbAdapter {
                getAdapter().bindParameter(statement, parameter);
        }
 
+       @Override
+       public void bindParameter(CallableStatement statement, CSParameter<?> 
parameter) throws Exception {
+               getAdapter().bindParameter(statement, parameter);
+       }
+
        /**
         * @since 5.0
         */
diff --git a/cayenne/src/main/java/org/apache/cayenne/dba/DbAdapter.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/DbAdapter.java
index de0c00f4b..e81f4ed08 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/DbAdapter.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/DbAdapter.java
@@ -21,6 +21,7 @@ package org.apache.cayenne.dba;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
+import org.apache.cayenne.access.jdbc.CSParameter;
 import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslator;
 import org.apache.cayenne.access.translator.procedure.ProcedureTranslator;
@@ -35,6 +36,7 @@ import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.SQLAction;
 import org.apache.cayenne.query.Select;
 
+import java.sql.CallableStatement;
 import java.sql.PreparedStatement;
 import java.util.Collection;
 import java.util.List;
@@ -253,6 +255,13 @@ public interface DbAdapter {
      */
     void bindParameter(PreparedStatement statement, PSParameter<?> parameter) 
throws Exception;
 
+    /**
+     * Binds an object value to CallableStatement's parameter.
+     *
+     * @since 5.0
+     */
+    void bindParameter(CallableStatement statement, CSParameter<?> parameter) 
throws Exception;
+
     /**
      * Returns the JDBC type that this adapter prefers to bind for a given 
mapped JDBC type. The
      * default implementation is an identity function; adapters whose drivers 
require a different
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 f62bfb7f9..cb55bb985 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/JdbcAdapter.java
@@ -22,6 +22,7 @@ package org.apache.cayenne.dba;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
+import org.apache.cayenne.access.jdbc.CSParameter;
 import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslator;
 import org.apache.cayenne.access.translator.ejbql.JdbcEJBQLTranslator;
@@ -49,6 +50,7 @@ import org.apache.cayenne.query.Select;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.SQLAction;
 
+import java.sql.CallableStatement;
 import java.sql.PreparedStatement;
 import java.sql.Types;
 import java.util.ArrayList;
@@ -623,16 +625,30 @@ public class JdbcAdapter implements DbAdapter {
 
     @Override
     public void bindParameter(PreparedStatement statement, PSParameter<?> 
parameter) throws Exception {
+        bind(statement, parameter.value(), parameter.psPosition(), 
parameter.psType(), parameter.psScale(),
+                parameter.binder());
+    }
+
+    @Override
+    public void bindParameter(CallableStatement statement, CSParameter<?> 
parameter) throws Exception {
+        bind(statement, parameter.value(), parameter.psPosition(), 
parameter.psType(), parameter.psScale(),
+                parameter.binder());
+    }
 
-        if (parameter.value() == null) {
-            statement.setNull(parameter.psPosition(), parameter.psType());
+    /**
+     * Binds a raw value to a statement parameter. This is the single 
extension point shared by both
+     * {@code bindParameter} overloads; adapters that need database-specific 
handling (e.g. of NULLs) should
+     * override this method rather than the public overloads.
+     *
+     * @since 5.0
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected void bind(PreparedStatement statement, Object value, int 
psPosition, int psType, int psScale,
+                        ExtendedType binder) throws Exception {
+        if (value == null) {
+            statement.setNull(psPosition, psType);
         } else {
-            ExtendedType t = parameter.binder();
-            t.setJdbcObject(statement,
-                    parameter.value(),
-                    parameter.psPosition(),
-                    parameter.psType(),
-                    parameter.psScale());
+            binder.setJdbcObject(statement, value, psPosition, psType, 
psScale);
         }
     }
 
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 99ca2b389..8907a52af 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
@@ -22,7 +22,6 @@ package org.apache.cayenne.dba.db2;
 import org.apache.cayenne.dba.NativeColumnType;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
-import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslator;
 import org.apache.cayenne.access.translator.ejbql.JdbcEJBQLTranslator;
 import org.apache.cayenne.access.types.BooleanType;
@@ -190,11 +189,13 @@ public class DB2Adapter extends JdbcAdapter {
     }
 
     @Override
-    public void bindParameter(PreparedStatement statement, PSParameter<?> 
parameter) throws Exception {
-        if (parameter.value() == null && (parameter.psType() == 0 || 
parameter.psType() == Types.BOOLEAN)) {
-            statement.setNull(parameter.psPosition(), Types.VARCHAR);
+    @SuppressWarnings("rawtypes")
+    protected void bind(PreparedStatement statement, Object value, int 
psPosition, int psType, int psScale,
+                        ExtendedType binder) throws Exception {
+        if (value == null && (psType == 0 || psType == Types.BOOLEAN)) {
+            statement.setNull(psPosition, Types.VARCHAR);
         } else {
-            super.bindParameter(statement, parameter);
+            super.bind(statement, value, psPosition, psType, psScale, binder);
         }
     }
     
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/dba/db2/DB2ProcedureAction.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/db2/DB2ProcedureAction.java
index cb26979cc..4792dc12f 100644
--- a/cayenne/src/main/java/org/apache/cayenne/dba/db2/DB2ProcedureAction.java
+++ b/cayenne/src/main/java/org/apache/cayenne/dba/db2/DB2ProcedureAction.java
@@ -49,7 +49,7 @@ class DB2ProcedureAction extends ProcedureAction {
                TranslatedProcedure translated = 
dataNode.getProcedureTranslator()
                                .translate(query, dataNode.getAdapter(), 
dataNode.getEntityResolver());
 
-               dataNode.getJdbcEventLogger().logQuery(translated.sql(), 
translated.bindings());
+               dataNode.getJdbcEventLogger().logQuery(translated.sql(), 
translated.params());
 
                try (CallableStatement statement = 
connection.prepareCall(translated.sql());) {
                        initStatement(statement);
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 e5b55e1b1..ce7122d88 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
@@ -20,7 +20,6 @@
 package org.apache.cayenne.dba.derby;
 
 import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslator;
 import org.apache.cayenne.access.translator.ejbql.JdbcEJBQLTranslator;
@@ -214,12 +213,13 @@ public class DerbyAdapter extends JdbcAdapter {
     }
 
     @Override
-    public void bindParameter(PreparedStatement statement, PSParameter<?> 
parameter) throws Exception {
-
-        if (parameter.value() == null && parameter.psType() == 0) {
-            statement.setNull(parameter.psPosition(), Types.VARCHAR);
+    @SuppressWarnings("rawtypes")
+    protected void bind(PreparedStatement statement, Object value, int 
psPosition, int psType, int psScale,
+                        ExtendedType binder) throws Exception {
+        if (value == null && psType == 0) {
+            statement.setNull(psPosition, Types.VARCHAR);
         } else {
-            super.bindParameter(statement, parameter);
+            super.bind(statement, value, psPosition, psType, psScale, binder);
         }
     }
 
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 83bfdb64d..6bf8fcd14 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
@@ -22,7 +22,6 @@ package org.apache.cayenne.dba.ingres;
 import org.apache.cayenne.dba.NativeColumnType;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
-import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.access.types.ExtendedType;
 import org.apache.cayenne.access.types.ExtendedTypeFactory;
 import org.apache.cayenne.access.types.ExtendedTypeMap;
@@ -116,12 +115,13 @@ public class IngresAdapter extends JdbcAdapter {
     }
 
     @Override
-    public void bindParameter(PreparedStatement statement, PSParameter<?> 
parameter) throws Exception {
-
-        if (parameter.value() == null && (parameter.psType() == Types.BIT)) {
-            statement.setNull(parameter.psPosition(), Types.SMALLINT);
+    @SuppressWarnings("rawtypes")
+    protected void bind(PreparedStatement statement, Object value, int 
psPosition, int psType, int psScale,
+                        ExtendedType binder) throws Exception {
+        if (value == null && (psType == Types.BIT)) {
+            statement.setNull(psPosition, Types.SMALLINT);
         } else {
-            super.bindParameter(statement, parameter);
+            super.bind(statement, value, psPosition, psType, psScale, binder);
         }
     }
 
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/dba/mysql/MySQLProcedureAction.java 
b/cayenne/src/main/java/org/apache/cayenne/dba/mysql/MySQLProcedureAction.java
index 7c541730c..91841872f 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/dba/mysql/MySQLProcedureAction.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/dba/mysql/MySQLProcedureAction.java
@@ -48,7 +48,7 @@ class MySQLProcedureAction extends ProcedureAction {
                TranslatedProcedure translated = 
dataNode.getProcedureTranslator()
                                .translate(query, dataNode.getAdapter(), 
dataNode.getEntityResolver());
 
-               dataNode.getJdbcEventLogger().logQuery(translated.sql(), 
translated.bindings());
+               dataNode.getJdbcEventLogger().logQuery(translated.sql(), 
translated.params());
 
                try (CallableStatement statement = 
connection.prepareCall(translated.sql());) {
                        bindParameters(statement, translated);
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 ffa747483..c3463f403 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
@@ -23,7 +23,6 @@ import org.apache.cayenne.dba.NativeColumnType;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
-import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslator;
 import org.apache.cayenne.access.types.ByteType;
 import org.apache.cayenne.access.types.ExtendedType;
@@ -261,21 +260,17 @@ public class OracleAdapter extends JdbcAdapter {
     }
 
     @Override
-    public void bindParameter(PreparedStatement statement, PSParameter<?> 
parameter) throws Exception {
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected void bind(PreparedStatement statement, Object value, int 
psPosition, int psType, int psScale,
+                        ExtendedType binder) throws Exception {
 
-        // 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 (parameter.value() == null && parameter.psType() == Types.BOOLEAN) {
+        // 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 (value == null && psType == Types.BOOLEAN) {
             ExtendedType typeProcessor = 
getExtendedTypes().getRegisteredType(Boolean.class);
-            typeProcessor.setJdbcObject(
-                    statement,
-                    parameter.value(),
-                    parameter.psPosition(),
-                    parameter.psType(),
-                    parameter.psScale());
+            typeProcessor.setJdbcObject(statement, value, psPosition, psType, 
psScale);
         } else {
-            super.bindParameter(statement, parameter);
+            super.bind(statement, value, psPosition, psType, psScale, binder);
         }
     }
 
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 3d7143679..a40391166 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
@@ -23,7 +23,6 @@ import org.apache.cayenne.dba.NativeColumnType;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
-import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslator;
 import org.apache.cayenne.access.types.ByteArrayType;
 import org.apache.cayenne.access.types.ByteType;
@@ -138,18 +137,20 @@ public class SQLServerAdapter extends JdbcAdapter {
     }
 
     @Override
-    public void bindParameter(PreparedStatement statement, PSParameter<?> 
parameter) throws Exception {
+    @SuppressWarnings("rawtypes")
+    protected void bind(PreparedStatement statement, Object value, int 
psPosition, int psType, int psScale,
+                        ExtendedType binder) throws Exception {
 
         // SQL Server driver doesn't like CLOBs and BLOBs as parameters
-        if (parameter.value() == null) {
-            int jdbcType = switch (parameter.psType()) {
+        if (value == null) {
+            int jdbcType = switch (psType) {
                 case Types.CLOB, 0 -> Types.VARCHAR;
                 case Types.BLOB -> Types.VARBINARY;
-                default -> parameter.psType();
+                default -> psType;
             };
-            statement.setNull(parameter.psPosition(), jdbcType);
+            statement.setNull(psPosition, jdbcType);
         } else {
-            super.bindParameter(statement, parameter);
+            super.bind(statement, value, psPosition, psType, psScale, binder);
         }
     }
 
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerProcedureAction.java
 
b/cayenne/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerProcedureAction.java
index d40ed6696..0af3bb37d 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerProcedureAction.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerProcedureAction.java
@@ -60,7 +60,7 @@ public class SQLServerProcedureAction extends ProcedureAction 
{
                TranslatedProcedure translated = 
dataNode.getProcedureTranslator()
                                .translate(query, dataNode.getAdapter(), 
dataNode.getEntityResolver());
 
-               dataNode.getJdbcEventLogger().logQuery(translated.sql(), 
translated.bindings());
+               dataNode.getJdbcEventLogger().logQuery(translated.sql(), 
translated.params());
 
                try (CallableStatement statement = 
connection.prepareCall(translated.sql());) {
                        bindParameters(statement, translated);
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 98450cfa1..8720855e3 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
@@ -21,7 +21,6 @@ package org.apache.cayenne.dba.sybase;
 
 import org.apache.cayenne.dba.NativeColumnType;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
-import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.access.translator.ejbql.EJBQLTranslator;
 import org.apache.cayenne.access.types.ByteArrayType;
 import org.apache.cayenne.access.types.ByteType;
@@ -143,18 +142,20 @@ public class SybaseAdapter extends JdbcAdapter {
     }
 
     @Override
-    public void bindParameter(PreparedStatement statement, PSParameter<?> 
parameter) throws Exception {
+    @SuppressWarnings("rawtypes")
+    protected void bind(PreparedStatement statement, Object value, int 
psPosition, int psType, int psScale,
+                        ExtendedType binder) throws Exception {
 
         // Sybase driver doesn't like CLOBs and BLOBs as parameters
-        if (parameter.value() == null) {
-            int jdbcType = switch (parameter.psType()) {
+        if (value == null) {
+            int jdbcType = switch (psType) {
                 case Types.CLOB, 0 -> Types.VARCHAR;
                 case Types.BLOB -> Types.VARBINARY;
-                default -> parameter.psType();
+                default -> psType;
             };
-            statement.setNull(parameter.psPosition(), jdbcType);
+            statement.setNull(psPosition, jdbcType);
         } else {
-            super.bindParameter(statement, parameter);
+            super.bind(statement, value, psPosition, psType, psScale, binder);
         }
     }
 
diff --git a/cayenne/src/main/java/org/apache/cayenne/log/JdbcEventLogger.java 
b/cayenne/src/main/java/org/apache/cayenne/log/JdbcEventLogger.java
index 7abd65dc7..78731c4dc 100644
--- a/cayenne/src/main/java/org/apache/cayenne/log/JdbcEventLogger.java
+++ b/cayenne/src/main/java/org/apache/cayenne/log/JdbcEventLogger.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.log;
 
+import org.apache.cayenne.access.jdbc.CSParameter;
 import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.map.DbAttribute;
 
@@ -40,6 +41,11 @@ public interface JdbcEventLogger {
         */
        void logQuery(String sql, PSParameter<?>[] bindings);
 
+       /**
+        * @since 5.0
+        */
+       void logQuery(String sql, CSParameter<?>[] bindings);
+
        /**
         * @since 4.0
         */
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/log/NoopJdbcEventLogger.java 
b/cayenne/src/main/java/org/apache/cayenne/log/NoopJdbcEventLogger.java
index 052fe0a8b..0b8053c74 100644
--- a/cayenne/src/main/java/org/apache/cayenne/log/NoopJdbcEventLogger.java
+++ b/cayenne/src/main/java/org/apache/cayenne/log/NoopJdbcEventLogger.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.log;
 
+import org.apache.cayenne.access.jdbc.CSParameter;
 import org.apache.cayenne.access.jdbc.PSParameter;
 import org.apache.cayenne.map.DbAttribute;
 
@@ -49,6 +50,10 @@ public class NoopJdbcEventLogger implements JdbcEventLogger {
        public void logQuery(String sql, PSParameter<?>[] bindings) {
        }
 
+       @Override
+       public void logQuery(String sql, CSParameter<?>[] bindings) {
+       }
+
        @Override
        public void logQueryParameters(String label, PSParameter<?>[] bindings) 
{
        }
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 5f0c8b42c..059df1cb8 100644
--- a/cayenne/src/main/java/org/apache/cayenne/log/Slf4jJdbcEventLogger.java
+++ b/cayenne/src/main/java/org/apache/cayenne/log/Slf4jJdbcEventLogger.java
@@ -19,7 +19,9 @@
 package org.apache.cayenne.log;
 
 import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.access.jdbc.CSParameter;
 import org.apache.cayenne.access.jdbc.PSParameter;
+import org.apache.cayenne.access.types.ExtendedType;
 import org.apache.cayenne.configuration.Constants;
 import org.apache.cayenne.configuration.RuntimeProperties;
 import org.apache.cayenne.di.Inject;
@@ -75,6 +77,19 @@ public class Slf4jJdbcEventLogger implements JdbcEventLogger 
{
         }
     }
 
+    @Override
+    public void logQuery(String sql, CSParameter<?>[] bindings) {
+        if (isLoggable()) {
+
+            StringBuilder buffer = new StringBuilder(sql).append(" ");
+            appendParameters(buffer, "bind", bindings);
+
+            if (!buffer.isEmpty()) {
+                LOGGER.info(buffer.toString());
+            }
+        }
+    }
+
     @Override
     public void logQueryParameters(String label, PSParameter<?>[] bindings) {
 
@@ -89,7 +104,6 @@ public class Slf4jJdbcEventLogger implements JdbcEventLogger 
{
         }
     }
 
-    @SuppressWarnings("unchecked")
     protected void appendParameters(StringBuilder buffer, String label, 
PSParameter<?>[] bindings) {
 
         int len = bindings.length;
@@ -98,41 +112,64 @@ public class Slf4jJdbcEventLogger implements 
JdbcEventLogger {
             boolean hasIncluded = false;
 
             for (int i = 0, j = 1; i < len; i++) {
-                PSParameter b = bindings[i];
-
-                if (hasIncluded) {
-                    buffer.append(", ");
-                } else {
-                    hasIncluded = true;
-                    buffer.append("[").append(label).append(": ");
-                }
+                PSParameter<?> b = bindings[i];
+                DbAttribute attribute = b.attribute();
+                appendParameter(buffer, label, hasIncluded, j++,
+                        attribute != null ? attribute.getName() : null, 
b.binder(), b.value());
+                hasIncluded = true;
+            }
 
+            buffer.append("]");
+        }
+    }
 
-                buffer.append(j++);
+    protected void appendParameters(StringBuilder buffer, String label, 
CSParameter<?>[] bindings) {
 
-                DbAttribute attribute = b.attribute();
-                if (attribute != null) {
-                    buffer.append("->");
-                    buffer.append(attribute.getName());
-                }
+        int len = bindings.length;
+        if (len > 0) {
 
-                buffer.append(":");
+            boolean hasIncluded = false;
 
-                if (b.binder() != null) {
-                    buffer.append(b.binder().toString(b.value()));
-                } else if (b.value() == null) {
-                    buffer.append("NULL");
-                } else {
-                    buffer.append(b.value().getClass().getName())
-                            .append("@")
-                            .append(System.identityHashCode(b.value()));
-                }
+            for (int i = 0, j = 1; i < len; i++) {
+                CSParameter<?> b = bindings[i];
+                appendParameter(buffer, label, hasIncluded, j++, 
b.param().getName(), b.binder(), b.value());
+                hasIncluded = true;
             }
 
             buffer.append("]");
         }
     }
 
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private void appendParameter(StringBuilder buffer, String label, boolean 
hasIncluded, int position, String name,
+                                 ExtendedType binder, Object value) {
+
+        if (hasIncluded) {
+            buffer.append(", ");
+        } else {
+            buffer.append("[").append(label).append(": ");
+        }
+
+        buffer.append(position);
+
+        if (name != null) {
+            buffer.append("->");
+            buffer.append(name);
+        }
+
+        buffer.append(":");
+
+        if (binder != null) {
+            buffer.append(binder.toString(value));
+        } else if (value == null) {
+            buffer.append("NULL");
+        } else {
+            buffer.append(value.getClass().getName())
+                    .append("@")
+                    .append(System.identityHashCode(value));
+        }
+    }
+
     @Override
     public void logSelectCount(int count, long time) {
         logSelectCount(count, time, null);


Reply via email to