diff --git a/src/main/java/io/tiledb/java/api/Array.java b/src/main/java/io/tiledb/java/api/Array.java index 40e5fda5..3e9269af 100644 --- a/src/main/java/io/tiledb/java/api/Array.java +++ b/src/main/java/io/tiledb/java/api/Array.java @@ -521,7 +521,6 @@ public Pair getNonEmptyDomainFromIndex(long index) throws TileDBError { */ public Pair getNonEmptyDomainFromName(String name) throws TileDBError { checkIsOpen(); - HashMap ret = new HashMap(); try (Domain domain = schema.getDomain(); NativeArray domainArray = new NativeArray(ctx, 2 * (int) domain.getRank(), domain.getType())) { diff --git a/src/main/java/io/tiledb/java/api/Datatype.java b/src/main/java/io/tiledb/java/api/Datatype.java index 2d5a8783..65062ed2 100644 --- a/src/main/java/io/tiledb/java/api/Datatype.java +++ b/src/main/java/io/tiledb/java/api/Datatype.java @@ -161,6 +161,8 @@ public Class javaClass() throws TileDBError { return String.class; case TILEDB_STRING_UCS4: return String.class; + case TILEDB_STRING_ASCII: + return String.class; case TILEDB_ANY: default: throw new TileDBError("No such enum value" + this.name()); diff --git a/src/main/java/io/tiledb/java/api/Dimension.java b/src/main/java/io/tiledb/java/api/Dimension.java index 8e3863b7..05424e5b 100644 --- a/src/main/java/io/tiledb/java/api/Dimension.java +++ b/src/main/java/io/tiledb/java/api/Dimension.java @@ -96,23 +96,31 @@ public Dimension(Context ctx, String name, Datatype type, Pair domain, T e private void createImpl(Context ctx, String name, Datatype dimType, Pair domain, T extent) throws TileDBError { SWIGTYPE_p_p_tiledb_dimension_t dimensionpp = tiledb.new_tiledb_dimension_tpp(); - try (NativeArray domainBuffer = new NativeArray(ctx, 2, dimType); - NativeArray tileExtent = new NativeArray(ctx, 1, dimType)) { - domainBuffer.setItem(0, domain.getFirst()); - domainBuffer.setItem(1, domain.getSecond()); - tileExtent.setItem(0, extent); + + if (dimType.equals(Datatype.TILEDB_STRING_ASCII)) { ctx.handleError( tiledb.tiledb_dimension_alloc( - ctx.getCtxp(), - name, - dimType.toSwigEnum(), - domainBuffer.toVoidPointer(), - tileExtent.toVoidPointer(), - dimensionpp)); - } catch (Exception err) { - tiledb.delete_tiledb_dimension_tpp(dimensionpp); - throw err; + ctx.getCtxp(), name, dimType.toSwigEnum(), null, null, dimensionpp)); + } else { + try (NativeArray domainBuffer = new NativeArray(ctx, 2, dimType); + NativeArray tileExtent = new NativeArray(ctx, 1, dimType)) { + domainBuffer.setItem(0, domain.getFirst()); + domainBuffer.setItem(1, domain.getSecond()); + tileExtent.setItem(0, extent); + ctx.handleError( + tiledb.tiledb_dimension_alloc( + ctx.getCtxp(), + name, + dimType.toSwigEnum(), + domainBuffer.toVoidPointer(), + tileExtent.toVoidPointer(), + dimensionpp)); + } catch (Exception err) { + tiledb.delete_tiledb_dimension_tpp(dimensionpp); + throw err; + } } + this.ctx = ctx; this.name = name; this.domain = domain; diff --git a/src/main/java/io/tiledb/java/api/NativeArray.java b/src/main/java/io/tiledb/java/api/NativeArray.java index a2a5afaf..f55a771c 100644 --- a/src/main/java/io/tiledb/java/api/NativeArray.java +++ b/src/main/java/io/tiledb/java/api/NativeArray.java @@ -196,6 +196,7 @@ private int getSize(Object buffer) throws TileDBError { { return ((long[]) buffer).length; } + case TILEDB_STRING_ASCII: case TILEDB_CHAR: { return stringToBytes(buffer).length; @@ -275,6 +276,7 @@ private void createNativeArrayFromBuffer(Object buffer) throws TileDBError { uint64_tArray = Utils.newInt64_tArray((long[]) buffer); break; } + case TILEDB_STRING_ASCII: case TILEDB_CHAR: { byte[] bytes = stringToBytes(buffer); @@ -357,6 +359,7 @@ private void allocateEmptyArray() throws TileDBError { uint64_tArray = new int64_tArray(size); break; } + case TILEDB_STRING_ASCII: case TILEDB_CHAR: { int8_tArray = new int8_tArray(size); @@ -438,6 +441,7 @@ public Object getItem(int index) throws ArrayIndexOutOfBoundsException, TileDBEr { return uint64_tArray.getitem(index); } + case TILEDB_STRING_ASCII: case TILEDB_CHAR: { return int8_tArray.getitem(index); @@ -527,6 +531,7 @@ public void setItem(int index, Object value) throws ArrayIndexOutOfBoundsExcepti uint64_tArray.setitem(index, (long) value); break; } + case TILEDB_STRING_ASCII: case TILEDB_CHAR: { for (byte b : stringToBytes(value)) { @@ -601,6 +606,7 @@ public SWIGTYPE_p_void toVoidPointer() throws TileDBError { { return PointerUtils.toVoid(uint64_tArray); } + case TILEDB_STRING_ASCII: case TILEDB_CHAR: { return PointerUtils.toVoid(int8_tArray); @@ -771,6 +777,7 @@ public Object toJavaArray(int position, int elements) throws TileDBError { { return Utils.int64ArrayGet(uint64_tArray, position, elements); } + case TILEDB_STRING_ASCII: case TILEDB_CHAR: { return Utils.int8ArrayGet(int8_tArray, position, elements); diff --git a/src/main/java/io/tiledb/java/api/Query.java b/src/main/java/io/tiledb/java/api/Query.java index b2baad23..5a1dc287 100644 --- a/src/main/java/io/tiledb/java/api/Query.java +++ b/src/main/java/io/tiledb/java/api/Query.java @@ -201,6 +201,104 @@ public synchronized Query addRange(int dimIdx, Object start, Object end) throws return this; } + /** + * Adds a 1D variable-sized range along a subarray dimension, which is in the form (start, end). + * Applicable only to variable-sized dimensions. + * + * @param dimIdx The index of the dimension to add the range to + * @param start The range start + * @param end The range end + * @return This query + * @throws TileDBError A TileDB exception + */ + public synchronized Query addRangeVar(int dimIdx, String start, String end) throws TileDBError { + Datatype dimType; + try (ArraySchema schema = array.getSchema(); + Domain domain = schema.getDomain()) { + dimType = domain.getType(); + } + + Types.javaTypeCheck(start.getClass(), dimType.javaClass()); + Types.javaTypeCheck(end.getClass(), dimType.javaClass()); + + try (NativeArray startArr = new NativeArray(ctx, 1, dimType); + NativeArray endArr = new NativeArray(ctx, 1, dimType)) { + startArr.setItem(0, start); + endArr.setItem(0, end); + + ctx.handleError( + tiledb.tiledb_query_add_range_var( + ctx.getCtxp(), + queryp, + dimIdx, + startArr.toVoidPointer(), + BigInteger.valueOf(start.length()), + endArr.toVoidPointer(), + BigInteger.valueOf(end.length()))); + } + + return this; + } + + /** + * Retrieves a range's start and end size for a given variable-length dimensions at a given range + * index. + * + * @param dimIdx The index of the dimension to add the range to + * @return This query + * @throws TileDBError A TileDB exception + */ + public synchronized Pair getRangeVarSize(int dimIdx, BigInteger rangeIdx) + throws TileDBError { + SWIGTYPE_p_unsigned_long_long startSize = tiledb.new_ullp(); + SWIGTYPE_p_unsigned_long_long endSize = tiledb.new_ullp(); + try { + ctx.handleError( + tiledb.tiledb_query_get_range_var_size( + ctx.getCtxp(), queryp, dimIdx, rangeIdx, startSize, endSize)); + + return new Pair( + tiledb.ullp_value(startSize).longValue(), tiledb.ullp_value(endSize).longValue()); + } catch (TileDBError error) { + throw error; + } + } + + /** + * Retrieves a specific range of the query subarray along a given variable-length dimension. + * + * @param dimIdx The index of the dimension to add the range to + * @return This query + * @throws TileDBError A TileDB exception + */ + public synchronized Pair getRangeVar(int dimIdx, BigInteger rangeIdx) + throws TileDBError { + Datatype dimType; + try (ArraySchema schema = array.getSchema(); + Domain domain = schema.getDomain()) { + dimType = domain.getType(); + } + + Pair size = this.getRangeVarSize(dimIdx, rangeIdx); + + try (NativeArray startArr = new NativeArray(ctx, size.getFirst().intValue(), dimType); + NativeArray endArr = new NativeArray(ctx, size.getSecond().intValue(), dimType)) { + + ctx.handleError( + tiledb.tiledb_query_get_range_var( + ctx.getCtxp(), + queryp, + dimIdx, + rangeIdx, + startArr.toVoidPointer(), + endArr.toVoidPointer())); + + Object start = new String((byte[]) startArr.toJavaArray()); + Object end = new String((byte[]) endArr.toJavaArray()); + return new Pair(start, end); + } + } + /** * Retrieves the number of ranges of the query subarray along a given dimension. * @@ -272,7 +370,7 @@ public synchronized Query setBuffer(String attr, NativeArray buffer) throws Tile if (attr.equals(tiledb.tiledb_coords())) { Types.typeCheck(domain.getType(), buffer.getNativeType()); } else if (domain.hasDimension(attr)) { - Types.typeCheck(domain.getType(), buffer.getNativeType()); + Types.typeCheck(domain.getDimension(attr).getType(), buffer.getNativeType()); } else { try (Attribute attribute = schema.getAttribute(attr)) { Types.typeCheck(attribute.getType(), buffer.getNativeType()); @@ -333,7 +431,7 @@ public synchronized Query setBuffer(String attr, NativeArray buffer, long buffer if (attr.equals(tiledb.tiledb_coords())) { Types.typeCheck(domain.getType(), buffer.getNativeType()); } else if (domain.hasDimension(attr)) { - Types.typeCheck(domain.getType(), buffer.getNativeType()); + Types.typeCheck(domain.getDimension(attr).getType(), buffer.getNativeType()); } else { try (Attribute attribute = schema.getAttribute(attr)) { Types.typeCheck(attribute.getType(), buffer.getNativeType()); @@ -391,9 +489,18 @@ public synchronized Query setBuffer(String attr, NativeArray offsets, NativeArra } // Type check the buffer native type matches the schema attribute type - try (ArraySchema schema = array.getSchema(); - Attribute attribute = schema.getAttribute(attr)) { - Types.typeCheck(attribute.getType(), buffer.getNativeType()); + try (ArraySchema schema = array.getSchema()) { + try (Domain domain = schema.getDomain()) { + if (attr.equals(tiledb.tiledb_coords())) { + Types.typeCheck(domain.getType(), buffer.getNativeType()); + } else if (domain.hasDimension(attr)) { + Types.typeCheck(domain.getDimension(attr).getType(), buffer.getNativeType()); + } else { + try (Attribute attribute = schema.getAttribute(attr)) { + Types.typeCheck(attribute.getType(), buffer.getNativeType()); + } + } + } } uint64_tArray offsets_array = PointerUtils.uint64_tArrayFromVoid(offsets.toVoidPointer()); diff --git a/src/main/java/io/tiledb/java/api/Types.java b/src/main/java/io/tiledb/java/api/Types.java index b6136891..98b2a15c 100644 --- a/src/main/java/io/tiledb/java/api/Types.java +++ b/src/main/java/io/tiledb/java/api/Types.java @@ -111,6 +111,7 @@ public static Class getJavaType(Datatype type) throws TileDBError { { return Long.class; } + case TILEDB_STRING_ASCII: case TILEDB_CHAR: { return String.class; diff --git a/src/test/java/io/tiledb/java/api/QueryTest.java b/src/test/java/io/tiledb/java/api/QueryTest.java index 5533c615..2d14239b 100644 --- a/src/test/java/io/tiledb/java/api/QueryTest.java +++ b/src/test/java/io/tiledb/java/api/QueryTest.java @@ -1,181 +1,445 @@ package io.tiledb.java.api; import static io.tiledb.java.api.ArrayType.TILEDB_DENSE; +import static io.tiledb.java.api.ArrayType.TILEDB_SPARSE; +import static io.tiledb.java.api.Layout.TILEDB_GLOBAL_ORDER; import static io.tiledb.java.api.Layout.TILEDB_ROW_MAJOR; import static io.tiledb.java.api.QueryType.TILEDB_READ; import static io.tiledb.java.api.QueryType.TILEDB_WRITE; +import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.Arrays; import java.util.HashMap; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +@RunWith(Enclosed.class) public class QueryTest { - private Context ctx; - private String arrayURI = "query"; + private static Context ctx; + private static String arrayURI = "query"; + + public static class DenseTests { + @Before + public void setup() throws Exception { + ctx = new Context(); + if (Files.exists(Paths.get(arrayURI))) { + TileDBObject.remove(ctx, arrayURI); + } + arrayCreate(); + arrayWrite(); + } - @Before - public void setup() throws Exception { - ctx = new Context(); - if (Files.exists(Paths.get(arrayURI))) { - TileDBObject.remove(ctx, arrayURI); + @After + public void teardown() throws Exception { + if (Files.exists(Paths.get(arrayURI))) { + TileDBObject.remove(ctx, arrayURI); + } } - arrayCreate(); - arrayWrite(); - } - @After - public void teardown() throws Exception { - if (Files.exists(Paths.get(arrayURI))) { - TileDBObject.remove(ctx, arrayURI); + public void arrayCreate() throws Exception { + // The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4]. + Dimension rows = + new Dimension<>(ctx, "rows", Integer.class, new Pair(1, 4), 2); + Dimension cols = + new Dimension<>(ctx, "cols", Integer.class, new Pair(1, 4), 2); + + // Create and set getDomain + Domain domain = new Domain(ctx); + domain.addDimension(rows); + domain.addDimension(cols); + + // Add two attributes "a1" and "a2", so each (i,j) cell can store + // a character on "a1" and a vector of two floats on "a2". + Attribute a1 = new Attribute(ctx, "a1", Character.class); + Attribute a2 = new Attribute(ctx, "a2", Float.class); + a2.setCellValNum(2); + + ArraySchema schema = new ArraySchema(ctx, TILEDB_DENSE); + schema.setTileOrder(TILEDB_ROW_MAJOR); + schema.setCellOrder(TILEDB_ROW_MAJOR); + schema.setDomain(domain); + schema.addAttribute(a1); + schema.addAttribute(a2); + + Array.create(arrayURI, schema); } - } - public void arrayCreate() throws Exception { - // The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4]. - Dimension rows = - new Dimension(ctx, "rows", Integer.class, new Pair(1, 4), 2); - Dimension cols = - new Dimension(ctx, "cols", Integer.class, new Pair(1, 4), 2); - - // Create and set getDomain - Domain domain = new Domain(ctx); - domain.addDimension(rows); - domain.addDimension(cols); - - // Add two attributes "a1" and "a2", so each (i,j) cell can store - // a character on "a1" and a vector of two floats on "a2". - Attribute a1 = new Attribute(ctx, "a1", Character.class); - Attribute a2 = new Attribute(ctx, "a2", Float.class); - a2.setCellValNum(2); - - ArraySchema schema = new ArraySchema(ctx, TILEDB_DENSE); - schema.setTileOrder(TILEDB_ROW_MAJOR); - schema.setCellOrder(TILEDB_ROW_MAJOR); - schema.setDomain(domain); - schema.addAttribute(a1); - schema.addAttribute(a2); - - Array.create(arrayURI, schema); - } + public void arrayWrite() throws Exception { + // Prepare cell buffers + NativeArray a1 = new NativeArray(ctx, "abcdefghijklmnop", String.class); + NativeArray a2 = + new NativeArray( + ctx, + new float[] { + 0.1f, 0.2f, 1.1f, 1.2f, 2.1f, 2.2f, 3.1f, 3.2f, + 4.1f, 4.2f, 5.1f, 5.2f, 6.1f, 6.2f, 7.1f, 7.2f, + 8.1f, 8.2f, 9.1f, 9.2f, 10.1f, 10.2f, 11.1f, 11.2f, + 12.1f, 12.2f, 13.1f, 13.2f, 14.1f, 14.2f, 15.1f, 15.2f + }, + Float.class); + + // Create query + Array array = new Array(ctx, arrayURI, TILEDB_WRITE); + Query query = new Query(array); + query.setLayout(TILEDB_ROW_MAJOR); + query.setBuffer("a1", a1); + query.setBuffer("a2", a2); + // Submit query + query.submit(); + query.close(); + array.close(); + } - public void arrayWrite() throws Exception { - // Prepare cell buffers - NativeArray a1 = new NativeArray(ctx, "abcdefghijklmnop", String.class); - NativeArray a2 = - new NativeArray( - ctx, - new float[] { - 0.1f, 0.2f, 1.1f, 1.2f, 2.1f, 2.2f, 3.1f, 3.2f, - 4.1f, 4.2f, 5.1f, 5.2f, 6.1f, 6.2f, 7.1f, 7.2f, - 8.1f, 8.2f, 9.1f, 9.2f, 10.1f, 10.2f, 11.1f, 11.2f, - 12.1f, 12.2f, 13.1f, 13.2f, 14.1f, 14.2f, 15.1f, 15.2f - }, - Float.class); - - // Create query - Array array = new Array(ctx, arrayURI, TILEDB_WRITE); - Query query = new Query(array); - query.setLayout(TILEDB_ROW_MAJOR); - query.setBuffer("a1", a1); - query.setBuffer("a2", a2); - // Submit query - query.submit(); - query.close(); - array.close(); - } + @Test + public void arrayReadTest() throws Exception { + Array array = new Array(ctx, arrayURI, TILEDB_READ); + + // Create query + Query query = new Query(array, TILEDB_READ); + + // Slice only rows 1, 2 and cols 2, 3, 4 + query.addRange(0, 1, 2); + query.addRange(1, 2, 4); + query.setLayout(TILEDB_ROW_MAJOR); + + // Prepare the vector that will hold the result + // (of size 6 elements for "a1" and 12 elements for "a2" since + // it stores two floats per cell) + + // Get the first 6 elements of each attribute/dimension + NativeArray dim1Array = new NativeArray(ctx, 6, Integer.class); + NativeArray dim2Array = new NativeArray(ctx, 6, Integer.class); + NativeArray a1Array = new NativeArray(ctx, 12, Character.class); + NativeArray a2Array = new NativeArray(ctx, 6, Float.class); + + query.setBuffer("rows", dim1Array); + query.setBuffer("cols", dim2Array); + query.setBuffer("a1", a1Array); + query.setBuffer("a2", a2Array); + + // Submit query + query.submit(); + + HashMap> resultElements = query.resultBufferElements(); + + Assert.assertEquals(Long.valueOf(3), resultElements.get("a1").getSecond()); + Assert.assertEquals(Long.valueOf(6), resultElements.get("a2").getSecond()); + + int[] dim1 = (int[]) query.getBuffer("rows"); + int[] dim2 = (int[]) query.getBuffer("cols"); + byte[] a1 = (byte[]) query.getBuffer("a1"); + float[] a2 = (float[]) query.getBuffer("a2"); + + Assert.assertArrayEquals(new int[] {1, 1, 1}, dim1); + Assert.assertArrayEquals(new int[] {2, 3, 4}, dim2); + Assert.assertArrayEquals(new byte[] {'b', 'c', 'd'}, a1); + Assert.assertArrayEquals(new float[] {1.1f, 1.2f, 2.1f, 2.2f, 3.1f, 3.2f}, a2, 0.01f); + + dim1Array.close(); + dim2Array.close(); + a1Array.close(); + a2Array.close(); + query.close(); + array.close(); + } + + @Test + public void arrayReadDimensionsTest() throws Exception { + Array array = new Array(ctx, arrayURI, TILEDB_READ); + + Query query = new Query(array, TILEDB_READ); + + query.addRange(0, 1, 4); + query.addRange(1, 1, 4); + query.setLayout(TILEDB_ROW_MAJOR); - @Test - public void arrayReadTest() throws Exception { - Array array = new Array(ctx, arrayURI, TILEDB_READ); - - // Create query - Query query = new Query(array, TILEDB_READ); - - // Slice only rows 1, 2 and cols 2, 3, 4 - query.addRange(0, 1, 2); - query.addRange(1, 2, 4); - query.setLayout(TILEDB_ROW_MAJOR); - - // Prepare the vector that will hold the result - // (of size 6 elements for "a1" and 12 elements for "a2" since - // it stores two floats per cell) - - // Get the first 6 elements of each attribute/dimension - NativeArray dim1Array = new NativeArray(ctx, 6, Integer.class); - NativeArray dim2Array = new NativeArray(ctx, 6, Integer.class); - NativeArray a1Array = new NativeArray(ctx, 12, Character.class); - NativeArray a2Array = new NativeArray(ctx, 6, Float.class); - - query.setBuffer("rows", dim1Array); - query.setBuffer("cols", dim2Array); - query.setBuffer("a1", a1Array); - query.setBuffer("a2", a2Array); - - // Submit query - query.submit(); - - HashMap> resultElements = query.resultBufferElements(); - - Assert.assertEquals(Long.valueOf(3), resultElements.get("a1").getSecond()); - Assert.assertEquals(Long.valueOf(6), resultElements.get("a2").getSecond()); - - int[] dim1 = (int[]) query.getBuffer("rows"); - int[] dim2 = (int[]) query.getBuffer("cols"); - byte[] a1 = (byte[]) query.getBuffer("a1"); - float[] a2 = (float[]) query.getBuffer("a2"); - - Assert.assertArrayEquals(new int[] {1, 1, 1}, dim1); - Assert.assertArrayEquals(new int[] {2, 3, 4}, dim2); - Assert.assertArrayEquals(new byte[] {'b', 'c', 'd'}, a1); - Assert.assertArrayEquals(new float[] {1.1f, 1.2f, 2.1f, 2.2f, 3.1f, 3.2f}, a2, 0.01f); - - dim1Array.close(); - dim2Array.close(); - a1Array.close(); - a2Array.close(); - query.close(); - array.close(); + // Get the first 6 elements of each attribute/dimension + NativeArray dim1Array = new NativeArray(ctx, 16, Integer.class); + NativeArray dim2Array = new NativeArray(ctx, 16, Integer.class); + + query.setBuffer("rows", dim1Array); + query.setBuffer("cols", dim2Array); + + // Submit query + query.submit(); + + HashMap> resultElements = query.resultBufferElements(); + + Assert.assertEquals(Long.valueOf(16), resultElements.get("rows").getSecond()); + Assert.assertEquals(Long.valueOf(16), resultElements.get("cols").getSecond()); + + int[] dim1 = (int[]) query.getBuffer("rows"); + int[] dim2 = (int[]) query.getBuffer("cols"); + + Assert.assertArrayEquals(new int[] {1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}, dim1); + Assert.assertArrayEquals(new int[] {1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4}, dim2); + + query.close(); + array.close(); + dim1Array.close(); + dim2Array.close(); + } } - @Test - public void arrayReadDimensionsTest() throws Exception { - Array array = new Array(ctx, arrayURI, TILEDB_READ); + public static class SparseTests { + @Before + public void setup() throws Exception { + ctx = new Context(); + if (Files.exists(Paths.get(arrayURI))) { + TileDBObject.remove(ctx, arrayURI); + } + arrayCreate(); + arrayWrite(); + } + + @After + public void teardown() throws Exception { + if (Files.exists(Paths.get(arrayURI))) { + TileDBObject.remove(ctx, arrayURI); + } + } + + public void arrayCreate() throws TileDBError { + // The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4]. + Dimension d1 = new Dimension(ctx, "d1", Datatype.TILEDB_STRING_ASCII, null, null); + + // Create and set getDomain + Domain domain = new Domain(ctx); + domain.addDimension(d1); + + // Add two attributes "a1" and "a2", so each (i,j) cell can store + // a character on "a1" and a vector of two floats on "a2". + Attribute a1 = new Attribute(ctx, "a1", Integer.class); + + ArraySchema schema = new ArraySchema(ctx, TILEDB_SPARSE); + schema.setTileOrder(TILEDB_ROW_MAJOR); + schema.setCellOrder(TILEDB_ROW_MAJOR); + schema.setDomain(domain); + schema.addAttribute(a1); + + Array.create(arrayURI, schema); + } + + public void arrayWrite() throws TileDBError { + + NativeArray d_data = new NativeArray(ctx, "aabbccddee", Datatype.TILEDB_STRING_ASCII); + NativeArray d_off = new NativeArray(ctx, new long[] {0, 2, 4, 6, 8}, Datatype.TILEDB_UINT64); + + // Prepare cell buffers + NativeArray a1 = new NativeArray(ctx, new int[] {1, 2, 3, 4, 5}, Integer.class); + + // Create query + Array array = new Array(ctx, arrayURI, TILEDB_WRITE); + Query query = new Query(array); + query.setLayout(TILEDB_GLOBAL_ORDER); + + query.setBuffer("d1", d_off, d_data); + query.setBuffer("a1", a1); + + // Submit query + query.submit(); + + query.finalizeQuery(); + query.close(); + array.close(); + } + + @Test + public void testReadStringDims() throws TileDBError { + NativeArray d_data = new NativeArray(ctx, 20, Datatype.TILEDB_STRING_ASCII); + NativeArray d_off = new NativeArray(ctx, 20, Datatype.TILEDB_UINT64); + + Query q = new Query(new Array(ctx, arrayURI), TILEDB_READ); + + q.setBuffer("d1", d_off, d_data); - Query query = new Query(array, TILEDB_READ); + q.addRangeVar(0, "a", "z"); - query.addRange(0, 1, 4); - query.addRange(1, 1, 4); - query.setLayout(TILEDB_ROW_MAJOR); + while (q.getQueryStatus() != QueryStatus.TILEDB_COMPLETED) { + q.submit(); - // Get the first 6 elements of each attribute/dimension - NativeArray dim1Array = new NativeArray(ctx, 16, Integer.class); - NativeArray dim2Array = new NativeArray(ctx, 16, Integer.class); + byte[] data = (byte[]) q.getBuffer("d1"); + long[] offsets = q.getVarBuffer("d1"); - query.setBuffer("rows", dim1Array); - query.setBuffer("cols", dim2Array); + String[] results = new String[offsets.length]; + int start = 0, end; - // Submit query - query.submit(); + // Convert bytes to string array + for (int i = 0; i < offsets.length; ++i) { + if (i < offsets.length - 1) { + end = (int) offsets[i + 1]; + results[i] = new String(Arrays.copyOfRange(data, start, end)); + start = end; + } else { + end = data.length; + results[i] = new String(Arrays.copyOfRange(data, start, end)); + } + } - HashMap> resultElements = query.resultBufferElements(); + Assert.assertArrayEquals(new String[] {"aa", "bb", "cc", "dd", "ee"}, results); + } + } + + @Test + public void testAddRangeVar() throws TileDBError { + Array arr = new Array(ctx, arrayURI); + NativeArray d_data = new NativeArray(ctx, 20, Datatype.TILEDB_STRING_ASCII); + NativeArray d_off = new NativeArray(ctx, 20, Datatype.TILEDB_UINT64); + + Query q = new Query(arr, TILEDB_READ); + + q.setBuffer("d1", d_off, d_data); + // Point-query + q.addRangeVar(0, "aa", "aa"); + q.submit(); + + byte[] data = (byte[]) q.getBuffer("d1"); + long[] offsets = q.getVarBuffer("d1"); + + Assert.assertArrayEquals(new String[] {"aa"}, bytesToStrings(offsets, data)); + + q.close(); + d_data.close(); + d_off.close(); + + d_data = new NativeArray(ctx, 20, Datatype.TILEDB_STRING_ASCII); + d_off = new NativeArray(ctx, 20, Datatype.TILEDB_UINT64); + q = new Query(arr, TILEDB_READ); + + q.setBuffer("d1", d_off, d_data); + // Range query ["dd", "ee"] + q.addRangeVar(0, "dd", "ee"); + q.submit(); + + data = (byte[]) q.getBuffer("d1"); + offsets = q.getVarBuffer("d1"); + + Assert.assertArrayEquals(new String[] {"dd", "ee"}, bytesToStrings(offsets, data)); + + // An invalid dimentions should throw an error + d_data = new NativeArray(ctx, 20, Datatype.TILEDB_STRING_ASCII); + d_off = new NativeArray(ctx, 20, Datatype.TILEDB_UINT64); + q = new Query(arr, TILEDB_READ); + + q.setBuffer("d1", d_off, d_data); + // We expect an error here + try { + int dimIdx = 123; + q.addRangeVar(dimIdx, "dd", "ee"); + Assert.fail("An error should be thrown for invalid dimension: " + dimIdx); + } catch (TileDBError error) { + } + } + + @Test(expected = TileDBError.class) + public void testAddRangeVarInvalidDimension() throws TileDBError { + Array arr = new Array(ctx, arrayURI); + NativeArray d_data = new NativeArray(ctx, 20, Datatype.TILEDB_STRING_ASCII); + NativeArray d_off = new NativeArray(ctx, 20, Datatype.TILEDB_UINT64); + + Query q = new Query(arr, TILEDB_READ); + + q.setBuffer("d1", d_off, d_data); + // Point-query + q.addRangeVar(123, "aa", "aa"); + } + + @Test + public void testGetRangeVar() throws TileDBError { + Array arr = new Array(ctx, arrayURI); + NativeArray d_data = new NativeArray(ctx, 20, Datatype.TILEDB_STRING_ASCII); + NativeArray d_off = new NativeArray(ctx, 20, Datatype.TILEDB_UINT64); - Assert.assertEquals(Long.valueOf(16), resultElements.get("rows").getSecond()); - Assert.assertEquals(Long.valueOf(16), resultElements.get("cols").getSecond()); + Query q = new Query(arr, TILEDB_READ); - int[] dim1 = (int[]) query.getBuffer("rows"); - int[] dim2 = (int[]) query.getBuffer("cols"); + q.setBuffer("d1", d_off, d_data); - Assert.assertArrayEquals(new int[] {1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}, dim1); - Assert.assertArrayEquals(new int[] {1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4}, dim2); + String rangeStart1 = "aaaaaa"; + String rangeEnd1 = "aaabb"; + + String rangeStart2 = "aaaaaa"; + String rangeEnd2 = "aaabb"; + + String rangeStart3 = "aaaaaa"; + String rangeEnd3 = "aaabb"; + + // Point-query + q.addRangeVar(0, rangeStart1, rangeEnd1); + q.addRangeVar(0, rangeStart2, rangeEnd2); + q.addRangeVar(0, rangeStart3, rangeEnd3); + + Pair range1 = q.getRangeVar(0, BigInteger.valueOf(0)); + Pair range2 = q.getRangeVar(0, BigInteger.valueOf(1)); + Pair range3 = q.getRangeVar(0, BigInteger.valueOf(2)); + + Assert.assertEquals(rangeStart1, range1.getFirst()); + Assert.assertEquals(rangeEnd1, range1.getSecond()); + Assert.assertEquals(rangeStart2, range2.getFirst()); + Assert.assertEquals(rangeEnd2, range2.getSecond()); + Assert.assertEquals(rangeStart3, range3.getFirst()); + Assert.assertEquals(rangeEnd3, range3.getSecond()); + } + + @Test + public void testGetRangeVarSize() throws TileDBError { + Array arr = new Array(ctx, arrayURI); + NativeArray d_data = new NativeArray(ctx, 20, Datatype.TILEDB_STRING_ASCII); + NativeArray d_off = new NativeArray(ctx, 20, Datatype.TILEDB_UINT64); + + Query q = new Query(arr, TILEDB_READ); + + q.setBuffer("d1", d_off, d_data); + + String rangeStart1 = "aaaaaa"; + String rangeEnd1 = "aaabb"; + + String rangeStart2 = "aaaaaa"; + String rangeEnd2 = "aaabb"; + + String rangeStart3 = "aaaaaa"; + String rangeEnd3 = "aaabb"; + + // Point-query + q.addRangeVar(0, rangeStart1, rangeEnd1); + q.addRangeVar(0, rangeStart2, rangeEnd2); + q.addRangeVar(0, rangeStart3, rangeEnd3); + + Pair size1 = q.getRangeVarSize(0, BigInteger.valueOf(0)); + Pair size2 = q.getRangeVarSize(0, BigInteger.valueOf(1)); + Pair size3 = q.getRangeVarSize(0, BigInteger.valueOf(2)); + + Assert.assertEquals(rangeStart1.length(), (long) size1.getFirst()); + Assert.assertEquals(rangeEnd1.length(), (long) size1.getSecond()); + Assert.assertEquals(rangeStart2.length(), (long) size2.getFirst()); + Assert.assertEquals(rangeEnd2.length(), (long) size2.getSecond()); + Assert.assertEquals(rangeStart3.length(), (long) size3.getFirst()); + Assert.assertEquals(rangeEnd3.length(), (long) size3.getSecond()); + } + } + + public static String[] bytesToStrings(long[] offsets, byte[] data) { + String[] results = new String[offsets.length]; + int start = 0, end; + + // Convert bytes to string array + for (int i = 0; i < offsets.length; ++i) { + if (i < offsets.length - 1) { + end = (int) offsets[i + 1]; + results[i] = new String(Arrays.copyOfRange(data, start, end)); + start = end; + } else { + end = data.length; + results[i] = new String(Arrays.copyOfRange(data, start, end)); + } + } - query.close(); - array.close(); - dim1Array.close(); - dim2Array.close(); + return results; } }