提交 06fb1080 authored 作者: Thomas Mueller's avatar Thomas Mueller

Remove unused code.

上级 a1f890af
......@@ -18,7 +18,8 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>A workaround for a Windows socket problem has been implemented. Thanks a lot to Sergi Vladykin.
<ul><li>H2 Console: asynchronous login (using a DatabaseEventListener) is no longer supported.
</li><li>A workaround for a Windows socket problem has been implemented. Thanks a lot to Sergi Vladykin.
</li><li>The Recover tool did not convert correctly convert CLOB data with non-ASCII characters.
</li><li>Tools: the method run(String... args) has been renamed to runTool(String... args)
so it can't be confused with run().
......
......@@ -31,7 +31,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
<h2>Priority 1</h2>
<ul>
<li>Bugfixes
</li><li>Issue 157: Support large inserts and updates (use the transaction log for rollback).
</li><li>Issues 161, 157: Support large inserts and updates (use the transaction log for rollback).
Problems: Session.commit (rows), cache, undoLog.
</li><li>More tests with MULTI_THREADED=1
</li><li>Optimization: result set caching (like MySQL); option to disable
......@@ -478,6 +478,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>TCP Server: use a nonce (number used once) to protect unencrypted channels against replay attacks.
</li><li>Simplify running scripts and recovery: CREATE FORCE USER (overwrites an existing user).
</li><li>Support CREATE DATABASE LINK (a custom JDBC driver is already supported).
</li><li>Isse 163: Allow to create foreign keys on metadata types.
</li></ul>
<h2>Not Planned</h2>
......
......@@ -152,15 +152,6 @@ public abstract class Query extends Prepared {
*/
public abstract void setDistinct(boolean b);
/**
* Get the alias (or column name) of the first column.
* This is used to convert IN(SELECT ...) queries to inner joins.
*
* @param s the session
* @return the alias or column name
*/
public abstract String getFirstColumnAlias(Session s);
/**
* Check if this expression and all sub-expressions can fulfill a criteria.
* If any part returns false, the result is false.
......
......@@ -191,10 +191,6 @@ public abstract class ScriptBase extends Prepared implements DataHandler {
return null;
}
public int getChecksum(byte[] data, int start, int end) {
return session.getDatabase().getChecksum(data, start, end);
}
public void checkPowerOff() throws SQLException {
session.getDatabase().checkPowerOff();
}
......
......@@ -15,9 +15,7 @@ import org.h2.api.Trigger;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.engine.Mode;
import org.h2.engine.Session;
import org.h2.expression.Alias;
import org.h2.expression.Comparison;
import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression;
......@@ -1101,21 +1099,4 @@ public class Select extends Query {
return isEverything(ExpressionVisitor.READONLY);
}
public String getFirstColumnAlias(Session s) {
if (SysProperties.CHECK) {
if (visibleColumnCount > 1) {
Message.throwInternalError("" + visibleColumnCount);
}
}
Expression expr = expressions.get(0);
if (expr instanceof Alias) {
return expr.getAlias();
}
Mode mode = s.getDatabase().getMode();
String name = s.getNextSystemIdentifier(getSQL());
expr = new Alias(expr, name, mode.aliasColumnName);
expressions.set(0, expr);
return expr.getAlias();
}
}
......@@ -349,10 +349,6 @@ public class SelectUnion extends Query {
right.updateAggregate(s);
}
public String getFirstColumnAlias(Session s) {
return null;
}
public void fireBeforeSelectTriggers() throws SQLException {
left.fireBeforeSelectTriggers();
right.fireBeforeSelectTriggers();
......
......@@ -1264,14 +1264,6 @@ public class Database implements DataHandler {
return cacheType;
}
public int getChecksum(byte[] data, int start, int end) {
int x = 0;
while (start < end) {
x += data[start++];
}
return x;
}
public String getCluster() {
return cluster;
}
......
......@@ -565,10 +565,6 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
// nothing to do
}
public int getChecksum(byte[] data, int start, int end) {
return 0;
}
public String getDatabasePath() {
return "";
}
......
......@@ -137,7 +137,7 @@ public class UndoLogRecord {
}
/**
* Save the row in the file using the data page as a buffer.
* Save the row in the file using a buffer.
*
* @param buff the buffer
* @param file the file
......@@ -164,7 +164,7 @@ public class UndoLogRecord {
}
/**
* Load an undo log record row using the data page as a buffer.
* Load an undo log record row using a buffer.
*
* @param buff the buffer
* @param file the source file
......
......@@ -54,10 +54,9 @@ public class Row implements SearchRow {
}
/**
* Get the number of bytes required for the data if the given data page
* would be used.
* Get the number of bytes required for the data.
*
* @param dummy the template data page
* @param dummy the template buffer
* @return the number of bytes
*/
public int getByteCount(Data dummy) throws SQLException {
......
......@@ -61,7 +61,7 @@ public class ConnectionInfo implements Comparable<ConnectionInfo> {
}
public int compareTo(ConnectionInfo o) {
return MathUtils.compareInt(lastAccess, o.lastAccess);
return -MathUtils.compareInt(lastAccess, o.lastAccess);
}
}
......@@ -27,7 +27,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import org.h2.api.DatabaseEventListener;
import org.h2.bnf.Bnf;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
......@@ -58,14 +57,12 @@ import org.h2.util.Tool;
* For each connection to a session, an object of this class is created.
* This class is used by the H2 Console.
*/
public class WebApp implements DatabaseEventListener {
public class WebApp {
protected WebServer server;
protected WebSession session;
protected Properties attributes;
protected String mimeType;
protected long listenerLastEvent;
protected int listenerLastState;
protected boolean cache;
protected boolean stop;
protected String headerLanguage;
......@@ -792,7 +789,7 @@ public class WebApp implements DatabaseEventListener {
prof.startCollecting();
Connection conn;
try {
conn = server.getConnection(driver, url, user, password, this);
conn = server.getConnection(driver, url, user, password);
} finally {
prof.stopCollecting();
profOpen = prof.getTop(3);
......@@ -854,7 +851,7 @@ public class WebApp implements DatabaseEventListener {
}
boolean isH2 = url.startsWith("jdbc:h2:");
try {
Connection conn = server.getConnection(driver, url, user, password, this);
Connection conn = server.getConnection(driver, url, user, password);
session.setConnection(conn);
session.put("url", url);
session.put("user", user);
......@@ -1715,54 +1712,6 @@ public class WebApp implements DatabaseEventListener {
return session;
}
public void closingDatabase() {
trace("Closing database");
}
public void diskSpaceIsLow(long stillAvailable) {
trace("No more disk space is available");
}
public void exceptionThrown(SQLException e, String sql) {
trace("Exception: " + e.toString() + " SQL: " + sql);
}
public void init(String url) {
trace("Init: " + url);
}
public void opened() {
trace("Database was opened");
}
public void setProgress(int state, String name, int x, int max) {
if (state == listenerLastState) {
long time = System.currentTimeMillis();
if (listenerLastEvent + 500 < time) {
return;
}
listenerLastEvent = time;
} else {
listenerLastState = state;
}
switch (state) {
case DatabaseEventListener.STATE_BACKUP_FILE:
trace("Backing up " + name + " " + (100L * x / max) + "%");
break;
case DatabaseEventListener.STATE_CREATE_INDEX:
trace("Creating index " + name + " " + (100L * x / max) + "%");
break;
case DatabaseEventListener.STATE_RECOVER:
trace("Recovering " + name + " " + (100L * x / max) + "%");
break;
case DatabaseEventListener.STATE_SCAN_FILE:
trace("Scanning file " + name + " " + (100L * x / max) + "%");
break;
default:
trace("Unknown state: " + state);
}
}
private void trace(String s) {
server.trace(s);
}
......
......@@ -26,7 +26,6 @@ import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import java.util.Map.Entry;
import org.h2.api.DatabaseEventListener;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.message.TraceSystem;
......@@ -570,10 +569,9 @@ public class WebServer implements Service {
* @param databaseUrl the database URL
* @param user the user name
* @param password the password
* @param listener the database event listener object
* @return the database connection
*/
Connection getConnection(String driver, String databaseUrl, String user, String password, DatabaseEventListener listener) throws SQLException {
Connection getConnection(String driver, String databaseUrl, String user, String password) throws SQLException {
driver = driver.trim();
databaseUrl = databaseUrl.trim();
org.h2.Driver.load();
......@@ -586,7 +584,6 @@ public class WebServer implements Service {
if (ifExists) {
databaseUrl += ";IFEXISTS=TRUE";
}
p.put("DATABASE_EVENT_LISTENER_OBJECT", listener);
// PostgreSQL would throw a NullPointerException
// if it is loaded before the H2 driver
// because it can't deal with non-String objects in the connection Properties
......
......@@ -11,19 +11,11 @@ import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Properties;
import java.util.StringTokenizer;
import org.h2.api.DatabaseEventListener;
import org.h2.engine.Constants;
import org.h2.message.TraceSystem;
import org.h2.util.IOUtils;
import org.h2.util.MemoryUtils;
......@@ -285,135 +277,6 @@ class WebThread extends WebApp implements Runnable {
return super.adminShutdown();
}
protected boolean loginAsync(final String driver, final String url, final String user, final String password) {
if (socket == null
|| !url.startsWith("jdbc:h2:")
|| url.startsWith("jdbc:h2:tcp:")
|| url.startsWith("jdbc:h2:ssl:")
|| url.startsWith("jdbc:h2:mem:")) {
// async login only possible for H2 embedded
return false;
}
/**
* This class is used for the asynchronous login.
*/
class LoginTask implements Runnable, DatabaseEventListener {
private final PrintWriter writer;
private final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
LoginTask() throws IOException {
String message = "HTTP/1.1 200 OK\n";
message += "Content-Type: " + mimeType + "\n\n";
output.write(message.getBytes());
writer = new PrintWriter(output);
writer.println("<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"stylesheet.css\" /></head>");
writer.println("<body><h2>Opening Database</h2>URL: " + PageParser.escapeHtml(url) + "<br />");
writer.println("User: " + PageParser.escapeHtml(user) + "<br />");
writer.println("Version: " + Constants.getFullVersion() + "<br /><br />");
writer.flush();
log("Start...");
}
public void closingDatabase() {
log("Closing database");
}
public void diskSpaceIsLow(long stillAvailable) {
log("No more disk space is available");
}
public void exceptionThrown(SQLException e, String sql) {
log("Exception: " + PageParser.escapeHtml(e.toString()) + " SQL: " + PageParser.escapeHtml(sql));
server.traceError(e);
}
public void init(String databaseUrl) {
log("Init: " + PageParser.escapeHtml(databaseUrl));
}
public void opened() {
log("Database was opened");
}
public void setProgress(int state, String name, int x, int max) {
if (state == listenerLastState) {
long time = System.currentTimeMillis();
if (time < listenerLastEvent + 1000) {
return;
}
listenerLastEvent = time;
} else {
listenerLastState = state;
}
name = PageParser.escapeHtml(name);
switch (state) {
case DatabaseEventListener.STATE_BACKUP_FILE:
log("Backing up " + name + " " + (100L * x / max) + "%");
break;
case DatabaseEventListener.STATE_CREATE_INDEX:
log("Creating index " + name + " " + (100L * x / max) + "%");
break;
case DatabaseEventListener.STATE_RECOVER:
log("Recovering " + name + " " + (100L * x / max) + "%");
break;
case DatabaseEventListener.STATE_SCAN_FILE:
log("Scanning file " + name + " " + (100L * x / max) + "%");
break;
default:
log("Unknown state: " + state);
}
}
private synchronized void log(String message) {
if (output != null) {
message = dateFormat.format(new Date()) + ": " + message;
writer.println(message + "<br />");
writer.flush();
}
server.trace(message);
}
public void run() {
String sessionId = (String) session.get("sessionId");
boolean isH2 = url.startsWith("jdbc:h2:");
try {
Connection conn = server.getConnection(driver, url, user, password, this);
session.setConnection(conn);
session.put("url", url);
session.put("user", user);
session.remove("error");
settingSave();
log("OK<script type=\"text/javascript\">top.location=\"frame.jsp?jsessionid=" + sessionId
+ "\"</script></body></htm>");
// return "frame.jsp";
} catch (Exception e) {
session.put("error", getLoginError(e, isH2));
log("Error<script type=\"text/javascript\">top.location=\"index.jsp?jsessionid=" + sessionId
+ "\"</script></body></html>");
// return "index.jsp";
}
synchronized (this) {
IOUtils.closeSilently(output);
try {
socket.close();
} catch (IOException e) {
// ignore
}
output = null;
}
}
}
try {
LoginTask login = new LoginTask();
Thread t = new Thread(login);
t.start();
} catch (IOException e) {
// ignore
}
return true;
}
private boolean allow() {
if (server.getAllowOthers()) {
return true;
......
......@@ -44,7 +44,7 @@ import org.h2.value.ValueTimestamp;
import org.h2.value.ValueUuid;
/**
* A data page is a byte buffer that contains persistent data of a page.
* This class represents a byte buffer that contains persistent data of a page.
*/
public class Data {
......@@ -237,31 +237,31 @@ public class Data {
}
/**
* Create a new data page for the given handler. The
* Create a new buffer for the given handler. The
* handler will decide what type of buffer is created.
*
* @param handler the data handler
* @param capacity the initial capacity of the buffer
* @return the data page
* @return the buffer
*/
public static Data create(DataHandler handler, int capacity) {
return new Data(handler, new byte[capacity]);
}
/**
* Create a new data page using the given data for the given handler. The
* Create a new buffer using the given data for the given handler. The
* handler will decide what type of buffer is created.
*
* @param handler the data handler
* @param buff the data
* @return the data page
* @return the buffer
*/
public static Data create(DataHandler handler, byte[] buff) {
return new Data(handler, buff);
}
/**
* Get the current write position of this data page, which is the current
* Get the current write position of this buffer, which is the current
* length.
*
* @return the length
......@@ -287,7 +287,7 @@ public class Data {
}
/**
* Append a number of bytes to this data page.
* Append a number of bytes to this buffer.
*
* @param buff the data
* @param off the offset in the data
......
......@@ -35,16 +35,6 @@ public interface DataHandler {
*/
FileStore openFile(String name, String mode, boolean mustExist) throws SQLException;
/**
* Calculate the checksum for the byte array.
*
* @param data the byte array
* @param start the starting offset
* @param end the end offset
* @return the checksum
*/
int getChecksum(byte[] data, int start, int end);
/**
* Check if the simulated power failure occurred.
* This call will decrement the countdown.
......
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.store;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.message.Message;
import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueByte;
import org.h2.value.ValueBytes;
import org.h2.value.ValueDate;
import org.h2.value.ValueDecimal;
import org.h2.value.ValueDouble;
import org.h2.value.ValueFloat;
import org.h2.value.ValueInt;
import org.h2.value.ValueJavaObject;
import org.h2.value.ValueLob;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueShort;
import org.h2.value.ValueString;
import org.h2.value.ValueStringFixed;
import org.h2.value.ValueStringIgnoreCase;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
import org.h2.value.ValueUuid;
/**
* A data page is a byte buffer that contains persistent data of a row or index
* page.
*/
public class DataPage {
/**
* The space required for the checksum and additional fillers.
*/
public static final int LENGTH_FILLER = 2;
/**
* The length of an integer value.
*/
public static final int LENGTH_INT = 4;
/**
* The length of a long value.
*/
public static final int LENGTH_LONG = 8;
/**
* Whether calculating (and checking) the checksum is enabled.
*/
private static final boolean CHECKSUM = true;
/**
* The data handler responsible for lob objects.
*/
protected DataHandler handler;
/**
* The data itself.
*/
protected byte[] data;
/**
* The current write or read position.
*/
protected int pos;
protected DataPage(DataHandler handler, byte[] data) {
this.handler = handler;
this.data = data;
}
/**
* Calculate the checksum and write.
*
*/
public void updateChecksum() {
if (CHECKSUM) {
int x = handler.getChecksum(data, 0, pos - 2);
data[pos - 2] = (byte) x;
}
}
/**
* Test if the checksum is correct.
*
* @param len the number of bytes
* @throws SQLException if the checksum does not match
*/
public void check(int len) throws SQLException {
if (CHECKSUM) {
int x = handler.getChecksum(data, 0, len - 2);
if (data[len - 2] == (byte) x) {
return;
}
throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1, "Invalid checksum");
}
}
/**
* Write an integer at the current position.
* The current position is incremented.
*
* @param x the value
*/
public void writeInt(int x) {
byte[] buff = data;
buff[pos++] = (byte) (x >> 24);
buff[pos++] = (byte) (x >> 16);
buff[pos++] = (byte) (x >> 8);
buff[pos++] = (byte) x;
}
/**
* Read an integer at the current position.
* The current position is incremented.
*
* @return the value
*/
public int readInt() {
byte[] buff = data;
return (buff[pos++] << 24) + ((buff[pos++] & 0xff) << 16) + ((buff[pos++] & 0xff) << 8) + (buff[pos++] & 0xff);
}
/**
* Get the length of a String value.
*
* @param s the value
* @return the length
*/
public int getStringLen(String s) {
return getStringLenUTF8(s);
}
/**
* Read a String value.
* The current position is incremented.
*
* @return the value
*/
public String readString() {
byte[] buff = data;
int p = pos;
int len = ((buff[p++] & 0xff) << 24) + ((buff[p++] & 0xff) << 16) + ((buff[p++] & 0xff) << 8)
+ (buff[p++] & 0xff);
char[] chars = new char[len];
for (int i = 0; i < len; i++) {
int x = buff[p++] & 0xff;
if (x < 0x80) {
chars[i] = (char) x;
} else if (x >= 0xe0) {
chars[i] = (char) (((x & 0xf) << 12) + ((buff[p++] & 0x3f) << 6) + (buff[p++] & 0x3f));
} else {
chars[i] = (char) (((x & 0x1f) << 6) + (buff[p++] & 0x3f));
}
}
pos = p;
return new String(chars);
}
/**
* Write a String value.
* The current position is incremented.
*
* @param s the value
*/
public void writeString(String s) {
int len = s.length();
checkCapacity(len * 3 + 4);
int p = pos;
byte[] buff = data;
buff[p++] = (byte) (len >> 24);
buff[p++] = (byte) (len >> 16);
buff[p++] = (byte) (len >> 8);
buff[p++] = (byte) len;
for (int i = 0; i < len; i++) {
int c = s.charAt(i);
if (c > 0 && c < 0x80) {
buff[p++] = (byte) c;
} else if (c >= 0x800) {
buff[p++] = (byte) (0xe0 | (c >> 12));
buff[p++] = (byte) (0x80 | ((c >> 6) & 0x3f));
buff[p++] = (byte) (0x80 | (c & 0x3f));
} else {
buff[p++] = (byte) (0xc0 | (c >> 6));
buff[p++] = (byte) (0x80 | (c & 0x3f));
}
}
pos = p;
}
/**
* Increase the size to the given length.
* The current position is set to the given value.
*
* @param len the new length
*/
public void fill(int len) {
if (pos > len) {
pos = len;
}
checkCapacity(len - pos);
pos = len;
}
/**
* Create a new data page for the given handler. The
* handler will decide what type of buffer is created.
*
* @param handler the data handler
* @param capacity the initial capacity of the buffer
* @return the data page
*/
public static DataPage create(DataHandler handler, int capacity) {
return new DataPage(handler, new byte[capacity]);
}
/**
* Create a new data page using the given data for the given handler. The
* handler will decide what type of buffer is created.
*
* @param handler the data handler
* @param buff the data
* @return the data page
*/
public static DataPage create(DataHandler handler, byte[] buff) {
return new DataPage(handler, buff);
}
/**
* Check if there is still enough capacity in the buffer.
* This method extends the buffer if required.
*
* @param plus the number of additional bytes required
*/
public void checkCapacity(int plus) {
if (pos + plus >= data.length) {
byte[] d = MemoryUtils.newBytes((data.length + plus) * 2);
// must copy everything, because pos could be 0 and data may be
// still required
System.arraycopy(data, 0, d, 0, data.length);
data = d;
}
}
/**
* Get the current write position of this data page, which is the current
* length.
*
* @return the length
*/
public int length() {
return pos;
}
/**
* Get the byte array used for this page.
*
* @return the byte array
*/
public byte[] getBytes() {
return data;
}
/**
* Set the position to 0.
*/
public void reset() {
pos = 0;
}
/**
* Read a data page from this page. The data from the current position to
* the end of the page is copied.
*
* @return the new page
*/
public DataPage readDataPageNoSize() {
int len = data.length - pos;
DataPage page = DataPage.create(handler, len);
System.arraycopy(data, pos, page.data, 0, len);
page.pos = len;
return page;
}
/**
* Append a number of bytes to this data page.
*
* @param buff the data
* @param off the offset in the data
* @param len the length in bytes
*/
public void write(byte[] buff, int off, int len) {
checkCapacity(len);
System.arraycopy(buff, off, data, pos, len);
pos += len;
}
/**
* Copy a number of bytes to the given buffer from the current position. The
* current position is incremented accordingly.
*
* @param buff the output buffer
* @param off the offset in the output buffer
* @param len the number of bytes to copy
*/
public void read(byte[] buff, int off, int len) {
System.arraycopy(data, pos, buff, off, len);
pos += len;
}
/**
* Append one single byte.
*
* @param x the value
*/
public void writeByte(byte x) {
data[pos++] = x;
}
/**
* Read one single byte.
*
* @return the value
*/
public int readByte() {
return data[pos++];
}
/**
* Read a long value. This method reads two int values and combines them.
*
* @return the long value
*/
public long readLong() {
return ((long) (readInt()) << 32) + (readInt() & 0xffffffffL);
}
/**
* Append a long value. This method writes two int values.
*
* @param x the value
*/
public void writeLong(long x) {
writeInt((int) (x >>> 32));
writeInt((int) x);
}
/**
* Append a value.
*
* @param v the value
*/
public void writeValue(Value v) throws SQLException {
checkCapacity(8);
// TODO text output: could be in the Value... classes
if (v == ValueNull.INSTANCE) {
data[pos++] = '-';
return;
}
int start = pos;
data[pos++] = (byte) (v.getType() + 'a');
switch (v.getType()) {
case Value.BOOLEAN:
case Value.BYTE:
case Value.SHORT:
case Value.INT:
writeInt(v.getInt());
break;
case Value.LONG:
writeLong(v.getLong());
break;
case Value.DECIMAL:
String s = v.getString();
writeString(s);
break;
case Value.TIME:
writeLong(v.getTimeNoCopy().getTime());
break;
case Value.DATE:
writeLong(v.getDateNoCopy().getTime());
break;
case Value.TIMESTAMP: {
Timestamp ts = v.getTimestampNoCopy();
writeLong(ts.getTime());
writeInt(ts.getNanos());
break;
}
case Value.JAVA_OBJECT:
case Value.BYTES: {
byte[] b = v.getBytesNoCopy();
writeInt(b.length);
write(b, 0, b.length);
break;
}
case Value.UUID: {
ValueUuid uuid = (ValueUuid) v;
writeLong(uuid.getHigh());
writeLong(uuid.getLow());
break;
}
case Value.STRING:
case Value.STRING_IGNORECASE:
case Value.STRING_FIXED:
writeString(v.getString());
break;
case Value.DOUBLE:
writeLong(Double.doubleToLongBits(v.getDouble()));
break;
case Value.FLOAT:
writeInt(Float.floatToIntBits(v.getFloat()));
break;
case Value.BLOB:
case Value.CLOB: {
ValueLob lob = (ValueLob) v;
lob.convertToFileIfRequired(handler);
byte[] small = lob.getSmall();
if (small == null) {
// -2 for historical reasons (-1 didn't store precision)
int type = -2;
if (!lob.isLinked()) {
type = -3;
}
writeInt(type);
writeInt(lob.getTableId());
writeInt(lob.getObjectId());
writeLong(lob.getPrecision());
writeByte((byte) (lob.useCompression() ? 1 : 0));
if (type == -3) {
writeString(lob.getFileName());
}
} else {
writeInt(small.length);
write(small, 0, small.length);
}
break;
}
case Value.ARRAY: {
Value[] list = ((ValueArray) v).getList();
writeInt(list.length);
for (Value x : list) {
writeValue(x);
}
break;
}
default:
Message.throwInternalError("type=" + v.getType());
}
if (SysProperties.CHECK2) {
if (pos - start != getValueLen(v)) {
throw Message
.throwInternalError("value size error: got " + (pos - start) + " expected " + getValueLen(v));
}
}
}
/**
* Calculate the number of bytes required to encode the given value.
*
* @param v the value
* @return the number of bytes required to store this value
*/
public int getValueLen(Value v) throws SQLException {
if (v == ValueNull.INSTANCE) {
return 1;
}
switch (v.getType()) {
case Value.BOOLEAN:
case Value.BYTE:
case Value.SHORT:
case Value.INT:
return 1 + LENGTH_INT;
case Value.LONG:
return 1 + LENGTH_LONG;
case Value.DOUBLE:
return 1 + LENGTH_LONG;
case Value.FLOAT:
return 1 + LENGTH_INT;
case Value.STRING:
case Value.STRING_IGNORECASE:
case Value.STRING_FIXED:
return 1 + getStringLen(v.getString());
case Value.DECIMAL:
return 1 + getStringLen(v.getString());
case Value.JAVA_OBJECT:
case Value.BYTES: {
int len = v.getBytesNoCopy().length;
return 1 + LENGTH_INT + len;
}
case Value.UUID:
return 1 + LENGTH_LONG + LENGTH_LONG;
case Value.TIME:
return 1 + LENGTH_LONG;
case Value.DATE:
return 1 + LENGTH_LONG;
case Value.TIMESTAMP:
return 1 + LENGTH_LONG + LENGTH_INT;
case Value.BLOB:
case Value.CLOB: {
int len = 1;
ValueLob lob = (ValueLob) v;
lob.convertToFileIfRequired(handler);
byte[] small = lob.getSmall();
if (small != null) {
len += LENGTH_INT + small.length;
} else {
len += LENGTH_INT + LENGTH_INT + LENGTH_INT + LENGTH_LONG + 1;
if (!lob.isLinked()) {
len += getStringLen(lob.getFileName());
}
}
return len;
}
case Value.ARRAY: {
Value[] list = ((ValueArray) v).getList();
int len = 1 + LENGTH_INT;
for (Value x : list) {
len += getValueLen(x);
}
return len;
}
default:
throw Message.throwInternalError("type=" + v.getType());
}
}
/**
* Read a value.
*
* @return the value
*/
public Value readValue() throws SQLException {
int dataType = data[pos++];
if (dataType == '-') {
return ValueNull.INSTANCE;
}
dataType = dataType - 'a';
switch (dataType) {
case Value.BOOLEAN:
return ValueBoolean.get(readInt() == 1);
case Value.BYTE:
return ValueByte.get((byte) readInt());
case Value.SHORT:
return ValueShort.get((short) readInt());
case Value.INT:
return ValueInt.get(readInt());
case Value.LONG:
return ValueLong.get(readLong());
case Value.DECIMAL:
return ValueDecimal.get(new BigDecimal(readString()));
case Value.DATE:
return ValueDate.getNoCopy(new Date(readLong()));
case Value.TIME:
// need to normalize the year, month and day
return ValueTime.get(new Time(readLong()));
case Value.TIMESTAMP: {
Timestamp ts = new Timestamp(readLong());
ts.setNanos(readInt());
return ValueTimestamp.getNoCopy(ts);
}
case Value.JAVA_OBJECT: {
int len = readInt();
byte[] b = MemoryUtils.newBytes(len);
read(b, 0, len);
return ValueJavaObject.getNoCopy(b);
}
case Value.BYTES: {
int len = readInt();
byte[] b = MemoryUtils.newBytes(len);
read(b, 0, len);
return ValueBytes.getNoCopy(b);
}
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 Value.DOUBLE:
return ValueDouble.get(Double.longBitsToDouble(readLong()));
case Value.FLOAT:
return ValueFloat.get(Float.intBitsToFloat(readInt()));
case Value.BLOB:
case Value.CLOB: {
int smallLen = readInt();
if (smallLen >= 0) {
byte[] small = MemoryUtils.newBytes(smallLen);
read(small, 0, smallLen);
return ValueLob.createSmallLob(dataType, small);
}
int tableId = readInt();
int objectId = readInt();
long precision = 0;
boolean compression = false;
// -1: historical (didn't store precision)
// -2: regular
// -3: regular, but not linked (in this case: including file name)
if (smallLen == -2 || smallLen == -3) {
precision = readLong();
compression = readByte() == 1;
}
ValueLob lob = ValueLob.open(dataType, handler, tableId, objectId, precision, compression);
if (smallLen == -3) {
lob.setFileName(readString(), false);
}
return lob;
}
case Value.ARRAY: {
int len = readInt();
Value[] list = new Value[len];
for (int i = 0; i < len; i++) {
list[i] = readValue();
}
return ValueArray.get(list);
}
default:
throw Message.throwInternalError("type=" + dataType);
}
}
/**
* Fill up the buffer with empty space and an (initially empty) checksum
* until the size is a multiple of Constants.FILE_BLOCK_SIZE.
*/
public void fillAligned() {
// TODO datapage: fillAligned should not use a fixed constant '2'
// 0..6 > 8, 7..14 > 16, 15..22 > 24, ...
fill(MathUtils.roundUpInt(pos + 2, Constants.FILE_BLOCK_SIZE));
}
/**
* Read an short integer at the current position.
* The current position is incremented.
*
* @return the value
*/
public int readShortInt() {
byte[] buff = data;
return ((buff[pos++] & 0xff) << 8) + (buff[pos++] & 0xff);
}
private static int getStringLenUTF8(String s) {
int plus = 4, len = s.length();
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if (c >= 0x800) {
plus += 2;
} else if (c == 0 || c >= 0x80) {
plus++;
}
}
return len + plus;
}
}
......@@ -691,7 +691,7 @@ public class Recover extends Tool implements DataHandler {
if (d == dataPage) {
dataPage = 0;
} else {
// ignore the pages before the starting data page
// ignore the pages before the starting page
continue;
}
}
......@@ -1124,17 +1124,6 @@ public class Recover extends Tool implements DataHandler {
return FileStore.open(this, name, "rw");
}
/**
* INTERNAL
*/
public int getChecksum(byte[] data, int start, int end) {
int x = 0;
while (start < end) {
x += data[start++];
}
return x;
}
/**
* INTERNAL
*/
......
......@@ -33,7 +33,7 @@ import org.h2.util.StringUtils;
/**
* Implementation of the BLOB and CLOB data types. Small objects are kept in
* memory and stored in the data page of the record.
* memory and stored in the record.
*
* Large objects are stored in their own files. When large objects are set in a
* prepared statement, they are first stored as 'temporary' files. Later, when
......
......@@ -287,37 +287,17 @@ java org.h2.test.TestAll timer
System.setProperty("h2.check2", "true");
/*
check client jar file size
simplify Message / ErrorCode / Resource
remove BitField
flatten package hierarchy (remove constant package)
Constants.FILE_BLOCK_SIZE and others
simplify SysProperties; combine with Constants
remove SortedProperties
remove TempFileDeleter (UndoLog, ResultDiskBuffer, RowList, ValueLob)
combine small classes (StringCache / utils...)
FileStore.sync, Database.sync() (CHECKPOINT SYNC)
document in performance section:
PreparedStatement prep = conn.prepareStatement(
"select * from table(x int = ?) t inner join test on t.x = test.id");
prep.setObject(1, new Object[] { "1", "2" });
ResultSet rs = prep.executeQuery();
remove unused methods
cleanup SortedProperties
headPos > boolean isNew?
verify Row - Page
fix class javadocs
test remote lob (temp file) read write
review package and class level javadocs
TestAll deleteIndex
FileStore.sync, Database.sync() (CHECKPOINT SYNC)
data page > buffer
try to reduce number of packages, classes
rename Page classes to normal names
use RuntimeException internally
Verify that Tomcat memory leak protection don't cause exceptions:
http://java.dzone.com/articles/memory-leak-protection-tomcat
document FETCH FIRST
power failure test: larger binaries and additional indexes
......
......@@ -271,10 +271,6 @@ public class TestDataPage extends TestBase implements DataHandler {
return null;
}
public int getChecksum(byte[] data, int s, int e) {
return e - s;
}
public void checkPowerOff() {
// nothing to do
}
......
......@@ -146,10 +146,6 @@ public class TestFile extends TestBase implements DataHandler {
// nothing to do
}
public int getChecksum(byte[] data, int s, int e) {
return 0;
}
public String getDatabasePath() {
return null;
}
......
......@@ -48,13 +48,13 @@ public class TestNetUtils extends TestBase {
while (!isInterrupted()) {
try {
Socket socket = serverSocket.accept();
System.out.println("opened " + counter);
// System.out.println("opened " + counter);
socket.close();
} catch (Exception e) {
// ignore
}
}
System.out.println("stopped ");
// System.out.println("stopped ");
}
};
......
......@@ -120,10 +120,6 @@ public class TestValueHashMap extends TestBase implements DataHandler {
return null;
}
public int getChecksum(byte[] data, int s, int e) {
return 0;
}
public void checkPowerOff() {
// nothing to do
}
......
......@@ -194,10 +194,6 @@ public class TestValueMemory extends TestBase implements DataHandler {
// nothing to do
}
public int getChecksum(byte[] data, int s, int e) {
return 0;
}
public String getDatabasePath() {
return baseDir + "/valueMemory";
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论