提交 616351ea authored 作者: Thomas Mueller's avatar Thomas Mueller

Page store: support clustered primary keys

上级 cc21adca
...@@ -4541,63 +4541,66 @@ Supporters ...@@ -4541,63 +4541,66 @@ Supporters
Many thanks for those who helped by finding and reporting bugs, gave valuable feedback, spread the word and have translated this project. Also many thanks to the donors who contributed via PayPal: Many thanks for those who helped by finding and reporting bugs, gave valuable feedback, spread the word and have translated this project. Also many thanks to the donors who contributed via PayPal:
@history_1025_a @history_1025_a
NetSuxxess GmbH, Germany
@history_1026_a
SkyCash, Poland SkyCash, Poland
@history_1026_li @history_1027_li
Donald Bleyl, USA Donald Bleyl, USA
@history_1027_li @history_1028_li
lumber-mill.co.jp, Japan lumber-mill.co.jp, Japan
@history_1028_li @history_1029_li
Frank Berger, Germany Frank Berger, Germany
@history_1029_li @history_1030_li
Ashwin Jayaprakash, USA Ashwin Jayaprakash, USA
@history_1030_li @history_1031_li
Florent Ramiere, France Florent Ramiere, France
@history_1031_li @history_1032_li
Jun Iyama, Japan Jun Iyama, Japan
@history_1032_li @history_1033_li
Antonio Casqueiro, Portugal Antonio Casqueiro, Portugal
@history_1033_li @history_1034_li
Oliver Computing LLC, USA Oliver Computing LLC, USA
@history_1034_li @history_1035_li
Harpal Grover Consulting Inc., USA Harpal Grover Consulting Inc., USA
@history_1035_li @history_1036_li
Elisabetta Berlini, Italy Elisabetta Berlini, Italy
@history_1036_li @history_1037_li
William Gilbert, USA William Gilbert, USA
@history_1037_li @history_1038_li
Antonio Dieguez, Chile Antonio Dieguez, Chile
@history_1038_a @history_1039_a
Ontology Works, USA Ontology Works, USA
@history_1039_li @history_1040_li
Pete Haidinyak, USA Pete Haidinyak, USA
@history_1040_li @history_1041_li
William Osmond, USA William Osmond, USA
@history_1041_li @history_1042_li
Joachim Ansorg, Germany Joachim Ansorg, Germany
@history_1042_li @history_1043_li
Oliver Soerensen, Germany Oliver Soerensen, Germany
@history_1043_li @history_1044_li
Christos Vasilakis, Greece Christos Vasilakis, Greece
@history_1044_li @history_1045_li
Fyodor Kupolov, Denmark Fyodor Kupolov, Denmark
@installation_1000_h1 @installation_1000_h1
...@@ -8935,13 +8938,16 @@ Document internal features such as BELONGS_TO_TABLE, NULL_TO_DEFAULT, SEQUENCE. ...@@ -8935,13 +8938,16 @@ Document internal features such as BELONGS_TO_TABLE, NULL_TO_DEFAULT, SEQUENCE.
@roadmap_1414_li @roadmap_1414_li
Issue 107: Prefer using the ORDER BY index if LIMIT is used. Issue 107: Prefer using the ORDER BY index if LIMIT is used.
@roadmap_1415_h2 @roadmap_1415_li
Support reading sequences using DatabaseMetaData.getTables(null, null, null, new String[]{"SEQUENCE"}). See PostgreSQL.
@roadmap_1416_h2
Not Planned Not Planned
@roadmap_1416_li @roadmap_1417_li
HSQLDB (did) support this: select id i from test where i<0 (other databases don't). Supporting it may break compatibility. HSQLDB (did) support this: select id i from test where i<0 (other databases don't). Supporting it may break compatibility.
@roadmap_1417_li @roadmap_1418_li
String.intern (so that Strings can be compared with ==) will not be used because some VMs have problems when used extensively. String.intern (so that Strings can be compared with ==) will not be used because some VMs have problems when used extensively.
@sourceError_1000_h1 @sourceError_1000_h1
......
...@@ -4541,63 +4541,66 @@ Unicodeをサポート ...@@ -4541,63 +4541,66 @@ Unicodeをサポート
#Many thanks for those who helped by finding and reporting bugs, gave valuable feedback, spread the word and have translated this project. Also many thanks to the donors who contributed via PayPal: #Many thanks for those who helped by finding and reporting bugs, gave valuable feedback, spread the word and have translated this project. Also many thanks to the donors who contributed via PayPal:
@history_1025_a @history_1025_a
#NetSuxxess GmbH, Germany
@history_1026_a
#SkyCash, Poland #SkyCash, Poland
@history_1026_li @history_1027_li
#Donald Bleyl, USA #Donald Bleyl, USA
@history_1027_li @history_1028_li
#lumber-mill.co.jp, Japan #lumber-mill.co.jp, Japan
@history_1028_li @history_1029_li
#Frank Berger, Germany #Frank Berger, Germany
@history_1029_li @history_1030_li
#Ashwin Jayaprakash, USA #Ashwin Jayaprakash, USA
@history_1030_li @history_1031_li
#Florent Ramiere, France #Florent Ramiere, France
@history_1031_li @history_1032_li
#Jun Iyama, Japan #Jun Iyama, Japan
@history_1032_li @history_1033_li
#Antonio Casqueiro, Portugal #Antonio Casqueiro, Portugal
@history_1033_li @history_1034_li
#Oliver Computing LLC, USA #Oliver Computing LLC, USA
@history_1034_li @history_1035_li
#Harpal Grover Consulting Inc., USA #Harpal Grover Consulting Inc., USA
@history_1035_li @history_1036_li
#Elisabetta Berlini, Italy #Elisabetta Berlini, Italy
@history_1036_li @history_1037_li
#William Gilbert, USA #William Gilbert, USA
@history_1037_li @history_1038_li
#Antonio Dieguez, Chile #Antonio Dieguez, Chile
@history_1038_a @history_1039_a
#Ontology Works, USA #Ontology Works, USA
@history_1039_li @history_1040_li
#Pete Haidinyak, USA #Pete Haidinyak, USA
@history_1040_li @history_1041_li
#William Osmond, USA #William Osmond, USA
@history_1041_li @history_1042_li
#Joachim Ansorg, Germany #Joachim Ansorg, Germany
@history_1042_li @history_1043_li
#Oliver Soerensen, Germany #Oliver Soerensen, Germany
@history_1043_li @history_1044_li
#Christos Vasilakis, Greece #Christos Vasilakis, Greece
@history_1044_li @history_1045_li
#Fyodor Kupolov, Denmark #Fyodor Kupolov, Denmark
@installation_1000_h1 @installation_1000_h1
...@@ -8935,13 +8938,16 @@ SQLコマンドがコマンドエリアに表示されます。 ...@@ -8935,13 +8938,16 @@ SQLコマンドがコマンドエリアに表示されます。
@roadmap_1414_li @roadmap_1414_li
#Issue 107: Prefer using the ORDER BY index if LIMIT is used. #Issue 107: Prefer using the ORDER BY index if LIMIT is used.
@roadmap_1415_h2 @roadmap_1415_li
#Support reading sequences using DatabaseMetaData.getTables(null, null, null, new String[]{"SEQUENCE"}). See PostgreSQL.
@roadmap_1416_h2
#Not Planned #Not Planned
@roadmap_1416_li @roadmap_1417_li
#HSQLDB (did) support this: select id i from test where i<0 (other databases don't). Supporting it may break compatibility. #HSQLDB (did) support this: select id i from test where i<0 (other databases don't). Supporting it may break compatibility.
@roadmap_1417_li @roadmap_1418_li
#String.intern (so that Strings can be compared with ==) will not be used because some VMs have problems when used extensively. #String.intern (so that Strings can be compared with ==) will not be used because some VMs have problems when used extensively.
@sourceError_1000_h1 @sourceError_1000_h1
......
...@@ -1510,26 +1510,27 @@ history_1021_p=Java is also future proof\: a lot of companies support Java, and ...@@ -1510,26 +1510,27 @@ history_1021_p=Java is also future proof\: a lot of companies support Java, and
history_1022_p=This software does not rely on many Java libraries or other software, to increase the portability and ease of use, and for performance reasons. For example, the encryption algorithms and many library functions are implemented in the database instead of using the existing libraries. Libraries that are not available in open source Java implementations (such as Swing) are not used or only used for specific features. history_1022_p=This software does not rely on many Java libraries or other software, to increase the portability and ease of use, and for performance reasons. For example, the encryption algorithms and many library functions are implemented in the database instead of using the existing libraries. Libraries that are not available in open source Java implementations (such as Swing) are not used or only used for specific features.
history_1023_h2=Supporters history_1023_h2=Supporters
history_1024_p=Many thanks for those who helped by finding and reporting bugs, gave valuable feedback, spread the word and have translated this project. Also many thanks to the donors who contributed via PayPal\: history_1024_p=Many thanks for those who helped by finding and reporting bugs, gave valuable feedback, spread the word and have translated this project. Also many thanks to the donors who contributed via PayPal\:
history_1025_a=SkyCash, Poland history_1025_a=NetSuxxess GmbH, Germany
history_1026_li=Donald Bleyl, USA history_1026_a=SkyCash, Poland
history_1027_li=lumber-mill.co.jp, Japan history_1027_li=Donald Bleyl, USA
history_1028_li=Frank Berger, Germany history_1028_li=lumber-mill.co.jp, Japan
history_1029_li=Ashwin Jayaprakash, USA history_1029_li=Frank Berger, Germany
history_1030_li=Florent Ramiere, France history_1030_li=Ashwin Jayaprakash, USA
history_1031_li=Jun Iyama, Japan history_1031_li=Florent Ramiere, France
history_1032_li=Antonio Casqueiro, Portugal history_1032_li=Jun Iyama, Japan
history_1033_li=Oliver Computing LLC, USA history_1033_li=Antonio Casqueiro, Portugal
history_1034_li=Harpal Grover Consulting Inc., USA history_1034_li=Oliver Computing LLC, USA
history_1035_li=Elisabetta Berlini, Italy history_1035_li=Harpal Grover Consulting Inc., USA
history_1036_li=William Gilbert, USA history_1036_li=Elisabetta Berlini, Italy
history_1037_li=Antonio Dieguez, Chile history_1037_li=William Gilbert, USA
history_1038_a=Ontology Works, USA history_1038_li=Antonio Dieguez, Chile
history_1039_li=Pete Haidinyak, USA history_1039_a=Ontology Works, USA
history_1040_li=William Osmond, USA history_1040_li=Pete Haidinyak, USA
history_1041_li=Joachim Ansorg, Germany history_1041_li=William Osmond, USA
history_1042_li=Oliver Soerensen, Germany history_1042_li=Joachim Ansorg, Germany
history_1043_li=Christos Vasilakis, Greece history_1043_li=Oliver Soerensen, Germany
history_1044_li=Fyodor Kupolov, Denmark history_1044_li=Christos Vasilakis, Greece
history_1045_li=Fyodor Kupolov, Denmark
installation_1000_h1=Installation installation_1000_h1=Installation
installation_1001_a=Requirements installation_1001_a=Requirements
installation_1002_a=Supported Platforms installation_1002_a=Supported Platforms
...@@ -2975,9 +2976,10 @@ roadmap_1411_li=Optimization for EXISTS\: convert to inner join if possible. ...@@ -2975,9 +2976,10 @@ roadmap_1411_li=Optimization for EXISTS\: convert to inner join if possible.
roadmap_1412_li=Improve database file locking (maybe use native file locking). The current approach seems to be problematic if the file system is on a remote share (see Google Group 'Lock file modification time is in the future'). roadmap_1412_li=Improve database file locking (maybe use native file locking). The current approach seems to be problematic if the file system is on a remote share (see Google Group 'Lock file modification time is in the future').
roadmap_1413_li=Document internal features such as BELONGS_TO_TABLE, NULL_TO_DEFAULT, SEQUENCE. roadmap_1413_li=Document internal features such as BELONGS_TO_TABLE, NULL_TO_DEFAULT, SEQUENCE.
roadmap_1414_li=Issue 107\: Prefer using the ORDER BY index if LIMIT is used. roadmap_1414_li=Issue 107\: Prefer using the ORDER BY index if LIMIT is used.
roadmap_1415_h2=Not Planned roadmap_1415_li=Support reading sequences using DatabaseMetaData.getTables(null, null, null, new String[]{"SEQUENCE"}). See PostgreSQL.
roadmap_1416_li=HSQLDB (did) support this\: select id i from test where i<0 (other databases don't). Supporting it may break compatibility. roadmap_1416_h2=Not Planned
roadmap_1417_li=String.intern (so that Strings can be compared with \=\=) will not be used because some VMs have problems when used extensively. roadmap_1417_li=HSQLDB (did) support this\: select id i from test where i<0 (other databases don't). Supporting it may break compatibility.
roadmap_1418_li=String.intern (so that Strings can be compared with \=\=) will not be used because some VMs have problems when used extensively.
sourceError_1000_h1=Online Error Analyzer sourceError_1000_h1=Online Error Analyzer
sourceError_1001_a=Home sourceError_1001_a=Home
sourceError_1002_a=Input sourceError_1002_a=Input
......
...@@ -31,6 +31,7 @@ import org.h2.command.ddl.CreateRole; ...@@ -31,6 +31,7 @@ import org.h2.command.ddl.CreateRole;
import org.h2.command.ddl.CreateSchema; import org.h2.command.ddl.CreateSchema;
import org.h2.command.ddl.CreateSequence; import org.h2.command.ddl.CreateSequence;
import org.h2.command.ddl.CreateTable; import org.h2.command.ddl.CreateTable;
import org.h2.command.ddl.CreateTableData;
import org.h2.command.ddl.CreateTrigger; import org.h2.command.ddl.CreateTrigger;
import org.h2.command.ddl.CreateUser; import org.h2.command.ddl.CreateUser;
import org.h2.command.ddl.CreateUserDataType; import org.h2.command.ddl.CreateUserDataType;
...@@ -3783,15 +3784,22 @@ public class Parser { ...@@ -3783,15 +3784,22 @@ public class Parser {
for (String c : cols) { for (String c : cols) {
columns.add(new Column(c, Value.STRING)); columns.add(new Column(c, Value.STRING));
} }
int id = database.allocateObjectId(true, true); CreateTableData data = new CreateTableData();
recursiveTable = schema.createTable(tempViewName, id, columns, true, false, true, false, Index.EMPTY_HEAD, session); data.id = database.allocateObjectId(true, true);
data.tableName = tempViewName;
data.temporary = true;
data.persistData = true;
data.persistIndexes = false;
data.headPos = Index.EMPTY_HEAD;
data.session = session;
recursiveTable = schema.createTable(data);
session.addLocalTempTable(recursiveTable); session.addLocalTempTable(recursiveTable);
String querySQL = StringCache.getNew(sqlCommand.substring(parseIndex)); String querySQL = StringCache.getNew(sqlCommand.substring(parseIndex));
read("AS"); read("AS");
Query withQuery = parseSelect(); Query withQuery = parseSelect();
withQuery.prepare(); withQuery.prepare();
session.removeLocalTempTable(recursiveTable); session.removeLocalTempTable(recursiveTable);
id = database.allocateObjectId(true, true); int id = database.allocateObjectId(true, true);
TableView view = new TableView(schema, id, tempViewName, querySQL, null, cols, session, true); TableView view = new TableView(schema, id, tempViewName, querySQL, null, cols, session, true);
view.setTemporary(true); view.setTemporary(true);
// view.setOnCommitDrop(true); // view.setOnCommitDrop(true);
...@@ -4720,9 +4728,6 @@ public class Parser { ...@@ -4720,9 +4728,6 @@ public class Parser {
read("PERSISTENT"); read("PERSISTENT");
command.setPersistData(false); command.setPersistData(false);
} }
if (readIf("CLUSTERED")) {
command.setClustered(true);
}
return command; return command;
} }
......
...@@ -244,7 +244,16 @@ public class AlterTableAlterColumn extends SchemaCommand { ...@@ -244,7 +244,16 @@ public class AlterTableAlterColumn extends SchemaCommand {
// still need a new id because using 0 would mean: the new table tries // still need a new id because using 0 would mean: the new table tries
// to use the rows of the table 0 (the meta table) // to use the rows of the table 0 (the meta table)
int id = db.allocateObjectId(true, true); int id = db.allocateObjectId(true, true);
TableData newTable = getSchema().createTable(tempName, id, newColumns, table.isTemporary(), table.isPersistIndexes(), table.isPersistData(), false, Index.EMPTY_HEAD, session); CreateTableData data = new CreateTableData();
data.tableName = tempName;
data.id = id;
data.columns = newColumns;
data.temporary = table.isTemporary();
data.persistData = table.isPersistData();
data.persistIndexes = table.isPersistIndexes();
data.headPos = Index.EMPTY_HEAD;
data.session = session;
TableData newTable = getSchema().createTable(data);
newTable.setComment(table.getComment()); newTable.setComment(table.getComment());
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
buff.append(newTable.getCreateSQL()); buff.append(newTable.getCreateSQL());
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
package org.h2.command.ddl; package org.h2.command.ddl;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.command.dml.Insert; import org.h2.command.dml.Insert;
import org.h2.command.dml.Query; import org.h2.command.dml.Query;
...@@ -30,23 +29,20 @@ import org.h2.value.DataType; ...@@ -30,23 +29,20 @@ import org.h2.value.DataType;
*/ */
public class CreateTable extends SchemaCommand { public class CreateTable extends SchemaCommand {
private String tableName; private CreateTableData data = new CreateTableData();
private ObjectArray<Prepared> constraintCommands = ObjectArray.newInstance(); private ObjectArray<Prepared> constraintCommands = ObjectArray.newInstance();
private ObjectArray<Column> columns = ObjectArray.newInstance();
private IndexColumn[] pkColumns; private IndexColumn[] pkColumns;
private boolean ifNotExists; private boolean ifNotExists;
private boolean persistIndexes = true;
private boolean persistData = true;
private boolean temporary;
private boolean globalTemporary; private boolean globalTemporary;
private boolean onCommitDrop; private boolean onCommitDrop;
private boolean onCommitTruncate; private boolean onCommitTruncate;
private Query asQuery; private Query asQuery;
private String comment; private String comment;
private boolean clustered;
public CreateTable(Session session, Schema schema) { public CreateTable(Session session, Schema schema) {
super(session, schema); super(session, schema);
data.persistIndexes = true;
data.persistData = true;
} }
public void setQuery(Query query) { public void setQuery(Query query) {
...@@ -54,11 +50,11 @@ public class CreateTable extends SchemaCommand { ...@@ -54,11 +50,11 @@ public class CreateTable extends SchemaCommand {
} }
public void setTemporary(boolean temporary) { public void setTemporary(boolean temporary) {
this.temporary = temporary; data.temporary = temporary;
} }
public void setTableName(String tableName) { public void setTableName(String tableName) {
this.tableName = tableName; data.tableName = tableName;
} }
/** /**
...@@ -67,10 +63,7 @@ public class CreateTable extends SchemaCommand { ...@@ -67,10 +63,7 @@ public class CreateTable extends SchemaCommand {
* @param column the column to add * @param column the column to add
*/ */
public void addColumn(Column column) { public void addColumn(Column column) {
if (columns == null) { data.columns.add(column);
columns = ObjectArray.newInstance();
}
columns.add(column);
} }
/** /**
...@@ -104,24 +97,24 @@ public class CreateTable extends SchemaCommand { ...@@ -104,24 +97,24 @@ public class CreateTable extends SchemaCommand {
session.commit(true); session.commit(true);
Database db = session.getDatabase(); Database db = session.getDatabase();
if (!db.isPersistent()) { if (!db.isPersistent()) {
persistIndexes = false; data.persistIndexes = false;
} }
if (getSchema().findTableOrView(session, tableName) != null) { if (getSchema().findTableOrView(session, data.tableName) != null) {
if (ifNotExists) { if (ifNotExists) {
return 0; return 0;
} }
throw Message.getSQLException(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, tableName); throw Message.getSQLException(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, data.tableName);
} }
if (asQuery != null) { if (asQuery != null) {
asQuery.prepare(); asQuery.prepare();
if (columns.size() == 0) { if (data.columns.size() == 0) {
generateColumnsFromQuery(); generateColumnsFromQuery();
} else if (columns.size() != asQuery.getColumnCount()) { } else if (data.columns.size() != asQuery.getColumnCount()) {
throw Message.getSQLException(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); throw Message.getSQLException(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
} }
} }
if (pkColumns != null) { if (pkColumns != null) {
for (Column c : columns) { for (Column c : data.columns) {
for (IndexColumn idxCol : pkColumns) { for (IndexColumn idxCol : pkColumns) {
if (c.getName().equals(idxCol.columnName)) { if (c.getName().equals(idxCol.columnName)) {
c.setNullable(false); c.setNullable(false);
...@@ -130,21 +123,23 @@ public class CreateTable extends SchemaCommand { ...@@ -130,21 +123,23 @@ public class CreateTable extends SchemaCommand {
} }
} }
ObjectArray<Sequence> sequences = ObjectArray.newInstance(); ObjectArray<Sequence> sequences = ObjectArray.newInstance();
for (Column c : columns) { for (Column c : data.columns) {
if (c.isAutoIncrement()) { if (c.isAutoIncrement()) {
int objId = getObjectId(true, true); int objId = getObjectId(true, true);
c.convertAutoIncrementToSequence(session, getSchema(), objId, temporary); c.convertAutoIncrementToSequence(session, getSchema(), objId, data.temporary);
} }
Sequence seq = c.getSequence(); Sequence seq = c.getSequence();
if (seq != null) { if (seq != null) {
sequences.add(seq); sequences.add(seq);
} }
} }
int id = getObjectId(true, true); data.id = getObjectId(true, true);
TableData table = getSchema().createTable(tableName, id, columns, temporary, persistIndexes, persistData, clustered, headPos, session); data.headPos = headPos;
data.session = session;
TableData table = getSchema().createTable(data);
table.setComment(comment); table.setComment(comment);
table.setGlobalTemporary(globalTemporary); table.setGlobalTemporary(globalTemporary);
if (temporary && !globalTemporary) { if (data.temporary && !globalTemporary) {
if (onCommitDrop) { if (onCommitDrop) {
table.setOnCommitDrop(true); table.setOnCommitDrop(true);
} }
...@@ -156,7 +151,7 @@ public class CreateTable extends SchemaCommand { ...@@ -156,7 +151,7 @@ public class CreateTable extends SchemaCommand {
db.addSchemaObject(session, table); db.addSchemaObject(session, table);
} }
try { try {
for (Column c : columns) { for (Column c : data.columns) {
c.prepareExpression(session); c.prepareExpression(session);
} }
for (Sequence sequence : sequences) { for (Sequence sequence : sequences) {
...@@ -234,7 +229,7 @@ public class CreateTable extends SchemaCommand { ...@@ -234,7 +229,7 @@ public class CreateTable extends SchemaCommand {
} }
public void setPersistIndexes(boolean persistIndexes) { public void setPersistIndexes(boolean persistIndexes) {
this.persistIndexes = persistIndexes; data.persistIndexes = persistIndexes;
} }
public void setGlobalTemporary(boolean globalTemporary) { public void setGlobalTemporary(boolean globalTemporary) {
...@@ -259,12 +254,8 @@ public class CreateTable extends SchemaCommand { ...@@ -259,12 +254,8 @@ public class CreateTable extends SchemaCommand {
this.comment = comment; this.comment = comment;
} }
public void setClustered(boolean clustered) {
this.clustered = clustered;
}
public void setPersistData(boolean persistData) { public void setPersistData(boolean persistData) {
this.persistData = persistData; data.persistData = persistData;
} }
} }
/*
* Copyright 2004-2009 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.command.ddl;
import org.h2.engine.Session;
import org.h2.schema.Schema;
import org.h2.table.Column;
import org.h2.util.ObjectArray;
/**
* The data required to create a table.
*/
public class CreateTableData {
/**
* The schema.
*/
public Schema schema;
/**
* The table name.
*/
public String tableName;
/**
* The object id.
*/
public int id;
/**
* The column list.
*/
public ObjectArray<Column> columns = ObjectArray.newInstance();
/**
* Whether this is a temporary table.
*/
public boolean temporary;
/**
* Whether the indexes should be persisted.
*/
public boolean persistIndexes;
/**
* Whether the data should be persisted.
*/
public boolean persistData;
/**
* The head position.
*/
public int headPos;
/**
* The session.
*/
public Session session;
}
...@@ -17,6 +17,7 @@ import java.util.Set; ...@@ -17,6 +17,7 @@ import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.command.ddl.CreateTableData;
import org.h2.command.dml.SetTypes; import org.h2.command.dml.SetTypes;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
...@@ -626,7 +627,8 @@ public class Database implements DataHandler { ...@@ -626,7 +627,8 @@ public class Database implements DataHandler {
roles.put(Constants.PUBLIC_ROLE_NAME, publicRole); roles.put(Constants.PUBLIC_ROLE_NAME, publicRole);
systemUser.setAdmin(true); systemUser.setAdmin(true);
systemSession = new Session(this, systemUser, ++nextSessionId); systemSession = new Session(this, systemUser, ++nextSessionId);
ObjectArray<Column> cols = ObjectArray.newInstance(); CreateTableData data = new CreateTableData();
ObjectArray<Column> cols = data.columns;
Column columnId = new Column("ID", Value.INT); Column columnId = new Column("ID", Value.INT);
columnId.setNullable(false); columnId.setNullable(false);
cols.add(columnId); cols.add(columnId);
...@@ -637,7 +639,14 @@ public class Database implements DataHandler { ...@@ -637,7 +639,14 @@ public class Database implements DataHandler {
if (pageStore != null) { if (pageStore != null) {
headPos = pageStore.getSystemTableHeadPos(); headPos = pageStore.getSystemTableHeadPos();
} }
meta = mainSchema.createTable("SYS", 0, cols, false, persistent, persistent, false, headPos, systemSession); data.tableName = "SYS";
data.id = 0;
data.temporary = false;
data.persistData = persistent;
data.persistIndexes = persistent;
data.headPos = headPos;
data.session = systemSession;
meta = mainSchema.createTable(data);
IndexColumn[] pkCols = IndexColumn.wrap(new Column[] { columnId }); IndexColumn[] pkCols = IndexColumn.wrap(new Column[] { columnId });
metaIdIndex = meta.addIndex(systemSession, "SYS_ID", 0, pkCols, IndexType.createPrimaryKey( metaIdIndex = meta.addIndex(systemSession, "SYS_ID", 0, pkCols, IndexType.createPrimaryKey(
false, false), Index.EMPTY_HEAD, null); false, false), Index.EMPTY_HEAD, null);
......
...@@ -56,7 +56,7 @@ public class PageBtreeIndex extends PageIndex { ...@@ -56,7 +56,7 @@ public class PageBtreeIndex extends PageIndex {
root.parentPageId = PageBtree.ROOT; root.parentPageId = PageBtree.ROOT;
store.updateRecord(root, true, root.data); store.updateRecord(root, true, root.data);
} else { } else {
rootPageId = store.getRootPageId(this); rootPageId = store.getRootPageId(id);
PageBtree root = getPage(rootPageId); PageBtree root = getPage(rootPageId);
rowCount = root.getRowCount(); rowCount = root.getRowCount();
if (rowCount == 0 && store.isRecoveryRunning()) { if (rowCount == 0 && store.isRecoveryRunning()) {
...@@ -297,12 +297,12 @@ public class PageBtreeIndex extends PageIndex { ...@@ -297,12 +297,12 @@ public class PageBtreeIndex extends PageIndex {
*/ */
SearchRow readRow(Data data, int offset, boolean onlyPosition) throws SQLException { SearchRow readRow(Data data, int offset, boolean onlyPosition) throws SQLException {
data.setPos(offset); data.setPos(offset);
int pos = data.readInt(); long pos = data.readVarLong();
if (onlyPosition) { if (onlyPosition) {
return tableData.getRow(null, pos); return tableData.getRow(null, (int) pos);
} }
SearchRow row = table.getTemplateSimpleRow(columns.length == 1); SearchRow row = table.getTemplateSimpleRow(columns.length == 1);
row.setPos(pos); row.setPos((int) pos);
for (Column col : columns) { for (Column col : columns) {
int idx = col.getColumnId(); int idx = col.getColumnId();
row.setValue(idx, data.readValue()); row.setValue(idx, data.readValue());
...@@ -320,7 +320,7 @@ public class PageBtreeIndex extends PageIndex { ...@@ -320,7 +320,7 @@ public class PageBtreeIndex extends PageIndex {
*/ */
void writeRow(Data data, int offset, SearchRow row, boolean onlyPosition) throws SQLException { void writeRow(Data data, int offset, SearchRow row, boolean onlyPosition) throws SQLException {
data.setPos(offset); data.setPos(offset);
data.writeInt(row.getPos()); data.writeVarLong(row.getPos());
if (!onlyPosition) { if (!onlyPosition) {
for (Column col : columns) { for (Column col : columns) {
int idx = col.getColumnId(); int idx = col.getColumnId();
......
...@@ -20,22 +20,36 @@ import org.h2.store.PageStore; ...@@ -20,22 +20,36 @@ import org.h2.store.PageStore;
/** /**
* A b-tree leaf page that contains index data. * A b-tree leaf page that contains index data.
* Format: * Format:
* <ul><li>0-3: parent page id (0 for root) * <ul><li>parent page id (0 for root): int
* </li><li>4-4: page type * </li><li>page type: byte
* </li><li>5-8: index id * </li><li>index id: varInt
* </li><li>9-10: entry count * </li><li>entry count: short
* </li><li>11-: list offsets (2 bytes each) * </li><li>list of offsets: shortInt
* </li><li>data * </li><li>data (pos: varLong, value,...)
* </li></ul> * </li></ul>
*/ */
public class PageBtreeLeaf extends PageBtree { public class PageBtreeLeaf extends PageBtree {
private static final int OFFSET_LENGTH = 2; private static final int OFFSET_LENGTH = 2;
private static final int OFFSET_START = 11;
PageBtreeLeaf(PageBtreeIndex index, int pageId, Data data) { PageBtreeLeaf(PageBtreeIndex index, int pageId, Data data) {
super(index, pageId, data); super(index, pageId, data);
start = OFFSET_START; }
/**
* Create a new page.
*
* @param index the index
* @param pageId the page id
* @param parentPageId the parent
* @return the page
*/
static PageBtreeLeaf create(PageBtreeIndex index, int pageId, int parentPageId) {
PageBtreeLeaf p = new PageBtreeLeaf(index, pageId, index.getPageStore().createData());
p.parentPageId = parentPageId;
p.writeHead();
p.start = p.data.length();
return p;
} }
/** /**
...@@ -57,7 +71,7 @@ public class PageBtreeLeaf extends PageBtree { ...@@ -57,7 +71,7 @@ public class PageBtreeLeaf extends PageBtree {
this.parentPageId = data.readInt(); this.parentPageId = data.readInt();
int type = data.readByte(); int type = data.readByte();
onlyPosition = (type & Page.FLAG_LAST) == 0; onlyPosition = (type & Page.FLAG_LAST) == 0;
int indexId = data.readInt(); int indexId = data.readVarInt();
if (indexId != index.getId()) { if (indexId != index.getId()) {
throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1, throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1,
"page:" + getPos() + " expected index:" + index.getId() + "page:" + getPos() + " expected index:" + index.getId() +
...@@ -78,11 +92,16 @@ public class PageBtreeLeaf extends PageBtree { ...@@ -78,11 +92,16 @@ public class PageBtreeLeaf extends PageBtree {
int last = entryCount == 0 ? pageSize : offsets[entryCount - 1]; int last = entryCount == 0 ? pageSize : offsets[entryCount - 1];
if (last - rowLength < start + OFFSET_LENGTH) { if (last - rowLength < start + OFFSET_LENGTH) {
if (entryCount > 1) { if (entryCount > 1) {
// split at the insertion point to better fill pages int x = find(row, false, true, true);
if (entryCount < 5) {
// required, otherwise the index doesn't work correctly
return entryCount / 2;
}
// split near the insertion point to better fill pages
// split in half would be: // split in half would be:
// return entryCount / 2; // return entryCount / 2;
int x = find(row, false, true, true); int third = entryCount / 3;
return x < 2 ? 2 : x >= entryCount - 3 ? entryCount - 3 : x; return x < third ? third : x >= 2 * third ? 2 * third : x;
} }
onlyPosition = true; onlyPosition = true;
// change the offsets (now storing only positions) // change the offsets (now storing only positions)
...@@ -213,16 +232,20 @@ public class PageBtreeLeaf extends PageBtree { ...@@ -213,16 +232,20 @@ public class PageBtreeLeaf extends PageBtree {
index.getPageStore().writePage(getPos(), data); index.getPageStore().writePage(getPos(), data);
} }
private void writeHead() {
data.writeInt(parentPageId);
data.writeByte((byte) (Page.TYPE_BTREE_LEAF | (onlyPosition ? 0 : Page.FLAG_LAST)));
data.writeVarInt(index.getId());
data.writeShortInt(entryCount);
}
private void write() throws SQLException { private void write() throws SQLException {
if (written) { if (written) {
return; return;
} }
readAllRows(); readAllRows();
data.reset(); data.reset();
data.writeInt(parentPageId); writeHead();
data.writeByte((byte) (Page.TYPE_BTREE_LEAF | (onlyPosition ? 0 : Page.FLAG_LAST)));
data.writeInt(index.getId());
data.writeShortInt(entryCount);
for (int i = 0; i < entryCount; i++) { for (int i = 0; i < entryCount; i++) {
data.writeShortInt(offsets[i]); data.writeShortInt(offsets[i]);
} }
......
...@@ -28,7 +28,7 @@ import org.h2.util.MemoryUtils; ...@@ -28,7 +28,7 @@ import org.h2.util.MemoryUtils;
* <li>9-10: entry count</li> * <li>9-10: entry count</li>
* <li>11-14: row count of all children (-1 if not known)</li> * <li>11-14: row count of all children (-1 if not known)</li>
* <li>15-18: rightmost child page id</li> * <li>15-18: rightmost child page id</li>
* <li>19- entries: 4 bytes leaf page id, 2 bytes offset to data</li> * <li>19- entries: leaf page id: int, offset: short</li>
* </ul> * </ul>
* The row is the largest row of the respective child, meaning * The row is the largest row of the respective child, meaning
* row[0] is the largest row of child[0]. * row[0] is the largest row of child[0].
......
...@@ -112,9 +112,11 @@ abstract class PageData extends Page { ...@@ -112,9 +112,11 @@ abstract class PageData extends Page {
* Get a cursor. * Get a cursor.
* *
* @param session the session * @param session the session
* @param min the smallest key
* @param max the largest key
* @return the cursor * @return the cursor
*/ */
abstract Cursor find(Session session) throws SQLException; abstract Cursor find(Session session, long min, long max) throws SQLException;
/** /**
* Get the key at this position. * Get the key at this position.
...@@ -151,7 +153,7 @@ abstract class PageData extends Page { ...@@ -151,7 +153,7 @@ abstract class PageData extends Page {
* *
* @return the last key * @return the last key
*/ */
abstract int getLastKey() throws SQLException; abstract long getLastKey() throws SQLException;
/** /**
* Get the first child leaf page of a page. * Get the first child leaf page of a page.
...@@ -194,7 +196,7 @@ abstract class PageData extends Page { ...@@ -194,7 +196,7 @@ abstract class PageData extends Page {
* @param key the key * @param key the key
* @return the row * @return the row
*/ */
abstract Row getRow(int key) throws SQLException; abstract Row getRow(long key) throws SQLException;
/** /**
* Get the estimated memory size. * Get the estimated memory size.
......
...@@ -9,7 +9,6 @@ package org.h2.index; ...@@ -9,7 +9,6 @@ package org.h2.index;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -21,19 +20,18 @@ import org.h2.store.PageStore; ...@@ -21,19 +20,18 @@ import org.h2.store.PageStore;
/** /**
* A leaf page that contains data of one or multiple rows. * A leaf page that contains data of one or multiple rows.
* Format: * Format:
* <ul><li>0-3: parent page id (0 for root) * <ul><li>parent page id (0 for root): int
* </li><li>4-4: page type * </li><li>page type: byte
* </li><li>5-8: table id * </li><li>table id: varInt
* </li><li>9-10: entry count * </li><li>column count: varInt
* </li><li>with overflow: 11-14: the first overflow page id * </li><li>entry count: short
* </li><li>11- or 15-: list of key / offset pairs (varLong key, 2 bytes offset) * </li><li>with overflow: the first overflow page id: int
* </li><li>list of key / offset pairs (key: varLong, offset: shortInt)
* </li><li>data * </li><li>data
* </li></ul> * </li></ul>
*/ */
public class PageDataLeaf extends PageData { public class PageDataLeaf extends PageData {
private static final int KEY_OFFSET_PAIR_START = 11;
/** /**
* The row offsets. * The row offsets.
*/ */
...@@ -64,9 +62,27 @@ public class PageDataLeaf extends PageData { ...@@ -64,9 +62,27 @@ public class PageDataLeaf extends PageData {
*/ */
private int overflowRowSize; private int overflowRowSize;
PageDataLeaf(PageScanIndex index, int pageId, Data data) { private int columnCount;
private PageDataLeaf(PageScanIndex index, int pageId, Data data) {
super(index, pageId, data); super(index, pageId, data);
start = KEY_OFFSET_PAIR_START; }
/**
* Create a new page.
*
* @param index the index
* @param pageId the page id
* @param parentPageId the parent
* @return the page
*/
static PageDataLeaf create(PageScanIndex index, int pageId, int parentPageId) {
PageDataLeaf p = new PageDataLeaf(index, pageId, index.getPageStore().createData());
p.parentPageId = parentPageId;
p.columnCount = index.getTable().getColumns().length;
p.writeHead();
p.start = p.data.length();
return p;
} }
/** /**
...@@ -87,12 +103,13 @@ public class PageDataLeaf extends PageData { ...@@ -87,12 +103,13 @@ public class PageDataLeaf extends PageData {
data.reset(); data.reset();
this.parentPageId = data.readInt(); this.parentPageId = data.readInt();
int type = data.readByte(); int type = data.readByte();
int tableId = data.readInt(); int tableId = data.readVarInt();
if (tableId != index.getId()) { if (tableId != index.getId()) {
throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1, throw Message.getSQLException(ErrorCode.FILE_CORRUPTED_1,
"page:" + getPos() + " expected table:" + index.getId() + "page:" + getPos() + " expected table:" + index.getId() +
" got:" + tableId + " type:" + type); " got:" + tableId + " type:" + type);
} }
columnCount = data.readVarInt();
entryCount = data.readShortInt(); entryCount = data.readShortInt();
offsets = new int[entryCount]; offsets = new int[entryCount];
keys = new long[entryCount]; keys = new long[entryCount];
...@@ -107,18 +124,33 @@ public class PageDataLeaf extends PageData { ...@@ -107,18 +124,33 @@ public class PageDataLeaf extends PageData {
start = data.length(); start = data.length();
} }
private int getRowLength(Row row) throws SQLException {
int size = 0;
for (int i = 0; i < columnCount; i++) {
size += data.getValueLen(row.getValue(i));
}
return size;
}
int addRowTry(Row row) throws SQLException { int addRowTry(Row row) throws SQLException {
int rowLength = row.getByteCount(data); int rowLength = getRowLength(row);
int pageSize = index.getPageStore().getPageSize(); int pageSize = index.getPageStore().getPageSize();
int last = entryCount == 0 ? pageSize : offsets[entryCount - 1]; int last = entryCount == 0 ? pageSize : offsets[entryCount - 1];
int keyOffsetPairLen = 2 + data.getVarLongLen(row.getPos()); int keyOffsetPairLen = 2 + data.getVarLongLen(row.getPos());
if (entryCount > 0 && last - rowLength < start + keyOffsetPairLen) { if (entryCount > 0 && last - rowLength < start + keyOffsetPairLen) {
// split at the insertion point to better fill pages int x = find(row.getPos());
if (entryCount > 1) {
if (entryCount < 5) {
// required, otherwise the index doesn't work correctly
return entryCount / 2;
}
// split near the insertion point to better fill pages
// split in half would be: // split in half would be:
// if (entryCount > 1) {
// return entryCount / 2; // return entryCount / 2;
// } int third = entryCount / 3;
return find(row.getPos()); return x < third ? third : x >= 2 * third ? 2 * third : x;
}
return x;
} }
int offset = last - rowLength; int offset = last - rowLength;
int[] newOffsets = new int[entryCount + 1]; int[] newOffsets = new int[entryCount + 1];
...@@ -130,8 +162,8 @@ public class PageDataLeaf extends PageData { ...@@ -130,8 +162,8 @@ public class PageDataLeaf extends PageData {
} else { } else {
readAllRows(); readAllRows();
x = find(row.getPos()); x = find(row.getPos());
if (SysProperties.CHECK && x < keys.length && keys[x] == row.getPos()) { if (x < keys.length && keys[x] == row.getPos()) {
throw Message.throwInternalError("" + row.getPos()); throw index.getDuplicateKeyException();
} }
System.arraycopy(offsets, 0, newOffsets, 0, x); System.arraycopy(offsets, 0, newOffsets, 0, x);
System.arraycopy(keys, 0, newKeys, 0, x); System.arraycopy(keys, 0, newKeys, 0, x);
...@@ -225,8 +257,9 @@ public class PageDataLeaf extends PageData { ...@@ -225,8 +257,9 @@ public class PageDataLeaf extends PageData {
rows = newRows; rows = newRows;
} }
Cursor find(Session session) { Cursor find(Session session, long min, long max) {
return new PageScanCursor(session, this, 0, index.isMultiVersion); int x = find(min);
return new PageScanCursor(session, this, x, max, index.isMultiVersion);
} }
/** /**
...@@ -238,7 +271,10 @@ public class PageDataLeaf extends PageData { ...@@ -238,7 +271,10 @@ public class PageDataLeaf extends PageData {
Row getRowAt(int at) throws SQLException { Row getRowAt(int at) throws SQLException {
Row r = rows[at]; Row r = rows[at];
if (r == null) { if (r == null) {
if (firstOverflowPageId != 0) { if (firstOverflowPageId == 0) {
data.setPos(offsets[at]);
r = index.readRow(data, columnCount);
} else {
if (rowRef != null) { if (rowRef != null) {
r = rowRef.get(); r = rowRef.get();
if (r != null) { if (r != null) {
...@@ -246,17 +282,19 @@ public class PageDataLeaf extends PageData { ...@@ -246,17 +282,19 @@ public class PageDataLeaf extends PageData {
} }
} }
PageStore store = index.getPageStore(); PageStore store = index.getPageStore();
Data buff = store.createData();
int pageSize = store.getPageSize(); int pageSize = store.getPageSize();
data.setPos(pageSize); int offset = offsets[at];
buff.write(data.getBytes(), offset, pageSize - offset);
int next = firstOverflowPageId; int next = firstOverflowPageId;
do { do {
PageDataOverflow page = index.getPageOverflow(next); PageDataOverflow page = index.getPageOverflow(next);
next = page.readInto(data); next = page.readInto(buff);
} while (next != 0); } while (next != 0);
overflowRowSize = data.length(); overflowRowSize = pageSize + buff.length();
buff.setPos(0);
r = index.readRow(buff, columnCount);
} }
data.setPos(offsets[at]);
r = index.readRow(data);
r.setPos((int) keys[at]); r.setPos((int) keys[at]);
if (firstOverflowPageId != 0) { if (firstOverflowPageId != 0) {
rowRef = new SoftReference<Row>(r); rowRef = new SoftReference<Row>(r);
...@@ -273,8 +311,7 @@ public class PageDataLeaf extends PageData { ...@@ -273,8 +311,7 @@ public class PageDataLeaf extends PageData {
PageData split(int splitPoint) throws SQLException { PageData split(int splitPoint) throws SQLException {
int newPageId = index.getPageStore().allocatePage(); int newPageId = index.getPageStore().allocatePage();
PageDataLeaf p2 = new PageDataLeaf(index, newPageId, index.getPageStore().createData()); PageDataLeaf p2 = PageDataLeaf.create(index, newPageId, parentPageId);
p2.parentPageId = parentPageId;
for (int i = splitPoint; i < entryCount;) { for (int i = splitPoint; i < entryCount;) {
p2.addRowTry(getRowAt(splitPoint)); p2.addRowTry(getRowAt(splitPoint));
removeRow(splitPoint); removeRow(splitPoint);
...@@ -282,7 +319,7 @@ public class PageDataLeaf extends PageData { ...@@ -282,7 +319,7 @@ public class PageDataLeaf extends PageData {
return p2; return p2;
} }
int getLastKey() throws SQLException { long getLastKey() throws SQLException {
// TODO re-use keys, but remove this mechanism // TODO re-use keys, but remove this mechanism
if (entryCount == 0) { if (entryCount == 0) {
return 0; return 0;
...@@ -337,7 +374,7 @@ public class PageDataLeaf extends PageData { ...@@ -337,7 +374,7 @@ public class PageDataLeaf extends PageData {
} }
} }
Row getRow(int key) throws SQLException { Row getRow(long key) throws SQLException {
int index = find(key); int index = find(key);
return getRowAt(index); return getRowAt(index);
} }
...@@ -366,13 +403,7 @@ public class PageDataLeaf extends PageData { ...@@ -366,13 +403,7 @@ public class PageDataLeaf extends PageData {
} }
} }
private void write() throws SQLException { private void writeHead() {
if (written) {
return;
}
readAllRows();
data.reset();
data.checkCapacity(overflowRowSize);
data.writeInt(parentPageId); data.writeInt(parentPageId);
int type; int type;
if (firstOverflowPageId == 0) { if (firstOverflowPageId == 0) {
...@@ -381,8 +412,19 @@ public class PageDataLeaf extends PageData { ...@@ -381,8 +412,19 @@ public class PageDataLeaf extends PageData {
type = Page.TYPE_DATA_LEAF; type = Page.TYPE_DATA_LEAF;
} }
data.writeByte((byte) type); data.writeByte((byte) type);
data.writeInt(index.getId()); data.writeVarInt(index.getId());
data.writeVarInt(columnCount);
data.writeShortInt(entryCount); data.writeShortInt(entryCount);
}
private void write() throws SQLException {
if (written) {
return;
}
readAllRows();
data.reset();
data.checkCapacity(overflowRowSize);
writeHead();
if (firstOverflowPageId != 0) { if (firstOverflowPageId != 0) {
data.writeInt(firstOverflowPageId); data.writeInt(firstOverflowPageId);
} }
...@@ -392,7 +434,10 @@ public class PageDataLeaf extends PageData { ...@@ -392,7 +434,10 @@ public class PageDataLeaf extends PageData {
} }
for (int i = 0; i < entryCount; i++) { for (int i = 0; i < entryCount; i++) {
data.setPos(offsets[i]); data.setPos(offsets[i]);
getRowAt(i).write(data); Row r = getRowAt(i);
for (int j = 0; j < columnCount; j++) {
data.writeValue(r.getValue(j));
}
} }
written = true; written = true;
} }
...@@ -405,7 +450,7 @@ public class PageDataLeaf extends PageData { ...@@ -405,7 +450,7 @@ public class PageDataLeaf extends PageData {
public void moveTo(Session session, int newPos) throws SQLException { public void moveTo(Session session, int newPos) throws SQLException {
PageStore store = index.getPageStore(); PageStore store = index.getPageStore();
PageDataLeaf p2 = new PageDataLeaf(index, newPos, store.createData()); PageDataLeaf p2 = PageDataLeaf.create(index, newPos, parentPageId);
readAllRows(); readAllRows();
p2.keys = keys; p2.keys = keys;
p2.overflowRowSize = overflowRowSize; p2.overflowRowSize = overflowRowSize;
......
...@@ -146,9 +146,10 @@ public class PageDataNode extends PageData { ...@@ -146,9 +146,10 @@ public class PageDataNode extends PageData {
} }
} }
Cursor find(Session session) throws SQLException { Cursor find(Session session, long min, long max) throws SQLException {
int child = childPageIds[0]; int x = find(min);
return index.getPage(child, getPos()).find(session); int child = childPageIds[x];
return index.getPage(child, getPos()).find(session, min, max);
} }
PageData split(int splitPoint) throws SQLException { PageData split(int splitPoint) throws SQLException {
...@@ -191,7 +192,7 @@ public class PageDataNode extends PageData { ...@@ -191,7 +192,7 @@ public class PageDataNode extends PageData {
check(); check();
} }
int getLastKey() throws SQLException { long getLastKey() throws SQLException {
return index.getPage(childPageIds[entryCount], getPos()).getLastKey(); return index.getPage(childPageIds[entryCount], getPos()).getLastKey();
} }
...@@ -250,7 +251,7 @@ public class PageDataNode extends PageData { ...@@ -250,7 +251,7 @@ public class PageDataNode extends PageData {
} }
} }
Row getRow(int key) throws SQLException { Row getRow(long key) throws SQLException {
int at = find(key); int at = find(key);
PageData page = index.getPage(childPageIds[at], getPos()); PageData page = index.getPage(childPageIds[at], getPos());
return page.getRow(key); return page.getRow(key);
......
/*
* Copyright 2004-2009 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.index;
import java.sql.SQLException;
import org.h2.engine.Session;
import org.h2.message.Message;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.store.PageStore;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
import org.h2.table.TableData;
/**
* An index that delegates indexing to the page data index.
*/
public class PageDelegateIndex extends PageIndex {
private final PageScanIndex mainIndex;
public PageDelegateIndex(TableData table, int id, String name, IndexType indexType, PageScanIndex mainIndex, int headPos, Session session) throws SQLException {
IndexColumn[] columns = IndexColumn.wrap(new Column[] { table.getColumn(mainIndex.getMainIndexColumn())});
this.initBaseIndex(table, id, name, columns, indexType);
this.mainIndex = mainIndex;
if (!database.isPersistent() || id < 0) {
throw Message.throwInternalError("" + name);
}
PageStore store = database.getPageStore();
store.addIndex(this);
if (headPos == Index.EMPTY_HEAD) {
store.addMeta(this, session);
}
}
public void add(Session session, Row row) {
// nothing to do
}
public boolean canFindNext() {
return false;
}
public boolean canGetFirstOrLast() {
return true;
}
public void close(Session session) {
// nothing to do
}
public Cursor find(Session session, SearchRow first, SearchRow last) throws SQLException {
return mainIndex.find(session, first, last);
}
public Cursor findFirstOrLast(Session session, boolean first) throws SQLException {
return mainIndex.findFirstOrLast(session, first);
}
public Cursor findNext(Session session, SearchRow higherThan, SearchRow last) {
throw Message.throwInternalError();
}
public int getColumnIndex(Column col) {
return mainIndex.getColumnIndex(col);
}
public double getCost(Session session, int[] masks) {
return 10 * getCostRangeIndex(masks, mainIndex.getRowCount(session));
}
public boolean needRebuild() {
return false;
}
public void remove(Session session, Row row) {
// nothing to do
}
public void remove(Session session) throws SQLException {
session.getDatabase().getPageStore().removeMeta(this, session);
}
public void truncate(Session session) {
// nothing to do
}
public void checkRename() {
// ok
}
public long getRowCount(Session session) {
return mainIndex.getRowCount(session);
}
public long getRowCountApproximation() {
return mainIndex.getRowCountApproximation();
}
}
...@@ -21,14 +21,16 @@ class PageScanCursor implements Cursor { ...@@ -21,14 +21,16 @@ class PageScanCursor implements Cursor {
private PageDataLeaf current; private PageDataLeaf current;
private int idx; private int idx;
private final long max;
private Row row; private Row row;
private final boolean multiVersion; private final boolean multiVersion;
private final Session session; private final Session session;
private Iterator<Row> delta; private Iterator<Row> delta;
PageScanCursor(Session session, PageDataLeaf current, int idx, boolean multiVersion) { PageScanCursor(Session session, PageDataLeaf current, int idx, long max, boolean multiVersion) {
this.current = current; this.current = current;
this.idx = idx; this.idx = idx;
this.max = max;
this.multiVersion = multiVersion; this.multiVersion = multiVersion;
this.session = session; this.session = session;
if (multiVersion) { if (multiVersion) {
...@@ -50,7 +52,8 @@ class PageScanCursor implements Cursor { ...@@ -50,7 +52,8 @@ class PageScanCursor implements Cursor {
public boolean next() throws SQLException { public boolean next() throws SQLException {
if (!multiVersion) { if (!multiVersion) {
return nextRow(); nextRow();
return checkMax();
} }
while (true) { while (true) {
if (delta != null) { if (delta != null) {
...@@ -71,21 +74,34 @@ class PageScanCursor implements Cursor { ...@@ -71,21 +74,34 @@ class PageScanCursor implements Cursor {
} }
break; break;
} }
return row != null; return checkMax();
}
private boolean checkMax() throws SQLException {
if (row != null) {
if (max != Long.MAX_VALUE) {
long x = current.index.getLong(row, Long.MAX_VALUE);
if (x > max) {
row = null;
return false;
}
}
return true;
}
return false;
} }
private boolean nextRow() throws SQLException { private void nextRow() throws SQLException {
if (idx >= current.getEntryCount()) { if (idx >= current.getEntryCount()) {
current = current.getNextPage(); current = current.getNextPage();
idx = 0; idx = 0;
if (current == null) { if (current == null) {
row = null; row = null;
return false; return;
} }
} }
row = current.getRowAt(idx); row = current.getRowAt(idx);
idx++; idx++;
return true;
} }
public boolean previous() { public boolean previous() {
......
...@@ -27,6 +27,7 @@ import org.h2.util.MathUtils; ...@@ -27,6 +27,7 @@ import org.h2.util.MathUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueLob; import org.h2.value.ValueLob;
import org.h2.value.ValueNull;
/** /**
* The scan index allows to access a row by key. It can be used to iterate over * The scan index allows to access a row by key. It can be used to iterate over
...@@ -37,11 +38,12 @@ public class PageScanIndex extends PageIndex implements RowIndex { ...@@ -37,11 +38,12 @@ public class PageScanIndex extends PageIndex implements RowIndex {
private PageStore store; private PageStore store;
private TableData tableData; private TableData tableData;
private int lastKey; private long lastKey;
private long rowCount; private long rowCount;
private HashSet<Row> delta; private HashSet<Row> delta;
private int rowCountDiff; private int rowCountDiff;
private HashMap<Integer, Integer> sessionRowCount; private HashMap<Integer, Integer> sessionRowCount;
private int mainIndexColumn = -1;
public PageScanIndex(TableData table, int id, IndexColumn[] columns, IndexType indexType, int headPos, Session session) throws SQLException { public PageScanIndex(TableData table, int id, IndexColumn[] columns, IndexType indexType, int headPos, Session session) throws SQLException {
initBaseIndex(table, id, table.getName() + "_TABLE_SCAN", columns, indexType); initBaseIndex(table, id, table.getName() + "_TABLE_SCAN", columns, indexType);
...@@ -63,11 +65,10 @@ public class PageScanIndex extends PageIndex implements RowIndex { ...@@ -63,11 +65,10 @@ public class PageScanIndex extends PageIndex implements RowIndex {
// it should not for new tables, otherwise redo of other operations // it should not for new tables, otherwise redo of other operations
// must ensure this page is not used for other things // must ensure this page is not used for other things
store.addMeta(this, session); store.addMeta(this, session);
PageDataLeaf root = new PageDataLeaf(this, rootPageId, store.createData()); PageDataLeaf root = PageDataLeaf.create(this, rootPageId, PageData.ROOT);
root.parentPageId = PageData.ROOT;
store.updateRecord(root, true, root.data); store.updateRecord(root, true, root.data);
} else { } else {
rootPageId = store.getRootPageId(this); rootPageId = store.getRootPageId(id);
PageData root = getPage(rootPageId, 0); PageData root = getPage(rootPageId, 0);
lastKey = root.getLastKey(); lastKey = root.getLastKey();
rowCount = root.getRowCount(); rowCount = root.getRowCount();
...@@ -85,11 +86,15 @@ public class PageScanIndex extends PageIndex implements RowIndex { ...@@ -85,11 +86,15 @@ public class PageScanIndex extends PageIndex implements RowIndex {
} }
public void add(Session session, Row row) throws SQLException { public void add(Session session, Row row) throws SQLException {
if (mainIndexColumn != -1) {
row.setPos(row.getValue(mainIndexColumn).getInt());
} else {
if (row.getPos() == 0) { if (row.getPos() == 0) {
row.setPos(++lastKey); row.setPos((int) ++lastKey);
} else { } else {
lastKey = Math.max(lastKey, row.getPos() + 1); lastKey = Math.max(lastKey, row.getPos() + 1);
} }
}
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("add table:" + table.getId() + " " + row); trace.debug("add table:" + table.getId() + " " + row);
} }
...@@ -166,9 +171,7 @@ public class PageScanIndex extends PageIndex implements RowIndex { ...@@ -166,9 +171,7 @@ public class PageScanIndex extends PageIndex implements RowIndex {
PageData getPage(int id, int parent) throws SQLException { PageData getPage(int id, int parent) throws SQLException {
PageData p = (PageData) store.getPage(id); PageData p = (PageData) store.getPage(id);
if (p == null) { if (p == null) {
Data data = store.createData(); PageDataLeaf empty = PageDataLeaf.create(this, id, parent);
PageDataLeaf empty = new PageDataLeaf(this, id, data);
empty.parentPageId = parent;
return empty; return empty;
} }
if (p.index.rootPageId != rootPageId) { if (p.index.rootPageId != rootPageId) {
...@@ -186,13 +189,42 @@ public class PageScanIndex extends PageIndex implements RowIndex { ...@@ -186,13 +189,42 @@ public class PageScanIndex extends PageIndex implements RowIndex {
return false; return false;
} }
/**
* Get the key from the row
*
* @param row the row
* @param ifEmpty the value to use if the row is empty
* @return the key
*/
long getLong(SearchRow row, long ifEmpty) throws SQLException {
if (row == null) {
return ifEmpty;
}
Value v = row.getValue(mainIndexColumn);
if (v == null || v == ValueNull.INSTANCE) {
return ifEmpty;
}
return v.getLong();
}
public Cursor find(Session session, SearchRow first, SearchRow last) throws SQLException { public Cursor find(Session session, SearchRow first, SearchRow last) throws SQLException {
long min = getLong(first, Long.MIN_VALUE);
long max = getLong(last, Long.MAX_VALUE);
PageData root = getPage(rootPageId, 0); PageData root = getPage(rootPageId, 0);
return root.find(session); return root.find(session, min, max);
} }
public Cursor findFirstOrLast(Session session, boolean first) throws SQLException { public Cursor findFirstOrLast(Session session, boolean first) throws SQLException {
throw Message.getUnsupportedException("PAGE"); Cursor cursor;
PageData root = getPage(rootPageId, 0);
if (first) {
cursor = root.find(session, Long.MIN_VALUE, Long.MAX_VALUE);
} else {
long lastKey = root.getLastKey();
cursor = root.find(session, lastKey, lastKey);
}
cursor.next();
return cursor;
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks) {
...@@ -273,8 +305,7 @@ public class PageScanIndex extends PageIndex implements RowIndex { ...@@ -273,8 +305,7 @@ public class PageScanIndex extends PageIndex implements RowIndex {
private void removeAllRows() throws SQLException { private void removeAllRows() throws SQLException {
PageData root = getPage(rootPageId, 0); PageData root = getPage(rootPageId, 0);
root.freeChildren(); root.freeChildren();
root = new PageDataLeaf(this, rootPageId, store.createData()); root = PageDataLeaf.create(this, rootPageId, PageData.ROOT);
root.parentPageId = PageData.ROOT;
store.removeRecord(rootPageId); store.removeRecord(rootPageId);
store.updateRecord(root, true, null); store.updateRecord(root, true, null);
rowCount = 0; rowCount = 0;
...@@ -298,10 +329,15 @@ public class PageScanIndex extends PageIndex implements RowIndex { ...@@ -298,10 +329,15 @@ public class PageScanIndex extends PageIndex implements RowIndex {
* Read a row from the data page at the given position. * Read a row from the data page at the given position.
* *
* @param data the data page * @param data the data page
* @param columnCount the number of columns
* @return the row * @return the row
*/ */
Row readRow(Data data) throws SQLException { Row readRow(Data data, int columnCount) throws SQLException {
return tableData.readRow(data); Value[] values = new Value[columnCount];
for (int i = 0; i < columnCount; i++) {
values[i] = data.readValue();
}
return tableData.createRow(values);
} }
public long getRowCountApproximation() { public long getRowCountApproximation() {
...@@ -324,8 +360,9 @@ public class PageScanIndex extends PageIndex implements RowIndex { ...@@ -324,8 +360,9 @@ public class PageScanIndex extends PageIndex implements RowIndex {
} }
public int getColumnIndex(Column col) { public int getColumnIndex(Column col) {
// the scan index cannot use any columns if (col.getColumnId() == mainIndexColumn) {
// TODO it can if there is an INT primary key return 0;
}
return -1; return -1;
} }
...@@ -386,4 +423,12 @@ public class PageScanIndex extends PageIndex implements RowIndex { ...@@ -386,4 +423,12 @@ public class PageScanIndex extends PageIndex implements RowIndex {
store.addIndex(this); store.addIndex(this);
} }
public void setMainIndexColumn(int mainIndexColumn) {
this.mainIndexColumn = mainIndexColumn;
}
public int getMainIndexColumn() {
return mainIndexColumn;
}
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
package org.h2.result; package org.h2.result;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.command.ddl.CreateTableData;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.index.BtreeIndex; import org.h2.index.BtreeIndex;
...@@ -40,11 +41,16 @@ public class ResultTempTable implements ResultExternal { ...@@ -40,11 +41,16 @@ public class ResultTempTable implements ResultExternal {
Schema schema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN); Schema schema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN);
Column column = new Column(COLUMN_NAME, Value.ARRAY); Column column = new Column(COLUMN_NAME, Value.ARRAY);
column.setNullable(false); column.setNullable(false);
ObjectArray<Column> columns = ObjectArray.newInstance(); CreateTableData data = new CreateTableData();
columns.add(column); data.columns.add(column);
int tableId = session.getDatabase().allocateObjectId(true, true); data.id = session.getDatabase().allocateObjectId(true, true);
String tableName = "TEMP_RESULT_SET_" + tableId; data.tableName = "TEMP_RESULT_SET_" + data.id;
table = schema.createTable(tableName, tableId, columns, true, false, true, false, Index.EMPTY_HEAD, session); data.temporary = true;
data.persistIndexes = false;
data.persistData = true;
data.headPos = Index.EMPTY_HEAD;
data.session = session;
table = schema.createTable(data);
session.addLocalTempTable(table); session.addLocalTempTable(table);
int indexId = session.getDatabase().allocateObjectId(true, false); int indexId = session.getDatabase().allocateObjectId(true, false);
IndexColumn indexColumn = new IndexColumn(); IndexColumn indexColumn = new IndexColumn();
...@@ -54,9 +60,9 @@ public class ResultTempTable implements ResultExternal { ...@@ -54,9 +60,9 @@ public class ResultTempTable implements ResultExternal {
indexType = IndexType.createPrimaryKey(true, false); indexType = IndexType.createPrimaryKey(true, false);
IndexColumn[] indexCols = new IndexColumn[]{indexColumn}; IndexColumn[] indexCols = new IndexColumn[]{indexColumn};
if (session.getDatabase().isPageStoreEnabled()) { if (session.getDatabase().isPageStoreEnabled()) {
index = new PageBtreeIndex(table, indexId, tableName, indexCols, indexType, Index.EMPTY_HEAD, session); index = new PageBtreeIndex(table, indexId, data.tableName, indexCols, indexType, Index.EMPTY_HEAD, session);
} else { } else {
index = new BtreeIndex(session, table, indexId, tableName, indexCols, indexType, Index.EMPTY_HEAD); index = new BtreeIndex(session, table, indexId, data.tableName, indexCols, indexType, Index.EMPTY_HEAD);
} }
index.setTemporary(true); index.setTemporary(true);
session.addLocalTempTableIndex(index); session.addLocalTempTableIndex(index);
......
...@@ -9,7 +9,7 @@ package org.h2.schema; ...@@ -9,7 +9,7 @@ package org.h2.schema;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import org.h2.command.ddl.CreateTableData;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.constraint.Constraint; import org.h2.constraint.Constraint;
...@@ -21,7 +21,6 @@ import org.h2.engine.User; ...@@ -21,7 +21,6 @@ import org.h2.engine.User;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableData; import org.h2.table.TableData;
import org.h2.table.TableLink; import org.h2.table.TableLink;
...@@ -483,21 +482,14 @@ public class Schema extends DbObjectBase { ...@@ -483,21 +482,14 @@ public class Schema extends DbObjectBase {
/** /**
* Add a table to the schema. * Add a table to the schema.
* *
* @param tableName the table name * @param data the create table information
* @param id the object id
* @param columns the column list
* @param temporary whether this is a temporary table
* @param persistIndexes whether indexes of the table should be persistent
* @param persistData whether data of the table should be persistent
* @param clustered whether a clustered table should be created
* @param headPos the position (page number) of the head
* @param session the session
* @return the created {@link TableData} object * @return the created {@link TableData} object
*/ */
public TableData createTable(String tableName, int id, ObjectArray<Column> columns, boolean temporary, boolean persistIndexes, boolean persistData, boolean clustered, int headPos, Session session) public TableData createTable(CreateTableData data)
throws SQLException { throws SQLException {
synchronized (database) { synchronized (database) {
return new TableData(this, tableName, id, columns, temporary, persistIndexes, persistData, clustered, headPos, session); data.schema = this;
return new TableData(data);
} }
} }
......
...@@ -883,7 +883,7 @@ public class Data extends DataPage { ...@@ -883,7 +883,7 @@ public class Data extends DataPage {
* *
* @param x the value * @param x the value
*/ */
private void writeVarInt(int x) { public void writeVarInt(int x) {
while ((x & ~0x7f) != 0) { while ((x & ~0x7f) != 0) {
data[pos++] = (byte) (0x80 | (x & 0x7f)); data[pos++] = (byte) (0x80 | (x & 0x7f));
x >>>= 7; x >>>= 7;
......
...@@ -11,6 +11,7 @@ import java.io.OutputStream; ...@@ -11,6 +11,7 @@ import java.io.OutputStream;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import org.h2.command.ddl.CreateTableData;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
...@@ -24,6 +25,7 @@ import org.h2.index.PageBtreeNode; ...@@ -24,6 +25,7 @@ import org.h2.index.PageBtreeNode;
import org.h2.index.PageDataLeaf; import org.h2.index.PageDataLeaf;
import org.h2.index.PageDataNode; import org.h2.index.PageDataNode;
import org.h2.index.PageDataOverflow; import org.h2.index.PageDataOverflow;
import org.h2.index.PageDelegateIndex;
import org.h2.index.PageIndex; import org.h2.index.PageIndex;
import org.h2.index.PageScanIndex; import org.h2.index.PageScanIndex;
import org.h2.log.InDoubtTransaction; import org.h2.log.InDoubtTransaction;
...@@ -77,8 +79,13 @@ import org.h2.value.ValueString; ...@@ -77,8 +79,13 @@ import org.h2.value.ValueString;
*/ */
public class PageStore implements CacheWriter { public class PageStore implements CacheWriter {
// TODO can not use delegating index when starting if it was created later
// TODO re-use deleted keys; specially if the primary key is removed
// TODO table row: number of columns should be varInt not int
// TODO implement checksum; 0 for empty pages // TODO implement checksum; 0 for empty pages
// TODO in log, don't store empty space // TODO in log, don't store empty space between page head and page data
// TODO long primary keys don't use delegating index yet (setPos(): int)
// TODO utf-x: test if it's faster // TODO utf-x: test if it's faster
// TODO after opening the database, delay writing until required // TODO after opening the database, delay writing until required
...@@ -111,7 +118,7 @@ public class PageStore implements CacheWriter { ...@@ -111,7 +118,7 @@ public class PageStore implements CacheWriter {
// TODO check for file size (exception if not exact size expected) // TODO check for file size (exception if not exact size expected)
// TODO implement missing code for STORE_BTREE_ROWCOUNT (maybe enable) // TODO implement missing code for STORE_BTREE_ROWCOUNT (maybe enable)
// TODO store dates differently in Data; test moving db to another timezone // TODO store dates differently in Data; test moving db to another timezone
// TODO online backup using bsdif // TODO online backup using bsdiff
// TODO when removing DiskFile: // TODO when removing DiskFile:
// remove CacheObject.blockCount // remove CacheObject.blockCount
...@@ -452,7 +459,7 @@ public class PageStore implements CacheWriter { ...@@ -452,7 +459,7 @@ public class PageStore implements CacheWriter {
p = PageFreeList.read(this, data, pageId); p = PageFreeList.read(this, data, pageId);
break; break;
case Page.TYPE_DATA_LEAF: { case Page.TYPE_DATA_LEAF: {
int indexId = data.readInt(); int indexId = data.readVarInt();
PageScanIndex index = (PageScanIndex) metaObjects.get(indexId); PageScanIndex index = (PageScanIndex) metaObjects.get(indexId);
if (index == null) { if (index == null) {
Message.throwInternalError("index not found " + indexId); Message.throwInternalError("index not found " + indexId);
...@@ -479,7 +486,7 @@ public class PageStore implements CacheWriter { ...@@ -479,7 +486,7 @@ public class PageStore implements CacheWriter {
break; break;
} }
case Page.TYPE_BTREE_LEAF: { case Page.TYPE_BTREE_LEAF: {
int indexId = data.readInt(); int indexId = data.readVarInt();
PageBtreeIndex index = (PageBtreeIndex) metaObjects.get(indexId); PageBtreeIndex index = (PageBtreeIndex) metaObjects.get(indexId);
if (index == null) { if (index == null) {
Message.throwInternalError("index not found " + indexId); Message.throwInternalError("index not found " + indexId);
...@@ -784,7 +791,7 @@ public class PageStore implements CacheWriter { ...@@ -784,7 +791,7 @@ public class PageStore implements CacheWriter {
increaseFileSize(INCREMENT_PAGES); increaseFileSize(INCREMENT_PAGES);
} }
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("allocatePage " + pos); // trace.debug("allocatePage " + pos);
} }
return pos; return pos;
} }
...@@ -807,7 +814,7 @@ public class PageStore implements CacheWriter { ...@@ -807,7 +814,7 @@ public class PageStore implements CacheWriter {
*/ */
public void freePage(int pageId, boolean logUndo, Data old) throws SQLException { public void freePage(int pageId, boolean logUndo, Data old) throws SQLException {
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("freePage " + pageId); // trace.debug("freePage " + pageId);
} }
synchronized (database) { synchronized (database) {
cache.remove(pageId); cache.remove(pageId);
...@@ -900,6 +907,9 @@ public class PageStore implements CacheWriter { ...@@ -900,6 +907,9 @@ public class PageStore implements CacheWriter {
* @param data the data * @param data the data
*/ */
public void writePage(int pageId, Data data) throws SQLException { public void writePage(int pageId, Data data) throws SQLException {
if (pageId <= 0) {
Message.throwInternalError("write to page " + pageId);
}
synchronized (database) { synchronized (database) {
file.seek((long) pageId << pageSizeShift); file.seek((long) pageId << pageSizeShift);
file.write(data.getBytes(), 0, pageSize); file.write(data.getBytes(), 0, pageSize);
...@@ -1080,7 +1090,8 @@ public class PageStore implements CacheWriter { ...@@ -1080,7 +1090,8 @@ public class PageStore implements CacheWriter {
} }
private void openMetaIndex() throws SQLException { private void openMetaIndex() throws SQLException {
ObjectArray<Column> cols = ObjectArray.newInstance(); CreateTableData data = new CreateTableData();
ObjectArray<Column> cols = data.columns;
cols.add(new Column("ID", Value.INT)); cols.add(new Column("ID", Value.INT));
cols.add(new Column("TYPE", Value.INT)); cols.add(new Column("TYPE", Value.INT));
cols.add(new Column("PARENT", Value.INT)); cols.add(new Column("PARENT", Value.INT));
...@@ -1088,8 +1099,15 @@ public class PageStore implements CacheWriter { ...@@ -1088,8 +1099,15 @@ public class PageStore implements CacheWriter {
cols.add(new Column("OPTIONS", Value.STRING)); cols.add(new Column("OPTIONS", Value.STRING));
cols.add(new Column("COLUMNS", Value.STRING)); cols.add(new Column("COLUMNS", Value.STRING));
metaSchema = new Schema(database, 0, "", null, true); metaSchema = new Schema(database, 0, "", null, true);
metaTable = new TableData(metaSchema, "PAGE_INDEX", data.schema = metaSchema;
META_TABLE_ID, cols, false, true, true, false, 0, systemSession); data.tableName = "PAGE_INDEX";
data.id = META_TABLE_ID;
data.temporary = false;
data.persistData = true;
data.persistIndexes = true;
data.headPos = 0;
data.session = systemSession;
metaTable = new TableData(data);
metaIndex = (PageScanIndex) metaTable.getScanIndex( metaIndex = (PageScanIndex) metaTable.getScanIndex(
systemSession); systemSession);
metaObjects.clear(); metaObjects.clear();
...@@ -1115,6 +1133,8 @@ public class PageStore implements CacheWriter { ...@@ -1115,6 +1133,8 @@ public class PageStore implements CacheWriter {
} else { } else {
index.getSchema().remove(index); index.getSchema().remove(index);
} }
} else if (index instanceof PageDelegateIndex) {
index.getSchema().remove(index);
} }
index.remove(systemSession); index.remove(systemSession);
if (reservedPages != null && reservedPages.containsKey(headPos)) { if (reservedPages != null && reservedPages.containsKey(headPos)) {
...@@ -1134,25 +1154,31 @@ public class PageStore implements CacheWriter { ...@@ -1134,25 +1154,31 @@ public class PageStore implements CacheWriter {
String options = row.getValue(4).getString(); String options = row.getValue(4).getString();
String columnList = row.getValue(5).getString(); String columnList = row.getValue(5).getString();
String[] columns = StringUtils.arraySplit(columnList, ',', false); String[] columns = StringUtils.arraySplit(columnList, ',', false);
IndexType indexType = IndexType.createNonUnique(true); String[] ops = StringUtils.arraySplit(options, ',', false);
Index meta; Index meta;
if (trace.isDebugEnabled()) { if (trace.isDebugEnabled()) {
trace.debug("addMeta id=" + id + " type=" + type + " parent=" + parent + " columns=" + columnList); trace.debug("addMeta id=" + id + " type=" + type + " parent=" + parent + " columns=" + columnList);
} }
if (redo) { if (redo && rootPageId != 0) {
writePage(rootPageId, createData()); writePage(rootPageId, createData());
allocatePage(rootPageId); allocatePage(rootPageId);
} }
metaRootPageId.put(id, rootPageId); metaRootPageId.put(id, rootPageId);
if (type == META_TYPE_SCAN_INDEX) { if (type == META_TYPE_SCAN_INDEX) {
ObjectArray<Column> columnArray = ObjectArray.newInstance(); CreateTableData data = new CreateTableData();
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
Column col = new Column("C" + i, Value.INT); Column col = new Column("C" + i, Value.INT);
columnArray.add(col); data.columns.add(col);
} }
String[] ops = StringUtils.arraySplit(options, ',', true); data.schema = metaSchema;
boolean temp = ops.length == 3 && ops[2].equals("temp"); data.tableName = "T" + id;
TableData table = new TableData(metaSchema, "T" + id, id, columnArray, temp, true, true, false, 0, session); data.id = id;
data.temporary = ops[2].equals("temp");
data.persistData = true;
data.persistIndexes = true;
data.headPos = 0;
data.session = session;
TableData table = new TableData(data);
CompareMode mode = CompareMode.getInstance(ops[0], Integer.parseInt(ops[1])); CompareMode mode = CompareMode.getInstance(ops[0], Integer.parseInt(ops[1]));
table.setCompareMode(mode); table.setCompareMode(mode);
meta = table.getScanIndex(session); meta = table.getScanIndex(session);
...@@ -1177,6 +1203,16 @@ public class PageStore implements CacheWriter { ...@@ -1177,6 +1203,16 @@ public class PageStore implements CacheWriter {
ic.column = column; ic.column = column;
cols[i] = ic; cols[i] = ic;
} }
IndexType indexType;
if (ops[3].equals("d")) {
indexType = IndexType.createPrimaryKey(true, false);
Column[] tableColumns = table.getColumns();
for (int i = 0; i < cols.length; i++) {
tableColumns[cols[i].column.getColumnId()].setNullable(false);
}
} else {
indexType = IndexType.createNonUnique(true);
}
meta = table.addIndex(session, "I" + id, id, cols, indexType, id, null); meta = table.addIndex(session, "I" + id, id, cols, indexType, id, null);
} }
metaObjects.put(id, meta); metaObjects.put(id, meta);
...@@ -1214,9 +1250,13 @@ public class PageStore implements CacheWriter { ...@@ -1214,9 +1250,13 @@ public class PageStore implements CacheWriter {
String columnList = buff.toString(); String columnList = buff.toString();
Table table = index.getTable(); Table table = index.getTable();
CompareMode mode = table.getCompareMode(); CompareMode mode = table.getCompareMode();
String options = mode.getName()+ "," + mode.getStrength(); String options = mode.getName()+ "," + mode.getStrength() + ",";
if (table.isTemporary()) { if (table.isTemporary()) {
options += ",temp"; options += "temp";
}
options += ",";
if (index instanceof PageDelegateIndex) {
options += "d";
} }
Row row = metaTable.getTemplateRow(); Row row = metaTable.getTemplateRow();
row.setValue(0, ValueInt.get(index.getId())); row.setValue(0, ValueInt.get(index.getId()));
...@@ -1345,11 +1385,11 @@ public class PageStore implements CacheWriter { ...@@ -1345,11 +1385,11 @@ public class PageStore implements CacheWriter {
/** /**
* Get the root page of an index. * Get the root page of an index.
* *
* @param index the index * @param indexId the index id
* @return the root page * @return the root page
*/ */
public int getRootPageId(PageIndex index) { public int getRootPageId(int indexId) {
return metaRootPageId.get(index.getId()); return metaRootPageId.get(indexId);
} }
// TODO implement checksum // TODO implement checksum
......
...@@ -869,10 +869,6 @@ public abstract class Table extends SchemaObjectBase { ...@@ -869,10 +869,6 @@ public abstract class Table extends SchemaObjectBase {
this.onCommitTruncate = onCommitTruncate; this.onCommitTruncate = onCommitTruncate;
} }
boolean getClustered() {
return false;
}
/** /**
* If the index is still required by a constraint, transfer the ownership to * If the index is still required by a constraint, transfer the ownership to
* it. Otherwise, the index is removed. * it. Otherwise, the index is removed.
......
...@@ -12,6 +12,7 @@ import java.util.HashSet; ...@@ -12,6 +12,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.command.ddl.CreateTableData;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.constraint.Constraint; import org.h2.constraint.Constraint;
...@@ -27,6 +28,7 @@ import org.h2.index.IndexType; ...@@ -27,6 +28,7 @@ import org.h2.index.IndexType;
import org.h2.index.MultiVersionIndex; import org.h2.index.MultiVersionIndex;
import org.h2.index.NonUniqueHashIndex; import org.h2.index.NonUniqueHashIndex;
import org.h2.index.PageBtreeIndex; import org.h2.index.PageBtreeIndex;
import org.h2.index.PageDelegateIndex;
import org.h2.index.PageScanIndex; import org.h2.index.PageScanIndex;
import org.h2.index.RowIndex; import org.h2.index.RowIndex;
import org.h2.index.ScanIndex; import org.h2.index.ScanIndex;
...@@ -34,7 +36,7 @@ import org.h2.index.TreeIndex; ...@@ -34,7 +36,7 @@ import org.h2.index.TreeIndex;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.schema.Schema; import org.h2.result.SortOrder;
import org.h2.schema.SchemaObject; import org.h2.schema.SchemaObject;
import org.h2.store.DataPage; import org.h2.store.DataPage;
import org.h2.store.PageStore; import org.h2.store.PageStore;
...@@ -55,7 +57,6 @@ import org.h2.value.Value; ...@@ -55,7 +57,6 @@ import org.h2.value.Value;
* indexes. There is at least one index, the scan index. * indexes. There is at least one index, the scan index.
*/ */
public class TableData extends Table implements RecordReader { public class TableData extends Table implements RecordReader {
private final boolean clustered;
private RowIndex scanIndex; private RowIndex scanIndex;
private long rowCount; private long rowCount;
private Session lockExclusive; private Session lockExclusive;
...@@ -65,23 +66,21 @@ public class TableData extends Table implements RecordReader { ...@@ -65,23 +66,21 @@ public class TableData extends Table implements RecordReader {
private final ObjectArray<Index> indexes = ObjectArray.newInstance(); private final ObjectArray<Index> indexes = ObjectArray.newInstance();
private long lastModificationId; private long lastModificationId;
private boolean containsLargeObject; private boolean containsLargeObject;
private PageScanIndex mainIndex;
public TableData(Schema schema, String tableName, int id, ObjectArray<Column> columns, public TableData(CreateTableData data) throws SQLException {
boolean temporary, boolean persistIndexes, boolean persistData, boolean clustered, int headPos, Session session) throws SQLException { super(data.schema, data.id, data.tableName, data.persistIndexes, data.persistData);
super(schema, id, tableName, persistIndexes, persistData); Column[] cols = new Column[data.columns.size()];
Column[] cols = new Column[columns.size()]; data.columns.toArray(cols);
columns.toArray(cols);
setColumns(cols); setColumns(cols);
setTemporary(temporary); setTemporary(data.temporary);
this.clustered = clustered; if (database.isPageStoreEnabled() && data.persistData && database.isPersistent()) {
if (!clustered) { mainIndex = new PageScanIndex(this, data.id, IndexColumn.wrap(cols), IndexType.createScan(data.persistData), data.headPos, data.session);
if (database.isPageStoreEnabled() && persistData && database.isPersistent()) { scanIndex = mainIndex;
scanIndex = new PageScanIndex(this, id, IndexColumn.wrap(cols), IndexType.createScan(persistData), headPos, session);
} else { } else {
scanIndex = new ScanIndex(this, id, IndexColumn.wrap(cols), IndexType.createScan(persistData)); scanIndex = new ScanIndex(this, data.id, IndexColumn.wrap(cols), IndexType.createScan(data.persistData));
} }
indexes.add(scanIndex); indexes.add(scanIndex);
}
for (Column col : cols) { for (Column col : cols) {
if (DataType.isLargeObject(col.getType())) { if (DataType.isLargeObject(col.getType())) {
containsLargeObject = true; containsLargeObject = true;
...@@ -188,7 +187,20 @@ public class TableData extends Table implements RecordReader { ...@@ -188,7 +187,20 @@ public class TableData extends Table implements RecordReader {
Index index; Index index;
if (isPersistIndexes() && indexType.isPersistent()) { if (isPersistIndexes() && indexType.isPersistent()) {
if (database.isPageStoreEnabled()) { if (database.isPageStoreEnabled()) {
int mainIndexColumn;
if (database.isStarting() && database.getPageStore().getRootPageId(indexId) != 0) {
mainIndexColumn = -1;
} else if (!database.isStarting() && mainIndex.getRowCount(session) != 0) {
mainIndexColumn = -1;
} else {
mainIndexColumn = getMainIndexColumn(indexType, cols);
}
if (mainIndexColumn != -1) {
mainIndex.setMainIndexColumn(mainIndexColumn);
index = new PageDelegateIndex(this, indexId, indexName, indexType, mainIndex, headPos, session);
} else {
index = new PageBtreeIndex(this, indexId, indexName, cols, indexType, headPos, session); index = new PageBtreeIndex(this, indexId, indexName, cols, indexType, headPos, session);
}
} else { } else {
index = new BtreeIndex(session, this, indexId, indexName, cols, indexType, headPos); index = new BtreeIndex(session, this, indexId, indexName, cols, indexType, headPos);
} }
...@@ -272,6 +284,30 @@ public class TableData extends Table implements RecordReader { ...@@ -272,6 +284,30 @@ public class TableData extends Table implements RecordReader {
return index; return index;
} }
private int getMainIndexColumn(IndexType indexType, IndexColumn[] cols) {
if (mainIndex.getMainIndexColumn() != -1) {
return -1;
}
if (!indexType.isPrimaryKey() || cols.length != 1) {
return -1;
}
IndexColumn first = cols[0];
if (first.sortType != SortOrder.ASCENDING) {
return -1;
}
switch(first.column.getType()) {
case Value.BYTE:
case Value.SHORT:
case Value.INT:
int todoPosIsInt;
// case Value.LONG:
break;
default:
return -1;
}
return first.column.getColumnId();
}
public boolean canGetRowCount() { public boolean canGetRowCount() {
return true; return true;
} }
...@@ -625,8 +661,17 @@ public class TableData extends Table implements RecordReader { ...@@ -625,8 +661,17 @@ public class TableData extends Table implements RecordReader {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
data[i] = s.readValue(); data[i] = s.readValue();
} }
Row row = new Row(data, memoryPerRow); return createRow(data);
return row; }
/**
* Create a row from the values.
*
* @param data the value list
* @return the row
*/
public Row createRow(Value[] data) {
return new Row(data, memoryPerRow);
} }
/** /**
...@@ -706,10 +751,6 @@ public class TableData extends Table implements RecordReader { ...@@ -706,10 +751,6 @@ public class TableData extends Table implements RecordReader {
return lastModificationId; return lastModificationId;
} }
boolean getClustered() {
return clustered;
}
public boolean getContainsLargeObject() { public boolean getContainsLargeObject() {
return containsLargeObject; return containsLargeObject;
} }
......
...@@ -338,15 +338,8 @@ public class TableFilter implements ColumnResolver { ...@@ -338,15 +338,8 @@ public class TableFilter implements ColumnResolver {
*/ */
public Row get() throws SQLException { public Row get() throws SQLException {
if (current == null && currentSearchRow != null) { if (current == null && currentSearchRow != null) {
if (table.getClustered()) {
current = table.getTemplateRow();
for (int i = 0; i < currentSearchRow.getColumnCount(); i++) {
current.setValue(i, currentSearchRow.getValue(i));
}
} else {
current = cursor.get(); current = cursor.get();
} }
}
return current; return current;
} }
......
...@@ -810,10 +810,11 @@ public class Recover extends Tool implements DataHandler { ...@@ -810,10 +810,11 @@ public class Recover extends Tool implements DataHandler {
// type 1 // type 1
case Page.TYPE_DATA_LEAF: { case Page.TYPE_DATA_LEAF: {
pageTypeCount[type]++; pageTypeCount[type]++;
setStorage(s.readInt()); setStorage(s.readVarInt());
int columnCount = s.readVarInt();
int entries = s.readShortInt(); int entries = s.readShortInt();
writer.println("-- page " + page + ": data leaf " + (last ? "(last)" : "") + " table: " + storageId + " entries: " + entries); writer.println("-- page " + page + ": data leaf " + (last ? "(last)" : "") + " table: " + storageId + " entries: " + entries + " columns: " + columnCount);
dumpPageDataLeaf(store, pageSize, writer, s, last, page, entries); dumpPageDataLeaf(store, pageSize, writer, s, last, page, columnCount, entries);
break; break;
} }
// type 2 // type 2
...@@ -832,7 +833,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -832,7 +833,7 @@ public class Recover extends Tool implements DataHandler {
// type 4 // type 4
case Page.TYPE_BTREE_LEAF: { case Page.TYPE_BTREE_LEAF: {
pageTypeCount[type]++; pageTypeCount[type]++;
setStorage(s.readInt()); setStorage(s.readVarInt());
int entries = s.readShortInt(); int entries = s.readShortInt();
writer.println("-- page " + page + ": b-tree leaf " + (last ? "(last)" : "") + " table: " + storageId + " entries: " + entries); writer.println("-- page " + page + ": b-tree leaf " + (last ? "(last)" : "") + " table: " + storageId + " entries: " + entries);
if (trace) { if (trace) {
...@@ -1167,7 +1168,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -1167,7 +1168,7 @@ public class Recover extends Tool implements DataHandler {
} }
} }
private void dumpPageDataLeaf(FileStore store, int pageSize, PrintWriter writer, Data s, boolean last, long pageId, int entryCount) throws SQLException { private void dumpPageDataLeaf(FileStore store, int pageSize, PrintWriter writer, Data s, boolean last, long pageId, int columnCount, int entryCount) throws SQLException {
long[] keys = new long[entryCount]; long[] keys = new long[entryCount];
int[] offsets = new int[entryCount]; int[] offsets = new int[entryCount];
long next = 0; long next = 0;
...@@ -1194,10 +1195,12 @@ public class Recover extends Tool implements DataHandler { ...@@ -1194,10 +1195,12 @@ public class Recover extends Tool implements DataHandler {
store.readFully(s2.getBytes(), 0, pageSize); store.readFully(s2.getBytes(), 0, pageSize);
s2.setPos(4); s2.setPos(4);
int type = s2.readByte(); int type = s2.readByte();
int indexId = s2.readInt();
if (type == (Page.TYPE_DATA_OVERFLOW | Page.FLAG_LAST)) { if (type == (Page.TYPE_DATA_OVERFLOW | Page.FLAG_LAST)) {
int size = s2.readShortInt(); int size = s2.readShortInt();
writer.println("-- chain: " + next + " type: " + type + " size: " + size); writer.println("-- chain: " + next + " type: " + type + " size: " + size);
s.write(s2.getBytes(), 7, size); s.checkCapacity(size);
s.write(s2.getBytes(), s2.length(), size);
break; break;
} else if (type == Page.TYPE_DATA_OVERFLOW) { } else if (type == Page.TYPE_DATA_OVERFLOW) {
next = s2.readInt(); next = s2.readInt();
...@@ -1205,9 +1208,10 @@ public class Recover extends Tool implements DataHandler { ...@@ -1205,9 +1208,10 @@ public class Recover extends Tool implements DataHandler {
writeDataError(writer, "next:0", s2.getBytes(), 1); writeDataError(writer, "next:0", s2.getBytes(), 1);
break; break;
} }
int size = pageSize - 9; int size = pageSize - s2.length();
writer.println("-- chain: " + next + " type: " + type + " size: " + size + " next: " + next); writer.println("-- chain: " + next + " type: " + type + " size: " + size + " next: " + next);
s.write(s2.getBytes(), 9, size); s.checkCapacity(size);
s.write(s2.getBytes(), s2.length(), size);
} else { } else {
writeDataError(writer, "type: " + type, s2.getBytes(), 1); writeDataError(writer, "type: " + type, s2.getBytes(), 1);
break; break;
...@@ -1219,7 +1223,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -1219,7 +1223,7 @@ public class Recover extends Tool implements DataHandler {
int off = offsets[i]; int off = offsets[i];
writer.println("-- [" + i + "] storage: " + storageId + " key: " + key + " off: " + off); writer.println("-- [" + i + "] storage: " + storageId + " key: " + key + " off: " + off);
s.setPos(off); s.setPos(off);
Value[] data = createRecord(writer, s); Value[] data = createRecord(writer, s, columnCount);
if (data != null) { if (data != null) {
createTemporaryTable(writer); createTemporaryTable(writer);
writeRow(writer, s, data); writeRow(writer, s, data);
...@@ -1259,14 +1263,18 @@ public class Recover extends Tool implements DataHandler { ...@@ -1259,14 +1263,18 @@ public class Recover extends Tool implements DataHandler {
} }
private Value[] createRecord(PrintWriter writer, DataPage s) { private Value[] createRecord(PrintWriter writer, DataPage s) {
recordLength = s.readInt(); return createRecord(writer, s, s.readInt());
if (recordLength <= 0) { }
writeDataError(writer, "recordLength<0", s.getBytes(), blockCount);
private Value[] createRecord(PrintWriter writer, DataPage s, int columnCount) {
recordLength = columnCount;
if (columnCount <= 0) {
writeDataError(writer, "columnCount<0", s.getBytes(), blockCount);
return null; return null;
} }
Value[] data; Value[] data;
try { try {
data = new Value[recordLength]; data = new Value[columnCount];
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
writeDataError(writer, "out of memory", s.getBytes(), blockCount); writeDataError(writer, "out of memory", s.getBytes(), blockCount);
return null; return null;
......
...@@ -135,6 +135,8 @@ import org.h2.test.unit.TestValueHashMap; ...@@ -135,6 +135,8 @@ import org.h2.test.unit.TestValueHashMap;
import org.h2.test.unit.TestValueMemory; import org.h2.test.unit.TestValueMemory;
import org.h2.test.utils.OutputCatcher; import org.h2.test.utils.OutputCatcher;
import org.h2.tools.DeleteDbFiles; import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Recover;
import org.h2.tools.RunScript;
import org.h2.tools.Server; import org.h2.tools.Server;
import org.h2.util.MemoryUtils; import org.h2.util.MemoryUtils;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
...@@ -293,6 +295,7 @@ java org.h2.test.TestAll timer ...@@ -293,6 +295,7 @@ java org.h2.test.TestAll timer
System.setProperty("h2.maxMemoryRowsDistinct", "128"); System.setProperty("h2.maxMemoryRowsDistinct", "128");
System.setProperty("h2.check2", "true"); System.setProperty("h2.check2", "true");
int testRecoverToolProcessLog;
/* /*
System.setProperty("h2.optimizeInList", "true"); System.setProperty("h2.optimizeInList", "true");
...@@ -345,16 +348,19 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -345,16 +348,19 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new TestTimer().runTest(test); new TestTimer().runTest(test);
} }
} else { } else {
// System.setProperty(SysProperties.H2_PAGE_STORE, "true"); System.setProperty(SysProperties.H2_PAGE_STORE, "true");
// test.pageStore = true; test.pageStore = true;
// test.runTests();
// TestPerformance.main("-init", "-db", "1");
// Recover.execute("data", null);
System.setProperty(SysProperties.H2_PAGE_STORE, "false");
test.pageStore = false;
test.runTests(); test.runTests();
TestPerformance.main("-init", "-db", "1"); TestPerformance.main("-init", "-db", "1");
Recover.execute("data", null);
RunScript.execute("jdbc:h2:data/test2", "sa1", "sa1", "data/test.h2.sql", null, false);
Recover.execute("data", null);
// System.setProperty(SysProperties.H2_PAGE_STORE, "false");
// test.pageStore = false;
// test.runTests();
// TestPerformance.main("-init", "-db", "1");
} }
System.out.println(TestBase.formatTime(System.currentTimeMillis() - time) + " total"); System.out.println(TestBase.formatTime(System.currentTimeMillis() - time) + " total");
} }
......
...@@ -61,6 +61,7 @@ public class TestBackup extends TestBase { ...@@ -61,6 +61,7 @@ public class TestBackup extends TestBase {
private void testBackup() throws SQLException { private void testBackup() throws SQLException {
deleteDb("backup"); deleteDb("backup");
deleteDb("restored");
Connection conn1, conn2, conn3; Connection conn1, conn2, conn3;
Statement stat1, stat2, stat3; Statement stat1, stat2, stat3;
conn1 = getConnection("backup"); conn1 = getConnection("backup");
......
...@@ -126,8 +126,12 @@ public class TestBigResult extends TestBase { ...@@ -126,8 +126,12 @@ public class TestBigResult extends TestBase {
Connection conn = getConnection("bigResult"); Connection conn = getConnection("bigResult");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("DROP TABLE IF EXISTS TEST"); stat.execute("DROP TABLE IF EXISTS TEST");
stat.execute("CREATE TABLE TEST(" + "ID INT PRIMARY KEY, " + "Name VARCHAR(255), " + "FirstName VARCHAR(255), " stat.execute("CREATE TABLE TEST(" +
+ "Points INT," + "LicenseID INT)"); "ID INT PRIMARY KEY, " +
"Name VARCHAR(255), " +
"FirstName VARCHAR(255), " +
"Points INT," +
"LicenseID INT)");
int len = getSize(10, 5000); int len = getSize(10, 5000);
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST VALUES(?, ?, ?, ?, ?)"); PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST VALUES(?, ?, ?, ?, ?)");
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
......
...@@ -32,6 +32,7 @@ public class TestPageStore extends TestBase { ...@@ -32,6 +32,7 @@ public class TestPageStore extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
testCreatePkLater();
testTruncate(); testTruncate();
testLargeIndex(); testLargeIndex();
testUniqueIndex(); testUniqueIndex();
...@@ -39,6 +40,25 @@ public class TestPageStore extends TestBase { ...@@ -39,6 +40,25 @@ public class TestPageStore extends TestBase {
testFuzzOperations(); testFuzzOperations();
} }
private void testCreatePkLater() throws SQLException {
if (config.memory) {
return;
}
deleteDb("pageStore");
Connection conn;
Statement stat;
conn = getConnection("pageStore");
stat = conn.createStatement();
stat.execute("create table test(id int not null) as select 100");
stat.execute("create primary key on test(id)");
conn.close();
conn = getConnection("pageStore");
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("select * from test where id = 100");
assertTrue(rs.next());
conn.close();
}
private void testTruncate() throws SQLException { private void testTruncate() throws SQLException {
if (config.memory) { if (config.memory) {
return; return;
......
...@@ -610,4 +610,4 @@ lrem lstore monitorexit lmul monitorenter fadd interpreting ishl istore dcmpg ...@@ -610,4 +610,4 @@ lrem lstore monitorexit lmul monitorenter fadd interpreting ishl istore dcmpg
daload dstore saload anewarray tableswitch lushr ladd lshr lreturn acmpne daload dstore saload anewarray tableswitch lushr ladd lshr lreturn acmpne
locals multianewarray icmpne fneg faload ifeq decompiler zeroes forgot locals multianewarray icmpne fneg faload ifeq decompiler zeroes forgot
modern slight boost characteristics significantly gae vfs centrally ten modern slight boost characteristics significantly gae vfs centrally ten
approach risky getters approach risky getters suxxess gmb delegate delegating delegates
\ No newline at end of file \ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论