You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@geode.apache.org by "Barrett Oglesby (Jira)" <ji...@apache.org> on 2021/04/19 21:05:00 UTC

[jira] [Created] (GEODE-9174) A gfsh query with a UUID in the result may not be displayed properly

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)