提交 1e9b6d64 authored 作者: S.Vladykin's avatar S.Vladykin

Merge branch 'viewindex' into batchview2

......@@ -31,7 +31,7 @@ public class AlterView extends DefineCommand {
public int update() {
session.commit(true);
session.getUser().checkRight(view, Right.ALL);
DbException e = view.recompile(session, false);
DbException e = view.recompile(session, false, true);
if (e != null) {
throw e;
}
......
......@@ -811,7 +811,7 @@ public class Database implements DataHandler {
if (obj instanceof TableView) {
TableView view = (TableView) obj;
if (view.isInvalid()) {
view.recompile(session, true);
view.recompile(session, true, false);
if (!view.isInvalid()) {
recompileSuccessful = true;
}
......@@ -819,17 +819,7 @@ public class Database implements DataHandler {
}
}
} while (recompileSuccessful);
// when opening a database, views are initialized before indexes,
// so they may not have the optimal plan yet
// this is not a problem, it is just nice to see the newest plan
for (Table obj : getAllTablesAndViews(false)) {
if (obj instanceof TableView) {
TableView view = (TableView) obj;
if (!view.isInvalid()) {
view.recompile(systemSession, true);
}
}
}
TableView.clearIndexCaches(session.getDatabase());
}
private void initMetaTables() {
......
......@@ -482,7 +482,12 @@ public class Session extends SessionWithState {
}
}
Parser parser = new Parser(this);
try {
command = parser.prepareCommand(sql);
} finally {
// we can't reuse sub-query indexes, so just drop the whole cache
subQueryIndexCache = null;
}
if (queryCache != null) {
if (command.isCacheable()) {
queryCache.put(sql, command);
......@@ -1319,8 +1324,8 @@ public class Session extends SessionWithState {
public Map<Object, ViewIndex> getViewIndexCache(boolean subQuery) {
if (subQuery) {
// for sub-queries we don't need to use LRU because it should not grow too large
// for a single query and by the end of the statement we will drop the whole cache
// for sub-queries we don't need to use LRU because the cache should not
// grow too large for a single query (we drop the whole cache in the end of prepareLocal)
if (subQueryIndexCache == null) {
subQueryIndexCache = New.hashMap();
}
......@@ -1510,7 +1515,6 @@ public class Session extends SessionWithState {
*/
public void endStatement() {
startStatement = -1;
subQueryIndexCache = null;
closeTemporaryResults();
}
......
......@@ -13,6 +13,7 @@ import org.h2.api.ErrorCode;
import org.h2.command.Prepared;
import org.h2.command.dml.Query;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.DbObject;
import org.h2.engine.Session;
import org.h2.engine.User;
......@@ -80,10 +81,10 @@ public class TableView extends Table {
String[] oldColumnNames = this.columnNames;
boolean oldRecursive = this.recursive;
init(querySQL, null, columnNames, session, recursive);
DbException e = recompile(session, force);
DbException e = recompile(session, force, true);
if (e != null) {
init(oldQuerySQL, null, oldColumnNames, session, oldRecursive);
recompile(session, true);
recompile(session, true, false);
throw e;
}
}
......@@ -116,10 +117,11 @@ public class TableView extends Table {
*
* @param session the session
* @param force if exceptions should be ignored
* @param clearIndexCache if we need to clear view index cache
* @return the exception if re-compiling this or any dependent view failed
* (only when force is disabled)
*/
public synchronized DbException recompile(Session session, boolean force) {
public synchronized DbException recompile(Session session, boolean force, boolean clearIndexCache) {
try {
compileViewQuery(session, querySQL);
} catch (DbException e) {
......@@ -134,12 +136,15 @@ public class TableView extends Table {
initColumnsAndTables(session);
if (views != null) {
for (TableView v : views) {
DbException e = v.recompile(session, force);
DbException e = v.recompile(session, force, false);
if (e != null && !force) {
return e;
}
}
}
if (clearIndexCache) {
clearIndexCaches(database);
}
return force ? null : createException;
}
......@@ -399,10 +404,14 @@ public class TableView extends Table {
database.removeMeta(session, getId());
querySQL = null;
index = null;
clearIndexCaches(database);
invalidate();
}
public static void clearIndexCaches(Database database) {
for (Session s : database.getSessions(true)) {
s.clearViewIndexCache();
}
invalidate();
}
@Override
......
......@@ -45,7 +45,7 @@ public class TestAnnotationProcessor extends AbstractProcessor {
}
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.RELEASE_6;
return SourceVersion.latest();
}
@Override
......
......@@ -1782,49 +1782,6 @@ public class TestFunctions extends TestBase implements AggregateFunction {
}
private void testAnnotationProcessorsOutput() throws SQLException {
testAnnotationProcessorsOutput_emptyKey();
testAnnotationProcessorsOutput_invalidKey();
testAnnotationProcessorsOutput_oneInvalidKey();
testAnnotationProcessorsOutput_warnAndError();
}
private void testAnnotationProcessorsOutput_emptyKey() throws SQLException {
try {
System.setProperty(TestAnnotationProcessor.MESSAGES_KEY, "");
callCompiledFunction("test_atp_empty_key");
} finally {
System.clearProperty(TestAnnotationProcessor.MESSAGES_KEY);
}
}
private void testAnnotationProcessorsOutput_invalidKey() throws SQLException {
try {
System.setProperty(TestAnnotationProcessor.MESSAGES_KEY, "invalid");
callCompiledFunction("test_atp_invalid_key");
fail();
} catch (JdbcSQLException e) {
assertEquals(ErrorCode.SYNTAX_ERROR_1, e.getErrorCode());
assertContains(e.getMessage(), "'invalid'");
} finally {
System.clearProperty(TestAnnotationProcessor.MESSAGES_KEY);
}
}
private void testAnnotationProcessorsOutput_oneInvalidKey() throws SQLException {
try {
System.setProperty(TestAnnotationProcessor.MESSAGES_KEY, "invalid,foo");
callCompiledFunction("test_atp_one_invalid_key");
fail();
} catch (JdbcSQLException e) {
assertEquals(ErrorCode.SYNTAX_ERROR_1, e.getErrorCode());
assertContains(e.getMessage(), "enum");
assertContains(e.getMessage(), "Kind.invalid");
} finally {
System.clearProperty(TestAnnotationProcessor.MESSAGES_KEY);
}
}
private void testAnnotationProcessorsOutput_warnAndError() throws SQLException {
try {
System.setProperty(TestAnnotationProcessor.MESSAGES_KEY, "WARNING,foo1|ERROR,foo2");
callCompiledFunction("test_atp_warn_and_error");
......
......@@ -10,8 +10,9 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.api.ErrorCode;
import org.h2.engine.Session;
import org.h2.jdbc.JdbcConnection;
import org.h2.test.TestBase;
/**
......@@ -33,7 +34,7 @@ public class TestView extends TestBase {
@Override
public void test() throws SQLException {
deleteDb("view");
testSubQueryViewIndexCache();
testInnerSelectWithRownum();
testInnerSelectWithRange();
testEmptyColumn();
......@@ -51,6 +52,53 @@ public class TestView extends TestBase {
deleteDb("view");
}
public void testSubQueryViewIndexCache() throws SQLException {
if (config.networked) {
return;
}
Connection conn = getConnection("view");
Statement stat = conn.createStatement();
stat.execute("drop table test if exists");
stat.execute("create table test(id int primary key, name varchar(25) unique, age int unique)");
// check that initial cache size is empty
Session s = (Session) ((JdbcConnection) conn).getSession();
s.clearViewIndexCache();
assertTrue(s.getViewIndexCache(true).isEmpty());
assertTrue(s.getViewIndexCache(false).isEmpty());
// create view command should not affect caches
stat.execute("create view v as select * from test");
assertTrue(s.getViewIndexCache(true).isEmpty());
assertTrue(s.getViewIndexCache(false).isEmpty());
// check view index cache
stat.executeQuery("select * from v where id > 0").next();
int size1 = s.getViewIndexCache(false).size();
assertTrue(size1 > 0);
assertTrue(s.getViewIndexCache(true).isEmpty());
stat.executeQuery("select * from v where name = 'xyz'").next();
int size2 = s.getViewIndexCache(false).size();
assertTrue(size2 > size1);
assertTrue(s.getViewIndexCache(true).isEmpty());
// check we did not add anything to view cache if we run a sub-query
stat.executeQuery("select * from (select * from test) where age = 17").next();
int size3 = s.getViewIndexCache(false).size();
assertEquals(size2, size3);
assertTrue(s.getViewIndexCache(true).isEmpty());
// check clear works
s.clearViewIndexCache();
assertTrue(s.getViewIndexCache(false).isEmpty());
assertTrue(s.getViewIndexCache(true).isEmpty());
// drop everything
stat.execute("drop view v");
stat.execute("drop table test");
conn.close();
}
private void testInnerSelectWithRownum() throws SQLException {
Connection conn = getConnection("view");
Statement stat = conn.createStatement();
......
......@@ -14,7 +14,6 @@ import java.net.Socket;
import java.util.HashMap;
import java.util.TreeMap;
import java.util.Map.Entry;
import org.h2.build.code.SwitchSource;
import org.h2.build.doc.XMLParser;
......@@ -401,6 +400,23 @@ public class Build extends BuildBase {
writeFile(new File(fileName), checksums.getBytes());
}
private static String canonicalPath(File file) {
try {
return file.getCanonicalPath();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private FileList excludeTestMetaInfFiles(FileList files) {
FileList testMetaInfFiles = files("src/test/META-INF");
int basePathLength = canonicalPath(new File("src/test")).length();
for (File file : testMetaInfFiles) {
files = files.exclude(canonicalPath(file).substring(basePathLength + 1));
}
return files;
}
/**
* Create the regular h2.jar file.
*/
......@@ -424,6 +440,7 @@ public class Build extends BuildBase {
exclude("*.sh").
exclude("*.txt").
exclude("*.DS_Store");
files = excludeTestMetaInfFiles(files);
jar("bin/h2" + getJarSuffix(), files, "temp");
filter("src/installer/h2.sh", "bin/h2.sh", "h2.jar", "h2" + getJarSuffix());
filter("src/installer/h2.bat", "bin/h2.bat", "h2.jar", "h2" + getJarSuffix());
......@@ -455,6 +472,7 @@ public class Build extends BuildBase {
exclude("*.sh").
exclude("*.txt").
exclude("*.DS_Store");
files = excludeTestMetaInfFiles(files);
files.add(new File("temp/org/h2/tools/DeleteDbFiles.class"));
files.add(new File("temp/org/h2/tools/CompressTool.class"));
jar("bin/h2android" + getJarSuffix(), files, "temp");
......@@ -479,6 +497,7 @@ public class Build extends BuildBase {
exclude("*.sh").
exclude("*.txt").
exclude("*.DS_Store");
files = excludeTestMetaInfFiles(files);
long kb = jar("bin/h2-client" + getJarSuffix(), files, "temp");
if (kb < 350 || kb > 450) {
throw new RuntimeException("Expected file size 350 - 450 KB, got: " + kb);
......@@ -493,6 +512,7 @@ public class Build extends BuildBase {
manifestMVStore();
FileList files = files("temp");
files.exclude("*.DS_Store");
files = excludeTestMetaInfFiles(files);
jar("bin/h2-mvstore" + getJarSuffix(), files, "temp");
}
......@@ -525,6 +545,7 @@ public class Build extends BuildBase {
exclude("*.sh").
exclude("*.txt").
exclude("*.DS_Store");
files = excludeTestMetaInfFiles(files);
files.add(new File("temp/org/h2/tools/DeleteDbFiles.class"));
files.add(new File("temp/org/h2/tools/CompressTool.class"));
jar("bin/h2small" + getJarSuffix(), files, "temp");
......@@ -540,6 +561,7 @@ public class Build extends BuildBase {
FileList files = files("temp/org/h2/jaqu");
files.addAll(files("temp/META-INF/MANIFEST.MF"));
files.exclude("*.DS_Store");
files = excludeTestMetaInfFiles(files);
jar("bin/h2jaqu" + getJarSuffix(), files, "temp");
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论