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)

Reply via email to