This is an automated email from the ASF dual-hosted git repository. palashc pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/master by this push: new a211350de6 PHOENIX-7647 : BSON_UPDATE_EXPRESSION() set value if field key does not exist (#2202) a211350de6 is described below commit a211350de63af933cb229674e98c1c59df78472a Author: Palash Chauhan <palashc...@gmail.com> AuthorDate: Wed Jun 25 09:43:42 2025 -0700 PHOENIX-7647 : BSON_UPDATE_EXPRESSION() set value if field key does not exist (#2202) Co-authored-by: Palash Chauhan <p.chau...@pchauha-ltmgv47.internal.salesforce.com> --- .../util/bson/UpdateExpressionUtils.java | 21 +- .../java/org/apache/phoenix/end2end/Bson2IT.java | 334 +++++++++++++++++++++ .../util/bson/UpdateExpressionUtilsTest.java | 124 +++++++- 3 files changed, 471 insertions(+), 8 deletions(-) diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/util/bson/UpdateExpressionUtils.java b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/util/bson/UpdateExpressionUtils.java index 46fb9bd268..031a93b04c 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/expression/util/bson/UpdateExpressionUtils.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/expression/util/bson/UpdateExpressionUtils.java @@ -572,12 +572,19 @@ public class UpdateExpressionUtils { } /** - * Retrieve the value to be updated for the given current value. If the current value does not - * contain any arithmetic operators, the current value is returned without any modifications. + * Retrieve the value to be updated for the given current value. + * + * If the current value does not contain any arithmetic operators, + * the current value is returned without any modifications. + * * If the current value contains arithmetic expressions like "a + b" or "a - b", the values of * operands are retrieved from the given document and if the values are numeric, the given * arithmetic operation is performed. * + * If the current value is a bson document with an entry from $IF_NOT_EXISTS to a document + * with a key and a fallback value, we lookup if the key is already present in the document. + * If it is, we return its value. Otherwise, we return the provided fallback value. + * * @param curValue The current value. * @param bsonDocument The document with all field key-value pairs. * @return Updated values to be used by SET operation. @@ -628,6 +635,16 @@ public class UpdateExpressionUtils { } } return getBsonNumberFromNumber(newNum); + } else if (curValue instanceof BsonDocument + && ((BsonDocument) curValue).get("$IF_NOT_EXISTS") != null) { + BsonValue ifNotExistsDoc = ((BsonDocument) curValue).get("$IF_NOT_EXISTS"); + Map.Entry<String, BsonValue> ifNotExistsEntry + = ((BsonDocument) ifNotExistsDoc).entrySet().iterator().next(); + String ifNotExistsKey = ifNotExistsEntry.getKey(); + BsonValue ifNotExistsVal = ifNotExistsEntry.getValue(); + BsonValue val = CommonComparisonExpressionUtils + .getFieldFromDocument(ifNotExistsKey, bsonDocument); + return (val != null) ? val : ifNotExistsVal; } return curValue; } diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/Bson2IT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/Bson2IT.java index 2959b5c7e3..b901a495d0 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/Bson2IT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/Bson2IT.java @@ -358,6 +358,46 @@ public class Bson2IT extends ParallelStatsDisabledIT { assertEquals(bsonDocument2, document2); assertFalse(rs.next()); + + /* + updateExp = "SET newKey1 = if_not_exists(NestedMap1.ColorList[0], 42), + NestedMap1.NestedMap2.newKey21 = if_not_exists(keyNotExists, "foo"); + */ + updateExp = "{\n" + + " \"$SET\": {\n" + + "\"newKey1\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"NestedMap1.ColorList[0]\": 42\n" + + " }\n" + + " },\n" + + " \"NestedMap1.NestedMap2.newKey2\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"keyNotExists\": \"foo\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + stmt = conn.prepareStatement("UPSERT INTO " + tableName + + " VALUES (?,?) ON DUPLICATE KEY UPDATE COL = BSON_UPDATE_EXPRESSION(COL, '" + + updateExp + "')"); + stmt.setString(1, "pk0001"); + stmt.setString(2, "pk0002"); + stmt.executeUpdate(); + conn.commit(); + + query = "SELECT * FROM " + tableName; + rs = conn.createStatement().executeQuery(query); + + assertTrue(rs.next()); + assertEquals("pk0001", rs.getString(1)); + assertEquals("pk0002", rs.getString(2)); + + BsonDocument bsonDocument3 = getDocument3(); + BsonDocument document3 = (BsonDocument) rs.getObject(3); + assertEquals(bsonDocument3, document3); + + assertFalse(rs.next()); } } @@ -1147,4 +1187,298 @@ public class Bson2IT extends ParallelStatsDisabledIT { return RawBsonDocument.parse(json); } + private static RawBsonDocument getDocument3() { + String json = "{\n" + + " \"newKey1\" : \"Black\",\n" + + " \"Pictures\" : {\n" + + " \"$set\" : [ \"123_rear.jpg\", \"xyz5@_rear.jpg\", \"xyz_front.jpg\", \"xyz_rear.jpg\", \"123_front.jpg\", \"1235@_rear.jpg\" ]\n" + + " },\n" + + " \"PictureBinarySet\" : {\n" + + " \"$set\" : [ {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"MTIzYWJjX3JlYXIuanBn\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " }, {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"eHl6X3JlYXIuanBn\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " }, {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"eHl6YWJjX3JlYXIuanBn\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " }, {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"MTIzX2Zyb250LmpwZw==\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " } ]\n" + + " },\n" + + " \"Title\" : \"Cycle_1234_new\",\n" + + " \"InPublication\" : false,\n" + + " \"AddedId\" : 10,\n" + + " \"ColorBytes\" : {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"QmxhY2s=\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " },\n" + + " \"ISBN\" : \"111-1111111111\",\n" + + " \"NestedList1\" : [ -473.11999999999995, \"1234abcd\", [ \"xyz0123\", {\n" + + " \"InPublication\" : false,\n" + + " \"BinaryTitleSet\" : {\n" + + " \"$set\" : [ {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"Qm9vayAxMDExIFRpdGxlIEJpbmFyeQ==\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " }, {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"Qm9vayAxMDEwIFRpdGxlIEJpbmFyeQ==\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " }, {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"Qm9vayAxMTExIFRpdGxlIEJpbmFyeQ==\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " } ]\n" + + " },\n" + + " \"ISBN\" : \"111-1111111122\",\n" + + " \"IdSet\" : {\n" + + " \"$set\" : [ 20576024, -3.9457860486939475E7, 204850.69703847595, 4.86906704836275E21, 19306873 ]\n" + + " },\n" + + " \"Title\" : \"Book 101 Title\",\n" + + " \"Id\" : 101.01,\n" + + " \"TitleSet2\" : {\n" + + " \"$set\" : [ \"Book 1201 Title\", \"Book 1111 Title\", \"Book 1200 Title\" ]\n" + + " }\n" + + " } ], null, true ],\n" + + " \"NestedMap1\" : {\n" + + " \"InPublication\" : false,\n" + + " \"ColorList\" : [ \"Black\", {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"V2hpdGU=\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " }, \"Silver\" ],\n" + + " \"AddedId\" : 10,\n" + + " \"ISBN\" : \"111-1111111111\",\n" + + " \"NestedMap2\" : {\n" + + " \"NewID\" : \"12345\",\n" + + " \"NList\" : [ 12.22, -0.00234, null ],\n" + + " \"ISBN\" : \"111-1111111111999\",\n" + + " \"Title\" : \"Book 10122 Title\",\n" + + " \"Id\" : -12243.78\n" + + " \"newKey2\" : \"foo\"" + + " },\n" + + " \"Id\" : 101.01,\n" + + " \"NList1\" : [ {\n" + + " \"$set\" : [ \"Updated_set_01\", \"Updated_set_02\" ]\n" + + " }, -0.00234 ],\n" + + " \"NSet1\" : {\n" + + " \"$set\" : [ 123.45, 9586.7778, -124, 10238 ]\n" + + " }\n" + + " },\n" + + " \"Id1\" : \"12345\",\n" + + " \"attr_6\" : {\n" + + " \"n_attr_0\" : \"str_val_0\",\n" + + " \"n_attr_1\" : 1295.03,\n" + + " \"n_attr_2\" : {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"MjA0OHU1bmJsd2plaVdGR1RIKDRiZjkzMA==\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " },\n" + + " \"n_attr_3\" : true,\n" + + " \"n_attr_4\" : null\n" + + " },\n" + + " \"attr_5\" : [ 1224, \"str001\", {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"AAECAwQF\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " } ],\n" + + " \"NestedList12\" : [ -485.34, \"1234abcd\", [ {\n" + + " \"$set\" : [ \"xyz01234\", \"xyz0123\", \"abc01234\" ]\n" + + " }, {\n" + + " \"$set\" : [ {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"dmFsMDE=\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " }, {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"dmFsMDM=\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " }, {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"dmFsMDI=\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " }, {\n" + + " \"$binary\" : {\n" + + " \"base64\" : \"dmFsMDQ=\",\n" + + " \"subType\" : \"00\"\n" + + " }\n" + + " } ]\n" + + " } ] ],\n" + + " \"Id\" : \"12345\",\n" + + " \"attr_1\" : 1295.03,\n" + + " \"attr_0\" : \"str_val_0\",\n" + + " \"RelatedItems\" : {\n" + + " \"$set\" : [ 123.0948, -485.45582904, 1234, 0.111 ]\n" + + " }\n" + + "}"; + //{ + // "newKey1" : "Black", + // "Pictures" : { + // "$set" : [ "123_rear.jpg", "xyz5@_rear.jpg", "xyz_front.jpg", "xyz_rear.jpg", "123_front.jpg", "1235@_rear.jpg" ] + // }, + // "PictureBinarySet" : { + // "$set" : [ { + // "$binary" : { + // "base64" : "MTIzYWJjX3JlYXIuanBn", + // "subType" : "00" + // } + // }, { + // "$binary" : { + // "base64" : "eHl6X3JlYXIuanBn", + // "subType" : "00" + // } + // }, { + // "$binary" : { + // "base64" : "eHl6YWJjX3JlYXIuanBn", + // "subType" : "00" + // } + // }, { + // "$binary" : { + // "base64" : "MTIzX2Zyb250LmpwZw==", + // "subType" : "00" + // } + // } ] + // }, + // "Title" : "Cycle_1234_new", + // "InPublication" : false, + // "AddedId" : 10, + // "ColorBytes" : { + // "$binary" : { + // "base64" : "QmxhY2s=", + // "subType" : "00" + // } + // }, + // "ISBN" : "111-1111111111", + // "NestedList1" : [ -473.11999999999995, "1234abcd", [ "xyz0123", { + // "InPublication" : false, + // "BinaryTitleSet" : { + // "$set" : [ { + // "$binary" : { + // "base64" : "Qm9vayAxMDExIFRpdGxlIEJpbmFyeQ==", + // "subType" : "00" + // } + // }, { + // "$binary" : { + // "base64" : "Qm9vayAxMDEwIFRpdGxlIEJpbmFyeQ==", + // "subType" : "00" + // } + // }, { + // "$binary" : { + // "base64" : "Qm9vayAxMTExIFRpdGxlIEJpbmFyeQ==", + // "subType" : "00" + // } + // } ] + // }, + // "ISBN" : "111-1111111122", + // "IdSet" : { + // "$set" : [ 20576024, -3.9457860486939475E7, 204850.69703847595, 4.86906704836275E21, 19306873 ] + // }, + // "Title" : "Book 101 Title", + // "Id" : 101.01, + // "TitleSet2" : { + // "$set" : [ "Book 1201 Title", "Book 1111 Title", "Book 1200 Title" ] + // } + // } ], null, true ], + // "NestedMap1" : { + // "InPublication" : false, + // "ColorList" : [ "Black", { + // "$binary" : { + // "base64" : "V2hpdGU=", + // "subType" : "00" + // } + // }, "Silver" ], + // "AddedId" : 10, + // "ISBN" : "111-1111111111", + // "NestedMap2" : { + // "NewID" : "12345", + // "NList" : [ 12.22, -0.00234, null ], + // "ISBN" : "111-1111111111999", + // "Title" : "Book 10122 Title", + // "Id" : -12243.78, + // "newKey2" : "foo" + // }, + // "Id" : 101.01, + // "NList1" : [ { + // "$set" : [ "Updated_set_01", "Updated_set_02" ] + // }, -0.00234 ], + // "NSet1" : { + // "$set" : [ 123.45, 9586.7778, -124, 10238 ] + // } + // }, + // "Id1" : "12345", + // "attr_6" : { + // "n_attr_0" : "str_val_0", + // "n_attr_1" : 1295.03, + // "n_attr_2" : { + // "$binary" : { + // "base64" : "MjA0OHU1bmJsd2plaVdGR1RIKDRiZjkzMA==", + // "subType" : "00" + // } + // }, + // "n_attr_3" : true, + // "n_attr_4" : null + // }, + // "attr_5" : [ 1224, "str001", { + // "$binary" : { + // "base64" : "AAECAwQF", + // "subType" : "00" + // } + // } ], + // "NestedList12" : [ -485.34, "1234abcd", [ { + // "$set" : [ "xyz01234", "xyz0123", "abc01234" ] + // }, { + // "$set" : [ { + // "$binary" : { + // "base64" : "dmFsMDE=", + // "subType" : "00" + // } + // }, { + // "$binary" : { + // "base64" : "dmFsMDM=", + // "subType" : "00" + // } + // }, { + // "$binary" : { + // "base64" : "dmFsMDI=", + // "subType" : "00" + // } + // }, { + // "$binary" : { + // "base64" : "dmFsMDQ=", + // "subType" : "00" + // } + // } ] + // } ] ], + // "Id" : "12345", + // "attr_1" : 1295.03, + // "attr_0" : "str_val_0", + // "RelatedItems" : { + // "$set" : [ 123.0948, -485.45582904, 1234, 0.111 ] + // } + //} + return RawBsonDocument.parse(json); + } + } \ No newline at end of file diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/bson/UpdateExpressionUtilsTest.java b/phoenix-core/src/test/java/org/apache/phoenix/util/bson/UpdateExpressionUtilsTest.java index 10eb931391..6dea82c3a7 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/util/bson/UpdateExpressionUtilsTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/util/bson/UpdateExpressionUtilsTest.java @@ -285,6 +285,50 @@ public class UpdateExpressionUtilsTest { //{ // "$SET": { + // "attr_2": { + // "$IF_NOT_EXISTS": { + // "attr_1": 10.01 + // } + // }, + // "attr_20": { + // "$IF_NOT_EXISTS": { + // "attrNotExists": "foo" + // } + // }, + // "key9": { + // "$IF_NOT_EXISTS": { + // "Id": "val9" + // } + // }, + // "key90": { + // "$IF_NOT_EXISTS": { + // "ids": { + // "$set" : [ 123.0948, -485.45582904, 1234, 0.111 ] + // } + // } + // }, + // "attr_6.n_attr_10": { + // "$IF_NOT_EXISTS": { + // "attr_6.n_attr_10": true + // } + // }, + // "attr_6.n_attr_20": { + // "$IF_NOT_EXISTS": { + // "attr_6.n_attr_0": "str_val_1" + // } + // }, + // "NestedList1[2][1].ISBN2": { + // "$IF_NOT_EXISTS": { + // "NestedList1[2][1].ISBN2": { + // "ISBN": "111-1111111122" + // } + // } + // }, + // "NestedList1[2][1].ISBNCOPY": { + // "$IF_NOT_EXISTS": { + // "NestedList1[2][1].ISBN": "isbn" + // } + // }, // "NestedList1[0]": "NestedList1[0] + 12.22", // "NestedList1[3]": null, // "NestedList1[4]": true, @@ -305,6 +349,50 @@ public class UpdateExpressionUtilsTest { updateExpression = "{\n" + " \"$SET\": {\n" + + " \"attr_2\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"attr_1\": 10.01\n" + + " }\n" + + " },\n" + + " \"attr_20\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"attrNotExists\": \"foo\"\n" + + " }\n" + + " },\n" + + " \"key9\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"Id\": \"val9\"\n" + + " }\n" + + " },\n" + + " \"key90\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"ids\": {\n" + + " \"$set\" : [ 123.0948, -485.45582904, 1234, 0.111 ]\n" + + " }\n" + + " }\n" + + " },\n" + + " \"attr_6.n_attr_10\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"attr_6.n_attr_10\": true\n" + + " }\n" + + " },\n" + + " \"attr_6.n_attr_20\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"attr_6.n_attr_0\": \"str_val_1\"\n" + + " }\n" + + " },\n" + + " \"NestedList1[2][1].ISBN2\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"NestedList1[2][1].ISBN2\": {\n" + + " \"ISBN\": \"111-1111111122\"\n" + + " }\n" + + " }\n" + + " },\n" + + " \"NestedList1[2][1].ISBNCOPY\": {\n" + + " \"$IF_NOT_EXISTS\": {\n" + + " \"NestedList1[2][1].ISBN\": \"isbn\"\n" + + " }\n" + + " },\n" + " \"NestedList1[0]\": \"NestedList1[0] + 12.22\",\n" + " \"NestedList1[3]\": null,\n" + " \"NestedList1[4]\": true,\n" + @@ -1178,8 +1266,12 @@ public class UpdateExpressionUtilsTest { " \"Id\" : 101.01,\n" + " \"TitleSet2\" : {\n" + " \"$set\" : [ \"Book 1201 Title\", \"Book 1111 Title\", \"Book 1200 Title\" ]\n" + - " }\n" + - " } ], null, true ],\n" + + " },\n" + + " \"ISBN2\" : {\n" + + " \"ISBN\" : \"111-1111111122\"\n" + + " },\n" + + " \"ISBNCOPY\" : \"111-1111111122\"\n" + + " } ], null, true ],\n" + " \"NestedMap1\" : {\n" + " \"InPublication\" : false,\n" + " \"ISBN\" : \"111-1111111111\",\n" + @@ -1215,7 +1307,9 @@ public class UpdateExpressionUtilsTest { " }\n" + " },\n" + " \"n_attr_3\" : true,\n" + - " \"n_attr_4\" : null\n" + + " \"n_attr_4\" : null,\n" + + " \"n_attr_10\" : true,\n" + + " \"n_attr_20\" : \"str_val_0\"\n" + " },\n" + " \"attr_5\" : [ 1224, \"str001\", {\n" + " \"$binary\" : {\n" + @@ -1255,7 +1349,13 @@ public class UpdateExpressionUtilsTest { " \"$set\" : [ 123.0948, -485.45582904, 1234, 0.111 ]\n" + " },\n" + " \"Id1\" : \"12345\",\n" + - " \"AddedId\" : 10\n" + + " \"AddedId\" : 10,\n" + + " \"attr_2\" : 1295.03,\n" + + " \"attr_20\" : \"foo\",\n" + + " \"key9\" : \"12345\",\n" + + " \"key90\" : {\n" + + " \"$set\" : [ 123.0948, -485.45582904, 1234, 0.111 ]\n" + + " }\n" + "}"; //{ // "Pictures" : { @@ -1321,7 +1421,11 @@ public class UpdateExpressionUtilsTest { // "Id" : 101.01, // "TitleSet2" : { // "$set" : [ "Book 1201 Title", "Book 1111 Title", "Book 1200 Title" ] + // }, + // "ISBN2" : { + // "ISBN" : "111-1111111122" // } + // "ISBNCOPY" : "111-1111111122" // } ], null, true ], // "NestedMap1" : { // "InPublication" : false, @@ -1358,7 +1462,9 @@ public class UpdateExpressionUtilsTest { // } // }, // "n_attr_3" : true, - // "n_attr_4" : null + // "n_attr_4" : null, + // "n_attr_10" : true, + // "n_attr_20" : "str_val_0" // }, // "attr_5" : [ 1224, "str001", { // "$binary" : { @@ -1398,7 +1504,13 @@ public class UpdateExpressionUtilsTest { // "$set" : [ 123.0948, -485.45582904, 1234, 0.111 ] // }, // "Id1" : "12345", - // "AddedId" : 10 + // "AddedId" : 10, + // "attr_2" : 1295.03, + // "attr_20" : "foo", + // "key9" : 12345, + // "key90" : { + // "$set" : [ 123.0948, -485.45582904, 1234, 0.111 ] + // } //} return RawBsonDocument.parse(json); }