提交 8537c549 authored 作者: Owner's avatar Owner

Issue#573 Remove temp views for CTEs in WITH statement

上级 d351a574
...@@ -7,6 +7,8 @@ package org.h2.command; ...@@ -7,6 +7,8 @@ package org.h2.command;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
...@@ -45,6 +47,8 @@ public abstract class Command implements CommandInterface { ...@@ -45,6 +47,8 @@ public abstract class Command implements CommandInterface {
private boolean canReuse; private boolean canReuse;
private List<Runnable> cleanupCallbacks;
Command(Parser parser, String sql) { Command(Parser parser, String sql) {
this.session = parser.getSession(); this.session = parser.getSession();
this.sql = sql; this.sql = sql;
...@@ -228,6 +232,7 @@ public abstract class Command implements CommandInterface { ...@@ -228,6 +232,7 @@ public abstract class Command implements CommandInterface {
throw e; throw e;
} finally { } finally {
if (callStop) { if (callStop) {
commandCleanup();
stop(); stop();
} }
if (writing) { if (writing) {
...@@ -287,6 +292,7 @@ public abstract class Command implements CommandInterface { ...@@ -287,6 +292,7 @@ public abstract class Command implements CommandInterface {
} finally { } finally {
try { try {
if (callStop) { if (callStop) {
commandCleanup();
stop(); stop();
} }
} finally { } finally {
...@@ -298,6 +304,17 @@ public abstract class Command implements CommandInterface { ...@@ -298,6 +304,17 @@ public abstract class Command implements CommandInterface {
} }
} }
private void commandCleanup() {
if (cleanupCallbacks!=null){
for(Runnable eachCleanup:cleanupCallbacks){
eachCleanup.run();
// clean up done - must restart query (and dependency construction) to reuse
canReuse = false;
}
cleanupCallbacks.clear();
}
}
private long filterConcurrentUpdate(DbException e, long start) { private long filterConcurrentUpdate(DbException e, long start) {
int errorCode = e.getErrorCode(); int errorCode = e.getErrorCode();
if (errorCode != ErrorCode.CONCURRENT_UPDATE_1 && if (errorCode != ErrorCode.CONCURRENT_UPDATE_1 &&
...@@ -370,4 +387,8 @@ public abstract class Command implements CommandInterface { ...@@ -370,4 +387,8 @@ public abstract class Command implements CommandInterface {
} }
} }
public void setCleanupCallbacks(List<Runnable> cleanupCallbacks) {
this.cleanupCallbacks = cleanupCallbacks;
}
} }
...@@ -4899,6 +4899,26 @@ public class Parser { ...@@ -4899,6 +4899,26 @@ public class Parser {
Query q = parseSelectUnion(); Query q = parseSelectUnion();
q.setPrepareAlways(true); q.setPrepareAlways(true);
List<Runnable> cleanupCallbacks = new ArrayList<Runnable>();
// clean up temp views starting with last to first (in case of dependencies)
Collections.reverse(viewsCreated);
for (TableView view : viewsCreated){
if(view==null){
continue;
}
cleanupCallbacks.add(new Runnable(){
@Override
public void run() {
// check if view was previously deleted as their name is set to null
if(view.getName()!=null) {
session.removeLocalTempTable(view);
}
}
});
}
q.setCleanupCallbacks(cleanupCallbacks);
return q; return q;
} }
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
package org.h2.command; package org.h2.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.Database; import org.h2.engine.Database;
...@@ -55,6 +57,7 @@ public abstract class Prepared { ...@@ -55,6 +57,7 @@ public abstract class Prepared {
private int objectId; private int objectId;
private int currentRowNumber; private int currentRowNumber;
private int rowScanCount; private int rowScanCount;
private List<Runnable> cleanupCallbacks;
/** /**
* Create a new object. * Create a new object.
...@@ -173,6 +176,9 @@ public abstract class Prepared { ...@@ -173,6 +176,9 @@ public abstract class Prepared {
*/ */
public void setCommand(Command command) { public void setCommand(Command command) {
this.command = command; this.command = command;
if(command!=null && cleanupCallbacks!=null){
command.setCleanupCallbacks(cleanupCallbacks);
}
} }
/** /**
...@@ -434,4 +440,13 @@ public abstract class Prepared { ...@@ -434,4 +440,13 @@ public abstract class Prepared {
return false; return false;
} }
public List<Runnable> getCleanupCallbacks() {
return cleanupCallbacks;
}
public void setCleanupCallbacks(List<Runnable> cleanupCallbacks) {
this.cleanupCallbacks = cleanupCallbacks;
}
} }
...@@ -381,6 +381,12 @@ SET BINARY_COLLATION ...@@ -381,6 +381,12 @@ SET BINARY_COLLATION
"," ","
Sets the collation used for comparing BINARY columns, the default is SIGNED Sets the collation used for comparing BINARY columns, the default is SIGNED
for version 1." for version 1."
"Commands (Other)","SET BUILTIN_ALIAS_OVERRIDE","
SET BUILTIN_ALIAS_OVERRIDE
{ TRUE | FALSE } ] }
","
Allows the overriding of the builtin system date/time functions
for unit testing purposes."
"Commands (Other)","SET COLLATION"," "Commands (Other)","SET COLLATION","
SET [ DATABASE ] COLLATION SET [ DATABASE ] COLLATION
{ OFF | collationName [ STRENGTH { PRIMARY | SECONDARY | TERTIARY | IDENTICAL } ] } { OFF | collationName [ STRENGTH { PRIMARY | SECONDARY | TERTIARY | IDENTICAL } ] }
......
...@@ -9,6 +9,8 @@ import java.sql.Connection; ...@@ -9,6 +9,8 @@ import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.Statement; import java.sql.Statement;
import org.h2.jdbc.JdbcSQLException;
import org.h2.test.TestBase; import org.h2.test.TestBase;
/** /**
...@@ -186,6 +188,8 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -186,6 +188,8 @@ public class TestGeneralCommonTableQueries extends TestBase {
PreparedStatement prep; PreparedStatement prep;
ResultSet rs; ResultSet rs;
conn.setAutoCommit(false);
prep = conn.prepareStatement("WITH t1 AS (" prep = conn.prepareStatement("WITH t1 AS ("
+" SELECT R.X, 'T1' FROM SYSTEM_RANGE(?1,?2) R" +" SELECT R.X, 'T1' FROM SYSTEM_RANGE(?1,?2) R"
+")," +"),"
...@@ -210,6 +214,16 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -210,6 +214,16 @@ public class TestGeneralCommonTableQueries extends TestBase {
assertFalse(rs.next()); assertFalse(rs.next());
try{
prep = conn.prepareStatement("SELECT * FROM t1 UNION ALL SELECT * FROM t2 UNION ALL SELECT X, 'Q' FROM SYSTEM_RANGE(5,6)");
rs = prep.executeQuery();
fail("Temp view T1 was accessible after previous WITH statement finished - but should not have been.");
}
catch(JdbcSQLException e){
// ensure the T1 table has been removed even without auto commit
assertContains(e.getMessage(),"Table \"T1\" not found;");
}
conn.close(); conn.close();
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论