@Override public Value createBlob(InputStream in, long maxLength) { init(); int type = Value.BLOB; if (maxLength < 0) { maxLength = Long.MAX_VALUE; } int max = (int) Math.min(maxLength, database.getMaxLengthInplaceLob()); try { if (max != 0 && max < Integer.MAX_VALUE) { BufferedInputStream b = new BufferedInputStream(in, max); b.mark(max); byte[] small = new byte[max]; int len = IOUtils.readFully(b, small, max); if (len < max) { if (len < small.length) { small = Arrays.copyOf(small, len); } return ValueLobDb.createSmallLob(type, small); } b.reset(); in = b; } if (maxLength != Long.MAX_VALUE) { in = new LimitInputStream(in, maxLength); } return createLob(in, type); } catch (IllegalStateException e) { throw DbException.get(ErrorCode.OBJECT_CLOSED, e); } catch (IOException e) { throw DbException.convertIOException(e, null); } }
@Override public Value convertPrecision(long precision, boolean force) { if (this.precision <= precision) { return this; } ValueLobDb lob; if (type == CLOB) { if (handler == null) { try { int p = MathUtils.convertLongToInt(precision); String s = IOUtils.readStringAndClose(getReader(), p); byte[] data = s.getBytes(Constants.UTF8); lob = ValueLobDb.createSmallLob(type, data, s.length()); } catch (IOException e) { throw DbException.convertIOException(e, null); } } else { lob = ValueLobDb.createTempClob(getReader(), precision, handler); } } else { if (handler == null) { try { int p = MathUtils.convertLongToInt(precision); byte[] data = IOUtils.readBytesAndClose(getInputStream(), p); lob = ValueLobDb.createSmallLob(type, data, data.length); } catch (IOException e) { throw DbException.convertIOException(e, null); } } else { lob = ValueLobDb.createTempBlob(getInputStream(), precision, handler); } } return lob; }
private void testCastTrim() { Value v; String spaces = new String(new char[100]).replace((char) 0, ' '); v = ValueArray.get(new Value[] {ValueString.get("hello"), ValueString.get("world")}); assertEquals(10, v.getPrecision()); assertEquals(5, v.convertPrecision(5, true).getPrecision()); v = ValueArray.get(new Value[] {ValueString.get(""), ValueString.get("")}); assertEquals(0, v.getPrecision()); assertEquals("('')", v.convertPrecision(1, true).toString()); v = ValueBytes.get(spaces.getBytes()); assertEquals(100, v.getPrecision()); assertEquals(10, v.convertPrecision(10, false).getPrecision()); assertEquals(10, v.convertPrecision(10, false).getBytes().length); assertEquals(32, v.convertPrecision(10, false).getBytes()[9]); assertEquals(10, v.convertPrecision(10, true).getPrecision()); final Value vd = ValueDecimal.get(new BigDecimal("1234567890.123456789")); assertEquals(19, vd.getPrecision()); assertEquals("1234567890.1234567", vd.convertPrecision(10, true).getString()); new AssertThrows(ErrorCode.NUMERIC_VALUE_OUT_OF_RANGE_1) { @Override public void test() { vd.convertPrecision(10, false); } }; v = ValueLobDb.createSmallLob(Value.CLOB, spaces.getBytes(), 100); assertEquals(100, v.getPrecision()); assertEquals(10, v.convertPrecision(10, false).getPrecision()); assertEquals(10, v.convertPrecision(10, false).getString().length()); assertEquals(" ", v.convertPrecision(10, false).getString()); assertEquals(10, v.convertPrecision(10, true).getPrecision()); v = ValueLobDb.createSmallLob(Value.BLOB, spaces.getBytes(), 100); assertEquals(100, v.getPrecision()); assertEquals(10, v.convertPrecision(10, false).getPrecision()); assertEquals(10, v.convertPrecision(10, false).getBytes().length); assertEquals(32, v.convertPrecision(10, false).getBytes()[9]); assertEquals(10, v.convertPrecision(10, true).getPrecision()); ResultSet rs = new SimpleResultSet(); v = ValueResultSet.get(rs); assertEquals(Integer.MAX_VALUE, v.getPrecision()); assertEquals(Integer.MAX_VALUE, v.convertPrecision(10, false).getPrecision()); assertTrue(rs == v.convertPrecision(10, false).getObject()); assertFalse(rs == v.convertPrecision(10, true).getObject()); assertEquals(Integer.MAX_VALUE, v.convertPrecision(10, true).getPrecision()); v = ValueString.get(spaces); assertEquals(100, v.getPrecision()); assertEquals(10, v.convertPrecision(10, false).getPrecision()); assertEquals(" ", v.convertPrecision(10, false).getString()); assertEquals(" ", v.convertPrecision(10, true).getString()); }
/** * Create a temporary BLOB value from a stream. * * @param in the input stream * @param length the number of characters to read, or -1 for no limit * @param handler the data handler * @return the lob value */ public static ValueLobDb createTempBlob(InputStream in, long length, DataHandler handler) { try { long remaining = Long.MAX_VALUE; boolean compress = handler.getLobCompressionAlgorithm(Value.BLOB) != null; if (length >= 0 && length < remaining) { remaining = length; } int len = getBufferSize(handler, compress, remaining); byte[] buff; if (len >= Integer.MAX_VALUE) { buff = IOUtils.readBytesAndClose(in, -1); len = buff.length; } else { buff = DataUtils.newBytes(len); len = IOUtils.readFully(in, buff, len); } if (len <= handler.getMaxLengthInplaceLob()) { byte[] small = DataUtils.newBytes(len); System.arraycopy(buff, 0, small, 0, len); return ValueLobDb.createSmallLob(Value.BLOB, small, small.length); } ValueLobDb lob = new ValueLobDb(handler, buff, len, in, remaining); return lob; } catch (IOException e) { throw DbException.convertIOException(e, null); } }
/** * Create a temporary CLOB value from a stream. * * @param in the reader * @param length the number of characters to read, or -1 for no limit * @param handler the data handler * @return the lob value */ public static ValueLobDb createTempClob(Reader in, long length, DataHandler handler) { BufferedReader reader; if (in instanceof BufferedReader) { reader = (BufferedReader) in; } else { reader = new BufferedReader(in, Constants.IO_BUFFER_SIZE); } try { boolean compress = handler.getLobCompressionAlgorithm(Value.CLOB) != null; long remaining = Long.MAX_VALUE; if (length >= 0 && length < remaining) { remaining = length; } int len = getBufferSize(handler, compress, remaining); char[] buff; if (len >= Integer.MAX_VALUE) { String data = IOUtils.readStringAndClose(reader, -1); buff = data.toCharArray(); len = buff.length; } else { buff = new char[len]; reader.mark(len); len = IOUtils.readFully(reader, buff, len); } if (len <= handler.getMaxLengthInplaceLob()) { byte[] small = new String(buff, 0, len).getBytes(Constants.UTF8); return ValueLobDb.createSmallLob(Value.CLOB, small, len); } reader.reset(); ValueLobDb lob = new ValueLobDb(handler, reader, remaining); return lob; } catch (IOException e) { throw DbException.convertIOException(e, null); } }
/** * Convert a lob to another data type. The data is fully read in memory except when converting to * BLOB or CLOB. * * @param t the new type * @return the converted value */ @Override public Value convertTo(int t) { if (t == type) { return this; } else if (t == Value.CLOB) { if (handler != null) { Value copy = handler.getLobStorage().createClob(getReader(), -1); return copy; } else if (small != null) { return ValueLobDb.createSmallLob(t, small); } } else if (t == Value.BLOB) { if (handler != null) { Value copy = handler.getLobStorage().createBlob(getInputStream(), -1); return copy; } else if (small != null) { return ValueLobDb.createSmallLob(t, small); } } return super.convertTo(t); }
@Override public Value createClob(Reader reader, long maxLength) { init(); int type = Value.CLOB; if (maxLength < 0) { maxLength = Long.MAX_VALUE; } int max = (int) Math.min(maxLength, database.getMaxLengthInplaceLob()); try { if (max != 0 && max < Integer.MAX_VALUE) { BufferedReader b = new BufferedReader(reader, max); b.mark(max); char[] small = new char[max]; int len = IOUtils.readFully(b, small, max); if (len < max) { if (len < small.length) { small = Arrays.copyOf(small, len); } byte[] utf8 = new String(small, 0, len).getBytes(Constants.UTF8); return ValueLobDb.createSmallLob(type, utf8); } b.reset(); reader = b; } CountingReaderInputStream in = new CountingReaderInputStream(reader, maxLength); ValueLobDb lob = createLob(in, type); // the length is not correct lob = ValueLobDb.create(type, database, lob.getTableId(), lob.getLobId(), null, in.getLength()); return lob; } catch (IllegalStateException e) { throw DbException.get(ErrorCode.OBJECT_CLOSED, e); } catch (IOException e) { throw DbException.convertIOException(e, null); } }
/** * Read a value. * * @return the value */ public Value readValue() { int type = data[pos++] & 255; switch (type) { case Value.NULL: return ValueNull.INSTANCE; case BOOLEAN_TRUE: return ValueBoolean.get(true); case BOOLEAN_FALSE: return ValueBoolean.get(false); case INT_NEG: return ValueInt.get(-readVarInt()); case Value.INT: return ValueInt.get(readVarInt()); case LONG_NEG: return ValueLong.get(-readVarLong()); case Value.LONG: return ValueLong.get(readVarLong()); case Value.BYTE: return ValueByte.get(readByte()); case Value.SHORT: return ValueShort.get(readShortInt()); case DECIMAL_0_1: return (ValueDecimal) ValueDecimal.ZERO; case DECIMAL_0_1 + 1: return (ValueDecimal) ValueDecimal.ONE; case DECIMAL_SMALL_0: return ValueDecimal.get(BigDecimal.valueOf(readVarLong())); case DECIMAL_SMALL: { int scale = readVarInt(); return ValueDecimal.get(BigDecimal.valueOf(readVarLong(), scale)); } case Value.DECIMAL: { int scale = readVarInt(); int len = readVarInt(); byte[] buff = DataUtils.newBytes(len); read(buff, 0, len); BigInteger b = new BigInteger(buff); return ValueDecimal.get(new BigDecimal(b, scale)); } case LOCAL_DATE: { return ValueDate.fromDateValue(readVarLong()); } case Value.DATE: { long x = readVarLong() * MILLIS_PER_MINUTE; return ValueDate.get(new Date(DateTimeUtils.getTimeUTCWithoutDst(x))); } case LOCAL_TIME: { long nanos = readVarLong() * 1000000 + readVarLong(); return ValueTime.fromNanos(nanos); } case Value.TIME: // need to normalize the year, month and day return ValueTime.get(new Time(DateTimeUtils.getTimeUTCWithoutDst(readVarLong()))); case LOCAL_TIMESTAMP: { long dateValue = readVarLong(); long nanos = readVarLong() * 1000000 + readVarLong(); return ValueTimestamp.fromDateValueAndNanos(dateValue, nanos); } case Value.TIMESTAMP: { Timestamp ts = new Timestamp(DateTimeUtils.getTimeUTCWithoutDst(readVarLong())); ts.setNanos(readVarInt()); return ValueTimestamp.get(ts); } case Value.BYTES: { int len = readVarInt(); byte[] b = DataUtils.newBytes(len); read(b, 0, len); return ValueBytes.getNoCopy(b); } case Value.GEOMETRY: { int len = readVarInt(); byte[] b = DataUtils.newBytes(len); read(b, 0, len); return ValueGeometry.get(b); } case Value.JAVA_OBJECT: { int len = readVarInt(); byte[] b = DataUtils.newBytes(len); read(b, 0, len); return ValueJavaObject.getNoCopy(null, b, handler); } case Value.UUID: return ValueUuid.get(readLong(), readLong()); case Value.STRING: return ValueString.get(readString()); case Value.STRING_IGNORECASE: return ValueStringIgnoreCase.get(readString()); case Value.STRING_FIXED: return ValueStringFixed.get(readString()); case FLOAT_0_1: return ValueFloat.get(0); case FLOAT_0_1 + 1: return ValueFloat.get(1); case DOUBLE_0_1: return ValueDouble.get(0); case DOUBLE_0_1 + 1: return ValueDouble.get(1); case Value.DOUBLE: return ValueDouble.get(Double.longBitsToDouble(Long.reverse(readVarLong()))); case Value.FLOAT: return ValueFloat.get(Float.intBitsToFloat(Integer.reverse(readVarInt()))); case Value.BLOB: case Value.CLOB: { int smallLen = readVarInt(); if (smallLen >= 0) { byte[] small = DataUtils.newBytes(smallLen); read(small, 0, smallLen); return ValueLobDb.createSmallLob(type, small); } else if (smallLen == -3) { int tableId = readVarInt(); long lobId = readVarLong(); long precision = readVarLong(); ValueLobDb lob = ValueLobDb.create(type, handler, tableId, lobId, null, precision); return lob; } else { int tableId = readVarInt(); int objectId = readVarInt(); long precision = 0; boolean compression = false; // -1: regular; -2: regular, but not linked (in this case: // including file name) if (smallLen == -1 || smallLen == -2) { precision = readVarLong(); compression = readByte() == 1; } if (smallLen == -2) { String filename = readString(); return ValueLob.openUnlinked( type, handler, tableId, objectId, precision, compression, filename); } return ValueLob.openLinked(type, handler, tableId, objectId, precision, compression); } } case Value.ARRAY: { int len = readVarInt(); Value[] list = new Value[len]; for (int i = 0; i < len; i++) { list[i] = readValue(); } return ValueArray.get(list); } case Value.RESULT_SET: { SimpleResultSet rs = new SimpleResultSet(); rs.setAutoClose(false); int columns = readVarInt(); for (int i = 0; i < columns; i++) { rs.addColumn(readString(), readVarInt(), readVarInt(), readVarInt()); } while (true) { if (readByte() == 0) { break; } Object[] o = new Object[columns]; for (int i = 0; i < columns; i++) { o[i] = readValue().getObject(); } rs.addRow(o); } return ValueResultSet.get(rs); } default: if (type >= INT_0_15 && type < INT_0_15 + 16) { return ValueInt.get(type - INT_0_15); } else if (type >= LONG_0_7 && type < LONG_0_7 + 8) { return ValueLong.get(type - LONG_0_7); } else if (type >= BYTES_0_31 && type < BYTES_0_31 + 32) { int len = type - BYTES_0_31; byte[] b = DataUtils.newBytes(len); read(b, 0, len); return ValueBytes.getNoCopy(b); } else if (type >= STRING_0_31 && type < STRING_0_31 + 32) { return ValueString.get(readString(type - STRING_0_31)); } throw DbException.get(ErrorCode.FILE_CORRUPTED_1, "type: " + type); } }