diff --git a/javakdb/src/main/java/com/kx/c.java b/javakdb/src/main/java/com/kx/c.java index 79374c1..7ca587d 100644 --- a/javakdb/src/main/java/com/kx/c.java +++ b/javakdb/src/main/java/com/kx/c.java @@ -634,9 +634,19 @@ public static class Flip{ * Create a Flip (KDB+ table) from the values stored in a Dict. * @param dict Values stored in the dict should be an array of Strings for the column names (keys), with an * array of arrays for the column values + * @throws IllegalArgumentException if the dict values are not an array of column data (Object[]). This can be + * the case when a splayed/partitioned table stored on disk is received (kdb+ transmits a mapping of column names + * to an on-disk path symbol rather than the column data), or when the Dict was constructed with values that are + * not column arrays. + * @see Splayed tables */ public Flip(Dict dict){ x=(String[])dict.x; + if(!(dict.y instanceof Object[])) + throw new IllegalArgumentException("A Flip requires the dictionary values to be an array of column data" + +" (Object[]) but received: "+dict.y+". This can occur when a splayed/partitioned table stored on disk is" + +" received (kdb+ transmits an on-disk path reference rather than the columns), or when the Dict was" + +" constructed with values that are not column arrays."); y=(Object[])dict.y; } /** diff --git a/javakdb/src/test/java/com/kx/CTest.java b/javakdb/src/test/java/com/kx/CTest.java index 7660d4f..df17d6d 100644 --- a/javakdb/src/test/java/com/kx/CTest.java +++ b/javakdb/src/test/java/com/kx/CTest.java @@ -931,6 +931,41 @@ public void testDeserializeEmptyTable() } } + @Test + public void testDeserializeSplayedTableReference() + { + // response from executing 'get `:test/ set ([] a:til 10)' + // A splayed (on-disk) table is transmitted as table(98) -> dict(99) whose value is the + // file-path symbol `:test/ (type -11) rather than the column data, so it cannot be + // represented as an in-memory Flip. This should surface as a clear IllegalArgumentException + // rather than an opaque ClassCastException (issue #51). + 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}; + com.kx.c c=new com.kx.c(); + try { + c.deserialize(buff); + Assert.fail("Expected an IllegalArgumentException to be thrown"); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().contains(":test/")); + } catch (Exception e) { + Assert.fail(e.toString()); + } + } + + @Test + public void testFlipFromDictWithNonColumnValues() + { + // The same guard also protects against a Dict that was simply constructed with values that are + // not column arrays (i.e. a caller bug, not a splayed table); the message describes the actual + // condition rather than assuming a specific cause. + c.Dict dict = new c.Dict(new String[]{"a"}, "not-a-column-list"); + try { + new c.Flip(dict); + Assert.fail("Expected an IllegalArgumentException to be thrown"); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().contains("Object[]")); + } + } + @Test public void testMonthToString() {