javakdb icon indicating copy to clipboard operation
javakdb copied to clipboard

ClassCastException on reading splay table

Open dzmipt opened this issue 4 years ago • 3 comments

The bug is inside c.java which parses the result from kdb.

If you run GridViewer with the following query

String query ="get `:test/ set ([] a:til 10)";

then you get the following exception

Dec 07, 2020 10:04:00 PM kx.examples.GridViewer main
SEVERE: null
java.lang.ClassCastException: java.lang.String cannot be cast to [Ljava.lang.Object;
	at kx.c$Flip.<init>(c.java:479)
	at kx.c.r(c.java:977)
	at kx.c.deserialize(c.java:1395)
	at kx.c.readMsg(c.java:1522)
	at kx.c.k(c.java:1602)
	at kx.c.k(c.java:1617)
	at kx.examples.GridViewer.main(GridViewer.java:48)

dzmipt avatar Dec 07 '20 19:12 dzmipt

In reality, kdb doesn't return content of the table (btw, I am playing with 3.6 - interesting how other version behaviours). Here is what the server returns from another q console

q)h:hopen 5001
q)h"tables[]"
,`test1
q)t:h"test1"
q)t
+`a`b!`:test1/

So the Flip has column names and a symbol for the table. A different q console, also get crazy from such object:

q)meta t
'test1/a. OS reports: No such file or directory
  [0]  meta t
       ^
q))count t
'pn
  [4]  count t
       ^

I think that either c() should returns some special c.SpecialFlip class. Another option is to correctly read the object into c.Flip but gives user ability to understand that content couldn't be retrieved and also reference to the symbolic name.

dzmipt avatar Dec 07 '20 19:12 dzmipt

With debugging:

get `:test/ set ([] a:til 10) Current decoding thinks data contains type 98, which contains type 99 (which has type 11 & type -11). The -11 appears to be set to ":test/".

([]a:10?100) Current decoding thinks data contains type 98, which contains type 98, contains type 99 (which has type 11 & type 0 and 7)

Investigating further ...

sshanks-kx avatar Dec 24 '20 12:12 sshanks-kx

Example of unit test that can be added to recreate (note: doesn't yet have intended action as change required, but allows quick testing)

    @Test
    public void testSplayResponse()
    {
        // response from executing 'get `:test/ set ([] a:til 10)'
        // "\x01\x02\x00\x00\x1b\x00\x00\x00\x62\x00\x63\x0b\x00\x01\x00\x00\x00\x61\x00\xf5\x3a\x74\x65\x73\x74\x2f\x00"
        byte[] buff = {(byte)0x01, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x1b, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x62, (byte)0x00, (byte)0x63, (byte)0x0b, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x61, (byte)0x00, (byte)0xf5, (byte)0x3a, (byte)0x74, (byte)0x65, (byte)0x73, (byte)0x74, (byte)0x2f, (byte)0x00};
        kx.c c=new kx.c();
        try{
            Object res = c.deserialize(buff);
        } catch (Exception e) {
            Assert.fail(e.toString());
        }
    }

Running mvn -Dtest=cTest#testSplayResponse test

Example of using KDB+ directly as a client were it doesn't have access to 'test' dir containing table dir (i.e. ran on same host but from different dir from KDB+ server)

q -p 5001 (server)

client instance

q)h:hopen `::5001
q)h"get `:test/ set ([] a:til 10)"
+(,`a)!`:test/
q)a:h"get `:test/ set ([] a:til 10)"
q)type a
98h
q)a[`a]
'test/a. OS reports: No such file or directory
  [0]  a[`a]

Will look further at potential changes that could be made & update.

sshanks-kx avatar Jan 05 '21 12:01 sshanks-kx