/** * A record is added to a table, or removed from a table. * * @param session the session * @param tableId the table id * @param row the row to add * @param add true if the row is added, false if it is removed */ void logAddOrRemoveRow(Session session, int tableId, Row row, boolean add) { if (trace.isDebugEnabled()) { trace.debug( "log " + (add ? "+" : "-") + " s: " + session.getId() + " table: " + tableId + " row: " + row); } session.addLogPos(logSectionId, logPos); logPos++; Data data = dataBuffer; data.reset(); int columns = row.getColumnCount(); data.writeVarInt(columns); data.checkCapacity(row.getByteCount(data)); if (session.isRedoLogBinaryEnabled()) { for (int i = 0; i < columns; i++) { data.writeValue(row.getValue(i)); } } else { for (int i = 0; i < columns; i++) { Value v = row.getValue(i); if (v.getType() == Value.BYTES) { data.writeValue(ValueNull.INSTANCE); } else { data.writeValue(v); } } } Data buffer = getBuffer(); buffer.writeByte((byte) (add ? ADD : REMOVE)); buffer.writeVarInt(session.getId()); buffer.writeVarInt(tableId); buffer.writeVarLong(row.getKey()); if (add) { buffer.writeVarInt(data.length()); buffer.checkCapacity(data.length()); buffer.write(data.getBytes(), 0, data.length()); } write(buffer); }
/** * Append a value. * * @param v the value */ public void writeValue(Value v) { int start = pos; if (v == ValueNull.INSTANCE) { data[pos++] = 0; return; } int type = v.getType(); switch (type) { case Value.BOOLEAN: writeByte((byte) (v.getBoolean().booleanValue() ? BOOLEAN_TRUE : BOOLEAN_FALSE)); break; case Value.BYTE: writeByte((byte) type); writeByte(v.getByte()); break; case Value.SHORT: writeByte((byte) type); writeShortInt(v.getShort()); break; case Value.INT: { int x = v.getInt(); if (x < 0) { writeByte((byte) INT_NEG); writeVarInt(-x); } else if (x < 16) { writeByte((byte) (INT_0_15 + x)); } else { writeByte((byte) type); writeVarInt(x); } break; } case Value.LONG: { long x = v.getLong(); if (x < 0) { writeByte((byte) LONG_NEG); writeVarLong(-x); } else if (x < 8) { writeByte((byte) (LONG_0_7 + x)); } else { writeByte((byte) type); writeVarLong(x); } break; } case Value.DECIMAL: { BigDecimal x = v.getBigDecimal(); if (BigDecimal.ZERO.equals(x)) { writeByte((byte) DECIMAL_0_1); } else if (BigDecimal.ONE.equals(x)) { writeByte((byte) (DECIMAL_0_1 + 1)); } else { int scale = x.scale(); BigInteger b = x.unscaledValue(); int bits = b.bitLength(); if (bits <= 63) { if (scale == 0) { writeByte((byte) DECIMAL_SMALL_0); writeVarLong(b.longValue()); } else { writeByte((byte) DECIMAL_SMALL); writeVarInt(scale); writeVarLong(b.longValue()); } } else { writeByte((byte) type); writeVarInt(scale); byte[] bytes = b.toByteArray(); writeVarInt(bytes.length); write(bytes, 0, bytes.length); } } break; } case Value.TIME: if (SysProperties.STORE_LOCAL_TIME) { writeByte((byte) LOCAL_TIME); ValueTime t = (ValueTime) v; long nanos = t.getNanos(); long millis = nanos / 1000000; nanos -= millis * 1000000; writeVarLong(millis); writeVarLong(nanos); } else { writeByte((byte) type); writeVarLong(DateTimeUtils.getTimeLocalWithoutDst(v.getTime())); } break; case Value.DATE: { if (SysProperties.STORE_LOCAL_TIME) { writeByte((byte) LOCAL_DATE); long x = ((ValueDate) v).getDateValue(); writeVarLong(x); } else { writeByte((byte) type); long x = DateTimeUtils.getTimeLocalWithoutDst(v.getDate()); writeVarLong(x / MILLIS_PER_MINUTE); } break; } case Value.TIMESTAMP: { if (SysProperties.STORE_LOCAL_TIME) { writeByte((byte) LOCAL_TIMESTAMP); ValueTimestamp ts = (ValueTimestamp) v; long dateValue = ts.getDateValue(); writeVarLong(dateValue); long nanos = ts.getNanos(); long millis = nanos / 1000000; nanos -= millis * 1000000; writeVarLong(millis); writeVarLong(nanos); } else { Timestamp ts = v.getTimestamp(); writeByte((byte) type); writeVarLong(DateTimeUtils.getTimeLocalWithoutDst(ts)); writeVarInt(ts.getNanos()); } break; } case Value.GEOMETRY: case Value.JAVA_OBJECT: { writeByte((byte) type); byte[] b = v.getBytesNoCopy(); int len = b.length; writeVarInt(len); write(b, 0, len); break; } case Value.BYTES: { byte[] b = v.getBytesNoCopy(); int len = b.length; if (len < 32) { writeByte((byte) (BYTES_0_31 + len)); write(b, 0, len); } else { writeByte((byte) type); writeVarInt(len); write(b, 0, len); } break; } case Value.UUID: { writeByte((byte) type); ValueUuid uuid = (ValueUuid) v; writeLong(uuid.getHigh()); writeLong(uuid.getLow()); break; } case Value.STRING: { String s = v.getString(); int len = s.length(); if (len < 32) { writeByte((byte) (STRING_0_31 + len)); writeStringWithoutLength(s, len); } else { writeByte((byte) type); writeString(s); } break; } case Value.STRING_IGNORECASE: case Value.STRING_FIXED: writeByte((byte) type); writeString(v.getString()); break; case Value.DOUBLE: { double x = v.getDouble(); if (x == 1.0d) { writeByte((byte) (DOUBLE_0_1 + 1)); } else { long d = Double.doubleToLongBits(x); if (d == ValueDouble.ZERO_BITS) { writeByte((byte) DOUBLE_0_1); } else { writeByte((byte) type); writeVarLong(Long.reverse(d)); } } break; } case Value.FLOAT: { float x = v.getFloat(); if (x == 1.0f) { writeByte((byte) (FLOAT_0_1 + 1)); } else { int f = Float.floatToIntBits(x); if (f == ValueFloat.ZERO_BITS) { writeByte((byte) FLOAT_0_1); } else { writeByte((byte) type); writeVarInt(Integer.reverse(f)); } } break; } case Value.BLOB: case Value.CLOB: { writeByte((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(t); writeVarInt(lob.getTableId()); writeVarInt(lob.getObjectId()); writeVarLong(lob.getPrecision()); writeByte((byte) (lob.isCompressed() ? 1 : 0)); if (t == -2) { writeString(lob.getFileName()); } } else { writeVarInt(small.length); write(small, 0, small.length); } } else { ValueLobDb lob = (ValueLobDb) v; byte[] small = lob.getSmall(); if (small == null) { writeVarInt(-3); writeVarInt(lob.getTableId()); writeVarLong(lob.getLobId()); writeVarLong(lob.getPrecision()); } else { writeVarInt(small.length); write(small, 0, small.length); } } break; } case Value.ARRAY: { writeByte((byte) type); Value[] list = ((ValueArray) v).getList(); writeVarInt(list.length); for (Value x : list) { writeValue(x); } break; } case Value.RESULT_SET: { writeByte((byte) type); try { ResultSet rs = ((ValueResultSet) v).getResultSet(); rs.beforeFirst(); ResultSetMetaData meta = rs.getMetaData(); int columnCount = meta.getColumnCount(); writeVarInt(columnCount); for (int i = 0; i < columnCount; i++) { writeString(meta.getColumnName(i + 1)); writeVarInt(meta.getColumnType(i + 1)); writeVarInt(meta.getPrecision(i + 1)); writeVarInt(meta.getScale(i + 1)); } while (rs.next()) { writeByte((byte) 1); for (int i = 0; i < columnCount; i++) { int t = DataType.getValueTypeFromResultSet(meta, i + 1); Value val = DataType.readValue(null, rs, i + 1, t); writeValue(val); } } writeByte((byte) 0); rs.beforeFirst(); } catch (SQLException e) { throw DbException.convert(e); } break; } default: DbException.throwInternalError("type=" + v.getType()); } if (SysProperties.CHECK2) { if (pos - start != getValueLen(v, handler)) { throw DbException.throwInternalError( "value size error: got " + (pos - start) + " expected " + getValueLen(v, handler)); } } }