Ostico / PhpOrient

PhpOrient - Official Php driver based on the binary protocol of OrientDB.
Other
68 stars 37 forks source link

Embedded attribute's numbers reset to 0, while storing record on OrientDB 2.2 #84

Closed andreyvk closed 7 years ago

andreyvk commented 7 years ago

Hi @Ostico,

I've come across a really bad issue on OrientDB 2.2.12. Record is losing data on it's embedded elements, when library is used, but works just fine through the OrientDB Studio. Could you please take a look at this?

Schema

create class SubTest

create property SubTest.id string

create property SubTest.value1 double
alter property SubTest.value1 default 0.0

create property SubTest.value1Name string

create property SubTest.value2 double
alter property SubTest.value2 default 0.0

create class Test extends V

create property Test.attr1 embeddedlist SubTest

After that you can execute the following code:

$client = new PhpOrient( 'localhost', 2424 );
$client->username = 'foo';
$client->password = 'bar';
$client->connect();
$client->dbOpen( 'test', 'foo', 'bar' );

//create record
$subOData = [
    "@type" => "d",
    "@class" => "SubTest",
    "id" => "123456-78980",
    "value1Name" => "Test",
    "value1" => 2000,
    "value2" => 33333,
];

$attr1Item = (new Record())->setOData($subOData)->setOClass("SubTest");

$odata = [
       "attr1" => [
           $attr1Item
       ],
];

$rec = ( new Record() )->setOClass("Test")->setOData( $odata )->setRid( new ID( /* YOUR CLUSTER ID FOR TEST CLASS */ ) );

$rec = $client->recordCreate( $rec );

//re-load record
$rec = $client->recordLoad( $rec->getRid() )[0];

//output
print_r($rec);

The output will be as follows. Please note that value1 and value2 of an embedded attrubute are 0's!

PhpOrient\Protocols\Binary\Data\Record Object
(
    [rid:protected] => PhpOrient\Protocols\Binary\Data\ID Object
        (
            [cluster] => 181
            [position] => 1
        )

    [oClass:protected] => Test
    [version:protected] => 1
    [oData:protected] => Array
        (
            [attr1] => Array
                (
                    [0] => PhpOrient\Protocols\Binary\Data\Record Object
                        (
                            [rid:protected] =>
                            [oClass:protected] => SubTest
                            [version:protected] => 0
                            [oData:protected] => Array
                                (
                                    [value2] => 0
                                    [value1] => 0
                                    [id] => 123456-78980
                                    [value1Name] => Test
                                )

                        )

                )

        )

)

However, the following SQL statement, ran from the studio works just fine. It creates exactly the same record like the code does.

insert into Test content { "attr1" : [ { "@class" : "SubTest", "@type" : "d", "id" : "123456-7890", "value1Name": "Test", "value1" : 2000, "value2" : 33333 } ] }
andreyvk commented 7 years ago

Sorry, forgot to mention that all that happens on the latest OrientDB 2.2.12

Ostico commented 7 years ago

Hi @andreyvk , i tried your code in an older version of OrientDB ( 2.2.5 ) and i get 0's both from the console and from the web interface.

So, this seems tied to a bug in the driver, because the driver do not transform the @type and to some kind of strange behaviour with OrientDB that nullify the values from the protocol interface.

insert into Test content { "attr1" : [ { "@class" : "SubTest", "@type" : "d", "id" : "123456-7890", "value1Name": "Test", "value1" : "2000", "value2" : 33333 } ] }

Here my results:

+----+-----+------+------------------------------------------------------------------------+
|#   |@RID |@CLASS|attr1                                                                   |
+----+-----+------+------------------------------------------------------------------------+
|0   |#21:0|Test  |[SubTest{value2:0.0,value1:0.0,@type:d,id:123456-78980,value1Name:Test}]| # <--- PhpOrient
|1   |#22:0|Test  |[SubTest{value2:0.0,value1:0.0,id:123456-7890,value1Name:Test}]         | # <--- Web console
|2   |#23:0|Test  |[SubTest{value2:0.0,value1:0.0,id:123456-7890,value1Name:Test}]         | # <--- console.sh
+----+-----+------+------------------------------------------------------------------------+

At moment i can't try with the new OrientDB version you mentioned, but i will try as soon as possible and update the issue.

andreyvk commented 7 years ago

Hi @Ostico ,

Many thanks for prompt reply! I've tried my query through the console on 2.2.12. The result seems to be fine. Here's the log:

OrientDB console v.2.2.12-SNAPSHOT (build 2.2.x@r2a76ee1efc4487d9dc5f43e1ddc2fba1c5a0167c; 2016-10-20 13:55:08+0000) www.orientdb.com
Type 'help' to display all the supported commands.
Installing extensions for GREMLIN language v.2.6.0

orientdb> connect remote:localhost/test foo bar

Connecting to database [remote:localhost/test] with user 'foo'...OK
orientdb {db=test}>

orientdb {db=test}> insert into Test content { "attr1" : [ { "@class" : "SubTest", "@type" : "d", "id" : "123456-7890", "value1Name": "Test", "value1" : 2000, "value2" : 33333 } ] }

Inserted record 'Test#181:3{attr1:[1]} v1' in 0.073000 sec(s).

orientdb {db=test}> select from #181:3

+----+------+------+----------------------------------------------------------------------+
|#   |@RID  |@CLASS|attr1                                                                 |
+----+------+------+----------------------------------------------------------------------+
|0   |#181:3|Test  |[SubTest{value2:33333.0,value1:2000.0,id:123456-7890,value1Name:Test}]|
+----+------+------+----------------------------------------------------------------------+

1 item(s) found. Query executed in 0.007 sec(s).
orientdb {db=test}>
tglman commented 7 years ago

hi @Ostico, @andreyvk,

I did try to reproduce this using java code in 2.2.x and i couldn't, can you give a bit of steps on how to setup this test using PhpOrient and run it, so i may be able to fix it.

Bye

Ostico commented 7 years ago

Hi @tglman ,

here the script i used to test the behaviour: https://gist.github.com/Ostico/3002ef24a3623adb55dd68e9a9fafc91

Follow the instructions in the comments to create the schema and install the driver. Let me know if you need more info.

andreyvk commented 7 years ago

@tglman I dunno about Java. As for PhpOrient here's a small thing i've prepared for you to test. Better run that in Linux:

PhpOrientTest.zip

  1. Download and unzip PhpOrientTest.zip
  2. cd PhpOrientTest
  3. Edit test.php and change db name, user and pass. Also on line 39 where it says /* YOUR CLUSTER ID FOR TEST CLASS */, change that to cluster number of class Test (see my very first message above for schema). E.g. ->setRid( new \PhpOrient\Protocols\Binary\Data\ID( 123 ) );
  4. Run test with php test.php from console (requires that you have php installed of course)
  5. If you dont have PHP installed, i think you can do that with sudo apt-get install php5 (that is if you are running Ubuntu)
tglman commented 7 years ago

Hi,

Thank you both of you, i'll giver a try and fix it.

Bye

Ostico commented 7 years ago

@andreyvk , by the way, it is not needed to insert the @type and @class in the nested record: https://gist.github.com/Ostico/3002ef24a3623adb55dd68e9a9fafc91#file-testembeddedvalues-php-L43

because you already set the correct OData in the Record Object and OrientDB does not accept any other value than @type 'd' and by default transforms your record into a Document type.

As example, if you change the @type to 'r' ( raw ) or 'b' ( binary ) and perform this command into the OrientDB console you get an exception:

orientdb {db=test_db}> insert into Test content { "attr1" : [ { "@class" : "SubTest", "@type" : "b", "id" : "123456-7890", "value1Name": "Test", "value1" : 2000, "value2" : 33333 } ] }

Error: com.orientechnologies.orient.core.exception.OSerializationException: Error on unmarshalling JSON content for record: "attr1": [{"@class": "SubTest", "@type": "b", "id": "123456-7890", "value1Name": "Test", "value1": 2000, "value2": 33333}]
    DB name="test_db"
    DB name="test_db"

Error: java.lang.ClassCastException: com.orientechnologies.orient.core.record.impl.ORecordBytes cannot be cast to com.orientechnologies.orient.core.record.impl.ODocument
andreyvk commented 7 years ago

@Ostico thanks! You are right. I think I was testing smth before and forgot to remove those attrs. I normally dont do that.

tglman commented 7 years ago

Hi @Ostico, @andreyvk,

I just fixed this in 2.2.x branch, and it will be released in 2.2.13 in 1/2 weeks, it was a problem inside the CSV serializer, so hard to figure out from our internal test case.

I get the change to say that we are planning to remove the CSV serializer in 3.0, so please start to think to implement the binary serializer, if you have question reach me, we can even ship something different in 3.0 for better help you to the migration.

Bye

tglman commented 7 years ago

Forgetting:

Can you please add this case to the test case of PhpOrient (when the fixed is released), se we can have an early trigger if something wrong happen, on the other side is almost impossible add this checks on our side.

Bye

andreyvk commented 7 years ago

@tglman , it's great to know, that the problem has been solved so quickly. Waiting for the next release! Big thanks to you and @Ostico !

Ostico commented 7 years ago

Tnx @tglman ,

I confirm it is fixed on OrientDB 2.2.13.