Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OrientDB 1.6.3: ClassCastException expanding a field (OTrackedMap, OIdentifiable) #2044

Closed
andrii0lomakin opened this issue Feb 17, 2014 · 12 comments
Assignees
Milestone

Comments

@andrii0lomakin
Copy link
Member

Hi!
I am facing with a very weird behaviour of a select statement.
I cannot execute expand() or contains() function because a ClassCastException is raised or no records at all are returned.

I have a "games" class that for out test, at the moment contains just one record:
"@Rid": "#24:0",
"@Version": 2,
"@Class": "games",
"players": [
{
"username": "[email protected]",
"name": "john doe",
"points": 0
},
{
"username": "[email protected]",
"name": "jane doe",
"department": "one",
"points": 0
},
{
"username": "[email protected]",
"name": "dana scully",
"department": "two",
"points": 0
}
],
"status": "open",
"player_turn": 0,
"id": "ff342a9b-79cd-4494-983e-6ec4a1a47c8a",
"_creation_date": "2014-02-15T13:49:51.051+0100",
"_author": "admin"

As you can see the field "players" is a collection of JSON objects.
If I perform a query against the class I have:
orientdb> select from games
----+-----+-------+------+-----------+------------------------------------+-------+------+------+----------------------------+-------

|@Rid |players|status|player_turn|id |_links |_audit|_allow|_creation_date |_author

----+-----+-------+------+-----------+------------------------------------+-------+------+------+----------------------------+-------
0 |#24:0|[3] |open |0 |ff342a9b-79cd-4494-983e-6ec4a1a47c8a|#11:383|#3:370|[1] |2014-02-15T13:49:51.051+0100|admin
----+-----+-------+------+-----------+------------------------------------+-------+------+------+----------------------------+-------

or:
orientdb> select @this.toJson() from games
----+-----+-----------------------------------------------------------------------------------------------------------------

|@Rid |this

----+-----+-----------------------------------------------------------------------------------------------------------------
0 |#-2:1|{"@type":"d","@Rid":"#24:0","@Version":2,"@Class":"games","players":[{"username":"[email protected]","name":"john ...
----+-----+-----------------------------------------------------------------------------------------------------------------
1 item(s) found. Query executed in 0.041 sec(s).

Everything seems to be fine.
However when I try to expand the players field I have this error:

orientdb> select expand(players) from games
Error: com.orientechnologies.orient.core.exception.OCommandExecutionException: Error on execution of command: sql.select expand(players) from games
Error: java.lang.ClassCastException: com.orientechnologies.orient.core.db.record.OTrackedMap cannot be cast to com.orientechnologies.orient.core.db.re
cord.OIdentifiable

Furthermore I cannot execute any selection criteria against the players field:
orientdb> select from games where players contains (username = "[email protected]")
0 item(s) found. Query executed in 0.0020 sec(s).

orientdb> select from games where players[username] = "[email protected]"
0 item(s) found. Query executed in 0.0040 sec(s).

orientdb> select from games where players[username = "[email protected]"]
Error: com.orientechnologies.orient.core.exception.OCommandExecutionException: Error on execution of command: sql.select from games where players[user
name = "[email protected]"]
Caused by: com.orientechnologies.orient.core.exception.OCommandExecutionException: Error on execution of command: sql.select expand(players) from games
at com.orientechnologies.orient.core.storage.OStorageEmbedded.executeCommand(OStorageEmbedded.java:102)
at com.orientechnologies.orient.core.storage.OStorageEmbedded.command(OStorageEmbedded.java:85)
at com.orientechnologies.orient.core.sql.query.OSQLQuery.run(OSQLQuery.java:69)
at com.orientechnologies.orient.core.sql.query.OSQLSynchQuery.run(OSQLSynchQuery.java:82)
at com.orientechnologies.orient.core.query.OQueryAbstract.execute(OQueryAbstract.java:29)
... 26 more
Caused by: java.lang.ClassCastException: com.orientechnologies.orient.core.db.record.OTrackedMap cannot be cast to com.orientechnologies.orient.core.d
b.record.OIdentifiable
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLResultsetAbstract.getResult(OCommandExecutorSQLResultsetAbstract.java:163)
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.execute(OCommandExecutorSQLSelect.java:340)
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLDelegate.execute(OCommandExecutorSQLDelegate.java:57)
at com.orientechnologies.orient.core.storage.OStorageEmbedded.executeCommand(OStorageEmbedded.java:96)
... 30 more

and this is the second one:
Caused by: com.orientechnologies.orient.core.exception.OCommandExecutionException: Error on execution of command: sql.select from games where ( players[username="[email protected]"] )
at com.orientechnologies.orient.core.storage.OStorageEmbedded.executeCommand(OStorageEmbedded.java:102)
at com.orientechnologies.orient.core.storage.OStorageEmbedded.command(OStorageEmbedded.java:85)
at com.orientechnologies.orient.core.sql.query.OSQLQuery.run(OSQLQuery.java:69)
at com.orientechnologies.orient.core.sql.query.OSQLSynchQuery.run(OSQLSynchQuery.java:82)
at com.orientechnologies.orient.core.query.OQueryAbstract.execute(OQueryAbstract.java:29)
... 26 more
Caused by: java.lang.ClassCastException: com.orientechnologies.orient.core.db.record.OTrackedMap cannot be cast to java.lang.Boolean
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLResultsetAbstract.evaluateRecord(OCommandExecutorSQLResultsetAbstract.java:317)
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLResultsetAbstract.filter(OCommandExecutorSQLResultsetAbstract.java:310)
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.executeSearchRecord(OCommandExecutorSQLSelect.java:401)
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.executeSearch(OCommandExecutorSQLSelect.java:364)
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.execute(OCommandExecutorSQLSelect.java:333)
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLDelegate.execute(OCommandExecutorSQLDelegate.java:57)
at com.orientechnologies.orient.core.storage.OStorageEmbedded.executeCommand(OStorageEmbedded.java:96)
... 30 more

@lvca
Copy link
Member

lvca commented Feb 17, 2014

players seems to be a map. If you want to use as target of another select (like the one with expand()) you should call it against players.values() to return the collection of values.

@lvca lvca closed this as completed Feb 17, 2014
@lvca lvca modified the milestone: 1.7rc2 Feb 17, 2014
@lvca lvca self-assigned this Feb 17, 2014
@giastfader
Copy link
Contributor

Hi Luca,
I tried with players.values() but nothing is returned:

orientdb> select players.values() from games
----+-----
#   |@RID
----+-----
0   |#-2:1
----+-----
1 item(s) found. Query executed in 0.152 sec(s).

@lvca
Copy link
Member

lvca commented Feb 17, 2014

By looking at your JSON that isn't a MAP but a collection. So I don't know why a OTrackedMap object goes there. Could you debug in what case that OTrackedMap object goes in tempResult variable of the SQL select command?

@lvca lvca reopened this Feb 17, 2014
@giastfader
Copy link
Contributor

Ok, I will try it

@giastfader
Copy link
Contributor

Hi,
executing this query:

select from games where players[username="[email protected]"]

the problem is generated by the method OCommandExecutorSQLResultsetAbstract.evaluateRecord(), at this line:

    return (Boolean) compiledFilter.evaluate(iRecord, null, context);

The problem is that in this case the evaluate() method does not return a Boolean but an instance of OTrackedMap.
This because the parser executes the OSQLFilterCondition.evaluate() method and here happens the problem:

   if (operator == null) {
      if (l == null)
        // THE LEFT RETURNED NULL
        return Boolean.FALSE;

      // UNITARY OPERATOR: JUST RETURN LEFT RESULT
      return l;
    }

Actually operator is null and since l is not null l itself is returned.
l variable is an instance of the OTrackedMap class.
This variable then goes up through the stack:

OSQLFilterCondition.evaluate(OIdentifiable, ODocument, Object, OCommandContext) line: 296
OSQLFilterCondition.evaluate(OIdentifiable, ODocument, OCommandContext) line: 73
OSQLFilter.evaluate(ORecord, ODocument, OCommandContext) line: 63 OCommandExecutorSQLSelect(OCommandExecutorSQLResultsetAbstract).evaluateRecord(ORecord) line: 317

and generates the ClassCastExeption error.

Actually it seems that the variable tempResult is never involved.

@lvca
Copy link
Member

lvca commented Feb 21, 2014

Probably after the return that Map goes in the tempResult. So why are you writing a query like that?

@giastfader
Copy link
Contributor

I just want to extract all records that contain at least one player with the given email address.
As I wrote I tried different ways and no one seems to work.
Debugging the code I found that actually the filter works and right records are extracted, but that error occurs and the reply is never returned.
I'm open to any advice on how extract the right records.
However I think that the server should never throws a ClassCastException.

@lvca
Copy link
Member

lvca commented Feb 21, 2014

Why don't you use:

select from games where players contains ( username = "[email protected]" )

@giastfader
Copy link
Contributor

it returns no records

@giastfader
Copy link
Contributor

Ok, I digged into the code.
It seems that because players is an embedded collection, when the condition username = "[email protected]" is evaluated it returns false because the check is executed against the record, not against the items belonging to the players collection.

I think that the problem is in OSQLFilterItemField.getValue().
It is invoked with the following parameters:

iRecord=games#29:2{players:[3],status:open,player_turn:0,id:e0e39261-a473-4d7e-b528-388bbaa7d215,_links:#11:19,_audit:#3:49,_allow:[1],_allowRead:null,_allowWrite:null,_allowUpdate:null,_allowDelete:null,_creation_date:Fri Feb 21 15:57:12 CET 2014,_author:admin} v2
iContext: {current=games#29:2{players:[3],status:open,player_turn:0,id:e0e39261-a473-4d7e-b528-388bbaa7d215,_links:#11:19,_audit:#3:49,_allow:[1],_allowRead:null,_allowWrite:null,_allowUpdate:null,_allowDelete:null,_creation_date:Fri Feb 21 15:57:12 CET 2014,_author:admin} v2}
name (field of the OSQLFilterItemField instance): username

At line 62:

 Object v = ODocumentHelper.getFieldValue(doc, name);

the method getFieldValue() returns null and then all the statement is evaluated as false.

In other words the filed "username" isn't found inside the record

@lvca
Copy link
Member

lvca commented Feb 22, 2014

Can you provide a fix for it? Or a database to debug on that point?

@giastfader
Copy link
Contributor

Those methods are the focal points of the SQL parser, I woudn't make some damage making something wrong.
I send you the DB via email.
Thanks

@lvca lvca added bug and removed invalid labels Feb 27, 2014
@lvca lvca added this to the 1.7rc2 milestone Feb 27, 2014
lvca added a commit that referenced this issue Feb 27, 2014
@lvca lvca closed this as completed Feb 27, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants