From e4c33a93750d9b47e84bfba9e55f73e23bed244a Mon Sep 17 00:00:00 2001 From: Rui Ferreira Date: Wed, 24 May 2023 11:17:16 +0100 Subject: [PATCH 1/4] PDB-384: Make BLOB accept null values on all database engines --- .../abstraction/engine/impl/DB2Engine.java | 6 ++++++ .../abstraction/engine/impl/MySqlEngine.java | 6 ++++++ .../abstraction/engine/impl/OracleEngine.java | 6 ++++++ .../engine/impl/PostgreSqlEngine.java | 6 ++++++ .../engine/impl/SqlServerEngine.java | 6 ++++++ .../impl/abs/AbstractEngineSchemaTest.java | 2 ++ .../engine/impl/abs/EngineGeneralTest.java | 21 +++++++++++++++++++ 7 files changed, 53 insertions(+) diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java index 79149adf..81fbb368 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java @@ -56,6 +56,7 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.md5; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static java.lang.String.format; +import static java.util.Objects.isNull; import static org.apache.commons.lang3.StringUtils.join; /** @@ -124,6 +125,11 @@ protected void setPreparedStatementValue(final PreparedStatement ps, case JSON: case CLOB: case BLOB: + if (isNull(value)) { + ps.setBytes(index, null); + break; + } + ps.setBytes(index, objectToArray(value)); break; diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java index 5b712802..83d438dd 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java @@ -52,6 +52,7 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.md5; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static java.lang.String.format; +import static java.util.Objects.isNull; import static org.apache.commons.lang3.StringUtils.join; /** @@ -122,6 +123,11 @@ protected void setPreparedStatementValue(final PreparedStatement ps, final boolean fromBatch) throws Exception { switch (dbColumn.getDbColumnType()) { case BLOB: + if (isNull(value)) { + ps.setBytes(index, null); + break; + } + ps.setBytes(index, objectToArray(value)); break; diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/OracleEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/OracleEngine.java index d558f368..88dd00cd 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/OracleEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/OracleEngine.java @@ -63,6 +63,7 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.md5; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static java.lang.String.format; +import static java.util.Objects.isNull; import static java.util.stream.Collectors.joining; import static org.apache.commons.lang3.StringUtils.join; @@ -235,6 +236,11 @@ protected void setPreparedStatementValue(final PreparedStatement ps, final boolean fromBatch) throws Exception { switch (dbColumn.getDbColumnType()) { case BLOB: + if (isNull(value)) { + ps.setBytes(index, null); + break; + } + final byte[] valArray = objectToArray(value); if (fromBatch && valArray.length > MIN_SIZE_FOR_BLOB) { // Use a blob for columns greater than 4K when inside a batch diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java index c2e638e4..49420598 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java @@ -58,6 +58,7 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.md5; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static java.lang.String.format; +import static java.util.Objects.isNull; import static org.apache.commons.lang3.StringUtils.join; /** @@ -143,6 +144,11 @@ protected void setPreparedStatementValue(final PreparedStatement ps, final boolean fromBatch) throws Exception { switch (dbColumn.getDbColumnType()) { case BLOB: + if (isNull(value)) { + ps.setBytes(index, null); + break; + } + ps.setBytes(index, objectToArray(value)); break; diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java index 2ee98fa7..b2190623 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java @@ -51,6 +51,7 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.md5; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static java.lang.String.format; +import static java.util.Objects.isNull; import static org.apache.commons.lang3.StringUtils.join; /** @@ -149,6 +150,11 @@ protected void setPreparedStatementValue(final PreparedStatement ps, final boolean fromBatch) throws Exception { switch (dbColumn.getDbColumnType()) { case BLOB: + if (isNull(value)) { + ps.setBytes(index, null); + break; + } + ps.setBytes(index, objectToArray(value)); break; diff --git a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java index 8c09c432..323fdb74 100644 --- a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java +++ b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java @@ -15,6 +15,7 @@ */ package com.feedzai.commons.sql.abstraction.engine.impl.abs; +import com.feedzai.commons.sql.abstraction.ddl.DbColumn; import com.feedzai.commons.sql.abstraction.ddl.DbColumnType; import com.feedzai.commons.sql.abstraction.ddl.DbEntity; import com.feedzai.commons.sql.abstraction.ddl.DbEntityType; @@ -32,6 +33,7 @@ import com.feedzai.commons.sql.abstraction.engine.testconfig.DatabaseConfiguration; import com.feedzai.commons.sql.abstraction.entry.EntityEntry; import com.google.common.collect.Sets; +import java.sql.PreparedStatement; import org.assertj.core.api.MapAssert; import org.assertj.core.data.MapEntry; import org.junit.Before; diff --git a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/EngineGeneralTest.java b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/EngineGeneralTest.java index ba2c82e9..faa2bb90 100644 --- a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/EngineGeneralTest.java +++ b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/EngineGeneralTest.java @@ -2788,6 +2788,27 @@ public void testBlob() throws Exception { assertEquals(updBlob, result.get(0).get("COL2").toBlob()); } + /** + * Tests that persisting a null value to a BLOB type column persists a null value. + * + * @throws Exception If anything goes wrong on engine-related operations, namely adding an entity, persisting an + * entry and querying an entry. + */ + @Test + public void testBlobPersistNull() throws Exception { + DbEntity entity = dbEntity().name("TEST").addColumn("COL1", STRING).addColumn("COL2", BLOB) + .build(); + engine.addEntity(entity); + EntityEntry entry = entry().set("COL1", "CENINHAS").set("COL2", null) + .build(); + + engine.persist("TEST", entry); + + List> result = engine.query(select(all()).from(table("TEST"))); + assertEquals("CENINHAS", result.get(0).get("COL1").toString()); + assertNull(result.get(0).get("COL2").toObject()); + } + @Test public void testBlobSettingWithIndexTest() throws Exception { DbEntity entity = dbEntity().name("TEST").addColumn("COL1", STRING).addColumn("COL2", BLOB) From 60ea1a3d26934bd23c3046b315ebff0f679a4847 Mon Sep 17 00:00:00 2001 From: Rui Ferreira Date: Wed, 24 May 2023 16:17:27 +0100 Subject: [PATCH 2/4] Revert unused imports from AbstractEngineSchemaTest --- .../abstraction/engine/impl/abs/AbstractEngineSchemaTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java index 323fdb74..8c09c432 100644 --- a/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java +++ b/src/test/java/com/feedzai/commons/sql/abstraction/engine/impl/abs/AbstractEngineSchemaTest.java @@ -15,7 +15,6 @@ */ package com.feedzai.commons.sql.abstraction.engine.impl.abs; -import com.feedzai.commons.sql.abstraction.ddl.DbColumn; import com.feedzai.commons.sql.abstraction.ddl.DbColumnType; import com.feedzai.commons.sql.abstraction.ddl.DbEntity; import com.feedzai.commons.sql.abstraction.ddl.DbEntityType; @@ -33,7 +32,6 @@ import com.feedzai.commons.sql.abstraction.engine.testconfig.DatabaseConfiguration; import com.feedzai.commons.sql.abstraction.entry.EntityEntry; import com.google.common.collect.Sets; -import java.sql.PreparedStatement; import org.assertj.core.api.MapAssert; import org.assertj.core.data.MapEntry; import org.junit.Before; From a3b126d84c5259f6116c19dd7f5da20c6cb3bb1a Mon Sep 17 00:00:00 2001 From: Rui Ferreira Date: Wed, 24 May 2023 16:24:51 +0100 Subject: [PATCH 3/4] Put null check inside objectToArray method --- .../sql/abstraction/engine/AbstractDatabaseEngine.java | 10 +++++++++- .../commons/sql/abstraction/engine/impl/DB2Engine.java | 5 ----- .../sql/abstraction/engine/impl/MySqlEngine.java | 5 ----- .../sql/abstraction/engine/impl/OracleEngine.java | 9 +++------ .../sql/abstraction/engine/impl/PostgreSqlEngine.java | 5 ----- .../sql/abstraction/engine/impl/SqlServerEngine.java | 5 ----- 6 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/AbstractDatabaseEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/AbstractDatabaseEngine.java index 52386621..5fd2affa 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/AbstractDatabaseEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/AbstractDatabaseEngine.java @@ -96,6 +96,7 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static com.feedzai.commons.sql.abstraction.util.StringUtils.readString; import static java.lang.String.format; +import static java.util.Objects.isNull; /** * Provides a set of functions to interact with the database. @@ -2308,12 +2309,19 @@ private byte[] getReusableByteBuffer() { /** * Converts an object to byte array. + *

+ * If the given {@code val} is {@code null}, returns {@code null}. * * @param val The object to convert. - * @return The byte array representation of the object. + * @return The byte array representation of the object, if the given {@code val} is present; otherwise, returns + * {@code null}. * @throws IOException If the buffer is not enough to make the conversion. */ protected final synchronized byte[] objectToArray(Object val) throws IOException { + if (isNull(val)) { + return null; + } + final ByteArrayOutputStream bos = new InitiallyReusableByteArrayOutputStream(getReusableByteBuffer()); final ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(val); diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java index 81fbb368..039ae06d 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java @@ -125,11 +125,6 @@ protected void setPreparedStatementValue(final PreparedStatement ps, case JSON: case CLOB: case BLOB: - if (isNull(value)) { - ps.setBytes(index, null); - break; - } - ps.setBytes(index, objectToArray(value)); break; diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java index 83d438dd..1788df07 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java @@ -123,11 +123,6 @@ protected void setPreparedStatementValue(final PreparedStatement ps, final boolean fromBatch) throws Exception { switch (dbColumn.getDbColumnType()) { case BLOB: - if (isNull(value)) { - ps.setBytes(index, null); - break; - } - ps.setBytes(index, objectToArray(value)); break; diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/OracleEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/OracleEngine.java index 88dd00cd..7a45a9bf 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/OracleEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/OracleEngine.java @@ -236,13 +236,10 @@ protected void setPreparedStatementValue(final PreparedStatement ps, final boolean fromBatch) throws Exception { switch (dbColumn.getDbColumnType()) { case BLOB: - if (isNull(value)) { - ps.setBytes(index, null); - break; - } - final byte[] valArray = objectToArray(value); - if (fromBatch && valArray.length > MIN_SIZE_FOR_BLOB) { + if (isNull(valArray)) { + ps.setBytes(index, null); + } else if (fromBatch && valArray.length > MIN_SIZE_FOR_BLOB) { // Use a blob for columns greater than 4K when inside a batch // update because the Oracle driver creates one and only releases // it when the PreparedStatement is closed. This will be closed diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java index 49420598..62279ac2 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java @@ -144,11 +144,6 @@ protected void setPreparedStatementValue(final PreparedStatement ps, final boolean fromBatch) throws Exception { switch (dbColumn.getDbColumnType()) { case BLOB: - if (isNull(value)) { - ps.setBytes(index, null); - break; - } - ps.setBytes(index, objectToArray(value)); break; diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java index b2190623..7bdf9358 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java @@ -150,11 +150,6 @@ protected void setPreparedStatementValue(final PreparedStatement ps, final boolean fromBatch) throws Exception { switch (dbColumn.getDbColumnType()) { case BLOB: - if (isNull(value)) { - ps.setBytes(index, null); - break; - } - ps.setBytes(index, objectToArray(value)); break; From 1f1c20edee25d2785f036d51720a028e3ec3b565 Mon Sep 17 00:00:00 2001 From: Rui Ferreira Date: Wed, 24 May 2023 16:26:40 +0100 Subject: [PATCH 4/4] Revert dangling isNull imports from specific engine impl classes --- .../feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java | 1 - .../feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java | 1 - .../commons/sql/abstraction/engine/impl/PostgreSqlEngine.java | 1 - .../commons/sql/abstraction/engine/impl/SqlServerEngine.java | 1 - 4 files changed, 4 deletions(-) diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java index 039ae06d..79149adf 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/DB2Engine.java @@ -56,7 +56,6 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.md5; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static java.lang.String.format; -import static java.util.Objects.isNull; import static org.apache.commons.lang3.StringUtils.join; /** diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java index 1788df07..5b712802 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/MySqlEngine.java @@ -52,7 +52,6 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.md5; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static java.lang.String.format; -import static java.util.Objects.isNull; import static org.apache.commons.lang3.StringUtils.join; /** diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java index 62279ac2..c2e638e4 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/PostgreSqlEngine.java @@ -58,7 +58,6 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.md5; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static java.lang.String.format; -import static java.util.Objects.isNull; import static org.apache.commons.lang3.StringUtils.join; /** diff --git a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java index 7bdf9358..2ee98fa7 100644 --- a/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java +++ b/src/main/java/com/feedzai/commons/sql/abstraction/engine/impl/SqlServerEngine.java @@ -51,7 +51,6 @@ import static com.feedzai.commons.sql.abstraction.util.StringUtils.md5; import static com.feedzai.commons.sql.abstraction.util.StringUtils.quotize; import static java.lang.String.format; -import static java.util.Objects.isNull; import static org.apache.commons.lang3.StringUtils.join; /**