private ByteBuffer writeValue(ByteBuffer buff, Value v) {
   int start = buff.position();
   if (v == ValueNull.INSTANCE) {
     buff.put((byte) 0);
     return buff;
   }
   int type = v.getType();
   switch (type) {
     case Value.BOOLEAN:
       buff.put((byte) (v.getBoolean().booleanValue() ? BOOLEAN_TRUE : BOOLEAN_FALSE));
       break;
     case Value.BYTE:
       buff.put((byte) type);
       buff.put(v.getByte());
       break;
     case Value.SHORT:
       buff.put((byte) type);
       buff.putShort(v.getShort());
       break;
     case Value.INT:
       {
         int x = v.getInt();
         if (x < 0) {
           buff.put((byte) INT_NEG);
           writeVarInt(buff, -x);
         } else if (x < 16) {
           buff.put((byte) (INT_0_15 + x));
         } else {
           buff.put((byte) type);
           writeVarInt(buff, x);
         }
         break;
       }
     case Value.LONG:
       {
         long x = v.getLong();
         if (x < 0) {
           buff.put((byte) LONG_NEG);
           writeVarLong(buff, -x);
         } else if (x < 8) {
           buff.put((byte) (LONG_0_7 + x));
         } else {
           buff.put((byte) type);
           writeVarLong(buff, x);
         }
         break;
       }
     case Value.DECIMAL:
       {
         BigDecimal x = v.getBigDecimal();
         if (BigDecimal.ZERO.equals(x)) {
           buff.put((byte) DECIMAL_0_1);
         } else if (BigDecimal.ONE.equals(x)) {
           buff.put((byte) (DECIMAL_0_1 + 1));
         } else {
           int scale = x.scale();
           BigInteger b = x.unscaledValue();
           int bits = b.bitLength();
           if (bits <= 63) {
             if (scale == 0) {
               buff.put((byte) DECIMAL_SMALL_0);
               writeVarLong(buff, b.longValue());
             } else {
               buff.put((byte) DECIMAL_SMALL);
               writeVarInt(buff, scale);
               writeVarLong(buff, b.longValue());
             }
           } else {
             buff.put((byte) type);
             writeVarInt(buff, scale);
             byte[] bytes = b.toByteArray();
             writeVarInt(buff, bytes.length);
             buff = DataUtils.ensureCapacity(buff, bytes.length);
             buff.put(bytes, 0, bytes.length);
           }
         }
         break;
       }
     case Value.TIME:
       if (SysProperties.STORE_LOCAL_TIME) {
         buff.put((byte) LOCAL_TIME);
         ValueTime t = (ValueTime) v;
         long nanos = t.getNanos();
         long millis = nanos / 1000000;
         nanos -= millis * 1000000;
         writeVarLong(buff, millis);
         writeVarLong(buff, nanos);
       } else {
         buff.put((byte) type);
         writeVarLong(buff, DateTimeUtils.getTimeLocalWithoutDst(v.getTime()));
       }
       break;
     case Value.DATE:
       {
         if (SysProperties.STORE_LOCAL_TIME) {
           buff.put((byte) LOCAL_DATE);
           long x = ((ValueDate) v).getDateValue();
           writeVarLong(buff, x);
         } else {
           buff.put((byte) type);
           long x = DateTimeUtils.getTimeLocalWithoutDst(v.getDate());
           writeVarLong(buff, x / MILLIS_PER_MINUTE);
         }
         break;
       }
     case Value.TIMESTAMP:
       {
         if (SysProperties.STORE_LOCAL_TIME) {
           buff.put((byte) LOCAL_TIMESTAMP);
           ValueTimestamp ts = (ValueTimestamp) v;
           long dateValue = ts.getDateValue();
           writeVarLong(buff, dateValue);
           long nanos = ts.getNanos();
           long millis = nanos / 1000000;
           nanos -= millis * 1000000;
           writeVarLong(buff, millis);
           writeVarLong(buff, nanos);
         } else {
           Timestamp ts = v.getTimestamp();
           buff.put((byte) type);
           writeVarLong(buff, DateTimeUtils.getTimeLocalWithoutDst(ts));
           writeVarInt(buff, ts.getNanos());
         }
         break;
       }
     case Value.JAVA_OBJECT:
       {
         buff.put((byte) type);
         byte[] b = v.getBytesNoCopy();
         writeVarInt(buff, b.length);
         buff = DataUtils.ensureCapacity(buff, b.length);
         buff.put(b, 0, b.length);
         break;
       }
     case Value.BYTES:
       {
         byte[] b = v.getBytesNoCopy();
         int len = b.length;
         if (len < 32) {
           buff.put((byte) (BYTES_0_31 + len));
           buff.put(b, 0, b.length);
         } else {
           buff.put((byte) type);
           writeVarInt(buff, b.length);
           buff = DataUtils.ensureCapacity(buff, b.length);
           buff.put(b, 0, b.length);
         }
         break;
       }
     case Value.UUID:
       {
         buff.put((byte) type);
         ValueUuid uuid = (ValueUuid) v;
         buff.putLong(uuid.getHigh());
         buff.putLong(uuid.getLow());
         break;
       }
     case Value.STRING:
       {
         String s = v.getString();
         int len = s.length();
         if (len < 32) {
           buff.put((byte) (STRING_0_31 + len));
           buff = writeStringWithoutLength(buff, s, len);
         } else {
           buff.put((byte) type);
           buff = writeString(buff, s);
         }
         break;
       }
     case Value.STRING_IGNORECASE:
     case Value.STRING_FIXED:
       buff.put((byte) type);
       buff = writeString(buff, v.getString());
       break;
     case Value.DOUBLE:
       {
         double x = v.getDouble();
         if (x == 1.0d) {
           buff.put((byte) (DOUBLE_0_1 + 1));
         } else {
           long d = Double.doubleToLongBits(x);
           if (d == ValueDouble.ZERO_BITS) {
             buff.put((byte) DOUBLE_0_1);
           } else {
             buff.put((byte) type);
             writeVarLong(buff, Long.reverse(d));
           }
         }
         break;
       }
     case Value.FLOAT:
       {
         float x = v.getFloat();
         if (x == 1.0f) {
           buff.put((byte) (FLOAT_0_1 + 1));
         } else {
           int f = Float.floatToIntBits(x);
           if (f == ValueFloat.ZERO_BITS) {
             buff.put((byte) FLOAT_0_1);
           } else {
             buff.put((byte) type);
             writeVarInt(buff, Integer.reverse(f));
           }
         }
         break;
       }
     case Value.BLOB:
     case Value.CLOB:
       {
         buff.put((byte) type);
         if (v instanceof ValueLob) {
           ValueLob lob = (ValueLob) v;
           lob.convertToFileIfRequired(handler);
           byte[] small = lob.getSmall();
           if (small == null) {
             int t = -1;
             if (!lob.isLinked()) {
               t = -2;
             }
             writeVarInt(buff, t);
             writeVarInt(buff, lob.getTableId());
             writeVarInt(buff, lob.getObjectId());
             writeVarLong(buff, lob.getPrecision());
             buff.put((byte) (lob.useCompression() ? 1 : 0));
             if (t == -2) {
               buff = writeString(buff, lob.getFileName());
             }
           } else {
             writeVarInt(buff, small.length);
             buff = DataUtils.ensureCapacity(buff, small.length);
             buff.put(small, 0, small.length);
           }
         } else {
           ValueLobDb lob = (ValueLobDb) v;
           byte[] small = lob.getSmall();
           if (small == null) {
             writeVarInt(buff, -3);
             writeVarInt(buff, lob.getTableId());
             writeVarLong(buff, lob.getLobId());
             writeVarLong(buff, lob.getPrecision());
           } else {
             writeVarInt(buff, small.length);
             buff = DataUtils.ensureCapacity(buff, small.length);
             buff.put(small, 0, small.length);
           }
         }
         break;
       }
     case Value.ARRAY:
       {
         buff.put((byte) type);
         Value[] list = ((ValueArray) v).getList();
         writeVarInt(buff, list.length);
         for (Value x : list) {
           buff = DataUtils.ensureCapacity(buff, 0);
           buff = writeValue(buff, x);
         }
         break;
       }
     case Value.RESULT_SET:
       {
         buff.put((byte) type);
         try {
           ResultSet rs = ((ValueResultSet) v).getResultSet();
           rs.beforeFirst();
           ResultSetMetaData meta = rs.getMetaData();
           int columnCount = meta.getColumnCount();
           writeVarInt(buff, columnCount);
           for (int i = 0; i < columnCount; i++) {
             buff = DataUtils.ensureCapacity(buff, 0);
             buff = writeString(buff, meta.getColumnName(i + 1));
             writeVarInt(buff, meta.getColumnType(i + 1));
             writeVarInt(buff, meta.getPrecision(i + 1));
             writeVarInt(buff, meta.getScale(i + 1));
           }
           while (rs.next()) {
             buff.put((byte) 1);
             for (int i = 0; i < columnCount; i++) {
               int t = org.h2.value.DataType.convertSQLTypeToValueType(meta.getColumnType(i + 1));
               Value val = org.h2.value.DataType.readValue(null, rs, i + 1, t);
               buff = writeValue(buff, val);
             }
           }
           buff.put((byte) 0);
           rs.beforeFirst();
         } catch (SQLException e) {
           throw DbException.convert(e);
         }
         break;
       }
     default:
       DbException.throwInternalError("type=" + v.getType());
   }
   if (SysProperties.CHECK2) {
     if (buff.position() - start != Data.getValueLen(v, handler)) {
       throw DbException.throwInternalError(
           "value size error: got "
               + (buff.position() - start)
               + " expected "
               + Data.getValueLen(v, handler));
     }
   }
   return buff;
 }