neo4j / neo4j-java-driver

Neo4j Bolt driver for Java
Apache License 2.0
330 stars 155 forks source link

Result::fieldNames is empty after query execution #27

Closed FylmTM closed 9 years ago

FylmTM commented 9 years ago

We create 3 nodes in database:

CREATE (m:Movie {title: 'Lord of the Rings', author: 'J. R. R. Tolkien'})
CREATE (a:Actor {name: 'Orlando Bloom'})
CREATE (m:Movie {title: 'Troy', author: 'Homer'})

Then we try to execute select query:

MATCH (n) RETURN n

Expected: 3 nodes returned, under n key What we have: result contains 3 nodes, but fieldsNames property is empty.

Debug result:

// driver/src/main/java/org/neo4j/driver/internal/StandardTransaction.java:121
conn.sync(); // <<<< 1
return resultBuilder.build(); // <<<< 2
Sync phase (1)

ResultBuilder - stateful container. Field names are populated in fieldNames method. This method is called when success message received:

// /driver/src/main/java/org/neo4j/driver/internal/messaging/PackStreamMessageFormatV1.java:368
case MSG_SUCCESS:
    unpackSuccessMessage( handler );
    break;

When we execute query we have this handling order:

So, on first success we correctly receive fieldNames:

fieldLookup.toString()
// {n=0}

But, when second success is received we call fieldNames() on ResultBuilder with no names. So, second success message doesn't containt any names. And this message overrides fieldNames from first success message.

Build phase (2)

Now in builder state we have valid body with 3 records. But fieldNames is empty.


I am not sure where I should look to fix this problem. If you can point me to correct place in the code, I can try to fix this problem and open pull request.

FylmTM commented 9 years ago

Update.

// driver/src/main/java/org/neo4j/driver/internal/connector/socket/SocketClient.java:111
        while ( handler.receivedresponses() < pendingmessages.size() )
        {
            reader.read( handler );
        }

pendingMessages variables has two messages for select query:

[
[RUN "MATCH (n) RETURN n as n" {}], 
[PULL_ALL]
]

First one - just puts field names into collector (correctly) Second one - puts records into collector body, and then overrides fieldNames in collector, in org.neo4j.driver.internal.connector.socket.SocketResponseHandler#handleSuccessMessage method with empty array.

jakewins commented 9 years ago

Hey mate!

This is actually by design - we only return the field names once, in the SUCCESS message sent for the RUN command. This is to avoid redundancy on the wire - and to highlight that the field names is metadata associated with the RUN command. The SUCCESS message sent in response to a RUN constitutes query metadata.

If you want to know the field names, simply store the result of the SUCCESS message returned from the RUN.

Also note; these APIs are internal, not part of the API of the driver.

Eg: This is by design, closing this as a wontfix

/j