Repository: kudu Updated Branches: refs/heads/master ee8592a1f -> 02ca419bd
KUDU-1424. Add getters to PartialRow - Adds getters for each type to PartialRow - Adds public isNull and isSet methods - Adds unit tests for PartialRow - Fixes javadoc in PartialRow and RowResult Change-Id: I7c751eda9e8d6da5dd6ddd2ec798259bc037fb7d Reviewed-on: http://gerrit.cloudera.org:8080/6554 Tested-by: Kudu Jenkins Reviewed-by: Jean-Daniel Cryans <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/02ca419b Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/02ca419b Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/02ca419b Branch: refs/heads/master Commit: 02ca419bd158ad90a74e2cc66c8c5f7425e93b14 Parents: ee8592a Author: Grant Henke <[email protected]> Authored: Tue Apr 4 23:58:48 2017 -0500 Committer: Jean-Daniel Cryans <[email protected]> Committed: Tue Apr 11 18:36:32 2017 +0000 ---------------------------------------------------------------------- .../java/org/apache/kudu/client/PartialRow.java | 436 ++++++++++++++++--- .../java/org/apache/kudu/client/RowResult.java | 96 ++-- .../org/apache/kudu/client/TestPartialRow.java | 270 ++++++++++++ 3 files changed, 713 insertions(+), 89 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/02ca419b/java/kudu-client/src/main/java/org/apache/kudu/client/PartialRow.java ---------------------------------------------------------------------- diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/PartialRow.java b/java/kudu-client/src/main/java/org/apache/kudu/client/PartialRow.java index c53dd53..f31d71a 100644 --- a/java/kudu-client/src/main/java/org/apache/kudu/client/PartialRow.java +++ b/java/kudu-client/src/main/java/org/apache/kudu/client/PartialRow.java @@ -33,6 +33,7 @@ import org.apache.kudu.Type; import org.apache.kudu.annotations.InterfaceAudience; import org.apache.kudu.annotations.InterfaceStability; import org.apache.kudu.util.StringUtil; +import org.jboss.netty.util.CharsetUtil; /** * Class used to represent parts of a row along with its schema.<p> @@ -109,11 +110,12 @@ public class PartialRow { * Add a boolean for the specified column. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addBoolean(int columnIndex, boolean val) { + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.BOOL); rowAlloc[getPositionInRowAllocAndSetBitSet(columnIndex)] = (byte) (val ? 1 : 0); } @@ -122,8 +124,8 @@ public class PartialRow { * Add a boolean for the specified column. * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addBoolean(String columnName, boolean val) { @@ -131,14 +133,41 @@ public class PartialRow { } /** + * Get the specified column's boolean + * @param columnName name of the column to get data for + * @return a boolean + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public boolean getBoolean(String columnName) { + return getBoolean(this.schema.getColumnIndex(columnName)); + } + + /** + * Get the specified column's boolean + * @param columnIndex Column index in the schema + * @return a boolean + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public boolean getBoolean(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.BOOL); + checkValue(columnIndex); + byte b = rowAlloc[schema.getColumnOffset(columnIndex)]; + return b == 1; + } + + /** * Add a byte for the specified column. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addByte(int columnIndex, byte val) { + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.INT8); rowAlloc[getPositionInRowAllocAndSetBitSet(columnIndex)] = val; } @@ -147,8 +176,8 @@ public class PartialRow { * Add a byte for the specified column. * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addByte(String columnName, byte val) { @@ -156,14 +185,40 @@ public class PartialRow { } /** + * Get the specified column's byte + * @param columnName name of the column to get data for + * @return a byte + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public byte getByte(String columnName) { + return getByte(this.schema.getColumnIndex(columnName)); + } + + /** + * Get the specified column's byte + * @param columnIndex Column index in the schema + * @return a byte + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public byte getByte(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.INT8); + checkValue(columnIndex); + return rowAlloc[schema.getColumnOffset(columnIndex)]; + } + + /** * Add a short for the specified column. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addShort(int columnIndex, short val) { + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.INT16); Bytes.setShort(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex)); } @@ -172,8 +227,8 @@ public class PartialRow { * Add a short for the specified column. * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addShort(String columnName, short val) { @@ -181,14 +236,40 @@ public class PartialRow { } /** + * Get the specified column's short + * @param columnName name of the column to get data for + * @return a short + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public short getShort(String columnName) { + return getShort(this.schema.getColumnIndex(columnName)); + } + + /** + * Get the specified column's short + * @param columnIndex Column index in the schema + * @return a short + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public short getShort(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.INT16); + checkValue(columnIndex); + return Bytes.getShort(rowAlloc, schema.getColumnOffset(columnIndex)); + } + + /** * Add an int for the specified column. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addInt(int columnIndex, int val) { + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.INT32); Bytes.setInt(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex)); } @@ -197,8 +278,8 @@ public class PartialRow { * Add an int for the specified column. * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addInt(String columnName, int val) { @@ -206,14 +287,40 @@ public class PartialRow { } /** + * Get the specified column's integer + * @param columnName name of the column to get data for + * @return an integer + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public int getInt(String columnName) { + return getInt(this.schema.getColumnIndex(columnName)); + } + + /** + * Get the specified column's integer + * @param columnIndex Column index in the schema + * @return an integer + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public int getInt(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.INT32); + checkValue(columnIndex); + return Bytes.getInt(rowAlloc, schema.getColumnOffset(columnIndex)); + } + + /** * Add an long for the specified column. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addLong(int columnIndex, long val) { + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.INT64, Type.UNIXTIME_MICROS); Bytes.setLong(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex)); } @@ -227,8 +334,8 @@ public class PartialRow { * * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addLong(String columnName, long val) { @@ -236,14 +343,49 @@ public class PartialRow { } /** + * Get the specified column's long + * + * If this is a UNIXTIME_MICROS column, the long value corresponds to a number of microseconds + * since midnight, January 1, 1970 UTC. + * + * @param columnName name of the column to get data for + * @return a long + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public long getLong(String columnName) { + return getLong(this.schema.getColumnIndex(columnName)); + } + + /** + * Get the specified column's long + * + * If this is a UNIXTIME_MICROS column, the long value corresponds to a number of microseconds + * since midnight, January 1, 1970 UTC. + * + * @param columnIndex Column index in the schema + * @return a long + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public long getLong(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.INT64, Type.UNIXTIME_MICROS); + checkColumnExists(schema.getColumnByIndex(columnIndex)); + checkValue(columnIndex); + return Bytes.getLong(rowAlloc, schema.getColumnOffset(columnIndex)); + } + + /** * Add an float for the specified column. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addFloat(int columnIndex, float val) { + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.FLOAT); Bytes.setFloat(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex)); } @@ -252,8 +394,8 @@ public class PartialRow { * Add an float for the specified column. * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addFloat(String columnName, float val) { @@ -261,14 +403,40 @@ public class PartialRow { } /** + * Get the specified column's float + * @param columnName name of the column to get data for + * @return a float + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public float getFloat(String columnName) { + return getFloat(this.schema.getColumnIndex(columnName)); + } + + /** + * Get the specified column's float + * @param columnIndex Column index in the schema + * @return a float + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public float getFloat(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.FLOAT); + checkValue(columnIndex); + return Bytes.getFloat(rowAlloc, schema.getColumnOffset(columnIndex)); + } + + /** * Add an double for the specified column. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addDouble(int columnIndex, double val) { + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.DOUBLE); Bytes.setDouble(rowAlloc, val, getPositionInRowAllocAndSetBitSet(columnIndex)); } @@ -277,8 +445,8 @@ public class PartialRow { * Add an double for the specified column. * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addDouble(String columnName, double val) { @@ -286,12 +454,37 @@ public class PartialRow { } /** + * Get the specified column's double + * @param columnName name of the column to get data for + * @return a double + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public double getDouble(String columnName) { + return getDouble(this.schema.getColumnIndex(columnName)); + } + + /** + * Get the specified column's double + * @param columnIndex Column index in the schema + * @return a double + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public double getDouble(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.DOUBLE); + checkValue(columnIndex); + return Bytes.getDouble(rowAlloc, schema.getColumnOffset(columnIndex)); + } + + /** * Add a String for the specified column. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addString(int columnIndex, String val) { addStringUtf8(columnIndex, Bytes.fromString(val)); @@ -301,8 +494,8 @@ public class PartialRow { * Add a String for the specified column. * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addString(String columnName, String val) { @@ -310,17 +503,43 @@ public class PartialRow { } /** + * Get the specified column's string. + * @param columnName name of the column to get data for + * @return a string + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public String getString(String columnName) { + return getString(this.schema.getColumnIndex(columnName)); + } + + /** + * Get the specified column's string. + * @param columnIndex Column index in the schema + * @return a string + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public String getString(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.STRING); + checkValue(columnIndex); + return new String(getVarLengthData(columnIndex).array(), CharsetUtil.UTF_8); + } + + /** * Add a String for the specified value, encoded as UTF8. * Note that the provided value must not be mutated after this. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addStringUtf8(int columnIndex, byte[] val) { - // TODO: use Utf8.isWellFormed from Guava 16 to verify that + // TODO: use Utf8.isWellFormed from Guava 16 to verify that. // the user isn't putting in any garbage data. + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.STRING); addVarLengthData(columnIndex, val); } @@ -330,8 +549,8 @@ public class PartialRow { * Note that the provided value must not be mutated after this. * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied * */ @@ -344,11 +563,12 @@ public class PartialRow { * Note that the provided value must not be mutated after this. * @param columnIndex the column's index in the schema * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addBinary(int columnIndex, byte[] val) { + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.BINARY); addVarLengthData(columnIndex, val); } @@ -359,11 +579,12 @@ public class PartialRow { * data must not be mutated after this. * @param columnIndex the column's index in the schema * @param value byte buffer to get the value from - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied + * @throws IndexOutOfBoundsException if the column doesn't exist */ public void addBinary(int columnIndex, ByteBuffer value) { + checkNotFrozen(); checkColumn(schema.getColumnByIndex(columnIndex), Type.BINARY); addVarLengthData(columnIndex, value); } @@ -373,8 +594,8 @@ public class PartialRow { * Note that the provided value must not be mutated after this. * @param columnName Name of the column * @param val value to add - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addBinary(String columnName, byte[] val) { @@ -387,14 +608,73 @@ public class PartialRow { * data must not be mutated after this. * @param columnName Name of the column * @param value byte buffer to get the value from - * @throws IllegalArgumentException if the column doesn't exist or if the value doesn't match - * the column's type + * @throws IllegalArgumentException if the column doesn't exist + * or if the value doesn't match the column's type * @throws IllegalStateException if the row was already applied */ public void addBinary(String columnName, ByteBuffer value) { addBinary(schema.getColumnIndex(columnName), value); } + /** + * Get a copy of the specified column's binary data. + * @param columnName name of the column to get data for + * @return a byte[] with the binary data. + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public byte[] getBinaryCopy(String columnName) { + return getBinaryCopy(this.schema.getColumnIndex(columnName)); + } + + /** + * Get a copy of the specified column's binary data. + * @param columnIndex Column index in the schema + * @return a byte[] with the binary data. + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public byte[] getBinaryCopy(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.BINARY); + checkValue(columnIndex); + byte[] data = getVarLengthData(columnIndex).array(); + byte[] ret = new byte[data.length]; + System.arraycopy(data, 0, ret, 0, data.length); + return ret; + } + + /** + * Get the specified column's binary data. + * + * This doesn't copy the data and instead returns a ByteBuffer that wraps it. + * + * @param columnName name of the column to get data for + * @return a ByteBuffer with the binary data. + * @throws IllegalArgumentException if the column doesn't exist, + * is null, is unset, or the type doesn't match the column's type + */ + public ByteBuffer getBinary(String columnName) { + return getBinary(this.schema.getColumnIndex(columnName)); + } + + /** + * Get the specified column's binary data. + * + * This doesn't copy the data and instead returns a ByteBuffer that wraps it. + * + * @param columnIndex Column index in the schema + * @return a ByteBuffer with the binary data. + * @throws IllegalArgumentException if the column is null, is unset, + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public ByteBuffer getBinary(int columnIndex) { + checkColumn(schema.getColumnByIndex(columnIndex), Type.BINARY); + checkValue(columnIndex); + return getVarLengthData(columnIndex); + } + private void addVarLengthData(int columnIndex, byte[] val) { addVarLengthData(columnIndex, ByteBuffer.wrap(val)); } @@ -411,6 +691,10 @@ public class PartialRow { // We don't set anything in row alloc, it will be managed at encoding time. } + private ByteBuffer getVarLengthData(int columnIndex) { + return varLengthData.get(columnIndex).duplicate(); + } + /** * Set the specified column to null * @param columnIndex the column's index in the schema @@ -444,15 +728,35 @@ public class PartialRow { } /** + * Get if the specified column is NULL + * @param columnName name of the column in the schema + * @return true if the column cell is null and the column is nullable, + * false otherwise + * @throws IllegalArgumentException if the column doesn't exist + */ + public boolean isNull(String columnName) { + return isNull(this.schema.getColumnIndex(columnName)); + } + + /** + * Get if the specified column is NULL + * @param columnIndex Column index in the schema + * @return true if the column cell is null and the column is nullable, + * false otherwise + * @throws IndexOutOfBoundsException if the column doesn't exist + */ + public boolean isNull(int columnIndex) { + checkColumnExists(schema.getColumnByIndex(columnIndex)); + return schema.getColumnByIndex(columnIndex).isNullable() && isSetToNull(columnIndex); + } + + /** * Verifies if the column exists and belongs to one of the specified types - * It also does some internal accounting * @param column column the user wants to set * @param types types we expect * @throws IllegalArgumentException if the column or type was invalid - * @throws IllegalStateException if the row was already applied */ private void checkColumn(ColumnSchema column, Type... types) { - checkNotFrozen(); checkColumnExists(column); for (Type type : types) { if (column.getType().equals(type)) { @@ -474,6 +778,20 @@ public class PartialRow { } /** + * @param columnIndex Column index in the schema + * @throws IllegalArgumentException if the column is unset or null + */ + private void checkValue(int columnIndex) { + if (!isSet(columnIndex)) { + throw new IllegalArgumentException("Column value is not set"); + } + + if (isNull(columnIndex)) { + throw new IllegalArgumentException("Column value is null"); + } + } + + /** * @throws IllegalStateException if the row was already applied */ private void checkNotFrozen() { @@ -493,12 +811,24 @@ public class PartialRow { } /** - * Tells if the specified column was set by the user - * @param column column's index in the schema - * @return true if it was set, else false + * Get if the specified column has been set + * @param columnName name of the column in the schema + * @return true if the column has been set + * @throws IllegalArgumentException if the column doesn't exist + */ + public boolean isSet(String columnName) { + return isSet(this.schema.getColumnIndex(columnName)); + } + + /** + * Get if the specified column has been set + * @param columnIndex Column index in the schema + * @return true if the column has been set + * @throws IndexOutOfBoundsException if the column doesn't exist */ - boolean isSet(int column) { - return this.columnsBitSet.get(column); + public boolean isSet(int columnIndex) { + checkColumnExists(schema.getColumnByIndex(columnIndex)); + return this.columnsBitSet.get(columnIndex); } /** http://git-wip-us.apache.org/repos/asf/kudu/blob/02ca419b/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java ---------------------------------------------------------------------- diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java b/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java index 7a10380..951084b 100644 --- a/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java +++ b/java/kudu-client/src/main/java/org/apache/kudu/client/RowResult.java @@ -79,14 +79,14 @@ public class RowResult { } this.rowSize = this.schema.getRowSize(); columnOffsets = new int[columnOffsetsSize]; - // Empty projection, usually used for quick row counting + // Empty projection, usually used for quick row counting. if (columnOffsetsSize == 0) { return; } int currentOffset = 0; columnOffsets[0] = currentOffset; - // Pre-compute the columns offsets in rowData for easier lookups later - // If the schema has nullables, we also add the offset for the null bitmap at the end + // Pre-compute the columns offsets in rowData for easier lookups later. + // If the schema has nullables, we also add the offset for the null bitmap at the end. for (int i = 1; i < columnOffsetsSize; i++) { int previousSize = schema.getColumnByIndex(i - 1).getType().getSize(); columnOffsets[i] = previousSize + currentOffset; @@ -124,8 +124,9 @@ public class RowResult { /** * Get the specified column's integer * @param columnName name of the column to get data for - * @return An integer - * @throws IllegalArgumentException if the column is null + * @return an integer + * @throws IllegalArgumentException if the column doesn't exist, is null, + * or if the type doesn't match the column's type */ public int getInt(String columnName) { return getInt(this.schema.getColumnIndex(columnName)); @@ -134,8 +135,9 @@ public class RowResult { /** * Get the specified column's integer * @param columnIndex Column index in the schema - * @return An integer + * @return an integer * @throws IllegalArgumentException if the column is null + * or if the type doesn't match the column's type * @throws IndexOutOfBoundsException if the column doesn't exist */ public int getInt(int columnIndex) { @@ -149,8 +151,9 @@ public class RowResult { /** * Get the specified column's short * @param columnName name of the column to get data for - * @return A short - * @throws IllegalArgumentException if the column is null + * @return a short + * @throws IllegalArgumentException if the column doesn't exist, is null, + * or if the type doesn't match the column's type */ public short getShort(String columnName) { return getShort(this.schema.getColumnIndex(columnName)); @@ -159,8 +162,9 @@ public class RowResult { /** * Get the specified column's short * @param columnIndex Column index in the schema - * @return A short + * @return a short * @throws IllegalArgumentException if the column is null + * or if the type doesn't match the column's type * @throws IndexOutOfBoundsException if the column doesn't exist */ public short getShort(int columnIndex) { @@ -174,8 +178,9 @@ public class RowResult { /** * Get the specified column's boolean * @param columnName name of the column to get data for - * @return A boolean - * @throws IllegalArgumentException if the column is null + * @return a boolean + * @throws IllegalArgumentException if the column doesn't exist, is null, + * or if the type doesn't match the column's type */ public boolean getBoolean(String columnName) { return getBoolean(this.schema.getColumnIndex(columnName)); @@ -184,8 +189,9 @@ public class RowResult { /** * Get the specified column's boolean * @param columnIndex Column index in the schema - * @return A boolean + * @return a boolean * @throws IllegalArgumentException if the column is null + * or if the type doesn't match the column's type * @throws IndexOutOfBoundsException if the column doesn't exist */ public boolean getBoolean(int columnIndex) { @@ -201,8 +207,9 @@ public class RowResult { /** * Get the specified column's byte * @param columnName name of the column to get data for - * @return A byte - * @throws IllegalArgumentException if the column is null + * @return a byte + * @throws IllegalArgumentException if the column doesn't exist, is null, + * or if the type doesn't match the column's type */ public byte getByte(String columnName) { return getByte(this.schema.getColumnIndex(columnName)); @@ -212,8 +219,9 @@ public class RowResult { /** * Get the specified column's byte * @param columnIndex Column index in the schema - * @return A byte + * @return a byte * @throws IllegalArgumentException if the column is null + * or if the type doesn't match the column's type * @throws IndexOutOfBoundsException if the column doesn't exist */ public byte getByte(int columnIndex) { @@ -231,8 +239,8 @@ public class RowResult { * since midnight, January 1, 1970 UTC. * * @param columnName name of the column to get data for - * @return A positive long - * @throws IllegalArgumentException if the column is null\ + * @return a positive long + * @throws IllegalArgumentException if the column doesn't exist or is null */ public long getLong(String columnName) { return getLong(this.schema.getColumnIndex(columnName)); @@ -245,14 +253,14 @@ public class RowResult { * since midnight, January 1, 1970 UTC. * * @param columnIndex Column index in the schema - * @return A positive long + * @return a positive long * @throws IllegalArgumentException if the column is null * @throws IndexOutOfBoundsException if the column doesn't exist */ public long getLong(int columnIndex) { checkValidColumn(columnIndex); checkNull(columnIndex); - // Can't check type because this could be a long, string, or Timestamp + // Can't check type because this could be a long, string, or Timestamp. return Bytes.getLong(this.rowData.getRawArray(), this.rowData.getRawOffset() + getCurrentRowDataOffsetForColumn(columnIndex)); @@ -261,7 +269,9 @@ public class RowResult { /** * Get the specified column's float * @param columnName name of the column to get data for - * @return A float + * @return a float + * @throws IllegalArgumentException if the column doesn't exist, is null, + * or if the type doesn't match the column's type */ public float getFloat(String columnName) { return getFloat(this.schema.getColumnIndex(columnName)); @@ -270,7 +280,10 @@ public class RowResult { /** * Get the specified column's float * @param columnIndex Column index in the schema - * @return A float + * @return a float + * @throws IllegalArgumentException if the column is null + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist */ public float getFloat(int columnIndex) { checkValidColumn(columnIndex); @@ -284,7 +297,9 @@ public class RowResult { /** * Get the specified column's double * @param columnName name of the column to get data for - * @return A double + * @return a double + * @throws IllegalArgumentException if the column doesn't exist, is null, + * or if the type doesn't match the column's type */ public double getDouble(String columnName) { return getDouble(this.schema.getColumnIndex(columnName)); @@ -294,7 +309,10 @@ public class RowResult { /** * Get the specified column's double * @param columnIndex Column index in the schema - * @return A double + * @return a double + * @throws IllegalArgumentException if the column is null + * or if the type doesn't match the column's type + * @throws IndexOutOfBoundsException if the column doesn't exist */ public double getDouble(int columnIndex) { checkValidColumn(columnIndex); @@ -307,7 +325,7 @@ public class RowResult { /** * Get the schema used for this scanner's column projection. - * @return A column projection as a schema. + * @return a column projection as a schema. */ public Schema getColumnProjection() { return this.schema; @@ -316,8 +334,9 @@ public class RowResult { /** * Get the specified column's string. * @param columnName name of the column to get data for - * @return A string - * @throws IllegalArgumentException if the column is null + * @return a string + * @throws IllegalArgumentException if the column doesn't exist, is null, + * or if the type doesn't match the column's type */ public String getString(String columnName) { return getString(this.schema.getColumnIndex(columnName)); @@ -327,15 +346,16 @@ public class RowResult { /** * Get the specified column's string. * @param columnIndex Column index in the schema - * @return A string + * @return a string * @throws IllegalArgumentException if the column is null + * or if the type doesn't match the column's type * @throws IndexOutOfBoundsException if the column doesn't exist */ public String getString(int columnIndex) { checkValidColumn(columnIndex); checkNull(columnIndex); checkType(columnIndex, Type.STRING); - // C++ puts a Slice in rowData which is 16 bytes long for simplity, but we only support ints + // C++ puts a Slice in rowData which is 16 bytes long for simplity, but we only support ints. long offset = getLong(columnIndex); long length = rowData.getLong(getCurrentRowDataOffsetForColumn(columnIndex) + 8); assert offset < Integer.MAX_VALUE; @@ -349,7 +369,8 @@ public class RowResult { * Get a copy of the specified column's binary data. * @param columnName name of the column to get data for * @return a byte[] with the binary data. - * @throws IllegalArgumentException if the column is null + * @throws IllegalArgumentException if the column doesn't exist, is null, + * or if the type doesn't match the column's type * @throws IndexOutOfBoundsException if the column doesn't exist */ public byte[] getBinaryCopy(String columnName) { @@ -362,13 +383,14 @@ public class RowResult { * @param columnIndex Column index in the schema * @return a byte[] with the binary data. * @throws IllegalArgumentException if the column is null + * or if the type doesn't match the column's type * @throws IndexOutOfBoundsException if the column doesn't exist */ public byte[] getBinaryCopy(int columnIndex) { checkValidColumn(columnIndex); checkNull(columnIndex); // C++ puts a Slice in rowData which is 16 bytes long for simplicity, - // but we only support ints + // but we only support ints. long offset = getLong(columnIndex); long length = rowData.getLong(getCurrentRowDataOffsetForColumn(columnIndex) + 8); assert offset < Integer.MAX_VALUE; @@ -385,8 +407,9 @@ public class RowResult { * This doesn't copy the data and instead returns a ByteBuffer that wraps it. * * @param columnName name of the column to get data for - * @return a byte[] with the binary data. - * @throws IllegalArgumentException if the column is null + * @return a ByteBuffer with the binary data. + * @throws IllegalArgumentException if the column doesn't exist, is null, + * or if the type doesn't match the column's type * @throws IndexOutOfBoundsException if the column doesn't exist */ public ByteBuffer getBinary(String columnName) { @@ -399,8 +422,9 @@ public class RowResult { * This doesn't copy the data and instead returns a ByteBuffer that wraps it. * * @param columnIndex Column index in the schema - * @return a byte[] with the binary data. + * @return a ByteBuffer with the binary data. * @throws IllegalArgumentException if the column is null + * or if the type doesn't match the column's type * @throws IndexOutOfBoundsException if the column doesn't exist */ public ByteBuffer getBinary(int columnIndex) { @@ -408,7 +432,7 @@ public class RowResult { checkNull(columnIndex); checkType(columnIndex, Type.BINARY); // C++ puts a Slice in rowData which is 16 bytes long for simplicity, - // but we only support ints + // but we only support ints. long offset = getLong(columnIndex); long length = rowData.getLong(getCurrentRowDataOffsetForColumn(columnIndex) + 8); assert offset < Integer.MAX_VALUE; @@ -419,7 +443,7 @@ public class RowResult { /** * Get if the specified column is NULL - * @param columnName name of the column to get data for + * @param columnName name of the column in the schema * @return true if the column cell is null and the column is nullable, * false otherwise * @throws IndexOutOfBoundsException if the column doesn't exist @@ -586,7 +610,7 @@ public class RowResult { * the iterator as well as its data. */ public String toStringLongFormat() { - StringBuilder buf = new StringBuilder(this.rowSize); // super rough estimation + StringBuilder buf = new StringBuilder(this.rowSize); // super rough estimation. buf.append(this.toString()); buf.append("{"); buf.append(rowToString()); http://git-wip-us.apache.org/repos/asf/kudu/blob/02ca419b/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartialRow.java ---------------------------------------------------------------------- diff --git a/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartialRow.java b/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartialRow.java index 9885ad2..f1ecfee 100644 --- a/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartialRow.java +++ b/java/kudu-client/src/test/java/org/apache/kudu/client/TestPartialRow.java @@ -17,17 +17,190 @@ package org.apache.kudu.client; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.nio.ByteBuffer; +import org.apache.kudu.ColumnSchema; +import org.apache.kudu.Type; import org.junit.Test; import org.apache.kudu.Schema; +import sun.reflect.generics.reflectiveObjects.NotImplementedException; public class TestPartialRow { @Test + public void testGetters() { + PartialRow partialRow = getPartialRowWithAllTypes(); + assertEquals(true, partialRow.getBoolean("bool")); + assertEquals(42, partialRow.getByte("int8")); + assertEquals(43, partialRow.getShort("int16")); + assertEquals(44, partialRow.getInt("int32")); + assertEquals(45, partialRow.getLong("int64")); + assertEquals(1234567890, partialRow.getLong("timestamp")); + assertEquals(52.35F, partialRow.getFloat("float"), 0.0f); + assertEquals(53.35, partialRow.getDouble("double"), 0.0); + assertEquals("fun with ütf\0", partialRow.getString("string")); + assertArrayEquals(new byte[] { 0, 1, 2, 3, 4 }, partialRow.getBinaryCopy("binary-array")); + assertArrayEquals(new byte[] { 5, 6, 7, 8, 9 }, partialRow.getBinaryCopy("binary-bytebuffer")); + assertEquals(ByteBuffer.wrap(new byte[] { 0, 1, 2, 3, 4 }), partialRow.getBinary("binary-array")); + assertEquals(ByteBuffer.wrap(new byte[] { 5, 6, 7, 8, 9 }), partialRow.getBinary("binary-bytebuffer")); + assertTrue(partialRow.isSet("null")); + assertTrue(partialRow.isNull("null")); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetNullColumn() { + PartialRow partialRow = getPartialRowWithAllTypes(); + assertTrue(partialRow.isSet("null")); + assertTrue(partialRow.isNull("null")); + partialRow.getString("null"); + } + + @Test(expected = IllegalArgumentException.class) + public void testSetNonNullableColumn() { + PartialRow partialRow = getPartialRowWithAllTypes(); + partialRow.setNull("int32"); + } + + @Test + public void testGetUnsetColumn() { + Schema schema = BaseKuduTest.getSchemaWithAllTypes(); + PartialRow partialRow = schema.newPartialRow(); + for (ColumnSchema columnSchema : schema.getColumns()) { + assertFalse(partialRow.isSet("null")); + assertFalse(partialRow.isNull("null")); + try { + callGetByName(partialRow, columnSchema.getName(), columnSchema.getType()); + fail("Expected IllegalArgumentException for type: " + columnSchema.getType()); + } catch (IllegalArgumentException ex) { + // This is the expected exception. + } + } + } + + @Test + public void testGetMissingColumnName() { + PartialRow partialRow = getPartialRowWithAllTypes(); + for (ColumnSchema columnSchema : partialRow.getSchema().getColumns()) { + try { + callGetByName(partialRow, "not-a-column", columnSchema.getType()); + fail("Expected IllegalArgumentException for type: " + columnSchema.getType()); + } catch (IllegalArgumentException ex) { + // This is the expected exception. + } + } + } + + @Test + public void testGetMissingColumnIndex() { + PartialRow partialRow = getPartialRowWithAllTypes(); + for (ColumnSchema columnSchema : partialRow.getSchema().getColumns()) { + try { + callGetByIndex(partialRow, 999, columnSchema.getType()); + fail("Expected IndexOutOfBoundsException for type: " + columnSchema.getType()); + } catch (IndexOutOfBoundsException ex) { + // This is the expected exception. + } + } + } + + @Test + public void testGetWrongTypeColumn() { + PartialRow partialRow = getPartialRowWithAllTypes(); + for (ColumnSchema columnSchema : partialRow.getSchema().getColumns()) { + try { + callGetByName(partialRow, columnSchema.getName(), getShiftedType(columnSchema.getType())); + fail("Expected IllegalArgumentException for type: " + columnSchema.getType()); + } catch (IllegalArgumentException ex) { + // This is the expected exception. + } + } + } + + @Test + public void testAddMissingColumnName() { + PartialRow partialRow = getPartialRowWithAllTypes(); + for (ColumnSchema columnSchema : partialRow.getSchema().getColumns()) { + try { + callAddByName(partialRow, "not-a-column", columnSchema.getType()); + fail("Expected IllegalArgumentException for type: " + columnSchema.getType()); + } catch (IllegalArgumentException ex) { + // This is the expected exception. + } + } + } + + @Test + public void testAddMissingColumnIndex() { + PartialRow partialRow = getPartialRowWithAllTypes(); + for (ColumnSchema columnSchema : partialRow.getSchema().getColumns()) { + try { + callAddByIndex(partialRow, 999, columnSchema.getType()); + fail("Expected IndexOutOfBoundsException for type: " + columnSchema.getType()); + } catch (IndexOutOfBoundsException ex) { + // This is the expected exception. + } + } + } + + @Test + public void testAddWrongTypeColumn() { + PartialRow partialRow = getPartialRowWithAllTypes(); + for (ColumnSchema columnSchema : partialRow.getSchema().getColumns()) { + try { + callAddByName(partialRow, columnSchema.getName(), getShiftedType(columnSchema.getType())); + fail("Expected IllegalArgumentException for type: " + columnSchema.getType()); + } catch (IllegalArgumentException ex) { + // This is the expected exception. + } + } + } + + @Test + public void testAddToFrozenRow() { + PartialRow partialRow = getPartialRowWithAllTypes(); + partialRow.freeze(); + for (ColumnSchema columnSchema : partialRow.getSchema().getColumns()) { + try { + callAddByName(partialRow, columnSchema.getName(), columnSchema.getType()); + fail("Expected IllegalStateException for type: " + columnSchema.getType()); + } catch (IllegalStateException ex) { + // This is the expected exception. + } + } + } + + @Test(expected = IllegalArgumentException.class) + public void testIsNullMissingColumnName() { + PartialRow partialRow = getPartialRowWithAllTypes(); + partialRow.isNull("not-a-column"); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIsNullMissingColumnIndex() { + PartialRow partialRow = getPartialRowWithAllTypes(); + partialRow.isNull(999); + } + + @Test(expected = IllegalArgumentException.class) + public void testIsSetMissingColumnName() { + PartialRow partialRow = getPartialRowWithAllTypes(); + partialRow.isSet("not-a-column"); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIsSetMissingColumnIndex() { + PartialRow partialRow = getPartialRowWithAllTypes(); + partialRow.isSet(999); + } + + @Test public void testToString() { Schema schema = BaseKuduTest.getSchemaWithAllTypes(); @@ -57,4 +230,101 @@ public class TestPartialRow { "string string=\"fun with ütf\\0\", binary binary-bytebuffer=[2, 3, 4])", row.toString()); } + + private PartialRow getPartialRowWithAllTypes() { + Schema schema = BaseKuduTest.getSchemaWithAllTypes(); + // Ensure we aren't missing any types + assertEquals(12, schema.getColumnCount()); + + PartialRow row = schema.newPartialRow(); + row.addByte("int8", (byte) 42); + row.addShort("int16", (short) 43); + row.addInt("int32", 44); + row.addLong("int64", 45); + row.addLong("timestamp", 1234567890); // Fri, 13 Feb 2009 23:31:30 UTC + row.addBoolean("bool", true); + row.addFloat("float", 52.35F); + row.addDouble("double", 53.35); + row.addString("string", "fun with ütf\0"); + row.addBinary("binary-array", new byte[] { 0, 1, 2, 3, 4 }); + ByteBuffer binaryBuffer = ByteBuffer.wrap(new byte[] { 5, 6, 7, 8, 9 }); + row.addBinary("binary-bytebuffer", binaryBuffer); + row.setNull("null"); + return row; + } + + // Shift the type one position to force the wrong type for all types. + private Type getShiftedType(Type type) { + int shiftedPosition = (type.ordinal() + 1) % Type.values().length; + return Type.values()[shiftedPosition]; + } + + private Object callGetByName(PartialRow partialRow, String columnName, Type type) { + switch (type) { + case INT8: return partialRow.getByte(columnName); + case INT16: return partialRow.getShort(columnName); + case INT32: return partialRow.getInt(columnName); + case INT64: return partialRow.getLong(columnName); + case UNIXTIME_MICROS: return partialRow.getLong(columnName); + case STRING: return partialRow.getString(columnName); + case BINARY: return partialRow.getBinary(columnName); + case FLOAT: return partialRow.getFloat(columnName); + case DOUBLE: return partialRow.getDouble(columnName); + case BOOL: return partialRow.getBoolean(columnName); + default: + throw new NotImplementedException(); + } + } + + private Object callGetByIndex(PartialRow partialRow, int columnIndex, Type type) { + switch (type) { + case INT8: return partialRow.getByte(columnIndex); + case INT16: return partialRow.getShort(columnIndex); + case INT32: return partialRow.getInt(columnIndex); + case INT64: return partialRow.getLong(columnIndex); + case UNIXTIME_MICROS: return partialRow.getLong(columnIndex); + case STRING: return partialRow.getString(columnIndex); + case BINARY: return partialRow.getBinary(columnIndex); + case FLOAT: return partialRow.getFloat(columnIndex); + case DOUBLE: return partialRow.getDouble(columnIndex); + case BOOL: return partialRow.getBoolean(columnIndex); + default: + throw new NotImplementedException(); + } + } + + private void callAddByName(PartialRow partialRow, String columnName, Type type) { + switch (type) { + case INT8: partialRow.addByte(columnName, (byte) 42); break; + case INT16: partialRow.addShort(columnName, (short) 43); break; + case INT32: partialRow.addInt(columnName, 44); break; + case INT64: partialRow.addLong(columnName, 45); break; + case UNIXTIME_MICROS: partialRow.addLong(columnName, 1234567890); break; + case STRING: partialRow.addString(columnName, "fun with ütf\0"); break; + case BINARY: partialRow.addBinary(columnName, new byte[] { 0, 1, 2, 3, 4 }); break; + case FLOAT: partialRow.addFloat(columnName, 52.35F); break; + case DOUBLE: partialRow.addDouble(columnName, 53.35); break; + case BOOL: partialRow.addBoolean(columnName, true); break; + default: + throw new NotImplementedException(); + } + } + + private void callAddByIndex(PartialRow partialRow, int columnIndex, Type type) { + switch (type) { + case INT8: partialRow.addByte(columnIndex, (byte) 42); break; + case INT16: partialRow.addShort(columnIndex, (short) 43); break; + case INT32: partialRow.addInt(columnIndex, 44); break; + case INT64: partialRow.addLong(columnIndex, 45); break; + case UNIXTIME_MICROS: partialRow.addLong(columnIndex, 1234567890); break; + case STRING: partialRow.addString(columnIndex, "fun with ütf\0"); break; + case BINARY: partialRow.addBinary(columnIndex, new byte[] { 0, 1, 2, 3, 4 }); break; + case FLOAT: partialRow.addFloat(columnIndex, 52.35F); break; + case DOUBLE: partialRow.addDouble(columnIndex, 53.35); break; + case BOOL: partialRow.addBoolean(columnIndex, true); break; + default: + throw new NotImplementedException(); + } + } + }
