Unverified 提交 3a7253d5 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #749 from katzyn/build_errors

Fix some build checks in sources
......@@ -199,7 +199,7 @@ public class Parser {
return o1 == o2 ? 0 : compareTableFilters(o1, o2);
}
};
private final Database database;
private final Session session;
/**
......@@ -1136,7 +1136,8 @@ public class Parser {
command.setQueryAlias(readFromAlias(null, Arrays.asList("ON")));
String[] querySQLOutput = new String[]{null};
List<Column> columnTemplateList = TableView.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 */,
......@@ -5153,24 +5154,24 @@ public class Parser {
private Prepared parseWith() {
List<TableView> viewsCreated = new ArrayList<>();
readIf("RECURSIVE");
// this WITH statement might not be a temporary view - allow optional keyword to tell us that
// this keyword. This feature will not be documented - H2 internal use only.
// this WITH statement might not be a temporary view - allow optional keyword to
// tell us that 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
// as in CREATE VIEW abc AS WITH my_cte - this auto detects that condition
if (session.isParsingCreateView()) {
isPersistent = true;
}
do {
viewsCreated.add(parseSingleCommonTableExpression(isPersistent));
} while (readIf(","));
Prepared p = null;
// reverse the order of constructed CTE views - as the destruction order
// (since later created view may depend on previously created views -
// (since later created view may depend on previously created views -
// we preserve that dependency order in the destruction sequence )
// used in setCteCleanups
Collections.reverse(viewsCreated);
......@@ -5220,7 +5221,7 @@ public class Parser {
ArrayList<Column> columns = New.arrayList();
String[] cols = null;
Database db = session.getDatabase();
// column names are now optional - they can be inferred from the named
// query, if not supplied by user
if (readIf("(")) {
......@@ -5231,7 +5232,7 @@ public class Parser {
columns.add(new Column(c, Value.STRING));
}
}
Table oldViewFound = null;
if (isPersistent) {
oldViewFound = getSchema().findTableOrView(session, cteViewName);
......@@ -5251,8 +5252,8 @@ public class Parser {
}
if (isPersistent) {
oldViewFound.lock(session, true, true);
session.getDatabase().removeSchemaObject(session, oldViewFound);
session.getDatabase().removeSchemaObject(session, oldViewFound);
} else {
session.removeLocalTempTable(oldViewFound);
}
......@@ -5275,7 +5276,7 @@ public class Parser {
Query withQuery = parseSelect();
if (isPersistent) {
withQuery.session = session;
}
}
read(")");
columnTemplateList = TableView.createQueryColumnTemplateList(cols, withQuery, querySQLOutput);
......@@ -5285,43 +5286,45 @@ public class Parser {
TableView view = createCTEView(cteViewName,
querySQLOutput[0], columnTemplateList,
true/* allowRecursiveQueryDetection */,
true/* add to session */,
true/* allowRecursiveQueryDetection */,
true/* add to session */,
isPersistent, session);
return view;
}
private TableView createCTEView(String cteViewName, String querySQL,
List<Column> columnTemplateList, boolean allowRecursiveQueryDetection,
List<Column> columnTemplateList, boolean allowRecursiveQueryDetection,
boolean addViewToSession, boolean isPersistent, Session targetSession) {
Database db = targetSession.getDatabase();
Schema schema = getSchemaWithDefault();
int id = db.allocateObjectId();
Column[] columnTemplateArray = columnTemplateList.toArray(new Column[0]);
// No easy way to determine if this is a recursive query up front, so we just compile
// it twice - once without the flag set, and if we didn't see a recursive term,
// then we just compile it again.
TableView view;
synchronized (targetSession) {
synchronized (targetSession) {
view = new TableView(schema, id, cteViewName, querySQL,
parameters, columnTemplateArray, targetSession,
allowRecursiveQueryDetection, false /* literalsChecked */, true /* isTableExpression */, isPersistent);
allowRecursiveQueryDetection, false /* literalsChecked */, true /* isTableExpression */,
isPersistent);
if (!view.isRecursiveQueryDetected() && allowRecursiveQueryDetection) {
if (isPersistent) {
db.addSchemaObject(targetSession, view);
view.lock(targetSession, true, true);
targetSession.getDatabase().removeSchemaObject(targetSession, view);
targetSession.getDatabase().removeSchemaObject(targetSession, view);
} else {
session.removeLocalTempTable(view);
session.removeLocalTempTable(view);
}
view = new TableView(schema, id, cteViewName, querySQL, parameters,
columnTemplateArray, targetSession,
false/* assume recursive */, false /* literalsChecked */, true /* isTableExpression */, isPersistent);
false/* assume recursive */, false /* literalsChecked */, true /* isTableExpression */,
isPersistent);
}
// both removeSchemaObject and removeLocalTempTable hold meta locks
targetSession.getDatabase().unlockMeta(targetSession);
targetSession.getDatabase().unlockMeta(targetSession);
}
view.setTableExpression(true);
view.setTemporary(!isPersistent);
......@@ -6104,7 +6107,7 @@ public class Parser {
ArrayList<Column> columnsToRemove = New.arrayList();
Table table = tableIfTableExists(schema, tableName, ifTableExists);
// For Oracle compatibility - open bracket required
boolean openingBracketDetected = readIf("(");
boolean openingBracketDetected = readIf("(");
do {
String columnName = readColumnIdentifier();
if (table == null) {
......@@ -6118,7 +6121,7 @@ public class Parser {
} while (readIf(","));
if (openingBracketDetected) {
// For Oracle compatibility - close bracket
read(")");
read(")");
}
command.setTableName(tableName);
command.setIfTableExists(ifTableExists);
......@@ -6145,7 +6148,7 @@ public class Parser {
// MySQL compatibility (optional)
readIf("COLUMN");
// Oracle specifies (but will not require) an opening parenthesis
boolean hasOpeningBracket = readIf("(");
boolean hasOpeningBracket = readIf("(");
String columnName = readColumnIdentifier();
AlterTableAlterColumn command = null;
NullConstraintType nullConstraint = parseNotNullConstraint();
......@@ -6754,7 +6757,7 @@ public class Parser {
/**
* Enumeration describing null constraints
*/
private enum NullConstraintType {
private enum NullConstraintType {
NULL_IS_ALLOWED, NULL_IS_NOT_ALLOWED, NO_NULL_CONSTRAINT_FOUND
}
......@@ -6771,19 +6774,19 @@ public class Parser {
if (database.getMode().getEnum() == ModeEnum.Oracle) {
if (readIf("ENABLE")) {
// Leave constraint 'as is'
readIf("VALIDATE");
readIf("VALIDATE");
// Turn off constraint, allow NULLs
if (readIf("NOVALIDATE")) {
if (readIf("NOVALIDATE")) {
nullConstraint = NullConstraintType.NULL_IS_ALLOWED;
}
}
// Turn off constraint, allow NULLs
if (readIf("DISABLE")) {
if (readIf("DISABLE")) {
nullConstraint = NullConstraintType.NULL_IS_ALLOWED;
// ignore validate
readIf("VALIDATE");
readIf("VALIDATE");
// ignore novalidate
readIf("NOVALIDATE");
readIf("NOVALIDATE");
}
}
}
......
......@@ -71,10 +71,10 @@ public class CreateView extends SchemaCommand {
public void setForce(boolean force) {
this.force = force;
}
public void setTableExpression(boolean isTableExpression) {
this.isTableExpression = isTableExpression;
}
}
@Override
public int update() {
......@@ -117,9 +117,12 @@ public class CreateView extends SchemaCommand {
}
if (view == null) {
if (isTableExpression) {
view = TableView.createTableViewMaybeRecursive(getSchema(), id, viewName, querySQL, null, columnTemplatesAsStrings, session, false /* literalsChecked */, isTableExpression, true /*isPersistent*/, db);
view = TableView.createTableViewMaybeRecursive(getSchema(), id, viewName, querySQL, null,
columnTemplatesAsStrings, session, false /* literalsChecked */, isTableExpression,
true /* isPersistent */, db);
} else {
view = new TableView(getSchema(), id, viewName, querySQL, null, columnTemplatesAsUnknowns, session, false/* allow recursive */, false/* literalsChecked */, isTableExpression, true);
view = new TableView(getSchema(), id, viewName, querySQL, null, columnTemplatesAsUnknowns, session,
false/* allow recursive */, false/* literalsChecked */, isTableExpression, true);
}
} else {
// TODO support isTableExpression in replace function...
......@@ -135,10 +138,10 @@ public class CreateView extends SchemaCommand {
} else {
db.updateMeta(session, view);
}
// TODO: if we added any table expressions that aren't used by this view, detect them
// and drop them - otherwise they will leak and never get cleaned up.
return 0;
}
......
......@@ -68,13 +68,13 @@ public class DropView extends SchemaCommand {
}
}
}
// TODO: Where is the ConstraintReferential.CASCADE style drop processing ? It's
// supported from imported keys - but not for dependent db objects
// TODO: Where is the ConstraintReferential.CASCADE style drop processing ? It's
// supported from imported keys - but not for dependent db objects
TableView tableView = (TableView) view;
ArrayList<Table> copyOfDependencies = new ArrayList<Table>(tableView.getTables());
view.lock(session, true, true);
session.getDatabase().removeSchemaObject(session, view);
......
......@@ -80,7 +80,7 @@ import org.h2.value.Value;
* action is always triggered. This is because the embedded UPDATE and DELETE statement's
* returned update row count is used to detect a matching join.
* If neither of the two the statements are provided, no matching join is NEVER detected.
*
*
* A fix for this is now implemented as described below:
* We now generate a "matchSelect" query and use that to always detect
* a match join - rather than relying on UPDATE or DELETE statements.
......
......@@ -1062,10 +1062,11 @@ public class Select extends Query {
Table t = f.getTable();
TableView tableView = t.isView() ? (TableView) t : null;
if (tableView != null && tableView.isRecursive() && tableView.isTableExpression()) {
if (tableView.isPersistent()) {
// skip the generation of plan SQL for this already recursive persistent ctes, since using a with
// statement will re-create the common table expression views.
// skip the generation of plan SQL for this already recursive persistent CTEs,
// since using a with statement will re-create the common table expression
// views.
continue;
} else {
buff.append("WITH RECURSIVE ").append(t.getName()).append('(');
......@@ -1074,7 +1075,7 @@ public class Select extends Query {
buff.appendExceptFirst(",");
buff.append(c.getName());
}
buff.append(") AS ").append(t.getSQL()).append("\n");
buff.append(") AS ").append(t.getSQL()).append("\n");
}
}
}
......
......@@ -90,7 +90,7 @@ import org.h2.value.ValueInt;
public class Database implements DataHandler {
private static int initialPowerOffCount;
private static final ThreadLocal<Session> META_LOCK_DEBUGGING = new ThreadLocal<Session>();
private static final ThreadLocal<Throwable> META_LOCK_DEBUGGING_STACK = new ThreadLocal<Throwable>();
......@@ -768,7 +768,7 @@ public class Database implements DataHandler {
Collections.sort(records);
synchronized (systemSession) {
for (MetaRecord rec : records) {
rec.execute(this, systemSession, eventListener);
rec.execute(this, systemSession, eventListener);
}
}
if (mvStore != null) {
......@@ -902,7 +902,7 @@ public class Database implements DataHandler {
}
}
/**
/**
* Lock the metadata table for updates.
*
* @param session the session
......@@ -933,7 +933,7 @@ public class Database implements DataHandler {
boolean wasLocked = meta.lock(session, true, true);
return wasLocked;
}
/**
* Unlock the metadata table.
*
......@@ -1912,7 +1912,7 @@ public class Database implements DataHandler {
t.getSQL());
}
obj.removeChildrenAndResources(session);
}
removeMeta(session, id);
}
......
......@@ -123,7 +123,7 @@ public class Session extends SessionWithState {
private long modificationMetaID = -1;
private SubQueryInfo subQueryInfo;
private int parsingView;
private Deque<String> viewNameStack = new ArrayDeque<String>();
private Deque<String> viewNameStack = new ArrayDeque<String>();
private int preparingQueryExpression;
private volatile SmallLRUCache<Object, ViewIndex> viewIndexCache;
private HashMap<Object, ViewIndex> subQueryIndexCache;
......@@ -229,6 +229,16 @@ public class Session extends SessionWithState {
return subQueryInfo;
}
/**
* Stores name of currently parsed view in a stack so it can be determined
* during {@code prepare()}.
*
* @param parsingView
* {@code true} to store one more name, {@code false} to remove it
* from stack
* @param viewName
* name of the view
*/
public void setParsingCreateView(boolean parsingView, String viewName) {
// It can be recursive, thus implemented as counter.
this.parsingView += parsingView ? 1 : -1;
......@@ -238,7 +248,7 @@ public class Session extends SessionWithState {
} else {
assert viewName.equals(viewNameStack.peek());
viewNameStack.pop();
}
}
}
public String getParsingCreateViewName() {
if (viewNameStack.size() == 0) {
......@@ -695,7 +705,7 @@ public class Session extends SessionWithState {
Analyze.analyzeTable(this, table, rows, false);
}
// analyze can lock the meta
database.unlockMeta(this);
database.unlockMeta(this);
}
tablesToAnalyze = null;
}
......
......@@ -121,7 +121,7 @@ public interface JdbcStatementBackwardsCompat {
/**
* Enquotes the specified identifier.
*
* @param identifier
* @param identifier
* identifier to quote if required
* @param alwaysQuote
* if {@code true} identifier will be quoted unconditionally
......
......@@ -62,12 +62,12 @@ public class MVTable extends TableBase {
* The tables names this thread has a shared lock on.
*/
public static final DebuggingThreadLocal<ArrayList<String>> SHARED_LOCKS;
/**
* The type of trace lock events
*/
private enum TraceLockEvent{
TRACE_LOCK_OK("ok"),
TRACE_LOCK_WAITING_FOR("waiting for"),
TRACE_LOCK_REQUESTING_FOR("requesting for"),
......@@ -81,13 +81,13 @@ public class MVTable extends TableBase {
TraceLockEvent(String eventText) {
this.eventText = eventText;
}
public String getEventText() {
return eventText;
}
}
private static final String NO_EXTRA_INFO = "";
static {
if (SysProperties.THREAD_DEADLOCK_DETECTOR) {
WAITING_FOR_LOCK = new DebuggingThreadLocal<>();
......@@ -428,7 +428,7 @@ public class MVTable extends TableBase {
public boolean isLockedExclusivelyBy(Session session) {
return lockExclusiveSession == session;
}
@Override
public void unlock(Session s) {
if (database != null) {
......
......@@ -299,7 +299,7 @@ public class FilePathDisk extends FilePath {
// file name with a colon
if (name.startsWith(CLASSPATH_PREFIX)) {
String fileName = name.substring(CLASSPATH_PREFIX.length());
// Force absolute resolution in Class.getResourceAsStream
// Force absolute resolution in Class.getResourceAsStream
if (!fileName.startsWith("/")) {
fileName = "/" + fileName;
}
......
......@@ -1239,7 +1239,7 @@ public abstract class Table extends SchemaObjectBase {
public boolean isMVStore() {
return false;
}
public void setTableExpression(boolean tableExpression) {
this.tableExpression = tableExpression;
}
......
......@@ -67,7 +67,8 @@ public class TableView extends Table {
ArrayList<Parameter> params, Column[] columnTemplates, Session session,
boolean allowRecursive, boolean literalsChecked, boolean isTableExpression, boolean isPersistent) {
super(schema, id, name, false, true);
init(querySQL, params, columnTemplates, session, allowRecursive, literalsChecked, isTableExpression, isPersistent);
init(querySQL, params, columnTemplates, session, allowRecursive, literalsChecked, isTableExpression,
isPersistent);
}
/**
......@@ -90,7 +91,7 @@ public class TableView extends Table {
session, recursive, literalsChecked, isTableExpression, isPersistent);
DbException e = recompile(session, force, true);
if (e != null) {
init(oldQuerySQL, null, oldColumnTemplates, session, oldRecursive,
init(oldQuerySQL, null, oldColumnTemplates, session, oldRecursive,
literalsChecked, isTableExpression, isPersistent);
recompile(session, true, false);
throw e;
......@@ -98,7 +99,7 @@ public class TableView extends Table {
}
private synchronized void init(String querySQL, ArrayList<Parameter> params,
Column[] columnTemplates, Session session, boolean allowRecursive, boolean literalsChecked,
Column[] columnTemplates, Session session, boolean allowRecursive, boolean literalsChecked,
boolean isTableExpression, boolean isPersistent) {
this.querySQL = querySQL;
this.columnTemplates = columnTemplates;
......@@ -555,7 +556,7 @@ public class TableView extends Table {
String querySQL = query.getPlanSQL();
TableView v = new TableView(mainSchema, 0, name,
querySQL, query.getParameters(), null /* column templates */, session,
false/* allow recursive */, true /* literals have already been checked when parsing original query */,
false/* allow recursive */, true /* literals have already been checked when parsing original query */,
false /* is table expression */, false/* is persistent*/);
if (v.createException != null) {
throw v.createException;
......@@ -705,7 +706,7 @@ public class TableView extends Table {
}
return true;
}
public List<Table> getTables() {
return tables;
}
......@@ -713,11 +714,11 @@ public class TableView extends Table {
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 = TableView.createShadowTableForRecursiveTableExpression(isPersistent, session, name,
schema, Arrays.asList(columnTemplates), db);
......@@ -728,42 +729,44 @@ public class TableView extends Table {
for (Column columnTemplate: columnTemplates) {
columnNames.add(columnTemplate.getName());
}
try {
Prepared withQuery = session.prepare(querySQL, false, false);
if (isPersistent) {
withQuery.setSession(session);
}
columnTemplateList = TableView.createQueryColumnTemplateList(columnNames.toArray(new String[1]),
}
columnTemplateList = TableView.createQueryColumnTemplateList(columnNames.toArray(new String[1]),
(Query) withQuery, querySQLOutput);
} finally {
TableView.destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable);
}
// build with recursion turned on
TableView view = new TableView(schema, id, name, querySQL,
parameters, columnTemplateList.toArray(columnTemplates), session,
true/* try recursive */, literalsChecked, isTableExpression, isPersistent);
// is recursion really detected ? if not - recreate it without recursion flag and no recursive index
// is recursion really detected ? if not - recreate it without recursion flag
// and no recursive index
if (!view.isRecursiveQueryDetected()) {
if (isPersistent) {
db.addSchemaObject(session, view);
view.lock(session, true, true);
session.getDatabase().removeSchemaObject(session, view);
// during database startup - this method does not normally get called - and it needs to be
// to correctly un-register the table which the table expression uses...
// during database startup - this method does not normally get called - and it
// needs to be to correctly un-register the table which the table expression
// uses...
view.removeChildrenAndResources(session);
} else {
session.removeLocalTempTable(view);
session.removeLocalTempTable(view);
}
view = new TableView(schema, id, name, querySQL, parameters,
columnTemplates, session,
false/* detected not recursive */, literalsChecked, isTableExpression, isPersistent);
false/* detected not recursive */, literalsChecked, isTableExpression, isPersistent);
}
return view;
}
......@@ -797,14 +800,14 @@ public class TableView extends Table {
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();
......@@ -815,10 +818,10 @@ public class TableView extends Table {
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);
......@@ -837,11 +840,11 @@ public class TableView extends Table {
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);
}
......
......@@ -190,7 +190,7 @@ public class SourceCompiler {
/**
* Whether the passed source can be compiled using {@link javax.script.ScriptEngineManager}.
*
*
* @param source the source to test.
* @return <code>true</code> if {@link #getCompiledScript(String)} can be called.
*/
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.db;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.test.TestBase;
/**
* Base class for common table expression tests
*/
public abstract class AbstractBaseForCommonTableExpressions extends TestBase {
protected void testRepeatedQueryWithSetup(int maxRetries, String[] expectedRowData, String[] expectedColumnNames, int expectedNumbeOfRows, String setupSQL,
String withQuery, int closeAndReopenDatabaseConnectionOnIteration, String[] expectedColumnTypes) throws SQLException {
deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries");
PreparedStatement prep;
ResultSet rs;
for (int queryRunTries = 1; queryRunTries <= maxRetries; queryRunTries++) {
Statement stat = conn.createStatement();
stat.execute(setupSQL);
stat.close();
// close and re-open connection for one iteration to make sure the query work between connections
if (queryRunTries == closeAndReopenDatabaseConnectionOnIteration) {
conn.close();
conn = getConnection("commonTableExpressionQueries");
}
prep = conn.prepareStatement(withQuery);
rs = prep.executeQuery();
for (int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++) {
assertTrue(rs.getMetaData().getColumnLabel(columnIndex) != null);
assertEquals(expectedColumnNames[columnIndex - 1], rs.getMetaData().getColumnLabel(columnIndex));
assertEquals("wrongly type column "+rs.getMetaData().getColumnLabel(columnIndex)+" on iteration#"+queryRunTries,
expectedColumnTypes[columnIndex - 1], rs.getMetaData().getColumnTypeName(columnIndex));
}
int rowNdx = 0;
while (rs.next()) {
StringBuffer buf = new StringBuffer();
for (int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++) {
buf.append("|"+rs.getString(columnIndex));
}
assertEquals(expectedRowData[rowNdx], buf.toString());
rowNdx++;
}
assertEquals(expectedNumbeOfRows, rowNdx);
rs.close();
prep.close();
}
conn.close();
deleteDb("commonTableExpressionQueries");
}
}
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.db;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.test.TestBase;
/**
* Base class for common table expression tests
*/
public abstract class AbstractBaseForCommonTableExpressions extends TestBase {
protected void testRepeatedQueryWithSetup(int maxRetries, String[] expectedRowData, String[] expectedColumnNames,
int expectedNumberOfRows, String setupSQL, String withQuery,
int closeAndReopenDatabaseConnectionOnIteration, String[] expectedColumnTypes) throws SQLException {
deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries");
PreparedStatement prep;
ResultSet rs;
for (int queryRunTries = 1; queryRunTries <= maxRetries; queryRunTries++) {
Statement stat = conn.createStatement();
stat.execute(setupSQL);
stat.close();
// close and re-open connection for one iteration to make sure the query work
// between connections
if (queryRunTries == closeAndReopenDatabaseConnectionOnIteration) {
conn.close();
conn = getConnection("commonTableExpressionQueries");
}
prep = conn.prepareStatement(withQuery);
rs = prep.executeQuery();
for (int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++) {
assertTrue(rs.getMetaData().getColumnLabel(columnIndex) != null);
assertEquals(expectedColumnNames[columnIndex - 1], rs.getMetaData().getColumnLabel(columnIndex));
assertEquals(
"wrong type of column " + rs.getMetaData().getColumnLabel(columnIndex) + " on iteration #"
+ queryRunTries,
expectedColumnTypes[columnIndex - 1], rs.getMetaData().getColumnTypeName(columnIndex));
}
int rowNdx = 0;
while (rs.next()) {
StringBuffer buf = new StringBuffer();
for (int columnIndex = 1; columnIndex <= rs.getMetaData().getColumnCount(); columnIndex++) {
buf.append("|" + rs.getString(columnIndex));
}
assertEquals(expectedRowData[rowNdx], buf.toString());
rowNdx++;
}
assertEquals(expectedNumberOfRows, rowNdx);
rs.close();
prep.close();
}
conn.close();
deleteDb("commonTableExpressionQueries");
}
}
......@@ -302,7 +302,8 @@ public class TestCases extends TestBase {
throws SQLException {
assertThrows(expectedDropSuccess ? 0 : ErrorCode.CANNOT_DROP_2, stat)
.execute("drop table test " + (restrict ? "restrict" : "cascade"));
assertThrows(expectedDropSuccess ? ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 : 0, stat).execute("select * from test");
assertThrows(expectedDropSuccess ? ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 : 0, stat)
.execute("select * from test");
}
private void testDropTableNoReference(final boolean stdDropTableRestrict, final boolean restrict)
......
......@@ -2061,7 +2061,8 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertThrows(ErrorCode.INVALID_VALUE_2, stat).execute("select signal('00145', 'success class is invalid')");
assertThrows(ErrorCode.INVALID_VALUE_2, stat).execute("select signal('foo', 'SQLSTATE has 5 chars')");
assertThrows(ErrorCode.INVALID_VALUE_2, stat).execute("select signal('Ab123', 'SQLSTATE has only digits or upper-case letters')");
assertThrows(ErrorCode.INVALID_VALUE_2, stat)
.execute("select signal('Ab123', 'SQLSTATE has only digits or upper-case letters')");
try {
stat.execute("select signal('AB123', 'some custom error')");
fail("Should have thrown");
......
......@@ -78,8 +78,8 @@ public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExp
"t1(n) as (select 2 as first) " +
",t2(n) as (select 3 as first) " +
"select * from t1 union all select * from t2 where n<>?");
prep.setInt(1, 0);
prep.setInt(1, 0);
rs = prep.executeQuery();
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
......@@ -93,7 +93,7 @@ public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExp
",t3(n) as (select 4 as first) " +
"select * from t1 union all select * from t2 union all select * from t3 where n<>?");
prep.setInt(1, 4);
prep.setInt(1, 4);
rs = prep.executeQuery();
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
......@@ -116,8 +116,8 @@ public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExp
",t2 as (select first_col+1 from t1) " +
",t3 as (select 4 as first_col) " +
"select * from t1 union all select * from t2 union all select * from t3 where first_col<>?");
prep.setInt(1, 4);
prep.setInt(1, 4);
rs = prep.executeQuery();
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
......@@ -474,13 +474,13 @@ public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExp
conn.close();
deleteDb("commonTableExpressionQueries");
}
private void testSimple4RowRecursiveQuery() throws Exception {
String[] expectedRowData = new String[]{"|1", "|2", "|3"};
String[] expectedColumnTypes = new String[]{"INTEGER"};
String[] expectedColumnNames = new String[]{"N"};
String setupSQL = "-- do nothing";
String withQuery = "with recursive r(n) as (\n"+
"(select 1) union all (select n+1 from r where n < 3)\n"+
......@@ -489,18 +489,18 @@ public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExp
int maxRetries = 3;
int expectedNumberOfRows = expectedRowData.length;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, setupSQL,
withQuery, maxRetries - 1, expectedColumnTypes);
}
}
private void testSimple2By4RowRecursiveQuery() throws Exception {
String[] expectedRowData = new String[]{"|0|1|10", "|1|2|11", "|2|3|12", "|3|4|13"};
String[] expectedColumnTypes = new String[]{"INTEGER", "INTEGER", "INTEGER"};
String[] expectedColumnNames = new String[]{"K", "N", "N2"};
String setupSQL = "-- do nothing";
String withQuery = "with \n"+
"r1(n,k) as ((select 1, 0) union all (select n+1,k+1 from r1 where n <= 3)),"+
......@@ -509,31 +509,33 @@ public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExp
int maxRetries = 3;
int expectedNumberOfRows = expectedRowData.length;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, setupSQL,
withQuery, maxRetries - 1, expectedColumnTypes);
}
}
private void testSimple3RowRecursiveQueryWithLazyEval() throws Exception {
String[] expectedRowData = new String[]{"|6"};
String[] expectedColumnTypes = new String[]{"BIGINT"};
String[] expectedColumnNames = new String[]{"SUM(N)"};
// back up the config - to restore it after this test
TestAll backupConfig = config;
config = new TestAll();
try {
//Test with settings: lazy mvStore memory mvcc multiThreaded
// connection url is =mem:script;MV_STORE=true;LOG=1;LOCK_TIMEOUT=50;MVCC=TRUE;MULTI_THREADED=TRUE;LAZY_QUERY_EXECUTION=1
// Test with settings: lazy mvStore memory mvcc multiThreaded
// connection url is
// mem:script;MV_STORE=true;LOG=1;LOCK_TIMEOUT=50;MVCC=TRUE;
// MULTI_THREADED=TRUE;LAZY_QUERY_EXECUTION=1
config.lazy = true;
config.mvStore = true;
config.memory = true;
config.mvcc = true;
config.multiThreaded = true;
String setupSQL = "--no config set";
String withQuery = "select sum(n) from (\n"
+" with recursive r(n) as (\n"
......@@ -541,15 +543,15 @@ public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExp
+" )\n"
+" select n from r \n"
+")\n";
int maxRetries = 10;
int expectedNumberOfRows = expectedRowData.length;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, setupSQL,
withQuery, maxRetries - 1, expectedColumnTypes);
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows,
setupSQL, withQuery, maxRetries - 1, expectedColumnTypes);
} finally {
config = backupConfig;
}
}
}
}
......@@ -53,7 +53,7 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
" */\n" +
" /* scanCount: 1 */\n" +
"WHERE BB.A IS A.VAL)"};
String setupSQL =
"DROP TABLE IF EXISTS A; "
+"DROP TABLE IF EXISTS B; "
......@@ -74,7 +74,7 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
+"INSERT INTO C VALUES('carrot', 'imperator'); "
+"INSERT INTO C VALUES(null, 'banapple'); "
+"INSERT INTO A VALUES('meat'); ";
String withQuery = "WITH BB as (SELECT \n" +
"sum(1) as X, \n" +
"a \n" +
......@@ -87,14 +87,14 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
"FROM A \n" + "GROUP BY A.val";
int maxRetries = 3;
int expectedNumberOfRows = expectedRowData.length;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, setupSQL,
withQuery, maxRetries - 1, expectedColumnTypes);
}
private void testPersistentRecursiveTableInCreateView() throws Exception {
String setuoSQL = "--SET TRACE_LEVEL_SYSTEM_OUT 3;\n"
private void testPersistentRecursiveTableInCreateView() throws Exception {
String setupSQL = "--SET TRACE_LEVEL_SYSTEM_OUT 3;\n"
+"DROP TABLE IF EXISTS my_tree; \n"
+"DROP VIEW IF EXISTS v_my_tree; \n"
+"CREATE TABLE my_tree ( \n"
......@@ -119,7 +119,7 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
+"), \n"
+"unused_cte AS ( SELECT 1 AS unUsedColumn ) \n"
+"SELECT sub_tree_root_id, tree_level, parent_fk, child_fk FROM tree_cte; \n";
String withQuery = "SELECT * FROM v_my_tree";
int maxRetries = 4;
String[] expectedRowData = new String[]{"|1|0|null|1",
......@@ -135,13 +135,13 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
"|1|2|null|121"
};
String[] expectedColumnNames = new String[]{"SUB_TREE_ROOT_ID", "TREE_LEVEL", "PARENT_FK", "CHILD_FK"};
String[] expectedColumnTypes = new String[]{"INTEGER", "INTEGER", "INTEGER", "INTEGER"};
String[] expectedColumnTypes = new String[]{"INTEGER", "INTEGER", "INTEGER", "INTEGER"};
int expectedNumberOfRows = 11;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, setuoSQL,
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, setupSQL,
withQuery, maxRetries - 1, expectedColumnTypes);
}
private void testPersistentNonRecursiveTableInCreateView() throws Exception {
private void testPersistentNonRecursiveTableInCreateView() throws Exception {
String setupSQL = ""
+"DROP VIEW IF EXISTS v_my_nr_tree; \n"
+"DROP TABLE IF EXISTS my_table; \n"
......@@ -163,7 +163,7 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
+"), \n"
+"unused_cte AS ( SELECT 1 AS unUsedColumn ) \n"
+"SELECT sub_tree_root_id, tree_level, parent_fk, child_fk FROM tree_cte_nr; \n";
String withQuery = "SELECT * FROM v_my_nr_tree";
int maxRetries = 6;
String[] expectedRowData = new String[]{
......@@ -174,7 +174,7 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
"|121|0|12|121",
};
String[] expectedColumnNames = new String[]{"SUB_TREE_ROOT_ID", "TREE_LEVEL", "PARENT_FK", "CHILD_FK"};
String[] expectedColumnTypes = new String[]{"INTEGER", "INTEGER", "INTEGER", "INTEGER"};
String[] expectedColumnTypes = new String[]{"INTEGER", "INTEGER", "INTEGER", "INTEGER"};
int expectedNumberOfRows = 5;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, setupSQL,
withQuery, maxRetries - 1, expectedColumnTypes);
......
......@@ -506,7 +506,8 @@ public class TestTriggersConstraints extends TestBase implements Trigger {
} else if ("javascript".equals(sourceLang)) {
String triggerClassName = this.getClass().getName() + "."
+ TestTriggerAlterTable.class.getSimpleName();
final String body = "//javascript\nnew Packages." + triggerClassName + "();";
final String body = "//javascript\n"
+ "new Packages." + triggerClassName + "();";
stat.execute("create trigger test_upd before insert on test as $$"
+ body + " $$");
} else {
......
......@@ -75,11 +75,11 @@ public class TestMvccMultiThreaded2 extends TestBase {
// give any of the 100 threads a chance to start by yielding the processor to them
Thread.yield();
// gather stats on threads after they finished
@SuppressWarnings("unused")
int minProcessed = Integer.MAX_VALUE, maxProcessed = 0, totalProcessed = 0;
for (SelectForUpdate sfu : threads) {
// make sure all threads have stopped by joining with them
sfu.join();
......@@ -91,12 +91,13 @@ public class TestMvccMultiThreaded2 extends TestBase {
minProcessed = sfu.iterationsProcessed;
}
}
if (DISPLAY_STATS) {
System.out.println(String.format("+ INFO: TestMvccMultiThreaded2 RUN STATS threads=%d, minProcessed=%d, maxProcessed=%d, "+
"totalProcessed=%d, averagePerThread=%d, averagePerThreadPerSecond=%d\n",
TEST_THREAD_COUNT, minProcessed, maxProcessed, totalProcessed, totalProcessed/TEST_THREAD_COUNT,
totalProcessed/(TEST_THREAD_COUNT * TEST_TIME_SECONDS)));
System.out.println(String.format(
"+ INFO: TestMvccMultiThreaded2 RUN STATS threads=%d, minProcessed=%d, maxProcessed=%d, "
+ "totalProcessed=%d, averagePerThread=%d, averagePerThreadPerSecond=%d\n",
TEST_THREAD_COUNT, minProcessed, maxProcessed, totalProcessed, totalProcessed / TEST_THREAD_COUNT,
totalProcessed / (TEST_THREAD_COUNT * TEST_TIME_SECONDS)));
}
IOUtils.closeSilently(conn);
......@@ -107,7 +108,7 @@ public class TestMvccMultiThreaded2 extends TestBase {
* Worker test thread selecting for update
*/
private class SelectForUpdate extends Thread {
public int iterationsProcessed;
@Override
......@@ -118,10 +119,10 @@ public class TestMvccMultiThreaded2 extends TestBase {
try {
conn = getConnection(getTestName() + URL);
conn.setAutoCommit(false);
// give the other threads a chance to start up before going into our work loop
Thread.yield();
while (!done) {
try {
PreparedStatement ps = conn.prepareStatement(
......@@ -148,7 +149,7 @@ public class TestMvccMultiThreaded2 extends TestBase {
} catch (Exception e) {
TestBase.logError("General error from thread "+getName(), e);
throw e;
}
}
IOUtils.closeSilently(conn);
}
}
......
......@@ -135,7 +135,7 @@ public class TestScript extends TestBase {
}
for (String s : new String[] { "with", "mergeUsing" }) {
testScript("dml/" + s + ".sql");
}
}
deleteDb("script");
System.out.flush();
}
......
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
CREATE TABLE PARENT(ID INT, NAME VARCHAR, PRIMARY KEY(ID) );
> ok
MERGE INTO PARENT AS P
USING (SELECT X AS ID, 'Coco'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S
ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID)
WHEN MATCHED THEN
UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT
MATCHED THEN
INSERT (ID, NAME) VALUES (S.ID, S.NAME);
> update count: 2
SELECT * FROM PARENT;
> ID NAME
> -- -----
> 1 Coco1
> 2 Coco2
EXPLAIN PLAN
MERGE INTO PARENT AS P
USING (SELECT X AS ID, 'Coco'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S
ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID)
WHEN MATCHED THEN
UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT
MATCHED THEN
INSERT (ID, NAME) VALUES (S.ID, S.NAME);
> PLAN
> ---------------------------------------------------------------------------------------------------------------------------------
> MERGE INTO PUBLIC.PARENT(ID, NAME) KEY(ID) SELECT X AS ID, ('Coco' || X) AS NAME FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */
\ No newline at end of file
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
CREATE TABLE PARENT(ID INT, NAME VARCHAR, PRIMARY KEY(ID) );
> ok
MERGE INTO PARENT AS P
USING (SELECT X AS ID, 'Coco'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S
ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID)
WHEN MATCHED THEN
UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT
MATCHED THEN
INSERT (ID, NAME) VALUES (S.ID, S.NAME);
> update count: 2
SELECT * FROM PARENT;
> ID NAME
> -- -----
> 1 Coco1
> 2 Coco2
EXPLAIN PLAN
MERGE INTO PARENT AS P
USING (SELECT X AS ID, 'Coco'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S
ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID)
WHEN MATCHED THEN
UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT
MATCHED THEN
INSERT (ID, NAME) VALUES (S.ID, S.NAME);
> PLAN
> ---------------------------------------------------------------------------------------------------------------------------------
> MERGE INTO PUBLIC.PARENT(ID, NAME) KEY(ID) SELECT X AS ID, ('Coco' || X) AS NAME FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */
\ No newline at end of file
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
explain with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r;
> PLAN
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> WITH RECURSIVE R(N) AS ( (SELECT 1 FROM SYSTEM_RANGE(1, 1) /* PUBLIC.RANGE_INDEX */) UNION ALL (SELECT (N + 1) FROM PUBLIC.R /* PUBLIC.R.tableScan */ WHERE N < 3) ) SELECT N FROM R R /* null */
> rows: 1
select sum(n) from (
with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r
);
> SUM(N)
> ------
> 6
> rows: 1
select sum(n) from (select 0) join (
with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r
) on 1=1;
> SUM(N)
> ------
> 6
> rows: 1
select 0 from (
select 0 where 0 in (
with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r
)
);
> 0
> -
> rows: 0
with
r0(n,k) as (select -1, 0),
r1(n,k) as ((select 1, 0) union all (select n+1,k+1 from r1 where n <= 3)),
r2(n,k) as ((select 10,0) union all (select n+1,k+1 from r2 where n <= 13))
select r1.k, r0.n as N0, r1.n AS N1, r2.n AS n2 from r0 inner join r1 ON r1.k= r0.k inner join r2 ON r1.k= r2.k;
> K N0 N1 N2
> - -- -- --
> 0 -1 1 10
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
explain with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r;
> PLAN
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> WITH RECURSIVE R(N) AS ( (SELECT 1 FROM SYSTEM_RANGE(1, 1) /* PUBLIC.RANGE_INDEX */) UNION ALL (SELECT (N + 1) FROM PUBLIC.R /* PUBLIC.R.tableScan */ WHERE N < 3) ) SELECT N FROM R R /* null */
> rows: 1
select sum(n) from (
with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r
);
> SUM(N)
> ------
> 6
> rows: 1
select sum(n) from (select 0) join (
with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r
) on 1=1;
> SUM(N)
> ------
> 6
> rows: 1
select 0 from (
select 0 where 0 in (
with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r
)
);
> 0
> -
> rows: 0
with
r0(n,k) as (select -1, 0),
r1(n,k) as ((select 1, 0) union all (select n+1,k+1 from r1 where n <= 3)),
r2(n,k) as ((select 10,0) union all (select n+1,k+1 from r2 where n <= 13))
select r1.k, r0.n as N0, r1.n AS N1, r2.n AS n2 from r0 inner join r1 ON r1.k= r0.k inner join r2 ON r1.k= r2.k;
> K N0 N1 N2
> - -- -- --
> 0 -1 1 10
> rows: 1
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论