Skip to content

Commit 32892f1

Browse files
committed
Fix for Bug#107510 (Bug#34259416), Empty string given to set() from Collection.modify() replaces full document.
Change-Id: Iebd779f2467cd9c34e4a8931def97bd93cd6cf9b
1 parent 0604bf4 commit 32892f1

File tree

6 files changed

+125
-18
lines changed

6 files changed

+125
-18
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
Version 8.0.30
55

6+
- Fix for Bug#107510 (Bug#34259416), Empty string given to set() from Collection.modify() replaces full document.
7+
68
- Fix for Bug#106758 (33973048), DatabaseMetaData.getTypeInfo returns AUTO_INCREMENT = false for all datatypes.
79

810
- Fix for Bug#34090350, Update mappings for utf8mb3 and utf8mb4 collations.

src/main/resources/com/mysql/cj/LocalizedErrorMessages.properties

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ Blob.invalidStreamPos=Position ''pos'' can not be < 1 or > blob length.
7676
Blob.8=Emulated BLOB locators must come from a ResultSet with only one table selected, and all primary keys selected
7777
Blob.9=BLOB data not found! Did primary keys change?
7878

79-
8079
Buffer.0=Payload length can not be larger than buffer size.
8180
Buffer.1=Buffer length is less than expected payload length.
8281

@@ -190,7 +189,6 @@ ConnectionString.24=Using named pipes with DNS SRV lookup is not allowed.
190189
ConnectionString.25=The option ''{0}'' cannot be set. Live management of connections is not supported with DNS SRV lookup.
191190
ConnectionString.26=Unable to locate any hosts for {0}.
192191

193-
194192
ConnectionWrapper.0=Can''t set autocommit to ''true'' on an XAConnection
195193
ConnectionWrapper.1=Can''t call commit() on an XAConnection associated with a global transaction
196194
ConnectionWrapper.2=Can''t call rollback() on an XAConnection associated with a global transaction
@@ -676,6 +674,7 @@ Util.5=Error reading from InputStream
676674
#
677675
# Exceptions
678676
#
677+
679678
AssertionFailedException.0=ASSERTION FAILED: Exception
680679
AssertionFailedException.1=\ that should not be thrown, was thrown
681680
AssertionFailedException.2=ASSERTION FAILED: {0}

src/main/user-api/java/com/mysql/cj/xdevapi/ModifyStatement.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2020, Oracle and/or its affiliates.
2+
* Copyright (c) 2015, 2022, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify it under
55
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -76,11 +76,11 @@ public interface ModifyStatement extends Statement<ModifyStatement, Result> {
7676
/**
7777
* Nullify the given fields.
7878
*
79-
* @param fields
79+
* @param docPath
8080
* one or more field names
8181
* @return {@link ModifyStatement}
8282
*/
83-
ModifyStatement unset(String... fields);
83+
ModifyStatement unset(String... docPath);
8484

8585
/**
8686
* Takes in a patch object and applies it on all documents matching the modify() filter, using the JSON_MERGE_PATCH() function.
@@ -111,22 +111,22 @@ public interface ModifyStatement extends Statement<ModifyStatement, Result> {
111111
/**
112112
* Insert a value into the specified array.
113113
*
114-
* @param field
114+
* @param docPath
115115
* document path to the array field
116116
* @param value
117117
* value to insert
118118
* @return {@link ModifyStatement}
119119
*/
120-
ModifyStatement arrayInsert(String field, Object value);
120+
ModifyStatement arrayInsert(String docPath, Object value);
121121

122122
/**
123123
* Append a value to the specified array.
124124
*
125-
* @param field
125+
* @param docPath
126126
* document path to the array field
127127
* @param value
128128
* value to append
129129
* @return {@link ModifyStatement}
130130
*/
131-
ModifyStatement arrayAppend(String field, Object value);
131+
ModifyStatement arrayAppend(String docPath, Object value);
132132
}

src/main/user-impl/java/com/mysql/cj/xdevapi/ModifyStatementImpl.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2020, Oracle and/or its affiliates.
2+
* Copyright (c) 2015, 2022, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify it under
55
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -49,7 +49,7 @@ public class ModifyStatementImpl extends FilterableStatement<ModifyStatement, Re
4949
/* package private */ ModifyStatementImpl(MysqlxSession mysqlxSession, String schema, String collection, String criteria) {
5050
super(new DocFilterParams(schema, collection, false));
5151
this.mysqlxSession = mysqlxSession;
52-
if (criteria == null || criteria.trim().length() == 0) {
52+
if (criteria == null || criteria.trim().isEmpty()) {
5353
throw new XDevAPIError(Messages.getString("ModifyStatement.0", new String[] { "criteria" }));
5454
}
5555
this.filterParams.setCriteria(criteria);
@@ -95,9 +95,12 @@ public ModifyStatement change(String docPath, Object value) {
9595
}
9696

9797
@Override
98-
public ModifyStatement unset(String... fields) {
98+
public ModifyStatement unset(String... docPath) {
9999
resetPrepareState();
100-
this.updates.addAll(Arrays.stream(fields).map(docPath -> new UpdateSpec(UpdateType.ITEM_REMOVE, docPath)).collect(Collectors.toList()));
100+
if (docPath == null) {
101+
throw new XDevAPIError(Messages.getString("ModifyStatement.0", new String[] { "docPath" }));
102+
}
103+
this.updates.addAll(Arrays.stream(docPath).map(dp -> new UpdateSpec(UpdateType.ITEM_REMOVE, dp)).collect(Collectors.toList()));
101104
return this;
102105
}
103106

@@ -110,14 +113,14 @@ public ModifyStatement patch(DbDoc document) {
110113
@Override
111114
public ModifyStatement patch(String document) {
112115
resetPrepareState();
113-
this.updates.add(new UpdateSpec(UpdateType.MERGE_PATCH, "").setValue(Expression.expr(document)));
116+
this.updates.add(new UpdateSpec(UpdateType.MERGE_PATCH).setValue(Expression.expr(document)));
114117
return this;
115118
}
116119

117120
@Override
118-
public ModifyStatement arrayInsert(String field, Object value) {
121+
public ModifyStatement arrayInsert(String docPath, Object value) {
119122
resetPrepareState();
120-
this.updates.add(new UpdateSpec(UpdateType.ARRAY_INSERT, field).setValue(value));
123+
this.updates.add(new UpdateSpec(UpdateType.ARRAY_INSERT, docPath).setValue(value));
121124
return this;
122125
}
123126

src/main/user-impl/java/com/mysql/cj/xdevapi/UpdateSpec.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2020, Oracle and/or its affiliates.
2+
* Copyright (c) 2015, 2022, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify it under
55
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -29,6 +29,7 @@
2929

3030
package com.mysql.cj.xdevapi;
3131

32+
import com.mysql.cj.Messages;
3233
import com.mysql.cj.x.protobuf.MysqlxCrud.UpdateOperation;
3334
import com.mysql.cj.x.protobuf.MysqlxExpr.ColumnIdentifier;
3435
import com.mysql.cj.x.protobuf.MysqlxExpr.Expr;
@@ -43,6 +44,17 @@ public class UpdateSpec {
4344
private ColumnIdentifier source;
4445
private Expr value;
4546

47+
/**
48+
* Constructor.
49+
*
50+
* @param updateType
51+
* update operation type
52+
*/
53+
public UpdateSpec(UpdateType updateType) {
54+
this.updateType = UpdateOperation.UpdateType.valueOf(updateType.name());
55+
this.source = ColumnIdentifier.getDefaultInstance();
56+
}
57+
4658
/**
4759
* Constructor.
4860
*
@@ -53,6 +65,9 @@ public class UpdateSpec {
5365
*/
5466
public UpdateSpec(UpdateType updateType, String source) {
5567
this.updateType = UpdateOperation.UpdateType.valueOf(updateType.name());
68+
if (source == null || source.trim().isEmpty()) {
69+
throw new XDevAPIError(Messages.getString("ModifyStatement.0", new String[] { "docPath" }));
70+
}
5671
// accommodate parser's documentField() handling by removing "$"
5772
if (source.length() > 0 && source.charAt(0) == '$') {
5873
source = source.substring(1);

src/test/java/testsuite/x/devapi/CollectionModifyTest.java

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
2+
* Copyright (c) 2015, 2022, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify it under
55
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -49,6 +49,7 @@
4949
import org.junit.jupiter.api.Test;
5050

5151
import com.mysql.cj.ServerVersion;
52+
import com.mysql.cj.exceptions.CJException;
5253
import com.mysql.cj.xdevapi.AddResult;
5354
import com.mysql.cj.xdevapi.Collection;
5455
import com.mysql.cj.xdevapi.DbDoc;
@@ -1890,4 +1891,91 @@ public void testCollectionModifyAsyncMany() throws Exception {
18901891
doc = docs.next();
18911892
assertEquals((long) (maxrec) / 2, (long) (((JsonNumber) doc.get("cnt")).getInteger()));
18921893
}
1894+
1895+
/**
1896+
* Tests fix for Bug#107510 (Bug#34259416), Empty string given to set() from Collection.modify() replaces full document.
1897+
*
1898+
* @throws Exception
1899+
*/
1900+
@Test
1901+
public void testBug107510() throws Exception {
1902+
this.collection.add("{\"bug\": \"testBug107510\"}").execute();
1903+
DbDoc doc = this.collection.find().execute().fetchOne();
1904+
assertEquals("testBug107510", ((JsonString) doc.get("bug")).getString());
1905+
1906+
// .set()
1907+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1908+
this.collection.modify("true").set("", JsonParser.parseDoc("{\"bug\": \"testBug34259416\"}")).execute();
1909+
return null;
1910+
});
1911+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1912+
this.collection.modify("true").set(null, JsonParser.parseDoc("{\"bug\": \"testBug34259416\"}")).execute();
1913+
return null;
1914+
});
1915+
doc = this.collection.find().execute().fetchOne();
1916+
assertEquals("testBug107510", ((JsonString) doc.get("bug")).getString());
1917+
1918+
this.collection.modify("true").set("$", JsonParser.parseDoc("{\"bug\": \"testBug34259416\"}")).execute();
1919+
doc = this.collection.find().execute().fetchOne();
1920+
assertEquals("testBug34259416", ((JsonString) doc.get("bug")).getString());
1921+
1922+
this.collection.modify("true").set("$.type", "BUG1").execute();
1923+
doc = this.collection.find().execute().fetchOne();
1924+
assertEquals("testBug34259416", ((JsonString) doc.get("bug")).getString());
1925+
assertEquals("BUG1", ((JsonString) doc.get("type")).getString());
1926+
1927+
this.collection.modify("true").set(".type", "BUG2").execute();
1928+
doc = this.collection.find().execute().fetchOne();
1929+
assertEquals("testBug34259416", ((JsonString) doc.get("bug")).getString());
1930+
assertEquals("BUG2", ((JsonString) doc.get("type")).getString());
1931+
1932+
this.collection.modify("true").set("type", "BUG3").execute();
1933+
doc = this.collection.find().execute().fetchOne();
1934+
assertEquals("testBug34259416", ((JsonString) doc.get("bug")).getString());
1935+
assertEquals("BUG3", ((JsonString) doc.get("type")).getString());
1936+
1937+
// .unset()
1938+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1939+
this.collection.modify("true").unset("").execute();
1940+
return null;
1941+
});
1942+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1943+
this.collection.modify("true").unset((String) null).execute();
1944+
return null;
1945+
});
1946+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1947+
this.collection.modify("true").unset((String[]) null).execute();
1948+
return null;
1949+
});
1950+
1951+
// .change()
1952+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1953+
this.collection.modify("true").change("", "").execute();
1954+
return null;
1955+
});
1956+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1957+
this.collection.modify("true").change(null, "").execute();
1958+
return null;
1959+
});
1960+
1961+
// .arrayAppend()
1962+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1963+
this.collection.modify("true").arrayAppend("", "").execute();
1964+
return null;
1965+
});
1966+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1967+
this.collection.modify("true").arrayAppend(null, "").execute();
1968+
return null;
1969+
});
1970+
1971+
// .arrayInsert()
1972+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1973+
this.collection.modify("true").arrayInsert("", "").execute();
1974+
return null;
1975+
});
1976+
assertThrows(CJException.class, "Parameter 'docPath' must not be null or empty\\.", () -> {
1977+
this.collection.modify("true").arrayInsert(null, "").execute();
1978+
return null;
1979+
});
1980+
}
18931981
}

0 commit comments

Comments
 (0)