Unverified 提交 ac05e08c authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1388 from katzyn/operation

Extract UnaryOperation from Operation and other changes
...@@ -79,7 +79,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -79,7 +79,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Console: add accesskey to most important commands (A, AREA, BUTTON, INPUT, LABEL, LEGEND, TEXTAREA). </li><li>Console: add accesskey to most important commands (A, AREA, BUTTON, INPUT, LABEL, LEGEND, TEXTAREA).
</li><li>Test performance again with SQL Server, Oracle, DB2. </li><li>Test performance again with SQL Server, Oracle, DB2.
</li><li>Test with Spatial DB in a box / JTS: http://www.opengeospatial.org/standards/sfs - OpenGIS Implementation Specification. </li><li>Test with Spatial DB in a box / JTS: http://www.opengeospatial.org/standards/sfs - OpenGIS Implementation Specification.
</li><li>Write more tests and documentation for MVCC (Multi Version Concurrency Control). </li><li>Improve documentation of MVCC (Multi Version Concurrency Control).
</li><li>Find a tool to view large text file (larger than 100 MB), with find, page up and down (like less), truncate before / after. </li><li>Find a tool to view large text file (larger than 100 MB), with find, page up and down (like less), truncate before / after.
</li><li>Implement, test, document XAConnection and so on. </li><li>Implement, test, document XAConnection and so on.
</li><li>Pluggable data type (for streaming, hashing, compression, validation, conversion, encryption). </li><li>Pluggable data type (for streaming, hashing, compression, validation, conversion, encryption).
...@@ -219,7 +219,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -219,7 +219,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Integrate spatial functions from http://geosysin.iict.ch/irstv-trac/wiki/H2spatial/Download </li><li>Integrate spatial functions from http://geosysin.iict.ch/irstv-trac/wiki/H2spatial/Download
</li><li>Cluster: hot deploy (adding a node at runtime). </li><li>Cluster: hot deploy (adding a node at runtime).
</li><li>Support DatabaseMetaData.insertsAreDetected: updatable result sets should detect inserts. </li><li>Support DatabaseMetaData.insertsAreDetected: updatable result sets should detect inserts.
</li><li>Oracle: support DECODE method (convert to CASE WHEN).
</li><li>Native search: support "phrase search", wildcard search (* and ?), case-insensitive search, boolean operators, and grouping </li><li>Native search: support "phrase search", wildcard search (* and ?), case-insensitive search, boolean operators, and grouping
</li><li>Improve documentation of access rights. </li><li>Improve documentation of access rights.
</li><li>Support opening a database that is in the classpath, maybe using a new file system. Workaround: detect jar file using getClass().getProtectionDomain().getCodeSource().getLocation(). </li><li>Support opening a database that is in the classpath, maybe using a new file system. Workaround: detect jar file using getClass().getProtectionDomain().getCodeSource().getLocation().
...@@ -256,7 +255,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -256,7 +255,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>MySQL compatibility: real SQL statement for DESCRIBE TEST </li><li>MySQL compatibility: real SQL statement for DESCRIBE TEST
</li><li>Use a default delay of 1 second before closing a database. </li><li>Use a default delay of 1 second before closing a database.
</li><li>Write (log) to system table before adding to internal data structures. </li><li>Write (log) to system table before adding to internal data structures.
</li><li>Support direct lookup for MIN and MAX when using WHERE (see todo.txt / Direct Lookup).
</li><li>Support other array types (String[], double[]) in PreparedStatement.setObject(int, Object) (with test case). </li><li>Support other array types (String[], double[]) in PreparedStatement.setObject(int, Object) (with test case).
</li><li>Oracle compatibility: support NLS_DATE_FORMAT. </li><li>Oracle compatibility: support NLS_DATE_FORMAT.
</li><li>Support for Thread.interrupt to cancel running statements. </li><li>Support for Thread.interrupt to cancel running statements.
...@@ -322,7 +320,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -322,7 +320,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Doclet: convert tests in javadocs to a java class. </li><li>Doclet: convert tests in javadocs to a java class.
</li><li>Doclet: format fields like methods, but support sorting by name and value. </li><li>Doclet: format fields like methods, but support sorting by name and value.
</li><li>Doclet: shrink the html files. </li><li>Doclet: shrink the html files.
</li><li>MySQL compatibility: support SET NAMES 'latin1' - See also http://code.google.com/p/h2database/issues/detail?id=56
</li><li>Allow to scan index backwards starting with a value (to better support ORDER BY DESC). </li><li>Allow to scan index backwards starting with a value (to better support ORDER BY DESC).
</li><li>Java Service Wrapper: try http://yajsw.sourceforge.net/ </li><li>Java Service Wrapper: try http://yajsw.sourceforge.net/
</li><li>Batch parameter for INSERT, UPDATE, and DELETE, and commit after each batch. See also MySQL DELETE. </li><li>Batch parameter for INSERT, UPDATE, and DELETE, and commit after each batch. See also MySQL DELETE.
...@@ -334,7 +331,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -334,7 +331,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Sybase/DB2/Oracle compatibility: support out parameters in stored procedures - See http://code.google.com/p/h2database/issues/detail?id=83 </li><li>Sybase/DB2/Oracle compatibility: support out parameters in stored procedures - See http://code.google.com/p/h2database/issues/detail?id=83
</li><li>Combine Server and Console tool (only keep Server). </li><li>Combine Server and Console tool (only keep Server).
</li><li>Store the Lucene index in the database itself. </li><li>Store the Lucene index in the database itself.
</li><li>Oracle compatibility: support DECODE(x, ...).
</li><li>MVCC: compare concurrent update behavior with PostgreSQL and Oracle. </li><li>MVCC: compare concurrent update behavior with PostgreSQL and Oracle.
</li><li>HSQLDB compatibility: CREATE FUNCTION (maybe using a Function interface). </li><li>HSQLDB compatibility: CREATE FUNCTION (maybe using a Function interface).
</li><li>HSQLDB compatibility: support CALL "java.lang.Math.sqrt"(2.0) </li><li>HSQLDB compatibility: support CALL "java.lang.Math.sqrt"(2.0)
...@@ -346,7 +342,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -346,7 +342,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Support =ANY(array) as in PostgreSQL. See also http://www.postgresql.org/docs/8.0/interactive/arrays.html </li><li>Support =ANY(array) as in PostgreSQL. See also http://www.postgresql.org/docs/8.0/interactive/arrays.html
</li><li>IBM DB2 compatibility: support PREVIOUS VALUE FOR sequence. </li><li>IBM DB2 compatibility: support PREVIOUS VALUE FOR sequence.
</li><li>Compatibility: use different LIKE ESCAPE characters depending on the mode (disable for Derby, HSQLDB, DB2, Oracle, MSSQLServer). </li><li>Compatibility: use different LIKE ESCAPE characters depending on the mode (disable for Derby, HSQLDB, DB2, Oracle, MSSQLServer).
</li><li>Oracle compatibility: support CREATE SYNONYM table FOR schema.table.
</li><li>FTP: document the server, including -ftpTask option to execute / kill remote processes </li><li>FTP: document the server, including -ftpTask option to execute / kill remote processes
</li><li>FTP: problems with multithreading? </li><li>FTP: problems with multithreading?
</li><li>FTP: implement SFTP / FTPS </li><li>FTP: implement SFTP / FTPS
...@@ -410,7 +405,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -410,7 +405,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Issue 178: Optimizer: index usage when both ascending and descending indexes are available. </li><li>Issue 178: Optimizer: index usage when both ascending and descending indexes are available.
</li><li>Issue 179: Related subqueries in HAVING clause. </li><li>Issue 179: Related subqueries in HAVING clause.
</li><li>IBM DB2 compatibility: NOT NULL WITH DEFAULT. Similar to MySQL Mode.convertInsertNullToZero. </li><li>IBM DB2 compatibility: NOT NULL WITH DEFAULT. Similar to MySQL Mode.convertInsertNullToZero.
</li><li>Creating primary key: always create a constraint.
</li><li>Maybe use a different page layout: keep the data at the head of the page, and ignore the tail </li><li>Maybe use a different page layout: keep the data at the head of the page, and ignore the tail
(don't store / read it). This may increase write / read performance depending on the file system. (don't store / read it). This may increase write / read performance depending on the file system.
</li><li>Indexes of temporary tables are currently kept in-memory. Is this how it should be? </li><li>Indexes of temporary tables are currently kept in-memory. Is this how it should be?
...@@ -501,10 +495,10 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -501,10 +495,10 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>PostgreSQL compatibility: UPDATE with FROM. </li><li>PostgreSQL compatibility: UPDATE with FROM.
</li><li>Issue 297: Oracle compatibility for "at time zone". </li><li>Issue 297: Oracle compatibility for "at time zone".
</li><li>IBM DB2 compatibility: IDENTITY_VAL_LOCAL(). </li><li>IBM DB2 compatibility: IDENTITY_VAL_LOCAL().
</li><li>Support SQL/XML. </li><li>Support SQL/XML data type.
</li><li>Support concurrent opening of databases. </li><li>Support concurrent opening of databases.
</li><li>Improved error message and diagnostics in case of network configuration problems. </li><li>Improved error message and diagnostics in case of network configuration problems.
</li><li>TRUNCATE should reset the identity columns as in MySQL and MS SQL Server (and possibly other databases). </li><li>TRUNCATE should reset the identity columns by default in MySQL and MS SQL Server compatibility modes (and possibly other).
</li><li>Adding a primary key should make the columns 'not null' unless if there is a row with null </li><li>Adding a primary key should make the columns 'not null' unless if there is a row with null
(compatibility with MySQL, PostgreSQL, HSQLDB; not Derby). (compatibility with MySQL, PostgreSQL, HSQLDB; not Derby).
</li><li>ARRAY data type: support Integer[] and so on in Java functions (currently only Object[] is supported). </li><li>ARRAY data type: support Integer[] and so on in Java functions (currently only Object[] is supported).
...@@ -526,7 +520,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -526,7 +520,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Support [INNER | OUTER] JOIN USING(column [,...]). </li><li>Support [INNER | OUTER] JOIN USING(column [,...]).
</li><li>Support NATURAL [ { LEFT | RIGHT } [ OUTER ] | INNER ] JOIN (Derby, Oracle) </li><li>Support NATURAL [ { LEFT | RIGHT } [ OUTER ] | INNER ] JOIN (Derby, Oracle)
</li><li>GROUP BY columnNumber (similar to ORDER BY columnNumber) (MySQL, PostgreSQL, SQLite; not by HSQLDB and Derby). </li><li>GROUP BY columnNumber (similar to ORDER BY columnNumber) (MySQL, PostgreSQL, SQLite; not by HSQLDB and Derby).
</li><li>Sybase / MS SQL Server compatibility: CONVERT(..) parameters are swapped.
</li><li>Index conditions: WHERE AGE>1 should not scan through all rows with AGE=1. </li><li>Index conditions: WHERE AGE>1 should not scan through all rows with AGE=1.
</li><li>PHP support: H2 should support PDO, or test with PostgreSQL PDO. </li><li>PHP support: H2 should support PDO, or test with PostgreSQL PDO.
</li><li>Outer joins: if no column of the outer join table is referenced, the outer join table could be removed from the query. </li><li>Outer joins: if no column of the outer join table is referenced, the outer join table could be removed from the query.
...@@ -539,7 +532,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -539,7 +532,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
Keep an pointer to the data area and the column id that is already read. Keep an pointer to the data area and the column id that is already read.
</li><li>Long running transactions: log session id when detected. </li><li>Long running transactions: log session id when detected.
</li><li>Optimization: "select id from test" should use the index on id even without "order by". </li><li>Optimization: "select id from test" should use the index on id even without "order by".
</li><li>Issue 362: LIMIT support for UPDATE statements (MySQL compatibility).
</li><li>Sybase SQL Anywhere compatibility: SELECT TOP ... START AT ... </li><li>Sybase SQL Anywhere compatibility: SELECT TOP ... START AT ...
</li><li>Use Java 6 SQLException subclasses. </li><li>Use Java 6 SQLException subclasses.
</li><li>Issue 390: RUNSCRIPT FROM '...' CONTINUE_ON_ERROR </li><li>Issue 390: RUNSCRIPT FROM '...' CONTINUE_ON_ERROR
......
...@@ -148,6 +148,8 @@ import org.h2.engine.UserDataType; ...@@ -148,6 +148,8 @@ import org.h2.engine.UserDataType;
import org.h2.expression.Aggregate; import org.h2.expression.Aggregate;
import org.h2.expression.Aggregate.AggregateType; import org.h2.expression.Aggregate.AggregateType;
import org.h2.expression.Alias; import org.h2.expression.Alias;
import org.h2.expression.BinaryOperation;
import org.h2.expression.BinaryOperation.OpType;
import org.h2.expression.CompareLike; import org.h2.expression.CompareLike;
import org.h2.expression.Comparison; import org.h2.expression.Comparison;
import org.h2.expression.ConditionAndOr; import org.h2.expression.ConditionAndOr;
...@@ -163,13 +165,12 @@ import org.h2.expression.Function; ...@@ -163,13 +165,12 @@ import org.h2.expression.Function;
import org.h2.expression.FunctionCall; import org.h2.expression.FunctionCall;
import org.h2.expression.JavaAggregate; import org.h2.expression.JavaAggregate;
import org.h2.expression.JavaFunction; import org.h2.expression.JavaFunction;
import org.h2.expression.Operation;
import org.h2.expression.Operation.OpType;
import org.h2.expression.Parameter; 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.TableFunction;
import org.h2.expression.UnaryOperation;
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;
...@@ -1797,9 +1798,6 @@ public class Parser { ...@@ -1797,9 +1798,6 @@ public class Parser {
} }
private IndexHints parseIndexHints(Table table) { private IndexHints parseIndexHints(Table table) {
if (table == null) {
throw getSyntaxError();
}
read(OPEN_PAREN); read(OPEN_PAREN);
LinkedHashSet<String> indexNames = new LinkedHashSet<>(); LinkedHashSet<String> indexNames = new LinkedHashSet<>();
if (!readIf(CLOSE_PAREN)) { if (!readIf(CLOSE_PAREN)) {
...@@ -2858,7 +2856,7 @@ public class Parser { ...@@ -2858,7 +2856,7 @@ public class Parser {
Expression r = readSum(); Expression r = readSum();
while (true) { while (true) {
if (readIf(STRING_CONCAT)) { if (readIf(STRING_CONCAT)) {
r = new Operation(OpType.CONCAT, r, readSum()); r = new BinaryOperation(OpType.CONCAT, r, readSum());
} else if (readIf(TILDE)) { } else if (readIf(TILDE)) {
if (readIf(ASTERISK)) { if (readIf(ASTERISK)) {
Function function = Function.getFunction(database, "CAST"); Function function = Function.getFunction(database, "CAST");
...@@ -2888,9 +2886,9 @@ public class Parser { ...@@ -2888,9 +2886,9 @@ public class Parser {
Expression r = readFactor(); Expression r = readFactor();
while (true) { while (true) {
if (readIf(PLUS_SIGN)) { if (readIf(PLUS_SIGN)) {
r = new Operation(OpType.PLUS, r, readFactor()); r = new BinaryOperation(OpType.PLUS, r, readFactor());
} else if (readIf(MINUS_SIGN)) { } else if (readIf(MINUS_SIGN)) {
r = new Operation(OpType.MINUS, r, readFactor()); r = new BinaryOperation(OpType.MINUS, r, readFactor());
} else { } else {
return r; return r;
} }
...@@ -2901,11 +2899,11 @@ public class Parser { ...@@ -2901,11 +2899,11 @@ public class Parser {
Expression r = readTerm(); Expression r = readTerm();
while (true) { while (true) {
if (readIf(ASTERISK)) { if (readIf(ASTERISK)) {
r = new Operation(OpType.MULTIPLY, r, readTerm()); r = new BinaryOperation(OpType.MULTIPLY, r, readTerm());
} else if (readIf(SLASH)) { } else if (readIf(SLASH)) {
r = new Operation(OpType.DIVIDE, r, readTerm()); r = new BinaryOperation(OpType.DIVIDE, r, readTerm());
} else if (readIf(PERCENT)) { } else if (readIf(PERCENT)) {
r = new Operation(OpType.MODULUS, r, readTerm()); r = new BinaryOperation(OpType.MODULUS, r, readTerm());
} else { } else {
return r; return r;
} }
...@@ -3551,7 +3549,7 @@ public class Parser { ...@@ -3551,7 +3549,7 @@ public class Parser {
} }
read(); read();
} else { } else {
r = new Operation(OpType.NEGATE, readTerm(), null); r = new UnaryOperation(readTerm());
} }
break; break;
case PLUS_SIGN: case PLUS_SIGN:
...@@ -3610,7 +3608,7 @@ public class Parser { ...@@ -3610,7 +3608,7 @@ public class Parser {
Function function = Function.getFunction(database, "ARRAY_GET"); Function function = Function.getFunction(database, "ARRAY_GET");
function.setParameter(0, r); function.setParameter(0, r);
r = readExpression(); r = readExpression();
r = new Operation(OpType.PLUS, r, ValueExpression.get(ValueInt r = new BinaryOperation(OpType.PLUS, r, ValueExpression.get(ValueInt
.get(1))); .get(1)));
function.setParameter(1, r); function.setParameter(1, r);
r = function; r = function;
......
...@@ -12,17 +12,13 @@ import java.util.List; ...@@ -12,17 +12,13 @@ import java.util.List;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.engine.Mode.ModeEnum; import org.h2.engine.Mode.ModeEnum;
import org.h2.engine.Session;
import org.h2.expression.Alias; import org.h2.expression.Alias;
import org.h2.expression.Comparison;
import org.h2.expression.ConditionAndOr;
import org.h2.expression.ConditionNot;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn; import org.h2.expression.ExpressionColumn;
import org.h2.expression.ExpressionVisitor; import org.h2.expression.ExpressionVisitor;
import org.h2.expression.Function; import org.h2.expression.Function;
import org.h2.expression.Operation;
import org.h2.expression.Parameter; import org.h2.expression.Parameter;
import org.h2.expression.ValueExpression; import org.h2.expression.ValueExpression;
import org.h2.message.DbException; import org.h2.message.DbException;
...@@ -529,6 +525,7 @@ public abstract class Query extends Prepared { ...@@ -529,6 +525,7 @@ public abstract class Query extends Prepared {
*/ */
private static boolean checkOrderOther(Session session, Expression expr, ArrayList<String> expressionSQL) { private static boolean checkOrderOther(Session session, Expression expr, ArrayList<String> expressionSQL) {
if (expr.isConstant()) { if (expr.isConstant()) {
// ValueExpression or other
return true; return true;
} }
String exprSQL = expr.getSQL(); String exprSQL = expr.getSQL();
...@@ -537,38 +534,22 @@ public abstract class Query extends Prepared { ...@@ -537,38 +534,22 @@ public abstract class Query extends Prepared {
return true; return true;
} }
} }
int count = expr.getSubexpressionCount();
if (expr instanceof Function) { if (expr instanceof Function) {
Function function = (Function) expr; if (!((Function) expr).isDeterministic()) {
if (!function.isDeterministic()) {
return false; return false;
} }
for (Expression e : function.getArgs()) { } else if (count <= 0) {
if (!checkOrderOther(session, e, expressionSQL)) { // Expression is an ExpressionColumn, Parameter, SequenceValue or
return false; // has other unsupported type without subexpressions
} return false;
}
return true;
}
if (expr instanceof Operation) {
Operation operation = (Operation) expr;
Expression right = operation.getRightSubExpression();
return checkOrderOther(session, operation.getLeftSubExpression(), expressionSQL)
&& (right == null || checkOrderOther(session, right, expressionSQL));
}
if (expr instanceof ConditionAndOr) {
ConditionAndOr condition = (ConditionAndOr) expr;
return checkOrderOther(session, condition.getLeftSubExpression(), expressionSQL)
&& checkOrderOther(session, condition.getRightSubExpression(), expressionSQL);
}
if (expr instanceof ConditionNot) {
return checkOrderOther(session, ((ConditionNot) expr).getSubCondition(), expressionSQL);
} }
if (expr instanceof Comparison) { for (int i = 0; i < count; i++) {
Comparison condition = (Comparison) expr; if (!checkOrderOther(session, expr.getSubexpression(i), expressionSQL)) {
return checkOrderOther(session, condition.getLeftSubExpression(), expressionSQL) return false;
&& checkOrderOther(session, condition.getRightSubExpression(), expressionSQL); }
} }
return false; return true;
} }
/** /**
......
...@@ -21,7 +21,7 @@ import org.h2.value.ValueString; ...@@ -21,7 +21,7 @@ import org.h2.value.ValueString;
/** /**
* A mathematical expression, or string concatenation. * A mathematical expression, or string concatenation.
*/ */
public class Operation extends Expression { public class BinaryOperation extends Expression {
public enum OpType { public enum OpType {
/** /**
...@@ -50,11 +50,6 @@ public class Operation extends Expression { ...@@ -50,11 +50,6 @@ public class Operation extends Expression {
*/ */
DIVIDE, DIVIDE,
/**
* This operation represents a negation as in - ID.
*/
NEGATE,
/** /**
* This operation represents a modulus as in 5 % 2. * This operation represents a modulus as in 5 % 2.
*/ */
...@@ -66,7 +61,7 @@ public class Operation extends Expression { ...@@ -66,7 +61,7 @@ public class Operation extends Expression {
private int dataType; private int dataType;
private boolean convertRight = true; private boolean convertRight = true;
public Operation(OpType opType, Expression left, Expression right) { public BinaryOperation(OpType opType, Expression left, Expression right) {
this.opType = opType; this.opType = opType;
this.left = left; this.left = left;
this.right = right; this.right = right;
...@@ -74,23 +69,13 @@ public class Operation extends Expression { ...@@ -74,23 +69,13 @@ public class Operation extends Expression {
@Override @Override
public String getSQL() { public String getSQL() {
String sql; // don't remove the space, otherwise it might end up some thing like
if (opType == OpType.NEGATE) { // --1 which is a line remark
// don't remove the space, otherwise it might end up some thing like return '(' + left.getSQL() + ' ' + getOperationToken() + ' ' + right.getSQL() + ')';
// --1 which is a line remark
sql = "- " + left.getSQL();
} else {
// don't remove the space, otherwise it might end up some thing like
// --1 which is a line remark
sql = left.getSQL() + " " + getOperationToken() + " " + right.getSQL();
}
return "(" + sql + ")";
} }
private String getOperationToken() { private String getOperationToken() {
switch (opType) { switch (opType) {
case NEGATE:
return "-";
case CONCAT: case CONCAT:
return "||"; return "||";
case PLUS: case PLUS:
...@@ -112,18 +97,11 @@ public class Operation extends Expression { ...@@ -112,18 +97,11 @@ public class Operation extends Expression {
public Value getValue(Session session) { public Value getValue(Session session) {
Mode mode = session.getDatabase().getMode(); Mode mode = session.getDatabase().getMode();
Value l = left.getValue(session).convertTo(dataType, mode); Value l = left.getValue(session).convertTo(dataType, mode);
Value r; Value r = right.getValue(session);
if (right == null) { if (convertRight) {
r = null; r = r.convertTo(dataType, mode);
} else {
r = right.getValue(session);
if (convertRight) {
r = r.convertTo(dataType, mode);
}
} }
switch (opType) { switch (opType) {
case NEGATE:
return l == ValueNull.INSTANCE ? l : l.negate();
case CONCAT: { case CONCAT: {
if (l == ValueNull.INSTANCE) { if (l == ValueNull.INSTANCE) {
if (mode.nullConcatIsNull) { if (mode.nullConcatIsNull) {
...@@ -174,36 +152,22 @@ public class Operation extends Expression { ...@@ -174,36 +152,22 @@ public class Operation extends Expression {
@Override @Override
public void mapColumns(ColumnResolver resolver, int level) { public void mapColumns(ColumnResolver resolver, int level) {
left.mapColumns(resolver, level); left.mapColumns(resolver, level);
if (right != null) { right.mapColumns(resolver, level);
right.mapColumns(resolver, level);
}
} }
@Override @Override
public Expression optimize(Session session) { public Expression optimize(Session session) {
left = left.optimize(session); left = left.optimize(session);
right = right.optimize(session);
switch (opType) { switch (opType) {
case NEGATE:
dataType = left.getType();
if (dataType == Value.UNKNOWN) {
dataType = Value.DECIMAL;
} else if (dataType == Value.ENUM) {
dataType = Value.INT;
}
break;
case CONCAT: case CONCAT:
right = right.optimize(session);
dataType = Value.STRING; dataType = Value.STRING;
if (left.isConstant() && right.isConstant()) {
return ValueExpression.get(getValue(session));
}
break; break;
case PLUS: case PLUS:
case MINUS: case MINUS:
case MULTIPLY: case MULTIPLY:
case DIVIDE: case DIVIDE:
case MODULUS: case MODULUS:
right = right.optimize(session);
int l = left.getType(); int l = left.getType();
int r = right.getType(); int r = right.getType();
if ((l == Value.NULL && r == Value.NULL) || if ((l == Value.NULL && r == Value.NULL) ||
...@@ -234,7 +198,7 @@ public class Operation extends Expression { ...@@ -234,7 +198,7 @@ public class Operation extends Expression {
default: default:
DbException.throwInternalError("type=" + opType); DbException.throwInternalError("type=" + opType);
} }
if (left.isConstant() && (right == null || right.isConstant())) { if (left.isConstant() && right.isConstant()) {
return ValueExpression.get(getValue(session)); return ValueExpression.get(getValue(session));
} }
return this; return this;
...@@ -334,7 +298,7 @@ public class Operation extends Expression { ...@@ -334,7 +298,7 @@ public class Operation extends Expression {
// Oracle date add // Oracle date add
Function f = Function.getFunction(session.getDatabase(), "DATEADD"); Function f = Function.getFunction(session.getDatabase(), "DATEADD");
f.setParameter(0, ValueExpression.get(ValueString.get("SECOND"))); f.setParameter(0, ValueExpression.get(ValueString.get("SECOND")));
left = new Operation(OpType.MULTIPLY, ValueExpression.get(ValueInt left = new BinaryOperation(OpType.MULTIPLY, ValueExpression.get(ValueInt
.get(60 * 60 * 24)), left); .get(60 * 60 * 24)), left);
f.setParameter(1, left); f.setParameter(1, left);
f.setParameter(2, right); f.setParameter(2, right);
...@@ -361,7 +325,7 @@ public class Operation extends Expression { ...@@ -361,7 +325,7 @@ public class Operation extends Expression {
// Oracle date subtract // Oracle date subtract
Function f = Function.getFunction(session.getDatabase(), "DATEADD"); Function f = Function.getFunction(session.getDatabase(), "DATEADD");
f.setParameter(0, ValueExpression.get(ValueString.get("DAY"))); f.setParameter(0, ValueExpression.get(ValueString.get("DAY")));
right = new Operation(OpType.NEGATE, right, null); right = new UnaryOperation(right);
right = right.optimize(session); right = right.optimize(session);
f.setParameter(1, right); f.setParameter(1, right);
f.setParameter(2, left); f.setParameter(2, left);
...@@ -374,9 +338,9 @@ public class Operation extends Expression { ...@@ -374,9 +338,9 @@ public class Operation extends Expression {
// Oracle date subtract // Oracle date subtract
Function f = Function.getFunction(session.getDatabase(), "DATEADD"); Function f = Function.getFunction(session.getDatabase(), "DATEADD");
f.setParameter(0, ValueExpression.get(ValueString.get("SECOND"))); f.setParameter(0, ValueExpression.get(ValueString.get("SECOND")));
right = new Operation(OpType.MULTIPLY, ValueExpression.get(ValueInt right = new BinaryOperation(OpType.MULTIPLY, ValueExpression.get(ValueInt
.get(60 * 60 * 24)), right); .get(60 * 60 * 24)), right);
right = new Operation(OpType.NEGATE, right, null); right = new UnaryOperation(right);
right = right.optimize(session); right = right.optimize(session);
f.setParameter(1, right); f.setParameter(1, right);
f.setParameter(2, left); f.setParameter(2, left);
...@@ -437,9 +401,7 @@ public class Operation extends Expression { ...@@ -437,9 +401,7 @@ public class Operation extends Expression {
@Override @Override
public void setEvaluatable(TableFilter tableFilter, boolean b) { public void setEvaluatable(TableFilter tableFilter, boolean b) {
left.setEvaluatable(tableFilter, b); left.setEvaluatable(tableFilter, b);
if (right != null) { right.setEvaluatable(tableFilter, b);
right.setEvaluatable(tableFilter, b);
}
} }
@Override @Override
...@@ -449,74 +411,61 @@ public class Operation extends Expression { ...@@ -449,74 +411,61 @@ public class Operation extends Expression {
@Override @Override
public long getPrecision() { public long getPrecision() {
if (right != null) { switch (opType) {
switch (opType) { case CONCAT:
case CONCAT: return left.getPrecision() + right.getPrecision();
return left.getPrecision() + right.getPrecision(); default:
default: return Math.max(left.getPrecision(), right.getPrecision());
return Math.max(left.getPrecision(), right.getPrecision());
}
} }
return left.getPrecision();
} }
@Override @Override
public int getDisplaySize() { public int getDisplaySize() {
if (right != null) { switch (opType) {
switch (opType) { case CONCAT:
case CONCAT: return MathUtils.convertLongToInt((long) left.getDisplaySize() +
return MathUtils.convertLongToInt((long) left.getDisplaySize() + (long) right.getDisplaySize());
(long) right.getDisplaySize()); default:
default: return Math.max(left.getDisplaySize(), right.getDisplaySize());
return Math.max(left.getDisplaySize(), right.getDisplaySize());
}
} }
return left.getDisplaySize();
} }
@Override @Override
public int getScale() { public int getScale() {
if (right != null) { return Math.max(left.getScale(), right.getScale());
return Math.max(left.getScale(), right.getScale());
}
return left.getScale();
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session) {
left.updateAggregate(session); left.updateAggregate(session);
if (right != null) { right.updateAggregate(session);
right.updateAggregate(session);
}
} }
@Override @Override
public boolean isEverything(ExpressionVisitor visitor) { public boolean isEverything(ExpressionVisitor visitor) {
return left.isEverything(visitor) && return left.isEverything(visitor) && right.isEverything(visitor);
(right == null || right.isEverything(visitor));
} }
@Override @Override
public int getCost() { public int getCost() {
return left.getCost() + 1 + (right == null ? 0 : right.getCost()); return left.getCost() + right.getCost() + 1;
} }
/** @Override
* Get the left sub-expression of this operation. public int getSubexpressionCount() {
* return 2;
* @return the left sub-expression
*/
public Expression getLeftSubExpression() {
return left;
} }
/** @Override
* Get the right sub-expression of this operation. public Expression getSubexpression(int index) {
* switch (index) {
* @return the right sub-expression case 0:
*/ return left;
public Expression getRightSubExpression() { case 1:
return right; return right;
default:
throw new IndexOutOfBoundsException();
}
} }
} }
...@@ -587,22 +587,24 @@ public class Comparison extends Condition { ...@@ -587,22 +587,24 @@ public class Comparison extends Condition {
return null; return null;
} }
/** @Override
* Get the left sub-expression of this condition. public int getSubexpressionCount() {
* return compareType == IS_NULL || compareType == IS_NOT_NULL ? 1 : 2;
* @return the left sub-expression
*/
public Expression getLeftSubExpression() {
return left;
} }
/** @Override
* Get the right sub-expression of this condition. public Expression getSubexpression(int index) {
* switch (index) {
* @return the right sub-expression case 0:
*/ return left;
public Expression getRightSubExpression() { case 1:
return right; if (compareType != IS_NULL && compareType != IS_NOT_NULL) {
return right;
}
//$FALL-THROUGH$
default:
throw new IndexOutOfBoundsException();
}
} }
} }
...@@ -283,22 +283,21 @@ public class ConditionAndOr extends Condition { ...@@ -283,22 +283,21 @@ public class ConditionAndOr extends Condition {
return left.getCost() + right.getCost(); return left.getCost() + right.getCost();
} }
/** @Override
* Get the left sub-expression of this condition. public int getSubexpressionCount() {
* return 2;
* @return the left sub-expression
*/
public Expression getLeftSubExpression() {
return left;
} }
/** @Override
* Get the right sub-expression of this condition. public Expression getSubexpression(int index) {
* switch (index) {
* @return the right sub-expression case 0:
*/ return left;
public Expression getRightSubExpression() { case 1:
return right; return right;
default:
throw new IndexOutOfBoundsException();
}
} }
} }
...@@ -98,13 +98,17 @@ public class ConditionNot extends Condition { ...@@ -98,13 +98,17 @@ public class ConditionNot extends Condition {
return condition.getCost(); return condition.getCost();
} }
/** @Override
* Get the sub-expression of this condition. public int getSubexpressionCount() {
* return 1;
* @return the sub-expression }
*/
public Expression getSubCondition() { @Override
return condition; public Expression getSubexpression(int index) {
if (index == 0) {
return condition;
}
throw new IndexOutOfBoundsException();
} }
} }
...@@ -357,4 +357,24 @@ public abstract class Expression { ...@@ -357,4 +357,24 @@ public abstract class Expression {
} }
} }
/**
* Returns count of subexpressions.
*
* @return count of subexpressions
*/
public int getSubexpressionCount() {
return 0;
}
/**
* Returns subexpression with specified index.
*
* @param index 0-based index
* @return subexpression with specified index
* @throws IndexOutOfBoundsException if specified index is not valid
*/
public Expression getSubexpression(int index) {
throw new IndexOutOfBoundsException();
}
} }
...@@ -2710,4 +2710,14 @@ public class Function extends Expression implements FunctionCall { ...@@ -2710,4 +2710,14 @@ public class Function extends Expression implements FunctionCall {
return info.type == NEXTVAL; return info.type == NEXTVAL;
} }
@Override
public int getSubexpressionCount() {
return args.length;
}
@Override
public Expression getSubexpression(int index) {
return args[index];
}
} }
/*
* 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.expression;
import org.h2.engine.Session;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* Unary operation. Only negation operation is currently supported.
*/
public class UnaryOperation extends Expression {
private Expression arg;
private int dataType;
public UnaryOperation(Expression arg) {
this.arg = arg;
}
@Override
public String getSQL() {
// don't remove the space, otherwise it might end up some thing like
// --1 which is a line remark
return "(- " + arg.getSQL() + ')';
}
@Override
public Value getValue(Session session) {
Value a = arg.getValue(session).convertTo(dataType, session.getDatabase().getMode());
return a == ValueNull.INSTANCE ? a : a.negate();
}
@Override
public void mapColumns(ColumnResolver resolver, int level) {
arg.mapColumns(resolver, level);
}
@Override
public Expression optimize(Session session) {
arg = arg.optimize(session);
dataType = arg.getType();
if (dataType == Value.UNKNOWN) {
dataType = Value.DECIMAL;
} else if (dataType == Value.ENUM) {
dataType = Value.INT;
}
if (arg.isConstant()) {
return ValueExpression.get(getValue(session));
}
return this;
}
@Override
public void setEvaluatable(TableFilter tableFilter, boolean b) {
arg.setEvaluatable(tableFilter, b);
}
@Override
public int getType() {
return dataType;
}
@Override
public long getPrecision() {
return arg.getPrecision();
}
@Override
public int getDisplaySize() {
return arg.getDisplaySize();
}
@Override
public int getScale() {
return arg.getScale();
}
@Override
public void updateAggregate(Session session) {
arg.updateAggregate(session);
}
@Override
public boolean isEverything(ExpressionVisitor visitor) {
return arg.isEverything(visitor);
}
@Override
public int getCost() {
return arg.getCost() + 1;
}
@Override
public int getSubexpressionCount() {
return 1;
}
@Override
public Expression getSubexpression(int index) {
if (index == 0) {
return arg;
}
throw new IndexOutOfBoundsException();
}
}
...@@ -669,19 +669,17 @@ public class FullText { ...@@ -669,19 +669,17 @@ public class FullText {
ArrayList<String> data, Expression expr) { ArrayList<String> data, Expression expr) {
if (expr instanceof ConditionAndOr) { if (expr instanceof ConditionAndOr) {
ConditionAndOr and = (ConditionAndOr) expr; ConditionAndOr and = (ConditionAndOr) expr;
Expression left = and.getLeftSubExpression(); addColumnData(columns, data, and.getSubexpression(0));
Expression right = and.getRightSubExpression(); addColumnData(columns, data, and.getSubexpression(1));
addColumnData(columns, data, left);
addColumnData(columns, data, right);
} else { } else {
Comparison comp = (Comparison) expr; Comparison comp = (Comparison) expr;
ExpressionColumn ec = (ExpressionColumn) comp.getLeftSubExpression(); ExpressionColumn ec = (ExpressionColumn) comp.getSubexpression(0);
ValueExpression ev = (ValueExpression) comp.getRightSubExpression();
String columnName = ec.getColumnName(); String columnName = ec.getColumnName();
columns.add(columnName); columns.add(columnName);
if (ev == null) { if (expr.getSubexpressionCount() == 1) {
data.add(null); data.add(null);
} else { } else {
ValueExpression ev = (ValueExpression) comp.getSubexpression(1);
data.add(ev.getValue(null).getString()); data.add(ev.getValue(null).getString());
} }
} }
......
...@@ -66,6 +66,9 @@ SELECT DISTINCT NAME, ID + 1 FROM TEST ORDER BY UPPER(NAME) || (ID + 1); ...@@ -66,6 +66,9 @@ SELECT DISTINCT NAME, ID + 1 FROM TEST ORDER BY UPPER(NAME) || (ID + 1);
SELECT DISTINCT ID FROM TEST ORDER BY NAME; SELECT DISTINCT ID FROM TEST ORDER BY NAME;
> exception ORDER_BY_NOT_IN_RESULT > exception ORDER_BY_NOT_IN_RESULT
SELECT DISTINCT ID FROM TEST ORDER BY UPPER(NAME);
> exception ORDER_BY_NOT_IN_RESULT
SELECT DISTINCT ID FROM TEST ORDER BY CURRENT_TIMESTAMP; SELECT DISTINCT ID FROM TEST ORDER BY CURRENT_TIMESTAMP;
> exception ORDER_BY_NOT_IN_RESULT > exception ORDER_BY_NOT_IN_RESULT
......
...@@ -789,4 +789,4 @@ inconsistencies discover eliminated violates tweaks postpone leftovers ...@@ -789,4 +789,4 @@ inconsistencies discover eliminated violates tweaks postpone leftovers
tied ties tied ties
launched unavailable smallmoney erroneously multiplier newid pan streamline unmap preview unexpectedly presumably launched unavailable smallmoney erroneously multiplier newid pan streamline unmap preview unexpectedly presumably
converging smth rng curs casts unmapping unmapper converging smth rng curs casts unmapping unmapper
immediate hhmmss scheduled hhmm prematurely postponed arranges immediate hhmmss scheduled hhmm prematurely postponed arranges subexpression subexpressions
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论