Skip to content

Commit

Permalink
Fix element ID neo4j_value type for Bolt v5
Browse files Browse the repository at this point in the history
Trying to read actual element IDs received over Bolt v5 caused assertion failures in neo4j_node_elementid() and friends. According to the Bolt v5 protocol structure semantics, element IDs are transferred as strings. Because struct_deserialize() left them as NEO4J_STRING, reading out the element IDs failed as other code expects them to be NEO4J_ELEMENTID.

The issue doesn't show up on earlier Bolt versions because for those versions, the element IDs are synthesized from legacy numeric IDs during deserialisation. That special case uses the correct neo4j_value type NEO4J_ELEMENTID to begin with.

This change replaces the NEO4J_STRING neo4j_value type metadata of received element ID strings with NEO4J_ELEMENTID. The underlying string is not touched.
  • Loading branch information
johannessen committed Oct 31, 2024
1 parent e32267b commit 65b4d4d
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 1 deletion.
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#
dnl Process this file with autoconf to produce a configure script
AC_PREREQ([2.69])
AC_INIT([libneo4j-client],[5.0.3])
AC_INIT([libneo4j-client],[5.0.4])
AC_CONFIG_SRCDIR([lib/src/neo4j-client.h.in])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
Expand Down
11 changes: 11 additions & 0 deletions lib/src/deserialization.c
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,9 @@ int struct_deserialize(uint16_t nfields, neo4j_iostream_t *stream,
fields[3] = neo4j_elementid( eid );

}
else { // v5.0 node
fields[3] = neo4j_string_to_elementid(fields[3]);
}
fields[0] = neo4j_identity(neo4j_int_value(fields[0]));
if (neo4j_is_null(fields[0]))
{
Expand Down Expand Up @@ -857,6 +860,11 @@ int struct_deserialize(uint16_t nfields, neo4j_iostream_t *stream,
fields[7] = neo4j_elementid( eneid );

}
else { // v5.0 relationship
fields[5] = neo4j_string_to_elementid(fields[5]);
fields[6] = neo4j_string_to_elementid(fields[6]);
fields[7] = neo4j_string_to_elementid(fields[7]);
}
fields[0] = neo4j_identity(neo4j_int_value(fields[0]));
fields[1] = neo4j_identity(neo4j_int_value(fields[1]));
fields[2] = neo4j_identity(neo4j_int_value(fields[2]));
Expand Down Expand Up @@ -893,6 +901,9 @@ int struct_deserialize(uint16_t nfields, neo4j_iostream_t *stream,
fields[3] = neo4j_elementid( eid );

}
else { // v5.0 node
fields[3] = neo4j_string_to_elementid(fields[3]);
}
fields[0] = neo4j_identity(neo4j_int_value(fields[0]));
if (neo4j_is_null(fields[0]))
{
Expand Down
8 changes: 8 additions & 0 deletions lib/src/values.c
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,14 @@ neo4j_value_t neo4j_elementid(const char *value)
return v;
}

neo4j_value_t neo4j_string_to_elementid(neo4j_value_t value)
{
REQUIRE(neo4j_type(value) == NEO4J_STRING, neo4j_null);
value._type = NEO4J_ELEMENTID;
value._vt_off = ELEMENTID_VT_OFF;
return value;
}


// struct

Expand Down
11 changes: 11 additions & 0 deletions lib/src/values.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,17 @@ neo4j_value_t neo4j_identity(long long identity);
__neo4j_pure
neo4j_value_t neo4j_elementid(const char *eid);

/**
* Cast a neo4j string into a neo4j element ID.
*
* @internal
*
* @param [value] The neo4j string.
* @return The input value, modified to have the element ID type.
*/
__neo4j_pure
neo4j_value_t neo4j_string_to_elementid(neo4j_value_t value);

/**
* Get the signature of a neo4j struct.
*
Expand Down

0 comments on commit 65b4d4d

Please sign in to comment.