提交 c4ddebe6 authored 作者: Owner's avatar Owner

Moved methods into TableView from Parser, converted constants into TraceLogEvents

上级 a361c578
...@@ -43,7 +43,6 @@ import org.h2.command.ddl.CreateSchema; ...@@ -43,7 +43,6 @@ import org.h2.command.ddl.CreateSchema;
import org.h2.command.ddl.CreateSequence; import org.h2.command.ddl.CreateSequence;
import org.h2.command.ddl.CreateSynonym; import org.h2.command.ddl.CreateSynonym;
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;
...@@ -143,7 +142,6 @@ import org.h2.table.Table; ...@@ -143,7 +142,6 @@ import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.table.TableFilter.TableFilterVisitor; import org.h2.table.TableFilter.TableFilterVisitor;
import org.h2.table.TableView; import org.h2.table.TableView;
import org.h2.util.ColumnNamer;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
...@@ -1138,7 +1136,7 @@ public class Parser { ...@@ -1138,7 +1136,7 @@ public class Parser {
command.setQueryAlias(readFromAlias(null, Arrays.asList("ON"))); command.setQueryAlias(readFromAlias(null, Arrays.asList("ON")));
String[] querySQLOutput = new String[]{null}; String[] querySQLOutput = new String[]{null};
List<Column> columnTemplateList = createQueryColumnTemplateList(null, command.getQuery(), querySQLOutput); List<Column> columnTemplateList = TableView.createQueryColumnTemplateList(null, command.getQuery(), querySQLOutput);
TableView temporarySourceTableView = createCTEView( TableView temporarySourceTableView = createCTEView(
command.getQueryAlias(), querySQLOutput[0], command.getQueryAlias(), querySQLOutput[0],
columnTemplateList, false/* no recursion */, columnTemplateList, false/* no recursion */,
...@@ -5162,7 +5160,7 @@ public class Parser { ...@@ -5162,7 +5160,7 @@ public class Parser {
readIf("RECURSIVE"); readIf("RECURSIVE");
// this WITH statement might not be a temporary view - allow optional keyword to tell us that // this WITH statement might not be a temporary view - allow optional keyword to tell us that
// this keyword. This is a work in progress feature and will not be documented // this keyword. This feature will not be documented - H2 internal use only.
boolean isPersistent = readIf("PERSISTENT"); boolean isPersistent = readIf("PERSISTENT");
// this WITH statement is not a temporary view - it is part of a persistent view // this WITH statement is not a temporary view - it is part of a persistent view
...@@ -5278,7 +5276,7 @@ public class Parser { ...@@ -5278,7 +5276,7 @@ public class Parser {
// to work (its removed after creation in this method) // to work (its removed after creation in this method)
// only create table data and table if we don't have a working CTE already // only create table data and table if we don't have a working CTE already
if(oldViewFound == null){ if(oldViewFound == null){
recursiveTable = createShadowTableForRecursiveTableExpression(isPersistent, session, cteViewName, recursiveTable = TableView.createShadowTableForRecursiveTableExpression(isPersistent, session, cteViewName,
schema, columns, db); schema, columns, db);
} }
List<Column> columnTemplateList; List<Column> columnTemplateList;
...@@ -5291,10 +5289,10 @@ public class Parser { ...@@ -5291,10 +5289,10 @@ public class Parser {
withQuery.session = session; withQuery.session = session;
} }
read(")"); read(")");
columnTemplateList = createQueryColumnTemplateList(cols, withQuery, querySQLOutput); columnTemplateList = TableView.createQueryColumnTemplateList(cols, withQuery, querySQLOutput);
} finally { } finally {
destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable); TableView.destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable);
} }
TableView view = createCTEView(cteViewName, TableView view = createCTEView(cteViewName,
...@@ -5306,85 +5304,6 @@ public class Parser { ...@@ -5306,85 +5304,6 @@ public class Parser {
return view; return view;
} }
public static void destroyShadowTableForRecursiveExpression(boolean isPersistent, Session targetSession,
Table recursiveTable) {
if(recursiveTable!=null){
if(isPersistent){
recursiveTable.lock(targetSession, true, true);
targetSession.getDatabase().removeSchemaObject(targetSession, recursiveTable);
}else{
targetSession.removeLocalTempTable(recursiveTable);
}
// both removeSchemaObject and removeLocalTempTable hold meta locks - release them here
targetSession.getDatabase().unlockMeta(targetSession);
}
}
public static Table createShadowTableForRecursiveTableExpression(boolean isPersistent, Session targetSession,
String cteViewName, Schema schema, List<Column> columns, Database db) {
// create table data object
CreateTableData recursiveTableData = new CreateTableData();
recursiveTableData.id = db.allocateObjectId();
recursiveTableData.columns = new ArrayList<Column>(columns);
recursiveTableData.tableName = cteViewName;
recursiveTableData.temporary = !isPersistent;
recursiveTableData.persistData = true;
recursiveTableData.persistIndexes = isPersistent;
recursiveTableData.create = true;
recursiveTableData.session = targetSession;
// this gets a meta table lock that is not released
Table recursiveTable = schema.createTable(recursiveTableData);
if(isPersistent){
// this unlock is to prevent lock leak from schema.createTable()
db.unlockMeta(targetSession);
synchronized (targetSession) {
db.addSchemaObject(targetSession, recursiveTable);
}
}else{
targetSession.addLocalTempTable(recursiveTable);
}
return recursiveTable;
}
/**
* Creates a list of column templates from a query (usually from WITH query,
* but could be any query)
*
* @param cols - an optional list of column names (can be specified by WITH
* clause overriding usual select names)
* @param theQuery - the query object we want the column list for
* @param querySQLOutput - array of length 1 to receive extra 'output' field
* in addition to return value - containing the SQL query of the
* Query object
* @return a list of column object returned by withQuery
*/
public static List<Column> createQueryColumnTemplateList(String[] cols,
Query theQuery, String[] querySQLOutput) {
List<Column> columnTemplateList = new ArrayList<>();
theQuery.prepare();
// String array of length 1 is to receive extra 'output' field in addition to
// return value
querySQLOutput[0] = StringUtils.cache(theQuery.getPlanSQL());
ColumnNamer columnNamer = new ColumnNamer(theQuery.getSession());
ArrayList<Expression> withExpressions = theQuery.getExpressions();
for (int i = 0; i < withExpressions.size(); ++i) {
Expression columnExp = withExpressions.get(i);
// use the passed in column name if supplied, otherwise use alias
// (if found) otherwise use column name derived from column
// expression
String columnName = columnNamer.getColumnName(columnExp,i,cols);
columnTemplateList.add(new Column(columnName,
columnExp.getType()));
}
return columnTemplateList;
}
private TableView createCTEView(String cteViewName, String querySQL, private TableView createCTEView(String cteViewName, String querySQL,
List<Column> columnTemplateList, boolean allowRecursiveQueryDetection, List<Column> columnTemplateList, boolean allowRecursiveQueryDetection,
boolean addViewToSession, boolean isPersistent, Session targetSession) { boolean addViewToSession, boolean isPersistent, Session targetSession) {
......
...@@ -49,14 +49,30 @@ import org.h2.value.Value; ...@@ -49,14 +49,30 @@ import org.h2.value.Value;
*/ */
public class MVTable extends TableBase { public class MVTable extends TableBase {
private static final String NO_EXTRA_INFO = "";
// lock event types for tracing... // lock event types for tracing...
private static final String TRACE_LOCK_OK = "ok";
private static final String TRACE_LOCK_WAITING_FOR = "waiting for"; private enum TraceLockEvent{
private static final String TRACE_LOCK_REQUESTING_FOR = "requesting for";
private static final String TRACE_LOCK_TIMEOUT_AFTER = "timeout after "; TRACE_LOCK_OK("ok"),
private static final String TRACE_LOCK_UNLOCK = "unlock"; TRACE_LOCK_WAITING_FOR("waiting for"),
private static final String TRACE_LOCK_ADDED_FOR = "added for"; TRACE_LOCK_REQUESTING_FOR("requesting for"),
private static final String TRACE_LOCK_ADD_UPGRADED_FOR = "add (upgraded) for "; TRACE_LOCK_TIMEOUT_AFTER("timeout after "),
TRACE_LOCK_UNLOCK("unlock"),
TRACE_LOCK_ADDED_FOR("added for"),
TRACE_LOCK_ADD_UPGRADED_FOR("add (upgraded) for ");
private TraceLockEvent(String eventText){
this.eventText = eventText;
}
private final String eventText;
public String getEventText(){
return eventText;
}
}
/** /**
* The table name this thread is waiting to lock. * The table name this thread is waiting to lock.
...@@ -201,7 +217,7 @@ public class MVTable extends TableBase { ...@@ -201,7 +217,7 @@ public class MVTable extends TableBase {
} }
private void doLock1(Session session, int lockMode, boolean exclusive) { private void doLock1(Session session, int lockMode, boolean exclusive) {
traceLock(session, exclusive, TRACE_LOCK_REQUESTING_FOR); traceLock(session, exclusive, TraceLockEvent.TRACE_LOCK_REQUESTING_FOR, NO_EXTRA_INFO);
// don't get the current time unless necessary // don't get the current time unless necessary
long max = 0; long max = 0;
boolean checkDeadlock = false; boolean checkDeadlock = false;
...@@ -228,11 +244,11 @@ public class MVTable extends TableBase { ...@@ -228,11 +244,11 @@ public class MVTable extends TableBase {
max = now + TimeUnit.MILLISECONDS.toNanos(session.getLockTimeout()); max = now + TimeUnit.MILLISECONDS.toNanos(session.getLockTimeout());
} else if (now >= max) { } else if (now >= max) {
traceLock(session, exclusive, traceLock(session, exclusive,
TRACE_LOCK_TIMEOUT_AFTER + session.getLockTimeout()); TraceLockEvent.TRACE_LOCK_TIMEOUT_AFTER, NO_EXTRA_INFO+session.getLockTimeout());
throw DbException.get(ErrorCode.LOCK_TIMEOUT_1, getName()); throw DbException.get(ErrorCode.LOCK_TIMEOUT_1, getName());
} }
try { try {
traceLock(session, exclusive, TRACE_LOCK_WAITING_FOR); traceLock(session, exclusive, TraceLockEvent.TRACE_LOCK_WAITING_FOR, NO_EXTRA_INFO);
if (database.getLockMode() == Constants.LOCK_MODE_TABLE_GC) { if (database.getLockMode() == Constants.LOCK_MODE_TABLE_GC) {
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
long free = Runtime.getRuntime().freeMemory(); long free = Runtime.getRuntime().freeMemory();
...@@ -260,7 +276,7 @@ public class MVTable extends TableBase { ...@@ -260,7 +276,7 @@ public class MVTable extends TableBase {
if (exclusive) { if (exclusive) {
if (lockExclusiveSession == null) { if (lockExclusiveSession == null) {
if (lockSharedSessions.isEmpty()) { if (lockSharedSessions.isEmpty()) {
traceLock(session, exclusive, TRACE_LOCK_ADDED_FOR); traceLock(session, exclusive, TraceLockEvent.TRACE_LOCK_ADDED_FOR, NO_EXTRA_INFO);
session.addLock(this); session.addLock(this);
lockExclusiveSession = session; lockExclusiveSession = session;
if (SysProperties.THREAD_DEADLOCK_DETECTOR) { if (SysProperties.THREAD_DEADLOCK_DETECTOR) {
...@@ -272,7 +288,7 @@ public class MVTable extends TableBase { ...@@ -272,7 +288,7 @@ public class MVTable extends TableBase {
return true; return true;
} else if (lockSharedSessions.size() == 1 && } else if (lockSharedSessions.size() == 1 &&
lockSharedSessions.containsKey(session)) { lockSharedSessions.containsKey(session)) {
traceLock(session, exclusive, TRACE_LOCK_ADD_UPGRADED_FOR); traceLock(session, exclusive, TraceLockEvent.TRACE_LOCK_ADD_UPGRADED_FOR, NO_EXTRA_INFO);
lockExclusiveSession = session; lockExclusiveSession = session;
if (SysProperties.THREAD_DEADLOCK_DETECTOR) { if (SysProperties.THREAD_DEADLOCK_DETECTOR) {
if (EXCLUSIVE_LOCKS.get() == null) { if (EXCLUSIVE_LOCKS.get() == null) {
...@@ -298,7 +314,7 @@ public class MVTable extends TableBase { ...@@ -298,7 +314,7 @@ public class MVTable extends TableBase {
} }
} }
if (!lockSharedSessions.containsKey(session)) { if (!lockSharedSessions.containsKey(session)) {
traceLock(session, exclusive, TRACE_LOCK_OK); traceLock(session, exclusive, TraceLockEvent.TRACE_LOCK_OK, NO_EXTRA_INFO);
session.addLock(this); session.addLock(this);
lockSharedSessions.put(session, session); lockSharedSessions.put(session, session);
if (SysProperties.THREAD_DEADLOCK_DETECTOR) { if (SysProperties.THREAD_DEADLOCK_DETECTOR) {
...@@ -396,10 +412,10 @@ public class MVTable extends TableBase { ...@@ -396,10 +412,10 @@ public class MVTable extends TableBase {
} }
} }
private void traceLock(Session session, boolean exclusive, String statusText) { private void traceLock(Session session, boolean exclusive, TraceLockEvent eventEnum, String extraInfo) {
if (traceLock.isDebugEnabled()) { if (traceLock.isDebugEnabled()) {
traceLock.debug("{0} {1} {2} {3}", session.getId(), traceLock.debug("{0} {1} {2} {3}", session.getId(),
exclusive ? "exclusive write lock" : "shared read lock", statusText, exclusive ? "exclusive write lock" : "shared read lock", eventEnum.getEventText(),
getName()); getName());
} }
} }
...@@ -417,7 +433,7 @@ public class MVTable extends TableBase { ...@@ -417,7 +433,7 @@ public class MVTable extends TableBase {
@Override @Override
public void unlock(Session s) { public void unlock(Session s) {
if (database != null) { if (database != null) {
traceLock(s, lockExclusiveSession == s, TRACE_LOCK_UNLOCK); traceLock(s, lockExclusiveSession == s, TraceLockEvent.TRACE_LOCK_UNLOCK, NO_EXTRA_INFO);
if (lockExclusiveSession == s) { if (lockExclusiveSession == s) {
lockExclusiveSession = null; lockExclusiveSession = null;
if (SysProperties.THREAD_DEADLOCK_DETECTOR) { if (SysProperties.THREAD_DEADLOCK_DETECTOR) {
......
...@@ -11,8 +11,8 @@ import java.util.HashSet; ...@@ -11,8 +11,8 @@ import java.util.HashSet;
import java.util.List; 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.Parser;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.command.ddl.CreateTableData;
import org.h2.command.dml.Query; import org.h2.command.dml.Query;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
...@@ -710,12 +710,16 @@ public class TableView extends Table { ...@@ -710,12 +710,16 @@ public class TableView extends Table {
return tables; return tables;
} }
public boolean isPersistent() {
return isPersistent;
}
public static TableView createTableViewMaybeRecursive(Schema schema, int id, String name, String querySQL, public static TableView createTableViewMaybeRecursive(Schema schema, int id, String name, String querySQL,
ArrayList<Parameter> parameters, Column[] columnTemplates, Session session, ArrayList<Parameter> parameters, Column[] columnTemplates, Session session,
boolean literalsChecked, boolean isTableExpression, boolean isPersistent, Database db){ boolean literalsChecked, boolean isTableExpression, boolean isPersistent, Database db){
Table recursiveTable = Parser.createShadowTableForRecursiveTableExpression(isPersistent, session, name, Table recursiveTable = TableView.createShadowTableForRecursiveTableExpression(isPersistent, session, name,
schema, Arrays.asList(columnTemplates), db); schema, Arrays.asList(columnTemplates), db);
List<Column> columnTemplateList; List<Column> columnTemplateList;
...@@ -730,11 +734,11 @@ public class TableView extends Table { ...@@ -730,11 +734,11 @@ public class TableView extends Table {
if(isPersistent){ if(isPersistent){
withQuery.setSession(session); withQuery.setSession(session);
} }
columnTemplateList = Parser.createQueryColumnTemplateList(columnNames.toArray(new String[1]), columnTemplateList = TableView.createQueryColumnTemplateList(columnNames.toArray(new String[1]),
(Query) withQuery, querySQLOutput); (Query) withQuery, querySQLOutput);
} finally { } finally {
Parser.destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable); TableView.destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable);
} }
// build with recursion turned on // build with recursion turned on
...@@ -763,7 +767,83 @@ public class TableView extends Table { ...@@ -763,7 +767,83 @@ public class TableView extends Table {
return view; return view;
} }
public boolean isPersistent() {
return isPersistent; /**
* Creates a list of column templates from a query (usually from WITH query,
* but could be any query)
*
* @param cols - an optional list of column names (can be specified by WITH
* clause overriding usual select names)
* @param theQuery - the query object we want the column list for
* @param querySQLOutput - array of length 1 to receive extra 'output' field
* in addition to return value - containing the SQL query of the
* Query object
* @return a list of column object returned by withQuery
*/
public static List<Column> createQueryColumnTemplateList(String[] cols,
Query theQuery, String[] querySQLOutput) {
List<Column> columnTemplateList = new ArrayList<>();
theQuery.prepare();
// String array of length 1 is to receive extra 'output' field in addition to
// return value
querySQLOutput[0] = StringUtils.cache(theQuery.getPlanSQL());
ColumnNamer columnNamer = new ColumnNamer(theQuery.getSession());
ArrayList<Expression> withExpressions = theQuery.getExpressions();
for (int i = 0; i < withExpressions.size(); ++i) {
Expression columnExp = withExpressions.get(i);
// use the passed in column name if supplied, otherwise use alias
// (if found) otherwise use column name derived from column
// expression
String columnName = columnNamer.getColumnName(columnExp,i,cols);
columnTemplateList.add(new Column(columnName,
columnExp.getType()));
}
return columnTemplateList;
}
public static Table createShadowTableForRecursiveTableExpression(boolean isPersistent, Session targetSession,
String cteViewName, Schema schema, List<Column> columns, Database db) {
// create table data object
CreateTableData recursiveTableData = new CreateTableData();
recursiveTableData.id = db.allocateObjectId();
recursiveTableData.columns = new ArrayList<Column>(columns);
recursiveTableData.tableName = cteViewName;
recursiveTableData.temporary = !isPersistent;
recursiveTableData.persistData = true;
recursiveTableData.persistIndexes = isPersistent;
recursiveTableData.create = true;
recursiveTableData.session = targetSession;
// this gets a meta table lock that is not released
Table recursiveTable = schema.createTable(recursiveTableData);
if(isPersistent){
// this unlock is to prevent lock leak from schema.createTable()
db.unlockMeta(targetSession);
synchronized (targetSession) {
db.addSchemaObject(targetSession, recursiveTable);
}
}else{
targetSession.addLocalTempTable(recursiveTable);
}
return recursiveTable;
}
public static void destroyShadowTableForRecursiveExpression(boolean isPersistent, Session targetSession,
Table recursiveTable) {
if(recursiveTable!=null){
if(isPersistent){
recursiveTable.lock(targetSession, true, true);
targetSession.getDatabase().removeSchemaObject(targetSession, recursiveTable);
}else{
targetSession.removeLocalTempTable(recursiveTable);
}
// both removeSchemaObject and removeLocalTempTable hold meta locks - release them here
targetSession.getDatabase().unlockMeta(targetSession);
}
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论