提交 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;
import org.h2.command.ddl.CreateSequence;
import org.h2.command.ddl.CreateSynonym;
import org.h2.command.ddl.CreateTable;
import org.h2.command.ddl.CreateTableData;
import org.h2.command.ddl.CreateTrigger;
import org.h2.command.ddl.CreateUser;
import org.h2.command.ddl.CreateUserDataType;
......@@ -143,7 +142,6 @@ import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.table.TableFilter.TableFilterVisitor;
import org.h2.table.TableView;
import org.h2.util.ColumnNamer;
import org.h2.util.MathUtils;
import org.h2.util.New;
import org.h2.util.StatementBuilder;
......@@ -1138,7 +1136,7 @@ public class Parser {
command.setQueryAlias(readFromAlias(null, Arrays.asList("ON")));
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(
command.getQueryAlias(), querySQLOutput[0],
columnTemplateList, false/* no recursion */,
......@@ -5162,7 +5160,7 @@ public class Parser {
readIf("RECURSIVE");
// 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");
// this WITH statement is not a temporary view - it is part of a persistent view
......@@ -5278,7 +5276,7 @@ public class Parser {
// to work (its removed after creation in this method)
// only create table data and table if we don't have a working CTE already
if(oldViewFound == null){
recursiveTable = createShadowTableForRecursiveTableExpression(isPersistent, session, cteViewName,
recursiveTable = TableView.createShadowTableForRecursiveTableExpression(isPersistent, session, cteViewName,
schema, columns, db);
}
List<Column> columnTemplateList;
......@@ -5291,10 +5289,10 @@ public class Parser {
withQuery.session = session;
}
read(")");
columnTemplateList = createQueryColumnTemplateList(cols, withQuery, querySQLOutput);
columnTemplateList = TableView.createQueryColumnTemplateList(cols, withQuery, querySQLOutput);
} finally {
destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable);
TableView.destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable);
}
TableView view = createCTEView(cteViewName,
......@@ -5306,85 +5304,6 @@ public class Parser {
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,
List<Column> columnTemplateList, boolean allowRecursiveQueryDetection,
boolean addViewToSession, boolean isPersistent, Session targetSession) {
......
......@@ -49,14 +49,30 @@ import org.h2.value.Value;
*/
public class MVTable extends TableBase {
private static final String NO_EXTRA_INFO = "";
// lock event types for tracing...
private static final String TRACE_LOCK_OK = "ok";
private static final String TRACE_LOCK_WAITING_FOR = "waiting for";
private static final String TRACE_LOCK_REQUESTING_FOR = "requesting for";
private static final String TRACE_LOCK_TIMEOUT_AFTER = "timeout after ";
private static final String TRACE_LOCK_UNLOCK = "unlock";
private static final String TRACE_LOCK_ADDED_FOR = "added for";
private static final String TRACE_LOCK_ADD_UPGRADED_FOR = "add (upgraded) for ";
private enum TraceLockEvent{
TRACE_LOCK_OK("ok"),
TRACE_LOCK_WAITING_FOR("waiting for"),
TRACE_LOCK_REQUESTING_FOR("requesting 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.
......@@ -201,7 +217,7 @@ public class MVTable extends TableBase {
}
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
long max = 0;
boolean checkDeadlock = false;
......@@ -228,11 +244,11 @@ public class MVTable extends TableBase {
max = now + TimeUnit.MILLISECONDS.toNanos(session.getLockTimeout());
} else if (now >= max) {
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());
}
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) {
for (int i = 0; i < 20; i++) {
long free = Runtime.getRuntime().freeMemory();
......@@ -260,7 +276,7 @@ public class MVTable extends TableBase {
if (exclusive) {
if (lockExclusiveSession == null) {
if (lockSharedSessions.isEmpty()) {
traceLock(session, exclusive, TRACE_LOCK_ADDED_FOR);
traceLock(session, exclusive, TraceLockEvent.TRACE_LOCK_ADDED_FOR, NO_EXTRA_INFO);
session.addLock(this);
lockExclusiveSession = session;
if (SysProperties.THREAD_DEADLOCK_DETECTOR) {
......@@ -272,7 +288,7 @@ public class MVTable extends TableBase {
return true;
} else if (lockSharedSessions.size() == 1 &&
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;
if (SysProperties.THREAD_DEADLOCK_DETECTOR) {
if (EXCLUSIVE_LOCKS.get() == null) {
......@@ -298,7 +314,7 @@ public class MVTable extends TableBase {
}
}
if (!lockSharedSessions.containsKey(session)) {
traceLock(session, exclusive, TRACE_LOCK_OK);
traceLock(session, exclusive, TraceLockEvent.TRACE_LOCK_OK, NO_EXTRA_INFO);
session.addLock(this);
lockSharedSessions.put(session, session);
if (SysProperties.THREAD_DEADLOCK_DETECTOR) {
......@@ -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()) {
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());
}
}
......@@ -417,7 +433,7 @@ public class MVTable extends TableBase {
@Override
public void unlock(Session s) {
if (database != null) {
traceLock(s, lockExclusiveSession == s, TRACE_LOCK_UNLOCK);
traceLock(s, lockExclusiveSession == s, TraceLockEvent.TRACE_LOCK_UNLOCK, NO_EXTRA_INFO);
if (lockExclusiveSession == s) {
lockExclusiveSession = null;
if (SysProperties.THREAD_DEADLOCK_DETECTOR) {
......
......@@ -11,8 +11,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.h2.api.ErrorCode;
import org.h2.command.Parser;
import org.h2.command.Prepared;
import org.h2.command.ddl.CreateTableData;
import org.h2.command.dml.Query;
import org.h2.engine.Constants;
import org.h2.engine.Database;
......@@ -709,13 +709,17 @@ public class TableView extends Table {
public List<Table> getTables(){
return tables;
}
public boolean isPersistent() {
return isPersistent;
}
public static TableView createTableViewMaybeRecursive(Schema schema, int id, String name, String querySQL,
ArrayList<Parameter> parameters, Column[] columnTemplates, Session session,
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);
List<Column> columnTemplateList;
......@@ -730,11 +734,11 @@ public class TableView extends Table {
if(isPersistent){
withQuery.setSession(session);
}
columnTemplateList = Parser.createQueryColumnTemplateList(columnNames.toArray(new String[1]),
columnTemplateList = TableView.createQueryColumnTemplateList(columnNames.toArray(new String[1]),
(Query) withQuery, querySQLOutput);
} finally {
Parser.destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable);
TableView.destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable);
}
// build with recursion turned on
......@@ -763,7 +767,83 @@ public class TableView extends Table {
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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论