提交 573ff799 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 d93bc0ff
...@@ -106,6 +106,7 @@ import org.h2.expression.Parameter; ...@@ -106,6 +106,7 @@ import org.h2.expression.Parameter;
import org.h2.expression.Rownum; import org.h2.expression.Rownum;
import org.h2.expression.SequenceValue; import org.h2.expression.SequenceValue;
import org.h2.expression.Subquery; import org.h2.expression.Subquery;
import org.h2.expression.TableFunction;
import org.h2.expression.ValueExpression; import org.h2.expression.ValueExpression;
import org.h2.expression.Variable; import org.h2.expression.Variable;
import org.h2.expression.Wildcard; import org.h2.expression.Wildcard;
...@@ -1889,7 +1890,8 @@ public class Parser { ...@@ -1889,7 +1890,8 @@ public class Parser {
read(")"); read(")");
break; break;
} }
case Function.TABLE: { case Function.TABLE:
case Function.TABLE_DISTINCT: {
int i = 0; int i = 0;
ObjectArray columns = new ObjectArray(); ObjectArray columns = new ObjectArray();
do { do {
...@@ -1901,7 +1903,8 @@ public class Parser { ...@@ -1901,7 +1903,8 @@ public class Parser {
i++; i++;
} while (readIf(",")); } while (readIf(","));
read(")"); read(")");
function.setColumns(columns); TableFunction tf = (TableFunction) function;
tf.setColumns(columns);
break; break;
} }
default: default:
......
...@@ -105,7 +105,7 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -105,7 +105,7 @@ public class AlterTableAddConstraint extends SchemaCommand {
} }
if (index == null) { if (index == null) {
IndexType indexType = IndexType.createPrimaryKey(table.isPersistent(), primaryKeyHash); IndexType indexType = IndexType.createPrimaryKey(table.isPersistent(), primaryKeyHash);
String indexName = getSchema().getUniqueIndexName(table, Constants.PREFIX_PRIMARY_KEY); String indexName = table.getSchema().getUniqueIndexName(table, Constants.PREFIX_PRIMARY_KEY);
int id = getObjectId(true, false); int id = getObjectId(true, false);
try { try {
index = table.addIndex(session, indexName, id, indexColumns, indexType, Index.EMPTY_HEAD, null); index = table.addIndex(session, indexName, id, indexColumns, indexType, Index.EMPTY_HEAD, null);
...@@ -237,7 +237,7 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -237,7 +237,7 @@ public class AlterTableAddConstraint extends SchemaCommand {
} }
indexType.setBelongsToConstraint(true); indexType.setBelongsToConstraint(true);
String prefix = constraintName == null ? "CONSTRAINT" : constraintName; String prefix = constraintName == null ? "CONSTRAINT" : constraintName;
String indexName = getSchema().getUniqueIndexName(t, prefix + "_INDEX_"); String indexName = t.getSchema().getUniqueIndexName(t, prefix + "_INDEX_");
Index idx; Index idx;
try { try {
idx = t.addIndex(session, indexName, indexId, cols, indexType, Index.EMPTY_HEAD, null); idx = t.addIndex(session, indexName, indexId, cols, indexType, Index.EMPTY_HEAD, null);
...@@ -281,11 +281,6 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -281,11 +281,6 @@ public class AlterTableAddConstraint extends SchemaCommand {
if (index.getTable() != table || !index.getIndexType().isUnique()) { if (index.getTable() != table || !index.getIndexType().isUnique()) {
return false; return false;
} }
if (index.getIndexType().belongsToConstraint()) {
// the constraint might be dropped (also in an alter table
// statement)
return false;
}
Column[] indexCols = index.getColumns(); Column[] indexCols = index.getColumns();
if (indexCols.length > cols.length) { if (indexCols.length > cols.length) {
return false; return false;
...@@ -309,11 +304,6 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -309,11 +304,6 @@ public class AlterTableAddConstraint extends SchemaCommand {
// can't use the scan index or index of another table // can't use the scan index or index of another table
return false; return false;
} }
if (index.getIndexType().belongsToConstraint()) {
// the constraint might be dropped (also in an alter table
// statement)
return false;
}
Column[] indexCols = index.getColumns(); Column[] indexCols = index.getColumns();
if (indexCols.length < cols.length) { if (indexCols.length < cols.length) {
return false; return false;
......
...@@ -71,9 +71,9 @@ public class CreateIndex extends SchemaCommand { ...@@ -71,9 +71,9 @@ public class CreateIndex extends SchemaCommand {
} }
int id = getObjectId(true, false); int id = getObjectId(true, false);
if (primaryKey) { if (primaryKey) {
indexName = getSchema().getUniqueIndexName(table, Constants.PREFIX_PRIMARY_KEY); indexName = table.getSchema().getUniqueIndexName(table, Constants.PREFIX_PRIMARY_KEY);
} else if (indexName == null) { } else if (indexName == null) {
indexName = getSchema().getUniqueIndexName(table, Constants.PREFIX_INDEX); indexName = table.getSchema().getUniqueIndexName(table, Constants.PREFIX_INDEX);
} }
if (getSchema().findIndex(indexName) != null) { if (getSchema().findIndex(indexName) != null) {
if (ifNotExists) { if (ifNotExists) {
......
...@@ -308,6 +308,13 @@ public class ScriptCommand extends ScriptBase { ...@@ -308,6 +308,13 @@ public class ScriptCommand extends ScriptBase {
tempLobTableCreated = false; tempLobTableCreated = false;
} }
ObjectArray constraints = db.getAllSchemaObjects(DbObject.CONSTRAINT); ObjectArray constraints = db.getAllSchemaObjects(DbObject.CONSTRAINT);
constraints.sort(new Comparator() {
public int compare(Object o1, Object o2) {
Constraint c1 = (Constraint) o1;
Constraint c2 = (Constraint) o2;
return c1.compareTo(c2);
}
});
for (int i = 0; i < constraints.size(); i++) { for (int i = 0; i < constraints.size(); i++) {
Constraint constraint = (Constraint) constraints.get(i); Constraint constraint = (Constraint) constraints.get(i);
add(constraint.getCreateSQLWithoutIndexes(), false); add(constraint.getCreateSQLWithoutIndexes(), false);
......
...@@ -9,6 +9,7 @@ import java.sql.SQLException; ...@@ -9,6 +9,7 @@ import java.sql.SQLException;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.schema.Schema; import org.h2.schema.Schema;
...@@ -19,7 +20,7 @@ import org.h2.table.Table; ...@@ -19,7 +20,7 @@ import org.h2.table.Table;
/** /**
* The base class for constraint checking. * The base class for constraint checking.
*/ */
public abstract class Constraint extends SchemaObjectBase { public abstract class Constraint extends SchemaObjectBase implements Comparable {
/** /**
* The constraint type name for check constraints. * The constraint type name for check constraints.
...@@ -72,6 +73,13 @@ public abstract class Constraint extends SchemaObjectBase { ...@@ -72,6 +73,13 @@ public abstract class Constraint extends SchemaObjectBase {
*/ */
public abstract boolean usesIndex(Index index); public abstract boolean usesIndex(Index index);
/**
* This index is now the owner of the specified index.
*
* @param index
*/
public abstract void setIndexOwner(Index index);
/** /**
* Check if this constraint contains the given column. * Check if this constraint contains the given column.
* *
...@@ -136,4 +144,29 @@ public abstract class Constraint extends SchemaObjectBase { ...@@ -136,4 +144,29 @@ public abstract class Constraint extends SchemaObjectBase {
return null; return null;
} }
private int getConstraintTypeOrder() {
String constraintType = getConstraintType();
if (CHECK.equals(constraintType)) {
return 0;
} else if (PRIMARY_KEY.equals(constraintType)) {
return 1;
} else if (UNIQUE.equals(constraintType)) {
return 2;
} else if (REFERENTIAL.equals(constraintType)) {
return 3;
} else {
throw Message.getInternalError("type: " + constraintType);
}
}
public int compareTo(Object other) {
if (this == other) {
return 0;
}
Constraint otherConstraint = (Constraint) other;
int thisType = getConstraintTypeOrder();
int otherType = otherConstraint.getConstraintTypeOrder();
return thisType - otherType;
}
} }
...@@ -98,6 +98,10 @@ public class ConstraintCheck extends Constraint { ...@@ -98,6 +98,10 @@ public class ConstraintCheck extends Constraint {
return false; return false;
} }
public void setIndexOwner(Index index) {
throw Message.getInternalError();
}
public boolean containsColumn(Column col) { public boolean containsColumn(Column col) {
// TODO check constraints / containsColumn: this is cheating, maybe the // TODO check constraints / containsColumn: this is cheating, maybe the
// column is not referenced // column is not referenced
......
...@@ -202,10 +202,10 @@ public class ConstraintReferential extends Constraint { ...@@ -202,10 +202,10 @@ public class ConstraintReferential extends Constraint {
table.removeConstraint(this); table.removeConstraint(this);
refTable.removeConstraint(this); refTable.removeConstraint(this);
if (indexOwner) { if (indexOwner) {
database.removeSchemaObject(session, index); table.removeIndexOrTransferOwnership(session, index);
} }
if (refIndexOwner) { if (refIndexOwner) {
database.removeSchemaObject(session, refIndex); refTable.removeIndexOrTransferOwnership(session, refIndex);
} }
refTable = null; refTable = null;
index = null; index = null;
...@@ -515,6 +515,16 @@ public class ConstraintReferential extends Constraint { ...@@ -515,6 +515,16 @@ public class ConstraintReferential extends Constraint {
return idx == index || idx == refIndex; return idx == index || idx == refIndex;
} }
public void setIndexOwner(Index index) {
if (this.index == index) {
indexOwner = true;
} else if (this.refIndex == index) {
refIndexOwner = true;
} else {
throw Message.getInternalError();
}
}
public boolean containsColumn(Column col) { public boolean containsColumn(Column col) {
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
if (columns[i].column == col) { if (columns[i].column == col) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.h2.constraint; package org.h2.constraint;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.command.Parser; import org.h2.command.Parser;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.index.Index; import org.h2.index.Index;
...@@ -113,7 +114,7 @@ public class ConstraintUnique extends Constraint { ...@@ -113,7 +114,7 @@ public class ConstraintUnique extends Constraint {
public void removeChildrenAndResources(Session session) throws SQLException { public void removeChildrenAndResources(Session session) throws SQLException {
table.removeConstraint(this); table.removeConstraint(this);
if (indexOwner) { if (indexOwner) {
database.removeSchemaObject(session, index); table.removeIndexOrTransferOwnership(session, index);
} }
index = null; index = null;
columns = null; columns = null;
...@@ -129,6 +130,10 @@ public class ConstraintUnique extends Constraint { ...@@ -129,6 +130,10 @@ public class ConstraintUnique extends Constraint {
return idx == index; return idx == index;
} }
public void setIndexOwner(Index index) {
indexOwner = true;
}
public boolean containsColumn(Column col) { public boolean containsColumn(Column col) {
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
if (columns[i].column == col) { if (columns[i].column == col) {
......
...@@ -1486,6 +1486,7 @@ public class Database implements DataHandler { ...@@ -1486,6 +1486,7 @@ public class Database implements DataHandler {
log.setDisabled(!logData); log.setDisabled(!logData);
log.checkpoint(); log.checkpoint();
} }
traceSystem.getTrace(Trace.DATABASE).error("SET LOG " + level, null);
logLevel = level; logLevel = level;
} }
......
...@@ -209,7 +209,7 @@ public class ConditionIn extends Condition { ...@@ -209,7 +209,7 @@ public class ConditionIn extends Condition {
} }
Database db = session.getDatabase(); Database db = session.getDatabase();
Schema mainSchema = db.getSchema(Constants.SCHEMA_MAIN); Schema mainSchema = db.getSchema(Constants.SCHEMA_MAIN);
Function function = Function.getFunction(database, "TABLE_DISTINCT"); TableFunction function = new TableFunction(database, Function.getFunctionInfo("TABLE_DISTINCT"));
Expression[] array = new Expression[values.size()]; Expression[] array = new Expression[values.size()];
for (int i = 0; i < values.size(); i++) { for (int i = 0; i < values.size(); i++) {
Expression e = (Expression) values.get(i); Expression e = (Expression) values.get(i);
......
...@@ -22,7 +22,6 @@ import org.h2.engine.Database; ...@@ -22,7 +22,6 @@ import org.h2.engine.Database;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.result.LocalResult;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
import org.h2.security.BlockCipher; import org.h2.security.BlockCipher;
import org.h2.security.CipherFactory; import org.h2.security.CipherFactory;
...@@ -33,14 +32,12 @@ import org.h2.table.LinkSchema; ...@@ -33,14 +32,12 @@ import org.h2.table.LinkSchema;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.tools.CompressTool; import org.h2.tools.CompressTool;
import org.h2.tools.Csv; import org.h2.tools.Csv;
import org.h2.tools.SimpleResultSet;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils; import org.h2.util.MemoryUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.ObjectUtils; import org.h2.util.ObjectUtils;
import org.h2.util.RandomUtils; import org.h2.util.RandomUtils;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean; import org.h2.value.ValueBoolean;
...@@ -86,45 +83,42 @@ public class Function extends Expression implements FunctionCall { ...@@ -86,45 +83,42 @@ public class Function extends Expression implements FunctionCall {
public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202, CAST = 203, COALESCE = 204, NULLIF = 205, public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202, CAST = 203, COALESCE = 204, NULLIF = 205,
CASE = 206, NEXTVAL = 207, CURRVAL = 208, ARRAY_GET = 209, CSVREAD = 210, CSVWRITE = 211, CASE = 206, NEXTVAL = 207, CURRVAL = 208, ARRAY_GET = 209, CSVREAD = 210, CSVWRITE = 211,
MEMORY_FREE = 212, MEMORY_USED = 213, LOCK_MODE = 214, SCHEMA = 215, SESSION_ID = 216, ARRAY_LENGTH = 217, MEMORY_FREE = 212, MEMORY_USED = 213, LOCK_MODE = 214, SCHEMA = 215, SESSION_ID = 216, ARRAY_LENGTH = 217,
LINK_SCHEMA = 218, TABLE = 219, LEAST = 220, GREATEST = 221, TABLE_DISTINCT = 222, CANCEL_SESSION = 223, SET = 224; LINK_SCHEMA = 218, GREATEST = 219, LEAST = 220, CANCEL_SESSION = 221, SET = 222, TABLE = 223, TABLE_DISTINCT = 224;
private static final int VAR_ARGS = -1; private static final int VAR_ARGS = -1;
private static HashMap functions; private static final HashMap FUNCTIONS = new HashMap();
private static final HashMap DATE_PART = new HashMap();
private static final SimpleDateFormat FORMAT_DAYNAME = new SimpleDateFormat("EEEE", Locale.ENGLISH);
private static final SimpleDateFormat FORMAT_MONTHNAME = new SimpleDateFormat("MMMM", Locale.ENGLISH);
private static final char[] SOUNDEX_INDEX = new char[128];
private FunctionInfo info; private FunctionInfo info;
private Expression[] args; protected Expression[] args;
private ObjectArray varArgs; private ObjectArray varArgs;
private int dataType, scale; private int dataType, scale;
private long precision; private long precision;
private int displaySize; private int displaySize;
private Column[] columnList;
private Database database; private Database database;
private static HashMap datePart;
private static final SimpleDateFormat FORMAT_DAYNAME = new SimpleDateFormat("EEEE", Locale.ENGLISH);
private static final SimpleDateFormat FORMAT_MONTHNAME = new SimpleDateFormat("MMMM", Locale.ENGLISH);
private static final char[] SOUNDEX_INDEX = new char[128];
static {
datePart = new HashMap();
datePart.put("YY", ObjectUtils.getInteger(Calendar.YEAR));
datePart.put("YEAR", ObjectUtils.getInteger(Calendar.YEAR));
datePart.put("MM", ObjectUtils.getInteger(Calendar.MONTH));
datePart.put("MONTH", ObjectUtils.getInteger(Calendar.MONTH));
datePart.put("DD", ObjectUtils.getInteger(Calendar.DATE));
datePart.put("DAY", ObjectUtils.getInteger(Calendar.DATE));
datePart.put("HH", ObjectUtils.getInteger(Calendar.HOUR_OF_DAY));
datePart.put("HOUR", ObjectUtils.getInteger(Calendar.HOUR_OF_DAY));
datePart.put("MI", ObjectUtils.getInteger(Calendar.MINUTE));
datePart.put("MINUTE", ObjectUtils.getInteger(Calendar.MINUTE));
datePart.put("SS", ObjectUtils.getInteger(Calendar.SECOND));
datePart.put("SECOND", ObjectUtils.getInteger(Calendar.SECOND));
datePart.put("MS", ObjectUtils.getInteger(Calendar.MILLISECOND));
datePart.put("MILLISECOND", ObjectUtils.getInteger(Calendar.MILLISECOND));
}
static { static {
// DATE_PART
DATE_PART.put("YY", ObjectUtils.getInteger(Calendar.YEAR));
DATE_PART.put("YEAR", ObjectUtils.getInteger(Calendar.YEAR));
DATE_PART.put("MM", ObjectUtils.getInteger(Calendar.MONTH));
DATE_PART.put("MONTH", ObjectUtils.getInteger(Calendar.MONTH));
DATE_PART.put("DD", ObjectUtils.getInteger(Calendar.DATE));
DATE_PART.put("DAY", ObjectUtils.getInteger(Calendar.DATE));
DATE_PART.put("HH", ObjectUtils.getInteger(Calendar.HOUR_OF_DAY));
DATE_PART.put("HOUR", ObjectUtils.getInteger(Calendar.HOUR_OF_DAY));
DATE_PART.put("MI", ObjectUtils.getInteger(Calendar.MINUTE));
DATE_PART.put("MINUTE", ObjectUtils.getInteger(Calendar.MINUTE));
DATE_PART.put("SS", ObjectUtils.getInteger(Calendar.SECOND));
DATE_PART.put("SECOND", ObjectUtils.getInteger(Calendar.SECOND));
DATE_PART.put("MS", ObjectUtils.getInteger(Calendar.MILLISECOND));
DATE_PART.put("MILLISECOND", ObjectUtils.getInteger(Calendar.MILLISECOND));
// SOUNDEX_INDEX
String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R"; String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R";
char number = 0; char number = 0;
for (int i = 0; i < index.length(); i++) { for (int i = 0; i < index.length(); i++) {
...@@ -136,10 +130,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -136,10 +130,8 @@ public class Function extends Expression implements FunctionCall {
SOUNDEX_INDEX[Character.toLowerCase(c)] = number; SOUNDEX_INDEX[Character.toLowerCase(c)] = number;
} }
} }
}
static { // FUNCTIONS
functions = new HashMap();
addFunction("ABS", ABS, 1, Value.NULL); addFunction("ABS", ABS, 1, Value.NULL);
addFunction("ACOS", ACOS, 1, Value.DOUBLE); addFunction("ACOS", ACOS, 1, Value.DOUBLE);
addFunction("ASIN", ASIN, 1, Value.DOUBLE); addFunction("ASIN", ASIN, 1, Value.DOUBLE);
...@@ -284,12 +276,14 @@ public class Function extends Expression implements FunctionCall { ...@@ -284,12 +276,14 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotConst("SESSION_ID", SESSION_ID, 0, Value.INT); addFunctionNotConst("SESSION_ID", SESSION_ID, 0, Value.INT);
addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT); addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT);
addFunction("LINK_SCHEMA", LINK_SCHEMA, 6, Value.RESULT_SET); addFunction("LINK_SCHEMA", LINK_SCHEMA, 6, Value.RESULT_SET);
addFunctionWithNull("TABLE", TABLE, VAR_ARGS, Value.RESULT_SET);
addFunctionWithNull("TABLE_DISTINCT", TABLE_DISTINCT, VAR_ARGS, Value.RESULT_SET);
addFunctionWithNull("LEAST", LEAST, VAR_ARGS, Value.NULL); addFunctionWithNull("LEAST", LEAST, VAR_ARGS, Value.NULL);
addFunctionWithNull("GREATEST", GREATEST, VAR_ARGS, Value.NULL); addFunctionWithNull("GREATEST", GREATEST, VAR_ARGS, Value.NULL);
addFunction("CANCEL_SESSION", CANCEL_SESSION, 1, Value.BOOLEAN); addFunction("CANCEL_SESSION", CANCEL_SESSION, 1, Value.BOOLEAN);
addFunction("SET", SET, 2, Value.NULL, false, false); addFunction("SET", SET, 2, Value.NULL, false, false);
// TableFunction
addFunctionWithNull("TABLE", TABLE, VAR_ARGS, Value.RESULT_SET);
addFunctionWithNull("TABLE_DISTINCT", TABLE_DISTINCT, VAR_ARGS, Value.RESULT_SET);
} }
private static void addFunction(String name, int type, int parameterCount, int dataType, private static void addFunction(String name, int type, int parameterCount, int dataType,
...@@ -301,7 +295,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -301,7 +295,7 @@ public class Function extends Expression implements FunctionCall {
info.dataType = dataType; info.dataType = dataType;
info.nullIfParameterIsNull = nullIfParameterIsNull; info.nullIfParameterIsNull = nullIfParameterIsNull;
info.isDeterministic = isDeterm; info.isDeterministic = isDeterm;
functions.put(name, info); FUNCTIONS.put(name, info);
} }
private static void addFunctionNotConst(String name, int type, int parameterCount, int dataType) { private static void addFunctionNotConst(String name, int type, int parameterCount, int dataType) {
...@@ -316,15 +310,25 @@ public class Function extends Expression implements FunctionCall { ...@@ -316,15 +310,25 @@ public class Function extends Expression implements FunctionCall {
addFunction(name, type, parameterCount, dataType, false, true); addFunction(name, type, parameterCount, dataType, false, true);
} }
public static FunctionInfo getFunctionInfo(String name) {
return (FunctionInfo) FUNCTIONS.get(name);
}
public static Function getFunction(Database database, String name) throws SQLException { public static Function getFunction(Database database, String name) throws SQLException {
FunctionInfo info = (FunctionInfo) functions.get(name); FunctionInfo info = getFunctionInfo(name);
if (info == null) { if (info == null) {
return null; return null;
} }
switch(info.type) {
case TABLE:
case TABLE_DISTINCT:
return new TableFunction(database, info);
default:
return new Function(database, info); return new Function(database, info);
} }
}
private Function(Database database, FunctionInfo info) { protected Function(Database database, FunctionInfo info) {
this.database = database; this.database = database;
this.info = info; this.info = info;
if (info.parameterCount == VAR_ARGS) { if (info.parameterCount == VAR_ARGS) {
...@@ -638,12 +642,6 @@ public class Function extends Expression implements FunctionCall { ...@@ -638,12 +642,6 @@ public class Function extends Expression implements FunctionCall {
result = v0; result = v0;
break; break;
} }
case TABLE:
result = getTable(session, args, false, false);
break;
case TABLE_DISTINCT:
result = getTable(session, args, false, true);
break;
case MEMORY_FREE: case MEMORY_FREE:
session.getUser().checkAdmin(); session.getUser().checkAdmin();
result = ValueInt.get(MemoryUtils.getMemoryFree()); result = ValueInt.get(MemoryUtils.getMemoryFree());
...@@ -1130,7 +1128,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1130,7 +1128,7 @@ public class Function extends Expression implements FunctionCall {
// } // }
private static int getDatePart(String part) throws SQLException { private static int getDatePart(String part) throws SQLException {
Integer p = (Integer) datePart.get(StringUtils.toUpperEnglish(part)); Integer p = (Integer) DATE_PART.get(StringUtils.toUpperEnglish(part));
if (p == null) { if (p == null) {
throw Message.getSQLException(ErrorCode.INVALID_VALUE_2, new String[] { "date part", part }); throw Message.getSQLException(ErrorCode.INVALID_VALUE_2, new String[] { "date part", part });
} }
...@@ -1431,15 +1429,11 @@ public class Function extends Expression implements FunctionCall { ...@@ -1431,15 +1429,11 @@ public class Function extends Expression implements FunctionCall {
} }
} }
public void doneWithParameters() throws SQLException { protected void checkParameterCount(int len) throws SQLException {
if (info.parameterCount == VAR_ARGS) {
int len = varArgs.size();
int min = 0, max = Integer.MAX_VALUE; int min = 0, max = Integer.MAX_VALUE;
switch (info.type) { switch (info.type) {
case COALESCE: case COALESCE:
case CSVREAD: case CSVREAD:
case TABLE:
case TABLE_DISTINCT:
case LEAST: case LEAST:
case GREATEST: case GREATEST:
min = 1; min = 1;
...@@ -1492,6 +1486,12 @@ public class Function extends Expression implements FunctionCall { ...@@ -1492,6 +1486,12 @@ public class Function extends Expression implements FunctionCall {
throw Message.getSQLException(ErrorCode.INVALID_PARAMETER_COUNT_2, new String[] { info.name, throw Message.getSQLException(ErrorCode.INVALID_PARAMETER_COUNT_2, new String[] { info.name,
min + ".." + max }); min + ".." + max });
} }
}
public void doneWithParameters() throws SQLException {
if (info.parameterCount == VAR_ARGS) {
int len = varArgs.size();
checkParameterCount(len);
args = new Expression[len]; args = new Expression[len];
varArgs.toArray(args); varArgs.toArray(args);
varArgs = null; varArgs = null;
...@@ -1716,19 +1716,6 @@ public class Function extends Expression implements FunctionCall { ...@@ -1716,19 +1716,6 @@ public class Function extends Expression implements FunctionCall {
buff.append(args[1].getSQL()); buff.append(args[1].getSQL());
break; break;
} }
case TABLE_DISTINCT:
case TABLE: {
for (int i = 0; i < args.length; i++) {
if (i > 0) {
buff.append(", ");
}
buff.append(columnList[i].getCreateSQL());
buff.append("=");
Expression e = args[i];
buff.append(e.getSQL());
}
break;
}
default: { default: {
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
if (i > 0) { if (i > 0) {
...@@ -1784,12 +1771,6 @@ public class Function extends Expression implements FunctionCall { ...@@ -1784,12 +1771,6 @@ public class Function extends Expression implements FunctionCall {
ValueResultSet vr = ValueResultSet.getCopy(rs, 0); ValueResultSet vr = ValueResultSet.getCopy(rs, 0);
return vr; return vr;
} }
case TABLE: {
return getTable(session, args, true, false);
}
case TABLE_DISTINCT: {
return getTable(session, args, true, true);
}
default: default:
break; break;
} }
...@@ -1839,81 +1820,4 @@ public class Function extends Expression implements FunctionCall { ...@@ -1839,81 +1820,4 @@ public class Function extends Expression implements FunctionCall {
return cost; return cost;
} }
public ValueResultSet getTable(Session session, Expression[] args, boolean onlyColumnList, boolean distinct) throws SQLException {
int len = columnList.length;
Expression[] header = new Expression[len];
Database db = session.getDatabase();
for (int i = 0; i < len; i++) {
Column c = columnList[i];
ExpressionColumn col = new ExpressionColumn(db, c);
header[i] = col;
}
LocalResult result = new LocalResult(session, header, len);
if (distinct) {
result.setDistinct();
}
if (!onlyColumnList) {
Value[][] list = new Value[len][];
int rowCount = 0;
for (int i = 0; i < len; i++) {
Value v = args[i].getValue(session);
if (v == ValueNull.INSTANCE) {
list[i] = new Value[0];
} else {
ValueArray array = (ValueArray) v.convertTo(Value.ARRAY);
Value[] l = array.getList();
list[i] = l;
rowCount = Math.max(rowCount, l.length);
}
}
for (int row = 0; row < rowCount; row++) {
Value[] r = new Value[len];
for (int j = 0; j < len; j++) {
Value[] l = list[j];
Value v;
if (l.length <= row) {
v = ValueNull.INSTANCE;
} else {
Column c = columnList[j];
v = l[row];
v = v.convertTo(c.getType());
v = v.convertPrecision(c.getPrecision());
v = v.convertScale(true, c.getScale());
}
r[j] = v;
}
result.addRow(r);
}
}
result.done();
ValueResultSet vr = ValueResultSet.get(getSimpleResultSet(result, Integer.MAX_VALUE));
return vr;
}
SimpleResultSet getSimpleResultSet(LocalResult rs, int maxrows) throws SQLException {
int columnCount = rs.getVisibleColumnCount();
SimpleResultSet simple = new SimpleResultSet();
for (int i = 0; i < columnCount; i++) {
String name = rs.getColumnName(i);
int sqlType = DataType.convertTypeToSQLType(rs.getColumnType(i));
int precision = MathUtils.convertLongToInt(rs.getColumnPrecision(i));
int scale = rs.getColumnScale(i);
simple.addColumn(name, sqlType, precision, scale);
}
rs.reset();
for (int i = 0; i < maxrows && rs.next(); i++) {
Object[] list = new Object[columnCount];
for (int j = 0; j < columnCount; j++) {
list[j] = rs.currentRow()[j].getObject();
}
simple.addRow(list);
}
return simple;
}
public void setColumns(ObjectArray columns) {
this.columnList = new Column[columns.size()];
columns.toArray(columnList);
}
} }
...@@ -6,14 +6,15 @@ package org.h2.expression; ...@@ -6,14 +6,15 @@ package org.h2.expression;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.constant.ErrorCode;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.Message;
import org.h2.result.LocalResult; import org.h2.result.LocalResult;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.ObjectArray;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
...@@ -23,16 +24,26 @@ import org.h2.value.ValueResultSet; ...@@ -23,16 +24,26 @@ import org.h2.value.ValueResultSet;
/** /**
* Implementation of the functions TABLE(..) and TABLE_DISTINCT(..). * Implementation of the functions TABLE(..) and TABLE_DISTINCT(..).
*/ */
public class TableFunction extends Expression implements FunctionCall { public class TableFunction extends Function implements FunctionCall {
private boolean distinct; private boolean distinct;
private Expression[] args;
private Column[] columnList; private Column[] columnList;
TableFunction(Database database, FunctionInfo info) {
super(database, info);
distinct = info.type == Function.TABLE_DISTINCT;
}
public Value getValue(Session session) throws SQLException { public Value getValue(Session session) throws SQLException {
int todoClassIsNotUsed;
return getTable(session, args, false, distinct); return getTable(session, args, false, distinct);
} }
protected void checkParameterCount(int len) throws SQLException {
if (len < 1) {
throw Message.getSQLException(ErrorCode.INVALID_PARAMETER_COUNT_2, new String[] { getName(),
">0" });
}
}
public String getSQL() { public String getSQL() {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
buff.append(getName()); buff.append(getName());
...@@ -50,6 +61,37 @@ public class TableFunction extends Expression implements FunctionCall { ...@@ -50,6 +61,37 @@ public class TableFunction extends Expression implements FunctionCall {
return buff.toString(); return buff.toString();
} }
public String getName() {
return distinct ? "TABLE_DISTINCT" : "TABLE";
}
public int getRowCount(Session session) throws SQLException {
int len = columnList.length;
int rowCount = 0;
for (int i = 0; i < len; i++) {
Expression expr = args[i];
if (expr.isConstant()) {
Value v = expr.getValue(session);
if (v != ValueNull.INSTANCE) {
ValueArray array = (ValueArray) v.convertTo(Value.ARRAY);
Value[] l = array.getList();
rowCount = Math.max(rowCount, l.length);
}
}
}
return rowCount;
}
public ValueResultSet getValueForColumnList(Session session, Expression[] nullArgs) throws SQLException {
return getTable(session, args, true, false);
}
public void setColumns(ObjectArray columns) {
this.columnList = new Column[columns.size()];
columns.toArray(columnList);
}
public ValueResultSet getTable(Session session, Expression[] args, boolean onlyColumnList, boolean distinct) throws SQLException { public ValueResultSet getTable(Session session, Expression[] args, boolean onlyColumnList, boolean distinct) throws SQLException {
int len = columnList.length; int len = columnList.length;
Expression[] header = new Expression[len]; Expression[] header = new Expression[len];
...@@ -122,114 +164,4 @@ public class TableFunction extends Expression implements FunctionCall { ...@@ -122,114 +164,4 @@ public class TableFunction extends Expression implements FunctionCall {
return simple; return simple;
} }
public int getScale() {
return 0;
}
public void mapColumns(ColumnResolver resolver, int level) throws SQLException {
for (int i = 0; i < args.length; i++) {
args[i].mapColumns(resolver, level);
}
}
public int getCost() {
int cost = 3;
for (int i = 0; i < args.length; i++) {
cost += args[i].getCost();
}
return cost;
}
public int getDisplaySize() {
return Integer.MAX_VALUE;
}
public long getPrecision() {
return 0;
}
public int getType() {
return Value.RESULT_SET;
}
public boolean isEverything(ExpressionVisitor visitor) {
for (int i = 0; i < args.length; i++) {
Expression e = args[i];
if (e != null && !e.isEverything(visitor)) {
return false;
}
}
return true;
}
public Expression optimize(Session session) throws SQLException {
boolean allConst = true;
for (int i = 0; i < args.length; i++) {
Expression e = args[i].optimize(session);
args[i] = e;
if (!e.isConstant()) {
allConst = false;
}
}
if (allConst) {
return ValueExpression.get(getValue(session));
}
return this;
}
public void setEvaluatable(TableFilter tableFilter, boolean value) {
for (int i = 0; i < args.length; i++) {
Expression e = args[i];
if (e != null) {
e.setEvaluatable(tableFilter, value);
}
}
}
public void updateAggregate(Session session) throws SQLException {
for (int i = 0; i < args.length; i++) {
Expression e = args[i];
if (e != null) {
e.updateAggregate(session);
}
}
}
public boolean canGetRowCount() {
return true;
}
public Expression[] getArgs() {
return args;
}
public String getName() {
return distinct ? "TABLE_DISTINCT" : "TABLE";
}
public int getParameterCount() {
return args.length;
}
public int getRowCount(Session session) throws SQLException {
int len = columnList.length;
int rowCount = 0;
for (int i = 0; i < len; i++) {
Expression expr = args[i];
if (expr.isConstant()) {
Value v = expr.getValue(session);
if (v != ValueNull.INSTANCE) {
ValueArray array = (ValueArray) v.convertTo(Value.ARRAY);
Value[] l = array.getList();
rowCount = Math.max(rowCount, l.length);
}
}
}
return rowCount;
}
public ValueResultSet getValueForColumnList(Session session, Expression[] nullArgs) throws SQLException {
return getTable(session, args, true, false);
}
} }
...@@ -666,4 +666,26 @@ public abstract class Table extends SchemaObjectBase { ...@@ -666,4 +666,26 @@ public abstract class Table extends SchemaObjectBase {
return false; return false;
} }
/**
* If the index is still required by a constraint, transfer the ownership to it.
* Otherwise, the index is removed.
*
* @param session the session
* @param index the index that is no longer required
*/
public void removeIndexOrTransferOwnership(Session session, Index index) throws SQLException {
boolean stillNeeded = false;
for (int i = 0; constraints != null && i < constraints.size(); i++) {
Constraint cons = (Constraint) constraints.get(i);
if (cons.usesIndex(index)) {
cons.setIndexOwner(index);
database.update(session, cons);
stillNeeded = true;
}
}
if (!stillNeeded) {
database.removeSchemaObject(session, index);
}
}
} }
...@@ -91,9 +91,9 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -91,9 +91,9 @@ public class Server implements Runnable, ShutdownHandler {
* </li><li>-tcpShutdown {url} (shutdown the running TCP Server, URL example: tcp://localhost:9094) * </li><li>-tcpShutdown {url} (shutdown the running TCP Server, URL example: tcp://localhost:9094)
* </li><li>-pg (start the PG Server) * </li><li>-pg (start the PG Server)
* </li><li>-browser (start a browser and open a page to connect to the Web Server) * </li><li>-browser (start a browser and open a page to connect to the Web Server)
* </li><li>-log {true|false} (enable or disable logging) * </li><li>-log {true|false} (enable or disable logging, for all servers)
* </li><li>-baseDir {directory} (sets the base directory for database files; not for H2 Console) * </li><li>-baseDir {directory} (sets the base directory for H2 databases, for all servers)
* </li><li>-ifExists {true|false} (only existing databases may be opened) * </li><li>-ifExists {true|false} (only existing databases may be opened, for all servers)
* </li><li>-ftp (start the FTP Server) * </li><li>-ftp (start the FTP Server)
* </li></ul> * </li></ul>
* For each Server, additional options are available: * For each Server, additional options are available:
......
...@@ -151,14 +151,20 @@ java org.h2.test.TestAll timer ...@@ -151,14 +151,20 @@ java org.h2.test.TestAll timer
/* /*
implement max_query_time and use it for TestCrashAPI recovery tool: bad blocks should be converted to INSERT INTO SYSTEM_ERRORS(...),
and things should go into the .trace.db file
link from h2 console to sourceError RECOVER=2 should backup the database, run recovery, open the database
add sourceError as an official link
Recovery should work with encrypted databases
java org.h2.tool.Server -baseDir C:\temp\dbtest
web console: jdbc:h2:~/chin
C:\temp\dbtest\~
Automate real power off tests
Adjust cache memory usage Adjust cache memory usage
At startup, when corrupted, say if LOG=0 was used before
Extend tests that simulate power off Extend tests that simulate power off
Automate real power off tests
timer test timer test
// test with garbage at the end of the log file (must be consistently detected as such) // test with garbage at the end of the log file (must be consistently detected as such)
// TestRandomSQL is too random; most statements fails // TestRandomSQL is too random; most statements fails
...@@ -175,6 +181,9 @@ Roadmap: ...@@ -175,6 +181,9 @@ Roadmap:
History: History:
Statement.setQueryTimeout() is now supported. New session setting QUERY_TIMEOUT, and new system property h2.maxQueryTimeout. Statement.setQueryTimeout() is now supported. New session setting QUERY_TIMEOUT, and new system property h2.maxQueryTimeout.
Changing the transaction log level (SET LOG) is now written to the trace file by default.
In a SQL script, primary key constraints are now ordered before foreign key constraints.
It was not possible to create a referential constraint to a table in a different schema in some situations.
*/ */
......
...@@ -18,7 +18,7 @@ import org.h2.tools.DeleteDbFiles; ...@@ -18,7 +18,7 @@ import org.h2.tools.DeleteDbFiles;
/** /**
* A recovery test that checks the consistency of a database (if it exists), * A recovery test that checks the consistency of a database (if it exists),
* then deletes everything and runs in an endless loop executing random operations. * then deletes everything and runs in an endless loop executing random operations.
* This loop is usually stopped by turning off the computer. * This loop is usually stopped by switching off the computer.
*/ */
public class TestTimer extends TestBase { public class TestTimer extends TestBase {
...@@ -86,11 +86,25 @@ public class TestTimer extends TestBase { ...@@ -86,11 +86,25 @@ public class TestTimer extends TestBase {
Connection conn = getConnection("timer"); Connection conn = getConnection("timer");
// TODO validate transactions // TODO validate transactions
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("CREATE TABLE IF NOT EXISTS TEST(ID IDENTITY, NAME VARCHAR)");
ResultSet rs = stat.executeQuery("SELECT COUNT(*) FROM TEST"); ResultSet rs = stat.executeQuery("SELECT COUNT(*) FROM TEST");
rs.next(); rs.next();
int count = rs.getInt(1); int count = rs.getInt(1);
println("row count: " + count);
int real = 0;
rs = stat.executeQuery("SELECT * FROM TEST");
while (rs.next()) {
real++;
}
if (real != count) {
println("real count: " + real);
throw new Error("COUNT(*)=" + count + " SELECT=" + real);
}
rs = stat.executeQuery("SCRIPT");
while (rs.next()) {
rs.getString(1);
}
conn.close(); conn.close();
println("done, rows: " + count);
} catch (Throwable e) { } catch (Throwable e) {
logError("validate", e); logError("validate", e);
backup(); backup();
......
...@@ -2417,11 +2417,10 @@ alter table test add constraint fk foreign key(parent) references(id); ...@@ -2417,11 +2417,10 @@ alter table test add constraint fk foreign key(parent) references(id);
select TABLE_NAME, NON_UNIQUE, INDEX_NAME, ORDINAL_POSITION, COLUMN_NAME, CARDINALITY, PRIMARY_KEY from INFORMATION_SCHEMA.INDEXES; select TABLE_NAME, NON_UNIQUE, INDEX_NAME, ORDINAL_POSITION, COLUMN_NAME, CARDINALITY, PRIMARY_KEY from INFORMATION_SCHEMA.INDEXES;
> TABLE_NAME NON_UNIQUE INDEX_NAME ORDINAL_POSITION COLUMN_NAME CARDINALITY PRIMARY_KEY > TABLE_NAME NON_UNIQUE INDEX_NAME ORDINAL_POSITION COLUMN_NAME CARDINALITY PRIMARY_KEY
> ---------- ---------- ------------- ---------------- ----------- ----------- ----------- > ---------- ---------- ------------- ---------------- ----------- ----------- -----------
> TEST FALSE FK_INDEX_2 1 ID 0 FALSE
> TEST FALSE NU_INDEX_2 1 PARENT 0 FALSE > TEST FALSE NU_INDEX_2 1 PARENT 0 FALSE
> TEST FALSE PRIMARY_KEY_2 1 ID 0 TRUE > TEST FALSE PRIMARY_KEY_2 1 ID 0 TRUE
> TEST TRUE NI 1 PARENT 0 FALSE > TEST TRUE NI 1 PARENT 0 FALSE
> rows: 4 > rows: 3
select SEQUENCE_NAME, CURRENT_VALUE, INCREMENT, IS_GENERATED, REMARKS from INFORMATION_SCHEMA.SEQUENCES; select SEQUENCE_NAME, CURRENT_VALUE, INCREMENT, IS_GENERATED, REMARKS from INFORMATION_SCHEMA.SEQUENCES;
> SEQUENCE_NAME CURRENT_VALUE INCREMENT IS_GENERATED REMARKS > SEQUENCE_NAME CURRENT_VALUE INCREMENT IS_GENERATED REMARKS
...@@ -6977,10 +6976,13 @@ DROP TABLE PARENT; ...@@ -6977,10 +6976,13 @@ DROP TABLE PARENT;
DROP TABLE CHILD; DROP TABLE CHILD;
> ok > ok
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR, PARENT INT, CONSTRAINT P FOREIGN KEY(PARENT) REFERENCES(ID)); CREATE TABLE TEST(ID INT, CONSTRAINT PK PRIMARY KEY(ID), NAME VARCHAR, PARENT INT, CONSTRAINT P FOREIGN KEY(PARENT) REFERENCES(ID));
> ok > ok
ALTER TABLE TEST DROP PRIMARY KEY; ALTER TABLE TEST DROP PRIMARY KEY;
> exception
ALTER TABLE TEST DROP CONSTRAINT PK;
> ok > ok
INSERT INTO TEST VALUES(1, 'Frank', 1); INSERT INTO TEST VALUES(1, 'Frank', 1);
......
create schema Contact;
CREATE TABLE Account (id BIGINT);
CREATE TABLE Person (id BIGINT, FOREIGN KEY (id) REFERENCES Account(id));
CREATE TABLE Contact.Contact (id BIGINT, FOREIGN KEY (id) REFERENCES public.Person(id));
drop schema contact;
drop table account, person;
create schema Contact;
CREATE TABLE Account (id BIGINT primary key);
CREATE TABLE Person (id BIGINT primary key, FOREIGN KEY (id) REFERENCES Account);
CREATE TABLE Contact.Contact (id BIGINT primary key, FOREIGN KEY (id) REFERENCES public.Person);
drop schema contact;
drop table account, person;
select extract(hour from timestamp '2001-02-03 14:15:16'); select extract(hour from timestamp '2001-02-03 14:15:16');
> 14; > 14;
select extract(hour from '2001-02-03 14:15:16'); select extract(hour from '2001-02-03 14:15:16');
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论