提交 3db03fa6 authored 作者: Thomas Mueller's avatar Thomas Mueller

Support for not persistent in-memory tables in regular (persistent) databases.

上级 22e939fe
......@@ -18,7 +18,9 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>The H2 Console trimmed the password (removed leading and trailing spaces).
<ul><li>Support for not persistent in-memory tables in regular (persistent) databases
using CREATE MEMORY TABLE(..) NOT PERSISTENT. Thanks a lot to Sergi Vladykin for the patch!
</li><li>The H2 Console trimmed the password (removed leading and trailing spaces).
This is no longer the case, to support encrypted H2 database with an empty user password.
</li><li>The data type of a SUBSTRING method was wrong.
</li><li>ResultSet.findColumn and get methods with column label parameters
......
......@@ -3781,7 +3781,7 @@ public class Parser {
columns.add(new Column(cols[i], Value.STRING));
}
int id = database.allocateObjectId(true, true);
recursiveTable = schema.createTable(tempViewName, id, columns, false, false, Index.EMPTY_HEAD);
recursiveTable = schema.createTable(tempViewName, id, columns, false, true, false, Index.EMPTY_HEAD);
recursiveTable.setTemporary(true);
session.addLocalTempTable(recursiveTable);
String querySQL = StringCache.getNew(sqlCommand.substring(parseIndex));
......@@ -4590,7 +4590,7 @@ public class Parser {
return command;
}
private CreateTable parseCreateTable(boolean temp, boolean globalTemp, boolean persistent) throws SQLException {
private CreateTable parseCreateTable(boolean temp, boolean globalTemp, boolean persistIndexes) throws SQLException {
boolean ifNotExists = readIfNoExists();
String tableName = readIdentifierWithSchema();
if (temp && globalTemp && "SESSION".equals(schemaName)) {
......@@ -4601,7 +4601,7 @@ public class Parser {
}
Schema schema = getSchema();
CreateTable command = new CreateTable(session, schema);
command.setPersistent(persistent);
command.setPersistIndexes(persistIndexes);
command.setTemporary(temp);
command.setGlobalTemporary(globalTemp);
command.setIfNotExists(ifNotExists);
......@@ -4698,6 +4698,9 @@ public class Parser {
} else if (readIf("NOT")) {
read("LOGGED");
}
} else if (!persistIndexes && readIf("NOT")) {
read("PERSISTENT");
command.setPersistData(false);
}
if (readIf("CLUSTERED")) {
command.setClustered(true);
......
......@@ -134,7 +134,7 @@ public class AlterTableAddConstraint extends SchemaCommand {
}
}
if (index == null) {
IndexType indexType = IndexType.createPrimaryKey(table.getPersistent(), primaryKeyHash);
IndexType indexType = IndexType.createPrimaryKey(table.isPersistIndexes(), primaryKeyHash);
String indexName = table.getSchema().getUniqueIndexName(session, table, Constants.PREFIX_PRIMARY_KEY);
int id = getObjectId(true, false);
try {
......@@ -262,10 +262,10 @@ public class AlterTableAddConstraint extends SchemaCommand {
IndexType indexType;
if (unique) {
// for unique constraints
indexType = IndexType.createUnique(t.getPersistent(), false);
indexType = IndexType.createUnique(t.isPersistIndexes(), false);
} else {
// constraints
indexType = IndexType.createNonUnique(t.getPersistent());
indexType = IndexType.createNonUnique(t.isPersistIndexes());
}
indexType.setBelongsToConstraint(true);
String prefix = constraintName == null ? "CONSTRAINT" : constraintName;
......
......@@ -234,14 +234,13 @@ public class AlterTableAlterColumn extends SchemaCommand {
newColumns.remove(position);
newColumns.add(position, newColumn);
}
boolean persistent = table.getPersistent();
// create a table object in order to get the SQL statement
// can't just use this table, because most column objects are 'shared'
// with the old table
// 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)
int id = db.allocateObjectId(true, true);
TableData newTable = getSchema().createTable(tempName, id, newColumns, persistent, false, Index.EMPTY_HEAD);
TableData newTable = getSchema().createTable(tempName, id, newColumns, table.isPersistIndexes(), table.isPersistData(), false, Index.EMPTY_HEAD);
newTable.setComment(table.getComment());
StringBuffer buff = new StringBuffer(newTable.getCreateSQL());
StringBuffer columnList = new StringBuffer();
......
......@@ -59,7 +59,7 @@ public class CreateIndex extends SchemaCommand {
Table table = getSchema().getTableOrView(session, tableName);
session.getUser().checkRight(table, Right.ALL);
table.lock(session, true, true);
if (!table.getPersistent()) {
if (!table.isPersistIndexes()) {
persistent = false;
}
int id = getObjectId(true, false);
......
......@@ -35,7 +35,8 @@ public class CreateTable extends SchemaCommand {
private ObjectArray columns = new ObjectArray();
private IndexColumn[] pkColumns;
private boolean ifNotExists;
private boolean persistent = true;
private boolean persistIndexes = true;
private boolean persistData = true;
private boolean temporary;
private boolean globalTemporary;
private boolean onCommitDrop;
......@@ -103,7 +104,7 @@ public class CreateTable extends SchemaCommand {
session.commit(true);
Database db = session.getDatabase();
if (!db.isPersistent()) {
persistent = false;
persistIndexes = false;
}
if (getSchema().findTableOrView(session, tableName) != null) {
if (ifNotExists) {
......@@ -143,7 +144,7 @@ public class CreateTable extends SchemaCommand {
}
}
int id = getObjectId(true, true);
TableData table = getSchema().createTable(tableName, id, columns, persistent, clustered, headPos);
TableData table = getSchema().createTable(tableName, id, columns, persistIndexes, persistData, clustered, headPos);
table.setComment(comment);
table.setTemporary(temporary);
table.setGlobalTemporary(globalTemporary);
......@@ -239,8 +240,8 @@ public class CreateTable extends SchemaCommand {
return false;
}
public void setPersistent(boolean persistent) {
this.persistent = persistent;
public void setPersistIndexes(boolean persistIndexes) {
this.persistIndexes = persistIndexes;
}
public void setGlobalTemporary(boolean globalTemporary) {
......@@ -269,4 +270,8 @@ public class CreateTable extends SchemaCommand {
this.clustered = clustered;
}
public void setPersistData(boolean persistData) {
this.persistData = persistData;
}
}
......@@ -596,7 +596,7 @@ public class Database implements DataHandler {
if (pageStore != null) {
headPos = pageStore.getSystemTableHeadPos();
}
meta = mainSchema.createTable("SYS", 0, cols, persistent, false, headPos);
meta = mainSchema.createTable("SYS", 0, cols, persistent, persistent, false, headPos);
tableMap.put(0, meta);
IndexColumn[] pkCols = IndexColumn.wrap(new Column[] { columnId });
metaIdIndex = meta.addIndex(systemSession, "SYS_ID", 0, pkCols, IndexType.createPrimaryKey(
......
......@@ -219,7 +219,7 @@ public class PageBtreeIndex extends BaseIndex {
trace.debug("truncate");
}
removeAllRows();
if (tableData.getContainsLargeObject() && tableData.getPersistent()) {
if (tableData.getContainsLargeObject()) {
ValueLob.removeAllForTable(database, table.getId());
}
tableData.setRowCount(0);
......
......@@ -239,7 +239,7 @@ public class PageScanIndex extends BaseIndex implements RowIndex {
trace.debug("truncate");
}
removeAllRows();
if (tableData.getContainsLargeObject() && tableData.getPersistent()) {
if (tableData.getContainsLargeObject() && tableData.isPersistData()) {
ValueLob.removeAllForTable(database, table.getId());
}
tableData.setRowCount(0);
......
......@@ -49,7 +49,7 @@ public class ScanIndex extends BaseIndex implements RowIndex {
sessionRowCount = new HashMap();
}
tableData = table;
if (!database.isPersistent() || id < 0) {
if (!database.isPersistent() || id < 0 || !indexType.getPersistent()) {
return;
}
this.storage = database.getStorage(table, id, true);
......@@ -74,7 +74,7 @@ public class ScanIndex extends BaseIndex implements RowIndex {
} else {
storage.truncate(session);
}
if (tableData.getContainsLargeObject() && tableData.getPersistent()) {
if (tableData.getContainsLargeObject() && tableData.isPersistData()) {
ValueLob.removeAllForTable(database, table.getId());
}
tableData.setRowCount(0);
......
......@@ -480,11 +480,12 @@ TABLE [IF NOT EXISTS] name
[{AUTO_INCREMENT | IDENTITY}[(startInt [, incrementInt])]]
[SELECTIVITY selectivity]
[PRIMARY KEY [HASH] | UNIQUE]
| constraint} [,...] ) [ AS select ] } | { AS select }
| constraint} [,...] ) [AS select] [NOT PERSISTENT] } | { AS select }
","
Creates a new table.
Cached tables (the default) are persistent, and the number or rows is not limited by the main memory.
Memory tables are persistent, but the index data is kept in the main memory, so memory tables should not get too large.
Tables with the NOT PERSISTENT modifier are kept fully in memory, and all rows are lost when the database is closed.
Temporary tables are not persistent. Temporary tables can be global (accessible by all connections)
or local (only accessible by the current connection). The default is for temporary tables is global.
Identity and auto-increment columns are columns with a sequence as the default.
......
......@@ -46,7 +46,7 @@ public class ResultTempTable implements ResultExternal {
columns.add(column);
int tableId = session.getDatabase().allocateObjectId(true, true);
String tableName = "TEMP_RESULT_SET_" + tableId;
table = schema.createTable(tableName, tableId, columns, false, false, Index.EMPTY_HEAD);
table = schema.createTable(tableName, tableId, columns, false, true, false, Index.EMPTY_HEAD);
int indexId = session.getDatabase().allocateObjectId(true, false);
IndexColumn indexColumn = new IndexColumn();
indexColumn.column = column;
......
......@@ -470,14 +470,15 @@ public class Schema extends DbObjectBase {
* @param tableName the table name
* @param id the object id
* @param columns the column list
* @param persistent if the table should be persistent
* @param persistIndexes if indexes of the table should be persistent
* @param persistData if data of the table should be persistent
* @param clustered if a clustered table should be created
* @param headPos the position (page number) of the head
* @return the created {@link TableData} object
*/
public TableData createTable(String tableName, int id, ObjectArray columns, boolean persistent, boolean clustered, int headPos)
public TableData createTable(String tableName, int id, ObjectArray columns, boolean persistIndexes, boolean persistData, boolean clustered, int headPos)
throws SQLException {
return new TableData(this, tableName, id, columns, persistent, clustered, headPos);
return new TableData(this, tableName, id, columns, persistIndexes, persistData, clustered, headPos);
}
/**
......
......@@ -823,7 +823,7 @@ trace.setLevel(TraceSystem.DEBUG);
metaSchema = new Schema(database, 0, "", null, true);
int headPos = metaTableRootPageId;
metaTable = new TableData(metaSchema, "PAGE_INDEX",
META_TABLE_ID, cols, true, false, headPos);
META_TABLE_ID, cols, true, true, false, headPos);
metaIndex = (PageScanIndex) metaTable.getScanIndex(
database.getSystemSession());
metaObjects = new HashMap();
......@@ -865,7 +865,7 @@ trace.setLevel(TraceSystem.DEBUG);
Column col = new Column("C" + i, Value.INT);
columnArray.add(col);
}
TableData table = new TableData(metaSchema, "T" + id, id, columnArray, true, false, headPos);
TableData table = new TableData(metaSchema, "T" + id, id, columnArray, true, true, false, headPos);
meta = table.getScanIndex(database.getSystemSession());
} else {
PageScanIndex p = (PageScanIndex) metaObjects.get(ObjectUtils.getInteger(parent));
......
......@@ -40,7 +40,7 @@ public class FunctionTable extends Table {
private Value cachedValue;
public FunctionTable(Schema schema, Session session, Expression functionExpr, FunctionCall function) throws SQLException {
super(schema, 0, function.getName(), false);
super(schema, 0, function.getName(), false, true);
this.functionExpr = functionExpr;
this.function = function;
if (function instanceof TableFunction) {
......
......@@ -117,7 +117,7 @@ public class MetaTable extends Table {
*/
public MetaTable(Schema schema, int id, int type) throws SQLException {
// tableName will be set later
super(schema, id, null, true);
super(schema, id, null, true, true);
this.type = type;
Column[] cols;
String indexColumnName = null;
......@@ -632,7 +632,7 @@ public class MetaTable extends Table {
storageType = "LOCAL TEMPORARY";
}
} else {
storageType = table.getPersistent() ? "CACHED" : "MEMORY";
storageType = table.isPersistIndexes() ? "CACHED" : "MEMORY";
}
add(rows, new String[] {
// TABLE_CATALOG
......
......@@ -41,7 +41,7 @@ public class RangeTable extends Table {
* @param max the end expression
*/
public RangeTable(Schema schema, Expression min, Expression max) throws SQLException {
super(schema, 0, NAME, true);
super(schema, 0, NAME, true, true);
Column[] cols = new Column[]{
new Column("X", Value.LONG)
};
......
......@@ -84,7 +84,8 @@ public abstract class Table extends SchemaObjectBase {
protected int memoryPerRow;
private final HashMap columnMap = new HashMap();
private final boolean persistent;
private boolean persistIndexes;
private boolean persistData;
private ObjectArray triggers;
private ObjectArray constraints;
private ObjectArray sequences;
......@@ -93,9 +94,10 @@ public abstract class Table extends SchemaObjectBase {
private boolean onCommitDrop, onCommitTruncate;
private Row nullRow;
Table(Schema schema, int id, String name, boolean persistent) {
Table(Schema schema, int id, String name, boolean persistIndexes, boolean persistData) {
initSchemaObjectBase(schema, id, name, Trace.TABLE);
this.persistent = persistent;
this.persistIndexes = persistIndexes;
this.persistData = persistData;
}
public void rename(String newName) throws SQLException {
......@@ -583,10 +585,6 @@ public abstract class Table extends SchemaObjectBase {
}
}
public boolean getPersistent() {
return persistent;
}
private void remove(ObjectArray list, DbObject obj) {
if (list != null) {
int i = list.indexOf(obj);
......@@ -899,4 +897,12 @@ public abstract class Table extends SchemaObjectBase {
return null;
}
public boolean isPersistIndexes() {
return persistIndexes;
}
public boolean isPersistData() {
return persistData;
}
}
......@@ -61,17 +61,17 @@ public class TableData extends Table implements RecordReader {
private boolean containsLargeObject;
public TableData(Schema schema, String tableName, int id, ObjectArray columns,
boolean persistent, boolean clustered, int headPos) throws SQLException {
super(schema, id, tableName, persistent);
boolean persistIndexes, boolean persistData, boolean clustered, int headPos) throws SQLException {
super(schema, id, tableName, persistIndexes, persistData);
Column[] cols = new Column[columns.size()];
columns.toArray(cols);
setColumns(cols);
this.clustered = clustered;
if (!clustered) {
if (SysProperties.PAGE_STORE && database.isPersistent()) {
scanIndex = new PageScanIndex(this, id, IndexColumn.wrap(cols), IndexType.createScan(persistent), headPos);
if (SysProperties.PAGE_STORE && persistData && database.isPersistent()) {
scanIndex = new PageScanIndex(this, id, IndexColumn.wrap(cols), IndexType.createScan(persistData), headPos);
} else {
scanIndex = new ScanIndex(this, id, IndexColumn.wrap(cols), IndexType.createScan(persistent));
scanIndex = new ScanIndex(this, id, IndexColumn.wrap(cols), IndexType.createScan(persistData));
}
indexes.add(scanIndex);
}
......@@ -176,7 +176,7 @@ public class TableData extends Table implements RecordReader {
}
}
Index index;
if (getPersistent() && indexType.getPersistent()) {
if (isPersistIndexes() && indexType.getPersistent()) {
if (SysProperties.PAGE_STORE) {
index = new PageBtreeIndex(this, indexId, indexName, cols, indexType, headPos);
} else {
......@@ -545,7 +545,7 @@ public class TableData extends Table implements RecordReader {
buff.append("LOCAL ");
}
buff.append("TEMPORARY ");
} else if (getPersistent()) {
} else if (isPersistIndexes()) {
buff.append("CACHED ");
} else {
buff.append("MEMORY ");
......@@ -565,6 +565,9 @@ public class TableData extends Table implements RecordReader {
buff.append(column.getCreateSQL());
}
buff.append("\n)");
if (!getTemporary() && !isPersistIndexes() && !isPersistData()) {
buff.append("\nNOT PERSISTENT");
}
return buff.toString();
}
......
......@@ -59,7 +59,7 @@ public class TableLink extends Table {
public TableLink(Schema schema, int id, String name, String driver, String url, String user, String password,
String originalSchema, String originalTable, boolean emitUpdates, boolean force) throws SQLException {
super(schema, id, name, false);
super(schema, id, name, false, true);
this.driver = driver;
this.url = url;
this.user = user;
......
......@@ -48,7 +48,7 @@ public class TableView extends Table {
public TableView(Schema schema, int id, String name, String querySQL, ObjectArray params, String[] columnNames,
Session session, boolean recursive) throws SQLException {
super(schema, id, name, false);
super(schema, id, name, false, true);
this.querySQL = querySQL;
this.columnNames = columnNames;
this.recursive = recursive;
......
create memory table test(id int) as select 1 from dual not persistent;
insert into test values(1);
select count(1) from test;
> 2;
@reconnect;
select count(1) from test;
> 0;
drop table test;
create table test(t clob) as select 1;
select distinct t from test;
> 1;
......
......@@ -167,8 +167,7 @@ public class TestPageStore extends TestBase {
ObjectArray cols = new ObjectArray();
cols.add(new Column("ID", Value.INT));
schema = new Schema(db, 0, "", null, true);
table = new TableData(schema, "PAGE_INDEX",
1, cols, true, false, 100);
table = new TableData(schema, "PAGE_INDEX", 1, cols, true, true, false, 100);
index = (PageScanIndex) table.getScanIndex(
db.getSystemSession());
}
......@@ -178,8 +177,7 @@ public class TestPageStore extends TestBase {
cols.add(new Column("ID", Value.INT));
schema = new Schema(db, 0, "", null, true);
int id = db.allocateObjectId(true, true);
table = new TableData(schema, "BTREE_INDEX",
id, cols, true, false, 100);
table = new TableData(schema, "BTREE_INDEX", id, cols, true, true, false, 100);
id = db.allocateObjectId(true, true);
table.addIndex(db.getSystemSession(), "BTREE", id,
IndexColumn.wrap(table.getColumns()),
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论