提交 8ca2feb0 authored 作者: Owner's avatar Owner

Issue#479 Intermediate save before refactor to remove heuristic

上级 f21ea8cd
...@@ -199,10 +199,10 @@ WITH [ RECURSIVE ] { name [( columnName [,...] )] ...@@ -199,10 +199,10 @@ WITH [ RECURSIVE ] { name [( columnName [,...] )]
"," ","
Can be used to create a recursive query. Can be used to create a recursive query.
For recursive queries the first select has to be a UNION. For recursive queries the first select has to be a UNION.
Non-recursive queries are also supported, Non-recursive queries are also supported.
One or more common table entries can be use referred to by name. One or more common table entries can be use referred to by name..
Column name declarations are now optional - the column names will be inferred from the named select queries. Column name declarations are now optional - the column names will be inferred from the named select queries.
Positional parameters are not currently correctly supported. Positional parameters are not currently supported.
"," ","
WITH RECURSIVE t(n) AS ( WITH RECURSIVE t(n) AS (
SELECT 1 SELECT 1
......
...@@ -76,7 +76,7 @@ import org.h2.command.dml.Insert; ...@@ -76,7 +76,7 @@ import org.h2.command.dml.Insert;
import org.h2.command.dml.Merge; import org.h2.command.dml.Merge;
import org.h2.command.dml.NoOperation; import org.h2.command.dml.NoOperation;
import org.h2.command.dml.Query; import org.h2.command.dml.Query;
import org.h2.command.dml.RecursiveQuery; import org.h2.command.dml.RecursiveQueryHeuristic;
import org.h2.command.dml.Replace; import org.h2.command.dml.Replace;
import org.h2.command.dml.RunScriptCommand; import org.h2.command.dml.RunScriptCommand;
import org.h2.command.dml.ScriptCommand; import org.h2.command.dml.ScriptCommand;
...@@ -126,6 +126,7 @@ import org.h2.expression.Variable; ...@@ -126,6 +126,7 @@ import org.h2.expression.Variable;
import org.h2.expression.Wildcard; import org.h2.expression.Wildcard;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.DbNotRecursiveException;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
...@@ -4930,10 +4931,38 @@ public class Parser { ...@@ -4930,10 +4931,38 @@ public class Parser {
session.removeLocalTempTable(recursiveTable); session.removeLocalTempTable(recursiveTable);
} }
int id = database.allocateObjectId(); int id = database.allocateObjectId();
boolean isRecursive = RecursiveQuery.isRecursive(tempViewName,querySQL); boolean isRecursive = true;//RecursiveQueryHeuristic.isRecursive(tempViewName,querySQL);
TableView view = new TableView(schema, id, tempViewName, querySQL, TableView view = null;
do{
try{
view = new TableView(schema, id, tempViewName, querySQL,
parameters, columnTemplateList.toArray(new Column[0]), session, parameters, columnTemplateList.toArray(new Column[0]), session,
isRecursive); isRecursive);
}catch(DbNotRecursiveException e){
if(isRecursive==false){
throw e;
}
isRecursive = false;
view=null;
System.out.println("repeat new table by exeception");
continue;
}
HashSet<DbObject> subDependencies = new HashSet<DbObject>();
view.addStrictSubDependencies(subDependencies,false);
System.out.println("tempViewName="+tempViewName);
System.out.println("subDependencies="+subDependencies);
System.out.println("isRecursiveQueryDetected="+view.isRecursiveQueryDetected());
boolean isRecursiveByDeepAnalysis = subDependencies.contains(recursiveTable);
System.out.println("isRecursiveByDeepAnalysis="+isRecursiveByDeepAnalysis);
if(view.isRecursiveQueryDetected()!=isRecursive){
isRecursive = view.isRecursiveQueryDetected();
view = null;
System.out.println("repeat new table creation by view.isRecursiveQueryDetected()");
continue;
}
} while(view==null);
view.setTableExpression(true); view.setTableExpression(true);
view.setTemporary(true); view.setTemporary(true);
session.addLocalTempTable(view); session.addLocalTempTable(view);
......
...@@ -3,11 +3,11 @@ package org.h2.command.dml; ...@@ -3,11 +3,11 @@ package org.h2.command.dml;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class RecursiveQuery { public class RecursiveQueryHeuristic {
// A query is recursive if it references it's own name in its definition // A query is recursive if it references it's own name in its definition
public static boolean isRecursive(String tempViewName, String querySQL) { public static boolean isRecursive(String tempViewName, String querySQL) {
boolean foundAny = RecursiveQuery.foundAny(tempViewName,querySQL); boolean foundAny = RecursiveQueryHeuristic.foundAny(tempViewName,querySQL);
//System.out.println("foundAny="+foundAny); //System.out.println("foundAny="+foundAny);
return foundAny; return foundAny;
} }
......
...@@ -19,6 +19,7 @@ import org.h2.engine.Session; ...@@ -19,6 +19,7 @@ import org.h2.engine.Session;
import org.h2.expression.Comparison; import org.h2.expression.Comparison;
import org.h2.expression.Parameter; import org.h2.expression.Parameter;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.DbNotRecursiveException;
import org.h2.result.LocalResult; import org.h2.result.LocalResult;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -195,12 +196,12 @@ public class ViewIndex extends BaseIndex implements SpatialIndex { ...@@ -195,12 +196,12 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
query.setNeverLazy(true); query.setNeverLazy(true);
} }
if (!query.isUnion()) { if (!query.isUnion()) {
throw DbException.get(ErrorCode.SYNTAX_ERROR_2, throw DbNotRecursiveException.get(ErrorCode.SYNTAX_ERROR_2,
"recursive queries without UNION ALL"); "recursive queries without UNION ALL");
} }
SelectUnion union = (SelectUnion) query; SelectUnion union = (SelectUnion) query;
if (union.getUnionType() != SelectUnion.UNION_ALL) { if (union.getUnionType() != SelectUnion.UNION_ALL) {
throw DbException.get(ErrorCode.SYNTAX_ERROR_2, throw DbNotRecursiveException.get(ErrorCode.SYNTAX_ERROR_2,
"recursive queries without UNION ALL"); "recursive queries without UNION ALL");
} }
Query left = union.getLeft(); Query left = union.getLeft();
......
...@@ -70,11 +70,11 @@ public class DbException extends RuntimeException { ...@@ -70,11 +70,11 @@ public class DbException extends RuntimeException {
} }
} }
private DbException(SQLException e) { protected DbException(SQLException e) {
super(e.getMessage(), e); super(e.getMessage(), e);
} }
private static String translate(String key, String... params) { protected static String translate(String key, String... params) {
String message = null; String message = null;
if (MESSAGES != null) { if (MESSAGES != null) {
// Tomcat sets final static fields to null sometimes // Tomcat sets final static fields to null sometimes
......
package org.h2.message;
import java.sql.SQLException;
import org.h2.api.ErrorCode;
import org.h2.jdbc.JdbcSQLException;
public class DbNotRecursiveException extends DbException {
private static final long serialVersionUID = -5941745175474148318L;
public static DbNotRecursiveException get(int errorCode, String p1) {
return get(errorCode, new String[] { p1 });
}
public static DbNotRecursiveException get(int errorCode, String... params) {
return new DbNotRecursiveException(getJdbcSQLException(errorCode, null, params));
}
private static JdbcSQLException getJdbcSQLException(int errorCode,
Throwable cause, String... params) {
String sqlstate = ErrorCode.getState(errorCode);
String message = translate(sqlstate, params);
return new JdbcSQLException(message, null, sqlstate, errorCode, cause, null);
}
private DbNotRecursiveException(SQLException e) {
super(e);
}
}
...@@ -738,9 +738,6 @@ public class Column { ...@@ -738,9 +738,6 @@ public class Column {
public String toString() { public String toString() {
return name; return name;
} }
public String toStringWithType() {
return DataType.getTypeClassName(type)+":"+name;
}
/** /**
* Check whether the new column is of the same type and not more restricted * Check whether the new column is of the same type and not more restricted
......
...@@ -144,7 +144,8 @@ public class RangeTable extends Table { ...@@ -144,7 +144,8 @@ public class RangeTable extends Table {
@Override @Override
public TableType getTableType() { public TableType getTableType() {
throw DbException.throwInternalError(toString()); return TableType.SYSTEM_TABLE;
//throw DbException.throwInternalError(toString());
} }
@Override @Override
......
...@@ -352,12 +352,23 @@ public abstract class Table extends SchemaObjectBase { ...@@ -352,12 +352,23 @@ public abstract class Table extends SchemaObjectBase {
} }
/** /**
* Add all objects that this table depends on to the hash set. * Add all objects that this table depends on to the hash set, including this object.
* *
* @param dependencies the current set of dependencies * @param dependencies the current set of dependencies
*/ */
public void addDependencies(HashSet<DbObject> dependencies) { public void addDependencies(HashSet<DbObject> dependencies) {
if (dependencies.contains(this)) { addStrictSubDependencies(dependencies,false);
dependencies.add(this);
}
/**
* Add all objects that this table depends on to the hash set, excluding
* this object (unless it is has recursive references).
*
* @param dependencies the current set of dependencies
*/
public void addStrictSubDependencies(HashSet<DbObject> dependencies, boolean visitColumnTables) {
if (dependencies.contains(this)) {
// avoid endless recursion // avoid endless recursion
return; return;
} }
...@@ -370,14 +381,16 @@ public abstract class Table extends SchemaObjectBase { ...@@ -370,14 +381,16 @@ public abstract class Table extends SchemaObjectBase {
dependencies); dependencies);
for (Column col : columns) { for (Column col : columns) {
col.isEverything(visitor); col.isEverything(visitor);
if(visitColumnTables && col.getTable()!=null){
dependencies.add(col.getTable());
}
} }
if (constraints != null) { if (constraints != null) {
for (Constraint c : constraints) { for (Constraint c : constraints) {
c.isEverything(visitor); c.isEverything(visitor);
} }
} }
dependencies.add(this); }
}
@Override @Override
public ArrayList<DbObject> getChildren() { public ArrayList<DbObject> getChildren() {
......
...@@ -8,7 +8,9 @@ package org.h2.table; ...@@ -8,7 +8,9 @@ package org.h2.table;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.command.dml.Query; import org.h2.command.dml.Query;
...@@ -57,6 +59,7 @@ public class TableView extends Table { ...@@ -57,6 +59,7 @@ public class TableView extends Table {
private Query topQuery; private Query topQuery;
private ResultInterface recursiveResult; private ResultInterface recursiveResult;
private boolean tableExpression; private boolean tableExpression;
private boolean isRecursiveQueryDetected;
public TableView(Schema schema, int id, String name, String querySQL, public TableView(Schema schema, int id, String name, String querySQL,
ArrayList<Parameter> params, Column[] columnTemplates, Session session, ArrayList<Parameter> params, Column[] columnTemplates, Session session,
...@@ -94,6 +97,7 @@ public class TableView extends Table { ...@@ -94,6 +97,7 @@ public class TableView extends Table {
this.querySQL = querySQL; this.querySQL = querySQL;
this.columnTemplates = columnTemplates; this.columnTemplates = columnTemplates;
this.recursive = recursive; this.recursive = recursive;
this.isRecursiveQueryDetected = false;
index = new ViewIndex(this, querySQL, params, recursive); index = new ViewIndex(this, querySQL, params, recursive);
initColumnsAndTables(session); initColumnsAndTables(session);
} }
...@@ -206,6 +210,9 @@ public class TableView extends Table { ...@@ -206,6 +210,9 @@ public class TableView extends Table {
// if it can't be compiled, then it's a 'zero column table' // if it can't be compiled, then it's a 'zero column table'
// this avoids problems when creating the view when opening the // this avoids problems when creating the view when opening the
// database // database
if(isRecursiveQueryExceptionDetected(createException)){
this.isRecursiveQueryDetected = true;
}
tables = New.arrayList(); tables = New.arrayList();
cols = new Column[0]; cols = new Column[0];
if (recursive && columnTemplates != null) { if (recursive && columnTemplates != null) {
...@@ -665,5 +672,32 @@ public class TableView extends Table { ...@@ -665,5 +672,32 @@ public class TableView extends Table {
return true; return true;
} }
} }
/**
* Get a list of the tables used by this query (for recursion detection)
* @return
*/
public List<Table> getTables(){
return tables;
}
public boolean isRecursiveQueryDetected(){
return isRecursiveQueryDetected;
}
private boolean isRecursiveQueryExceptionDetected(DbException exception){
if (exception==null){
return false;
}
if (exception.getErrorCode()!=ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1){
return false;
}
if (! exception.getMessage().contains("\""+this.getName()+"\"")){
return false;
}
return true;
}
} }
...@@ -51,8 +51,9 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -51,8 +51,9 @@ public class TestGeneralCommonTableQueries extends TestBase {
* @param a ignored * @param a ignored
*/ */
public static void main(String... a) throws Exception { public static void main(String... a) throws Exception {
System.out.println("Testing starting");
TestBase.createCaller().init().test(); TestBase.createCaller().init().test();
//System.out.println("Testing done"); System.out.println("Testing done");
} }
@Override @Override
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论