Barrett Oglesby created GEODE-9174: -------------------------------------- Summary: A gfsh query with a UUID in the result may not be displayed properly Key: GEODE-9174 URL: https://issues.apache.org/jira/browse/GEODE-9174 Project: Geode Issue Type: Bug Components: gfsh, querying Reporter: Barrett Oglesby
For example, if the key is a UUID, then a query like this won't show the results even though there is one: {noformat} gfsh>query --query="select key from /data.entries where value.id = '55e907b6-a1fe-42ea-90a2-6a5698e9b27c'" Result : true Limit : 100 Rows : 1 {noformat} But a query like this will: {noformat} gfsh>query --query="select key,value from /data.entries where value.id = '55e907b6-a1fe-42ea-90a2-6a5698e9b27c'" Result : true Limit : 100 Rows : 1 key | value -------------------------------------- | --------------------------------------------------------------------------------------- "55e907b6-a1fe-42ea-90a2-6a5698e9b27c" | {"id":"55e907b6-a1fe-42ea-90a2-6a5698e9b27c","cusip":"AAPL","shares":22,"price":352.32} {noformat} Thats because of the way {{DataCommandResult.resolveObjectToColumns}} works. {noformat} private void resolveObjectToColumns(Map<String, String> columnData, Object value) { if (value instanceof PdxInstance) { resolvePdxToColumns(columnData, (PdxInstance) value); } else if (value instanceof Struct) { resolveStructToColumns(columnData, (StructImpl) value); } else { ObjectMapper mapper = new ObjectMapper(); JsonNode node = mapper.valueToTree(value); node.fieldNames().forEachRemaining(field -> { ... columnData.put(field, mapper.writeValueAsString(node.get(field))); }); } } {noformat} The value in the first query is a {{UUID}} so the last else clause is invoked. In this case, a {{JsonNode}} is used to determine the columns. {{ObjectMapper.valueToTree}} converts a {{UUID}} to a {{TextNode}}. {{TextNodes}} have no fieldNames, and {{JsonNode.fieldNames}} returns an {{EmptyIterator}} by default: {noformat} public Iterator<String> fieldNames() { return ClassUtil.emptyIterator(); } {noformat} So, {{resolveObjectToColumns}} doesn't fill in columnData, which causes the {{DataCommandResult.buildTable}} in the locator to not add any rows to the table. The value in the second query is a {{Struct}} so the second else clause is invoked. The {{resolveStructToColumns}} method does: {noformat} private void resolveStructToColumns(Map<String, String> columnData, StructImpl struct) { for (String field : struct.getFieldNames()) { columnData.put(field, valueToJson(struct.get(field))); } } {noformat} I'm not sure if there is a way to make {{ObjectMapper.valueToTree}} handle {{UUIDs}} differently, but they can easily be special-cased like {{PdxInstances}} and {{Structs}}: {noformat} } else if (value instanceof UUID) { columnData.put("uuid", valueToJson(value)); {noformat} I'm not sure if this is the best solution, but it works. With this clause added, the query does: {noformat} gfsh>query --query="select key from /data.entries where value.id = '55e907b6-a1fe-42ea-90a2-6a5698e9b27c'" Result : true Limit : 100 Rows : 1 uuid -------------------------------------- "55e907b6-a1fe-42ea-90a2-6a5698e9b27c" {noformat} -- This message was sent by Atlassian Jira (v8.3.4#803005)