Skip to content

Fix boolean coercion from numeric values for wildcard index queries (#5269)#5293

Open
qianheng-aws wants to merge 2 commits intoopensearch-project:mainfrom
qianheng-aws:bugfix
Open

Fix boolean coercion from numeric values for wildcard index queries (#5269)#5293
qianheng-aws wants to merge 2 commits intoopensearch-project:mainfrom
qianheng-aws:bugfix

Conversation

@qianheng-aws
Copy link
Copy Markdown
Collaborator

Description

[BugFix] When querying across indices with conflicting field mappings (boolean vs text) using wildcard patterns like source = repro*, numeric values such as 0 stored in the text-typed index were not coerced to boolean, causing OpenSearchParseException: node must be a boolean, found NUMBER.

Root cause: OpenSearchJsonContent.parseBooleanValue() only handled isBoolean() and isTextual() nodes but not numeric nodes. Added isNumber() handling consistent with ObjectContent.booleanValue() which already does ((Number) value).intValue() != 0.

Related Issues

Resolves #5269

Check List

  • New functionality includes testing
  • Javadoc added for new public API
  • Commits signed per DCO (-s)
  • spotlessCheck passed
  • Unit tests passed
  • Integration tests passed
  • Grammar changes: all three .g4 files synced (if applicable)

…pensearch-project#5269)

When querying across indices with conflicting field mappings (boolean vs
text), numeric values like 0 were not coerced to boolean, causing
"node must be a boolean, found NUMBER" error. Added numeric handling to
parseBooleanValue() consistent with ObjectContent.booleanValue().

Signed-off-by: Qianheng Chen <chenqiah@amazon.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Heng Qian <qianheng@amazon.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

PR Reviewer Guide 🔍

(Review updated until commit 614bd7d)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 Multiple PR themes

Sub-PR theme: Fix boolean coercion from numeric values in OpenSearchJsonContent

Relevant files:

  • opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/OpenSearchJsonContent.java
  • opensearch/src/test/java/org/opensearch/sql/opensearch/data/value/OpenSearchExprValueFactoryTest.java

Sub-PR theme: Add integration tests for wildcard index boolean/text mapping conflict

Relevant files:

  • integ-test/src/test/java/org/opensearch/sql/ppl/DataTypeIT.java
  • integ-test/src/yamlRestTest/resources/rest-api-spec/test/issues/5269.yml

⚡ Recommended focus areas for review

Floating Point Handling

The fix uses node.intValue() for numeric nodes, which truncates floating-point values (e.g., 0.5 would become 0 and thus false). Consider whether node.doubleValue() != 0 or node.numberValue().doubleValue() != 0 would be more appropriate to handle all numeric types consistently, especially since JSON numbers can be floats.

} else if (node.isNumber()) {
  return node.intValue() != 0;
Hardcoded Dates

The test uses hardcoded dates like 2026-03-25T20:25:00.000Z which are in the past relative to the PR date (2026-04-01). While not a bug, using relative or clearly arbitrary dates would make the test more maintainable and less confusing over time.

insertBool.setJsonEntity("{\"startTime\":\"2026-03-25T20:25:00.000Z\",\"flag\":false}");
client().performRequest(insertBool);

// Insert numeric value into text-typed index
Request insertText = new Request("PUT", "/" + indexText + "/_doc/1?refresh=true");
insertText.setJsonEntity("{\"startTime\":\"2026-03-24T20:25:00.000Z\",\"flag\":0}");

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

PR Code Suggestions ✨

Latest suggestions up to 614bd7d
Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Handle floating-point numeric boolean coercion correctly

Using node.intValue() on a floating-point number (e.g., 0.5) will truncate to 0,
incorrectly returning false. Consider using node.doubleValue() != 0 or
node.numberValue().doubleValue() != 0 to correctly handle all numeric types
including floats and doubles.

opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/OpenSearchJsonContent.java [215-216]

 } else if (node.isNumber()) {
-  return node.intValue() != 0;
+  return node.doubleValue() != 0;
 }
Suggestion importance[1-10]: 6

__

Why: Using node.intValue() truncates floating-point numbers (e.g., 0.5 becomes 0, returning false), while node.doubleValue() != 0 would correctly handle all numeric types. This is a valid edge case, though the primary use case in the PR is integer values like 0 and 1.

Low
General
Assert actual coerced boolean values in test

The test only verifies the count of returned rows but does not validate the actual
boolean values returned. Adding assertions on the actual flag values would make the
test more meaningful and ensure the coercion produces correct results (e.g., false
for numeric 0).

integ-test/src/test/java/org/opensearch/sql/ppl/DataTypeIT.java [181-182]

 JSONObject result = executeQuery("source=repro_bool_test_* | fields flag");
-assertEquals(2, result.getJSONArray("datarows").length());
+JSONArray datarows = result.getJSONArray("datarows");
+assertEquals(2, datarows.length());
+// Verify that both rows contain valid boolean values (false)
+for (int i = 0; i < datarows.length(); i++) {
+  assertFalse(datarows.getJSONArray(i).getBoolean(0));
+}
Suggestion importance[1-10]: 4

__

Why: The suggestion to validate actual flag values improves test coverage, but the improved code asserts false for both rows, which is incorrect since the indexBool document has flag: false and indexText has flag: 0 (both false), but the ordering isn't guaranteed. The suggestion has merit but the implementation may be fragile.

Low

Previous suggestions

Suggestions up to commit d237222
CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix numeric boolean coercion for floating-point values

Using intValue() on a floating-point number (e.g., 0.5) will truncate to 0,
incorrectly returning false. Use doubleValue() or node.numberValue().doubleValue()
to correctly handle all numeric types, or check node.asDouble() != 0 to avoid
truncation issues.

opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/OpenSearchJsonContent.java [215-216]

 } else if (node.isNumber()) {
-  return node.intValue() != 0;
+  return node.doubleValue() != 0;
 }
Suggestion importance[1-10]: 6

__

Why: Using intValue() on floating-point numbers truncates to integer, causing 0.5 to incorrectly return false. Using doubleValue() would handle all numeric types correctly, though the current PR's use case (integer 0 or 1) may not be affected in practice.

Low
General
Ensure both indices are cleaned up in teardown

If the first DELETE request throws an exception, the second index will not be
cleaned up, leaving test state behind. Add ignore_unavailable or wrap each delete in
its own try-catch to ensure both indices are always deleted.

integ-test/src/test/java/org/opensearch/sql/ppl/DataTypeIT.java [184-185]

-client().performRequest(new Request("DELETE", "/" + indexBool));
-client().performRequest(new Request("DELETE", "/" + indexText));
+try {
+  client().performRequest(new Request("DELETE", "/" + indexBool + "?ignore_unavailable=true"));
+} finally {
+  client().performRequest(new Request("DELETE", "/" + indexText + "?ignore_unavailable=true"));
+}
Suggestion importance[1-10]: 4

__

Why: If the first DELETE request fails, the second index won't be cleaned up. Wrapping each delete in a nested try-finally ensures both indices are always removed, improving test reliability.

Low

@qianheng-aws qianheng-aws added bugFix bug Something isn't working labels Apr 1, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Persistent review updated to latest commit 614bd7d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working bugFix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] PPL error node must be a boolean when mapping conflicts

1 participant