This is an automated email from the ASF dual-hosted git repository.
mihaibudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 2862a8d5de [CALCITE-7668] MongoDB adapter should escape embedded
quotes in field references
2862a8d5de is described below
commit 2862a8d5de5735ff74ba4ab38b3f57c0bf81f653
Author: bibi samina <[email protected]>
AuthorDate: Wed Jul 29 14:14:39 2026 +0530
[CALCITE-7668] MongoDB adapter should escape embedded quotes in field
references
---
.../apache/calcite/adapter/mongodb/MongoRules.java | 6 ++--
.../calcite/adapter/mongodb/MongoAdapterTest.java | 33 ++++++++++++++++++++++
2 files changed, 37 insertions(+), 2 deletions(-)
diff --git
a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
index 48e46e610d..fe7c65db10 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
@@ -110,7 +110,9 @@ static String maybeQuote(String s) {
}
static String quote(String s) {
- return "'" + s + "'"; // TODO: handle embedded quotes
+ // Escape backslash and the single-quote delimiter so that s cannot break
+ // out of the quoted token when the string is parsed by BsonDocument.parse.
+ return "'" + s.replace("\\", "\\\\").replace("'", "\\'") + "'";
}
private static boolean needsQuote(String s) {
@@ -181,7 +183,7 @@ protected RexToMongoTranslator(JavaTypeFactory typeFactory,
@Override public String visitCall(RexCall call) {
String name = isItem(call);
if (name != null) {
- return "'$" + name + "'";
+ return quote("$" + name);
}
final List<String> strings = visitList(call.operands);
if (call.getKind() == SqlKind.CAST) {
diff --git
a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java
b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java
index 7c79718e79..c4fef104f8 100644
---
a/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java
+++
b/mongodb/src/test/java/org/apache/calcite/adapter/mongodb/MongoAdapterTest.java
@@ -86,6 +86,13 @@ public class MongoAdapterTest implements SchemaFactory {
/** Number of records in local file. */
protected static final int ZIPS_SIZE = 149;
+ /** Field of the "datatypes" collection whose name contains a single quote
+ * and characters that would be pipeline syntax if it were not escaped. */
+ private static final String QUOTED_FIELD = "x', injected: {$literal: 1}, y:
'z";
+
+ /** Field of the "datatypes" collection whose name ends with a backslash. */
+ private static final String BACKSLASH_FIELD = "a\\";
+
@RegisterExtension
public static final MongoDatabasePolicy POLICY =
MongoDatabasePolicy.create();
@@ -119,6 +126,8 @@ public static void setUp() throws Exception {
doc.put("ownerId", new BsonString("531e7789e4b0853ddb861313"));
doc.put("arr", new BsonArray(Arrays.asList(new BsonString("a"), new
BsonString("b"))));
doc.put("binaryData", new
BsonBinary("binaryData".getBytes(StandardCharsets.UTF_8)));
+ doc.put(QUOTED_FIELD, new BsonString("quoted"));
+ doc.put(BACKSLASH_FIELD, new BsonString("backslash"));
datatypes.insertOne(doc);
schema = new MongoSchema(database);
@@ -743,6 +752,30 @@ private void checkPredicate(int expected, String q) {
.returnsUnordered("EXPR$0=[a, b]");
}
+ /** A field name that contains a single quote or a backslash must not be able
+ * to break out of the quoted token in the generated pipeline and add stage
+ * fields of its own.
+ *
+ * <p>The expected values were validated against a real MongoDB instance:
+ * without the escaping the first query parses as
+ * {@code {$project: {C: '$x', injected: {$literal: 1}, y: 'z'}}} and the
+ * injected field breaks the pipeline, so the query fails. */
+ @Test void testItemKeyWithEmbeddedQuote() {
+ assertModel(MODEL)
+ .query("select cast(_MAP['x'', injected: {$literal: 1}, y: ''z'] as
varchar) as c\n"
+ + "from \"mongo_raw\".\"datatypes\"")
+ .returnsUnordered("C=quoted")
+ .queryContains(
+ mongoChecker("{$project: {C: '$x\\', injected: {$literal: 1}, y:
\\'z'}}"));
+
+ assertModel(MODEL)
+ .query("select cast(_MAP['a\\'] as varchar) as c\n"
+ + "from \"mongo_raw\".\"datatypes\"")
+ .returnsUnordered("C=backslash")
+ .queryContains(
+ mongoChecker("{$project: {C: '$a\\\\'}}"));
+ }
+
/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-665">[CALCITE-665]
* ClassCastException in MongoDB adapter</a>. */