You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2016/02/10 01:05:43 UTC
[1/3] calcite git commit: [CALCITE-1083] SqlNode.equalsDeep has O(n ^
2) performance
Repository: calcite
Updated Branches:
refs/heads/master e0f29dd79 -> 72b2cfb79
[CALCITE-1083] SqlNode.equalsDeep has O(n ^ 2) performance
Cause of the problem is that Litmus.fail constructs an error message string, even if the particular implementation of Litmus does not use the string. Solution is to pass a format string and arguments, which are only converted to strings if the message is used, the same as SLF4J Logger does.
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/670fa73e
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/670fa73e
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/670fa73e
Branch: refs/heads/master
Commit: 670fa73e24a7b72d6ddafd69793474083bb4b9f0
Parents: e0f29dd
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Feb 9 15:04:03 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Feb 9 15:17:40 2016 -0800
----------------------------------------------------------------------
.../org/apache/calcite/plan/RelOptUtil.java | 18 ++++++---------
.../org/apache/calcite/rel/core/Aggregate.java | 3 ++-
.../java/org/apache/calcite/rel/core/Join.java | 4 ++--
.../org/apache/calcite/rel/core/Project.java | 8 +++----
.../java/org/apache/calcite/rex/RexChecker.java | 4 ++--
.../java/org/apache/calcite/rex/RexLiteral.java | 8 +++----
.../java/org/apache/calcite/rex/RexProgram.java | 7 +++---
.../java/org/apache/calcite/rex/RexUtil.java | 9 ++++----
.../apache/calcite/sql/SqlBinaryOperator.java | 2 +-
.../java/org/apache/calcite/sql/SqlCall.java | 4 ++--
.../org/apache/calcite/sql/SqlDataTypeSpec.java | 10 ++++-----
.../org/apache/calcite/sql/SqlDynamicParam.java | 4 ++--
.../org/apache/calcite/sql/SqlIdentifier.java | 6 ++---
.../calcite/sql/SqlIntervalQualifier.java | 2 +-
.../java/org/apache/calcite/sql/SqlLiteral.java | 4 ++--
.../org/apache/calcite/sql/SqlNodeList.java | 4 ++--
.../apache/calcite/sql/SqlPostfixOperator.java | 2 +-
.../apache/calcite/sql/SqlPrefixOperator.java | 2 +-
.../apache/calcite/sql/fun/SqlInOperator.java | 2 +-
.../calcite/sql/fun/SqlStdOperatorTable.java | 2 +-
.../apache/calcite/sql2rel/RelDecorrelator.java | 2 +-
.../java/org/apache/calcite/util/Litmus.java | 23 ++++++++++++--------
22 files changed, 66 insertions(+), 64 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 610867a..a03a0fa 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -227,7 +227,7 @@ public abstract class RelOptUtil {
if (!set.contains(correlationId)) {
return litmus.succeed();
} else {
- return litmus.fail("contains " + correlationId);
+ return litmus.fail("contains {}", correlationId);
}
}
@@ -1662,11 +1662,9 @@ public abstract class RelOptUtil {
}
if (type1 != type2) {
- return litmus.fail("type mismatch:\n"
- + desc1 + ":\n"
- + type1.getFullTypeString() + "\n"
- + desc2 + ":\n"
- + type2.getFullTypeString());
+ return litmus.fail("type mismatch:\n{}:\n{}\n{}:\n{}",
+ desc1, type1.getFullTypeString(),
+ desc2, type2.getFullTypeString());
}
return litmus.succeed();
}
@@ -1690,11 +1688,9 @@ public abstract class RelOptUtil {
RelDataType type2,
Litmus litmus) {
if (!areRowTypesEqual(type1, type2, false)) {
- return litmus.fail("Type mismatch:\n"
- + desc1 + ":\n"
- + type1.getFullTypeString() + "\n"
- + desc2 + ":\n"
- + type2.getFullTypeString());
+ return litmus.fail("Type mismatch:\n{}:\n{}\n{}:\n{}",
+ desc1, type1.getFullTypeString(),
+ desc2, type2.getFullTypeString());
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
index 4eedee7..2408ae5 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
@@ -382,7 +382,8 @@ public abstract class Aggregate extends SingleRel {
public boolean isValid(Litmus litmus) {
return super.isValid(litmus)
- && litmus.check(Util.isDistinct(getRowType().getFieldNames()), getRowType());
+ && litmus.check(Util.isDistinct(getRowType().getFieldNames()),
+ "distinct field names: {}", getRowType());
}
/**
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rel/core/Join.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Join.java b/core/src/main/java/org/apache/calcite/rel/core/Join.java
index 7c20f14..4a99f0d 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Join.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Join.java
@@ -155,8 +155,8 @@ public abstract class Join extends BiRel {
}
if (condition != null) {
if (condition.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
- return litmus.fail("condition must be boolean: "
- + condition.getType());
+ return litmus.fail("condition must be boolean: {}",
+ condition.getType());
}
// The input to the condition is a row type consisting of system
// fields, left fields, and right fields. Very similar to the
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rel/core/Project.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Project.java b/core/src/main/java/org/apache/calcite/rel/core/Project.java
index e92b04d..8089506 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Project.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Project.java
@@ -184,12 +184,12 @@ public abstract class Project extends SingleRel {
for (RexNode exp : exps) {
exp.accept(checker);
if (checker.getFailureCount() > 0) {
- return litmus.fail(checker.getFailureCount()
- + " failures in expression " + exp);
+ return litmus.fail("{} failures in expression {}",
+ checker.getFailureCount(), exp);
}
}
if (!Util.isDistinct(rowType.getFieldNames())) {
- return litmus.fail("field names not distinct: " + rowType);
+ return litmus.fail("field names not distinct: {}", rowType);
}
//CHECKSTYLE: IGNORE 1
if (false && !Util.isDistinct(
@@ -205,7 +205,7 @@ public abstract class Project extends SingleRel {
// because we need to allow
//
// SELECT a, b FROM c UNION SELECT x, x FROM z
- return litmus.fail("duplicate expressions: " + exps);
+ return litmus.fail("duplicate expressions: {}", exps);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rex/RexChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexChecker.java b/core/src/main/java/org/apache/calcite/rex/RexChecker.java
index c51d923..d573c51 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexChecker.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexChecker.java
@@ -111,8 +111,8 @@ public class RexChecker extends RexVisitorImpl<Boolean> {
final int index = ref.getIndex();
if ((index < 0) || (index >= inputTypeList.size())) {
++failCount;
- return litmus.fail("RexInputRef index " + index
- + " out of range 0.." + (inputTypeList.size() - 1));
+ return litmus.fail("RexInputRef index {} out of range 0..{}",
+ index, inputTypeList.size() - 1);
}
if (!ref.getType().isStruct()
&& !RelOptUtil.eq("ref", ref.getType(), "input",
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
index 26f8e4a..e28653f 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
@@ -275,7 +275,7 @@ public class RexLiteral extends RexNode {
List list = (List) o;
for (Object o1 : list) {
if (!validConstant(o1, litmus)) {
- return litmus.fail("not a constant: " + o1);
+ return litmus.fail("not a constant: {}", o1);
}
}
return litmus.succeed();
@@ -283,15 +283,15 @@ public class RexLiteral extends RexNode {
@SuppressWarnings("unchecked") final Map<Object, Object> map = (Map) o;
for (Map.Entry entry : map.entrySet()) {
if (!validConstant(entry.getKey(), litmus)) {
- return litmus.fail("not a constant: " + entry.getKey());
+ return litmus.fail("not a constant: {}", entry.getKey());
}
if (!validConstant(entry.getValue(), litmus)) {
- return litmus.fail("not a constant: " + entry.getValue());
+ return litmus.fail("not a constant: {}", entry.getValue());
}
}
return litmus.succeed();
} else {
- return litmus.fail("not a constant: " + o);
+ return litmus.fail("not a constant: {}", o);
}
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rex/RexProgram.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexProgram.java b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
index 30382c5..2762180 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexProgram.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
@@ -766,9 +766,10 @@ public class RexProgram {
String normalized = normalizedProgram.toString();
String string = toString();
if (!normalized.equals(string)) {
- return litmus.fail("Program is not normalized:\n"
- + "program: " + string + "\n"
- + "normalized: " + normalized + "\n");
+ final String message = "Program is not normalized:\n"
+ + "program: {}\n"
+ + "normalized: {}\n";
+ return litmus.fail(message, string, normalized);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index ce3e936..f26c783 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -521,7 +521,7 @@ public class RexUtil {
expr.accept(visitor);
} catch (ForwardRefFinder.IllegalForwardRefException e) {
Util.swallow(e, null);
- return litmus.fail("illegal forward reference in " + expr);
+ return litmus.fail("illegal forward reference in {}", expr);
}
}
return litmus.succeed();
@@ -542,7 +542,7 @@ public class RexUtil {
for (RexNode operand : rexCall.operands) {
if (!(operand instanceof RexLocalRef)
&& !(operand instanceof RexLiteral)) {
- return litmus.fail("contains non trivial agg: " + operand);
+ return litmus.fail("contains non trivial agg: {}", operand);
}
}
}
@@ -680,12 +680,11 @@ public class RexUtil {
}
for (int i = 0; i < fields.size(); i++) {
if (!(exprs.get(i) instanceof RexInputRef)) {
- return litmus.fail("expr[" + i + "] is not a RexInputRef");
+ return litmus.fail("expr[{}] is not a RexInputRef", i);
}
RexInputRef inputRef = (RexInputRef) exprs.get(i);
if (inputRef.getIndex() != i) {
- return litmus.fail("expr[" + i + "] has ordinal "
- + inputRef.getIndex());
+ return litmus.fail("expr[{}] has ordinal {}", i, inputRef.getIndex());
}
if (!RelOptUtil.eq("type1",
exprs.get(i).getType(),
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
index 34943c2..c1dece3 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
@@ -217,7 +217,7 @@ public class SqlBinaryOperator extends SqlOperator {
&& count > 2) {
return true;
}
- return litmus.fail("wrong operand count " + count + " for " + this);
+ return litmus.fail("wrong operand count {} for {}", count, this);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlCall.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCall.java b/core/src/main/java/org/apache/calcite/sql/SqlCall.java
index 59066b3..620f1a8 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCall.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCall.java
@@ -140,14 +140,14 @@ public abstract class SqlCall extends SqlNode {
return true;
}
if (!(node instanceof SqlCall)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
SqlCall that = (SqlCall) node;
// Compare operators by name, not identity, because they may not
// have been resolved yet.
if (!this.getOperator().getName().equals(that.getOperator().getName())) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
return equalDeep(this.getOperandList(), that.getOperandList(), litmus);
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
index 2cffb82..d4bfc6c 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
@@ -236,7 +236,7 @@ public class SqlDataTypeSpec extends SqlNode {
public boolean equalsDeep(SqlNode node, Litmus litmus) {
if (!(node instanceof SqlDataTypeSpec)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
SqlDataTypeSpec that = (SqlDataTypeSpec) node;
if (!SqlNode.equalDeep(
@@ -248,16 +248,16 @@ public class SqlDataTypeSpec extends SqlNode {
return litmus.fail(null);
}
if (this.precision != that.precision) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
if (this.scale != that.scale) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
if (!Objects.equals(this.timeZone, that.timeZone)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
if (!Objects.equals(this.charSetName, that.charSetName)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java b/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java
index 8fc771c..7db5fd7 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java
@@ -79,11 +79,11 @@ public class SqlDynamicParam extends SqlNode {
public boolean equalsDeep(SqlNode node, Litmus litmus) {
if (!(node instanceof SqlDynamicParam)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
SqlDynamicParam that = (SqlDynamicParam) node;
if (this.index != that.index) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
index bd0c5d5..2a6bca0 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
@@ -289,15 +289,15 @@ public class SqlIdentifier extends SqlNode {
public boolean equalsDeep(SqlNode node, Litmus litmus) {
if (!(node instanceof SqlIdentifier)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
SqlIdentifier that = (SqlIdentifier) node;
if (this.names.size() != that.names.size()) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
for (int i = 0; i < names.size(); i++) {
if (!this.names.get(i).equals(that.names.get(i))) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
}
return litmus.succeed();
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
index aa9729d..ae36bee 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
@@ -147,7 +147,7 @@ public class SqlIntervalQualifier extends SqlNode {
final String thisString = this.toString();
final String thatString = node.toString();
if (!thisString.equals(thatString)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
index 625e11c..f535c53 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
@@ -407,11 +407,11 @@ public class SqlLiteral extends SqlNode {
public boolean equalsDeep(SqlNode node, Litmus litmus) {
if (!(node instanceof SqlLiteral)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
SqlLiteral that = (SqlLiteral) node;
if (!this.equals(that)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java b/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java
index 392d967..0925864 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java
@@ -155,11 +155,11 @@ public class SqlNodeList extends SqlNode implements Iterable<SqlNode> {
public boolean equalsDeep(SqlNode node, Litmus litmus) {
if (!(node instanceof SqlNodeList)) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
SqlNodeList that = (SqlNodeList) node;
if (this.size() != that.size()) {
- return litmus.fail(this + "!=" + node);
+ return litmus.fail("{} != {}", this, node);
}
for (int i = 0; i < list.size(); i++) {
SqlNode thisChild = list.get(i);
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java
index 5fef8ae..31020d1 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java
@@ -91,7 +91,7 @@ public class SqlPostfixOperator extends SqlOperator {
@Override public boolean validRexOperands(int count, Litmus litmus) {
if (count != 1) {
- return litmus.fail("wrong operand count " + count + " for " + this);
+ return litmus.fail("wrong operand count {} for {}", count, this);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
index 8976a56..11eeb26 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
@@ -100,7 +100,7 @@ public class SqlPrefixOperator extends SqlOperator {
@Override public boolean validRexOperands(int count, Litmus litmus) {
if (count != 1) {
- return litmus.fail("wrong operand count " + count + " for " + this);
+ return litmus.fail("wrong operand count {} for {}", count, this);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
index 9e8105a..a20cea3 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
@@ -87,7 +87,7 @@ public class SqlInOperator extends SqlBinaryOperator {
@Override public boolean validRexOperands(int count, Litmus litmus) {
if (count == 0) {
- return litmus.fail("wrong operand count " + count + " for " + this);
+ return litmus.fail("wrong operand count {} for {}", count, this);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 464945d..db755a2 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -617,7 +617,7 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
@Override public boolean validRexOperands(int count, Litmus litmus) {
if (count != 0) {
- return litmus.fail("wrong operand count " + count + " for " + this);
+ return litmus.fail("wrong operand count {} for {}", count, this);
}
return litmus.succeed();
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index ecfd124..024cb5f 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -1323,7 +1323,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
Litmus ret) {
for (int value : integers) {
if (value >= limit) {
- return ret.fail("out of range; value: " + value + ", limit: " + limit);
+ return ret.fail("out of range; value: {}, limit: {}", value, limit);
}
}
return ret.succeed();
http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/util/Litmus.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Litmus.java b/core/src/main/java/org/apache/calcite/util/Litmus.java
index 1a74e6c..0f0be55 100644
--- a/core/src/main/java/org/apache/calcite/util/Litmus.java
+++ b/core/src/main/java/org/apache/calcite/util/Litmus.java
@@ -23,19 +23,20 @@ public interface Litmus {
/** Implementation of {@link org.apache.calcite.util.Litmus} that throws
* an {@link java.lang.AssertionError} on failure. */
Litmus THROW = new Litmus() {
- public boolean fail(String message) {
- throw new AssertionError(message);
+ public boolean fail(String message, Object... args) {
+ final String s = message == null ? null : String.format(message, args);
+ throw new AssertionError(s);
}
public boolean succeed() {
return true;
}
- public boolean check(boolean condition, Object info) {
+ public boolean check(boolean condition, String message, Object... args) {
if (condition) {
return succeed();
} else {
- return fail(info == null ? null : info.toString());
+ return fail(message, args);
}
}
};
@@ -43,7 +44,7 @@ public interface Litmus {
/** Implementation of {@link org.apache.calcite.util.Litmus} that returns
* a status code but does not throw. */
Litmus IGNORE = new Litmus() {
- public boolean fail(String message) {
+ public boolean fail(String message, Object... args) {
return false;
}
@@ -51,13 +52,17 @@ public interface Litmus {
return true;
}
- public boolean check(boolean condition, Object info) {
+ public boolean check(boolean condition, String message, Object... args) {
return condition;
}
};
- /** Called when test fails. Returns false or throws. */
- boolean fail(String message);
+ /** Called when test fails. Returns false or throws.
+ *
+ * @param message Message
+ * @param args Arguments
+ */
+ boolean fail(String message, Object... args);
/** Called when test succeeds. Returns true. */
boolean succeed();
@@ -68,7 +73,7 @@ public interface Litmus {
* if the condition is false, calls {@link #fail},
* converting {@code info} into a string message.
*/
- boolean check(boolean condition, Object info);
+ boolean check(boolean condition, String message, Object... args);
}
// End Litmus.java
[2/3] calcite git commit: [CALCITE-1062] In validation,
lookup a (possibly overloaded) operator from an operator table
(Hsuan-Yi Chu)
Posted by jh...@apache.org.
[CALCITE-1062] In validation, lookup a (possibly overloaded) operator from an operator table (Hsuan-Yi Chu)
Close apache/calcite#188
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/c1ceba45
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/c1ceba45
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/c1ceba45
Branch: refs/heads/master
Commit: c1ceba45e5939be812bbe0bba6ee27586862b8e0
Parents: 670fa73
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Mon Jan 18 23:20:57 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Feb 9 16:02:19 2016 -0800
----------------------------------------------------------------------
.../org/apache/calcite/sql/SqlFunction.java | 77 ++++-------
.../org/apache/calcite/sql/SqlOperator.java | 113 +++++++++++++++-
.../java/org/apache/calcite/sql/SqlUtil.java | 132 ++++++++++++++-----
.../calcite/sql/fun/SqlBetweenOperator.java | 8 +-
.../sql/util/ReflectiveSqlOperatorTable.java | 4 +-
.../calcite/sql2rel/SqlToRelConverter.java | 11 +-
.../calcite/sql/test/SqlOperatorBaseTest.java | 27 ++++
.../apache/calcite/test/SqlValidatorTest.java | 2 +-
8 files changed, 276 insertions(+), 98 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
index dc63209..2ed8bda 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
@@ -19,12 +19,10 @@ package org.apache.calcite.sql;
import org.apache.calcite.linq4j.function.Function1;
import org.apache.calcite.linq4j.function.Functions;
import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlOperandTypeChecker;
import org.apache.calcite.sql.type.SqlOperandTypeInference;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
-import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql.validate.SqlValidatorScope;
import org.apache.calcite.util.Util;
@@ -235,71 +233,44 @@ public class SqlFunction extends SqlOperator {
SqlValidatorScope scope,
SqlCall call,
boolean convertRowArgToColumnList) {
-
// Scope for operands. Usually the same as 'scope'.
final SqlValidatorScope operandScope = scope.getOperandScope(call);
// Indicate to the validator that we're validating a new function call
validator.pushFunctionCall();
- // If any arguments are named, construct a map.
- final ImmutableList.Builder<String> nameBuilder = ImmutableList.builder();
- final ImmutableList.Builder<SqlNode> argBuilder = ImmutableList.builder();
- for (SqlNode operand : call.getOperandList()) {
- if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
- final List<SqlNode> operandList = ((SqlCall) operand).getOperandList();
- nameBuilder.add(((SqlIdentifier) operandList.get(1)).getSimple());
- argBuilder.add(operandList.get(0));
- }
- }
- ImmutableList<String> argNames = nameBuilder.build();
- final List<SqlNode> args;
- if (argNames.isEmpty()) {
- args = call.getOperandList();
- argNames = null;
- } else {
- if (argNames.size() < call.getOperandList().size()) {
- throw validator.newValidationError(call,
- RESOURCE.someButNotAllArgumentsAreNamed());
- }
- int duplicate = Util.firstDuplicate(argNames);
- if (duplicate >= 0) {
- throw validator.newValidationError(call,
- RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
- }
- args = argBuilder.build();
- }
+ List<String> argNames = constructArgNameList(
+ call);
+
+ List<SqlNode> args = constructOperandList(
+ validator,
+ call,
+ argNames);
+
+ List<RelDataType> argTypes = constructArgTypeList(
+ validator,
+ scope,
+ call,
+ args,
+ convertRowArgToColumnList);
+
+ SqlFunction function = (SqlFunction) SqlUtil.lookupRoutine(
+ validator.getOperatorTable(),
+ getNameAsId(),
+ argTypes,
+ argNames,
+ SqlSyntax.FUNCTION,
+ getKind(),
+ getFunctionType());
try {
- final ImmutableList.Builder<RelDataType> argTypeBuilder =
- ImmutableList.builder();
boolean containsRowArg = false;
for (SqlNode operand : args) {
- RelDataType nodeType;
-
- // for row arguments that should be converted to ColumnList
- // types, set the nodeType to a ColumnList type but defer
- // validating the arguments of the row constructor until we know
- // for sure that the row argument maps to a ColumnList type
if (operand.getKind() == SqlKind.ROW && convertRowArgToColumnList) {
containsRowArg = true;
- RelDataTypeFactory typeFactory = validator.getTypeFactory();
- nodeType = typeFactory.createSqlType(SqlTypeName.COLUMN_LIST);
- } else {
- nodeType = validator.deriveType(operandScope, operand);
+ break;
}
- validator.setValidatedNodeType(operand, nodeType);
- argTypeBuilder.add(nodeType);
}
- final List<RelDataType> argTypes = argTypeBuilder.build();
- SqlFunction function =
- SqlUtil.lookupRoutine(
- validator.getOperatorTable(),
- getNameAsId(),
- argTypes,
- argNames,
- getFunctionType());
-
// if we have a match on function name and parameter count, but
// couldn't find a function with a COLUMN_LIST type, retry, but
// this time, don't convert the row argument to a COLUMN_LIST type;
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
index 476a1c5..e3d9c27 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
@@ -23,6 +23,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlOperandTypeChecker;
import org.apache.calcite.sql.type.SqlOperandTypeInference;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
+import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.util.SqlBasicVisitor;
import org.apache.calcite.sql.util.SqlVisitor;
import org.apache.calcite.sql.validate.SqlMonotonicity;
@@ -32,6 +33,8 @@ import org.apache.calcite.sql.validate.SqlValidatorUtil;
import org.apache.calcite.util.Litmus;
import org.apache.calcite.util.Util;
+import com.google.common.collect.ImmutableList;
+
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -480,12 +483,32 @@ public abstract class SqlOperator {
SqlValidator validator,
SqlValidatorScope scope,
SqlCall call) {
- for (SqlNode operand : call.getOperandList()) {
- RelDataType nodeType = validator.deriveType(scope, operand);
- assert nodeType != null;
- }
- RelDataType type = validateOperands(validator, scope, call);
+ List<SqlNode> args = constructOperandList(
+ validator,
+ call,
+ null);
+
+ List<RelDataType> argTypes = constructArgTypeList(
+ validator,
+ scope,
+ call,
+ args,
+ false);
+
+ SqlOperator sqlOperator = SqlUtil.lookupRoutine(
+ validator.getOperatorTable(),
+ new SqlIdentifier(
+ call.getOperator().getName(),
+ call.getParserPosition()),
+ argTypes,
+ null,
+ getSyntax(),
+ getKind(),
+ null);
+
+ ((SqlBasicCall) call).setOperator(sqlOperator);
+ RelDataType type = call.getOperator().validateOperands(validator, scope, call);
// Validate and determine coercibility and resulting collation
// name of binary operator if needed.
@@ -494,6 +517,86 @@ public abstract class SqlOperator {
return type;
}
+ protected List<String> constructArgNameList(SqlCall call) {
+ // If any arguments are named, construct a map.
+ final ImmutableList.Builder<String> nameBuilder = ImmutableList.builder();
+ for (SqlNode operand : call.getOperandList()) {
+ if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
+ final List<SqlNode> operandList = ((SqlCall) operand).getOperandList();
+ nameBuilder.add(((SqlIdentifier) operandList.get(1)).getSimple());
+ }
+ }
+ ImmutableList<String> argNames = nameBuilder.build();
+
+ if (argNames.isEmpty()) {
+ return null;
+ } else {
+ return argNames;
+ }
+ }
+
+ protected List<SqlNode> constructOperandList(
+ SqlValidator validator,
+ SqlCall call,
+ List<String> argNames) {
+ final ImmutableList.Builder<SqlNode> argBuilder = ImmutableList.builder();
+ for (SqlNode operand : call.getOperandList()) {
+ if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
+ final List<SqlNode> operandList = ((SqlCall) operand).getOperandList();
+ argBuilder.add(operandList.get(0));
+ }
+ }
+
+ final List<SqlNode> args;
+ if (argNames == null) {
+ args = call.getOperandList();
+ } else {
+ if (argNames.size() < call.getOperandList().size()) {
+ throw validator.newValidationError(call,
+ RESOURCE.someButNotAllArgumentsAreNamed());
+ }
+ int duplicate = Util.firstDuplicate(argNames);
+ if (duplicate >= 0) {
+ throw validator.newValidationError(call,
+ RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
+ }
+ args = argBuilder.build();
+ }
+
+ return args;
+ }
+
+ protected List<RelDataType> constructArgTypeList(
+ SqlValidator validator,
+ SqlValidatorScope scope,
+ SqlCall call,
+ List<SqlNode> args,
+ boolean convertRowArgToColumnList) {
+ // Scope for operands. Usually the same as 'scope'.
+ final SqlValidatorScope operandScope = scope.getOperandScope(call);
+
+ final ImmutableList.Builder<RelDataType> argTypeBuilder =
+ ImmutableList.builder();
+ for (SqlNode operand : args) {
+ RelDataType nodeType;
+ // for row arguments that should be converted to ColumnList
+ // types, set the nodeType to a ColumnList type but defer
+ // validating the arguments of the row constructor until we know
+ // for sure that the row argument maps to a ColumnList type
+ if (operand.getKind() == SqlKind.ROW && convertRowArgToColumnList) {
+ RelDataTypeFactory typeFactory = validator.getTypeFactory();
+ nodeType = typeFactory.createSqlType(SqlTypeName.COLUMN_LIST);
+ } else {
+ nodeType = validator.deriveType(operandScope, operand);
+ }
+ validator.setValidatedNodeType(operand, nodeType);
+ argTypeBuilder.add(nodeType);
+ }
+
+ final List<RelDataType> argTypes = argTypeBuilder.build();
+ return argTypes;
+ }
+
/**
* Returns whether this operator should be surrounded by space when
* unparsed.
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
index 87e73e0..2ba78aa 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
@@ -325,15 +325,22 @@ public abstract class SqlUtil {
* @return matching routine, or null if none found
* @sql.99 Part 2 Section 10.4
*/
- public static SqlFunction lookupRoutine(SqlOperatorTable opTab,
- SqlIdentifier funcName, List<RelDataType> argTypes,
- List<String> argNames, SqlFunctionCategory category) {
- List<SqlFunction> list =
+ public static SqlOperator lookupRoutine(
+ SqlOperatorTable opTab,
+ SqlIdentifier funcName,
+ List<RelDataType> argTypes,
+ List<String> argNames,
+ SqlSyntax sqlSyntax,
+ SqlKind sqlKind,
+ SqlFunctionCategory category) {
+ List<SqlOperator> list =
lookupSubjectRoutines(
opTab,
funcName,
argTypes,
argNames,
+ sqlSyntax,
+ sqlKind,
category);
if (list.isEmpty()) {
return null;
@@ -343,23 +350,42 @@ public abstract class SqlUtil {
}
}
+ private static void filterOperatorRoutinesByKind(
+ List<SqlOperator> routines,
+ SqlKind sqlKind) {
+ Iterator<SqlOperator> iter = routines.iterator();
+ while (iter.hasNext()) {
+ SqlOperator sqlOperator = iter.next();
+ if (sqlKind != sqlOperator.getKind()) {
+ iter.remove();
+ }
+ }
+ }
+
/**
* Looks up all subject routines matching the given name and argument types.
*
- * @param opTab operator table to search
- * @param funcName name of function being invoked
- * @param argTypes argument types
- * @param argNames argument names, or null if call by position
+ * @param opTab operator table to search
+ * @param funcName name of function being invoked
+ * @param argTypes argument types
+ * @param argNames argument names, or null if call by position
+ * @param sqlSyntax the SqlSyntax of the SqlOperator being looked up
+ * @param sqlKind the SqlKind of the SqlOperator being looked up
* @param category category of routine to look up
* @return list of matching routines
* @sql.99 Part 2 Section 10.4
*/
- public static List<SqlFunction> lookupSubjectRoutines(SqlOperatorTable opTab,
- SqlIdentifier funcName, List<RelDataType> argTypes,
- List<String> argNames, SqlFunctionCategory category) {
+ public static List<SqlOperator> lookupSubjectRoutines(
+ SqlOperatorTable opTab,
+ SqlIdentifier funcName,
+ List<RelDataType> argTypes,
+ List<String> argNames,
+ SqlSyntax sqlSyntax,
+ SqlKind sqlKind,
+ SqlFunctionCategory category) {
// start with all routines matching by name
- List<SqlFunction> routines =
- lookupSubjectRoutinesByName(opTab, funcName, category);
+ List<SqlOperator> routines =
+ lookupSubjectRoutinesByName(opTab, funcName, sqlSyntax, category);
// first pass: eliminate routines which don't accept the given
// number of arguments
@@ -373,8 +399,7 @@ public abstract class SqlUtil {
// second pass: eliminate routines which don't accept the given
// argument types
- filterRoutinesByParameterType(routines, argTypes, argNames);
-
+ filterRoutinesByParameterType(sqlSyntax, routines, argTypes, argNames);
// see if we can stop now; this is necessary for the case
// of builtin functions where we don't have param type info
if (routines.size() < 2) {
@@ -384,8 +409,11 @@ public abstract class SqlUtil {
// third pass: for each parameter from left to right, eliminate
// all routines except those with the best precedence match for
// the given arguments
- filterRoutinesByTypePrecedence(routines, argTypes);
+ filterRoutinesByTypePrecedence(sqlSyntax, routines, argTypes);
+ // fourth pass: eliminate routines which do not have the same
+ // SqlKind as requested
+ filterOperatorRoutinesByKind(routines, sqlKind);
return routines;
}
@@ -406,8 +434,8 @@ public abstract class SqlUtil {
List<RelDataType> argTypes,
SqlFunctionCategory category) {
// start with all routines matching by name
- List<SqlFunction> routines =
- lookupSubjectRoutinesByName(opTab, funcName, category);
+ List<SqlOperator> routines =
+ lookupSubjectRoutinesByName(opTab, funcName, SqlSyntax.FUNCTION, category);
// first pass: eliminate routines which don't accept the given
// number of arguments
@@ -416,29 +444,37 @@ public abstract class SqlUtil {
return routines.size() > 0;
}
- private static List<SqlFunction> lookupSubjectRoutinesByName(
+ private static List<SqlOperator> lookupSubjectRoutinesByName(
SqlOperatorTable opTab,
SqlIdentifier funcName,
+ SqlSyntax sqlSyntax,
SqlFunctionCategory category) {
- final List<SqlOperator> operators = Lists.newArrayList();
- opTab.lookupOperatorOverloads(funcName, category, SqlSyntax.FUNCTION,
- operators);
- List<SqlFunction> routines = new ArrayList<SqlFunction>();
- for (SqlOperator operator : operators) {
- if (operator instanceof SqlFunction) {
- routines.add((SqlFunction) operator);
+ final List<SqlOperator> sqlOperators = Lists.newArrayList();
+ opTab.lookupOperatorOverloads(
+ funcName,
+ category,
+ sqlSyntax,
+ sqlOperators);
+ List<SqlOperator> routines = Lists.newArrayList();
+ for (SqlOperator sqlOperator : sqlOperators) {
+ if (sqlSyntax == SqlSyntax.FUNCTION) {
+ if (sqlOperator instanceof SqlFunction) {
+ routines.add(sqlOperator);
+ }
+ } else if (sqlSyntax == sqlOperator.getSyntax()) {
+ routines.add(sqlOperator);
}
}
return routines;
}
private static void filterRoutinesByParameterCount(
- List<SqlFunction> routines,
+ List<SqlOperator> routines,
List<RelDataType> argTypes) {
- Iterator<SqlFunction> iter = routines.iterator();
+ Iterator<? extends SqlOperator> iter = routines.iterator();
while (iter.hasNext()) {
- SqlFunction function = iter.next();
- SqlOperandCountRange od = function.getOperandCountRange();
+ SqlOperator operator = iter.next();
+ SqlOperandCountRange od = operator.getOperandCountRange();
if (!od.isValidCount(argTypes.size())) {
iter.remove();
}
@@ -448,9 +484,21 @@ public abstract class SqlUtil {
/**
* @sql.99 Part 2 Section 10.4 Syntax Rule 6.b.iii.2.B
*/
- private static void filterRoutinesByParameterType(List<SqlFunction> routines,
+ private static void filterRoutinesByParameterType(
+ SqlSyntax sqlSyntax,
+ List<SqlOperator> routines,
final List<RelDataType> argTypes, List<String> argNames) {
- Iterator<SqlFunction> iter = routines.iterator();
+ if (sqlSyntax != SqlSyntax.FUNCTION) {
+ return;
+ }
+
+ List<SqlFunction> sqlFunctions = Lists.newArrayList();
+ for (SqlOperator sqlOperator : routines) {
+ sqlFunctions.add((SqlFunction) sqlOperator);
+ }
+ routines.clear();
+
+ Iterator<SqlFunction> iter = sqlFunctions.iterator();
loop:
while (iter.hasNext()) {
SqlFunction function = iter.next();
@@ -499,19 +547,32 @@ public abstract class SqlUtil {
}
}
}
+
+ routines.addAll(sqlFunctions);
}
/**
* @sql.99 Part 2 Section 9.4
*/
private static void filterRoutinesByTypePrecedence(
- List<SqlFunction> routines,
+ SqlSyntax sqlSyntax,
+ List<SqlOperator> routines,
List<RelDataType> argTypes) {
+ if (sqlSyntax != SqlSyntax.FUNCTION) {
+ return;
+ }
+
+ List<SqlFunction> sqlFunctions = Lists.newArrayList();
+ for (SqlOperator sqlOperator : routines) {
+ sqlFunctions.add((SqlFunction) sqlOperator);
+ }
+ routines.clear();
+
for (int i = 0; i < argTypes.size(); ++i) {
RelDataTypePrecedenceList precList =
argTypes.get(i).getPrecedenceList();
RelDataType bestMatch = null;
- for (SqlFunction function : routines) {
+ for (SqlFunction function : sqlFunctions) {
List<RelDataType> paramTypes = function.getParamTypes();
if (paramTypes == null) {
continue;
@@ -530,7 +591,7 @@ public abstract class SqlUtil {
}
}
if (bestMatch != null) {
- Iterator<SqlFunction> iter = routines.iterator();
+ Iterator<SqlFunction> iter = sqlFunctions.iterator();
while (iter.hasNext()) {
SqlFunction function = iter.next();
List<RelDataType> paramTypes = function.getParamTypes();
@@ -548,6 +609,7 @@ public abstract class SqlUtil {
}
}
}
+ routines.addAll(sqlFunctions);
}
/**
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
index 03b6646..4dff351 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
@@ -159,6 +159,12 @@ public class SqlBetweenOperator extends SqlInfixOperator {
return "{1} {0} {2} AND {3}";
}
+ @Override public String getName() {
+ return super.getName()
+ + " "
+ + flag.name();
+ }
+
public void unparse(
SqlWriter writer,
SqlCall call,
@@ -167,7 +173,7 @@ public class SqlBetweenOperator extends SqlInfixOperator {
final SqlWriter.Frame frame =
writer.startList(FRAME_TYPE, "", "");
call.operand(VALUE_OPERAND).unparse(writer, getLeftPrec(), 0);
- writer.sep(getName());
+ writer.sep(super.getName());
writer.sep(flag.name());
// If the expression for the lower bound contains a call to an AND
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
index 97691fa..3291095 100644
--- a/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
@@ -143,7 +143,7 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
}
public void register(SqlOperator op) {
- operators.put(op.getName(), op);
+ operators.put(op.getName().toUpperCase(), op);
if (op instanceof SqlBinaryOperator) {
mapNameToOp.put(Pair.of(op.getName(), SqlSyntax.BINARY), op);
} else if (op instanceof SqlPrefixOperator) {
@@ -159,7 +159,7 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
* @param function Function to register
*/
public void register(SqlFunction function) {
- operators.put(function.getName(), function);
+ operators.put(function.getName().toUpperCase(), function);
SqlFunctionCategory funcType = function.getFunctionType();
assert funcType != null
: "Function type for " + function.getName() + " not set";
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 5a51ca9..31a2b5c 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1831,8 +1831,17 @@ public class SqlToRelConverter {
SqlNode windowOrRef = call.operand(1);
final SqlWindow window =
validator.resolveWindow(windowOrRef, bb.scope, true);
+ final SqlOperator row_number_function = SqlUtil.lookupRoutine(
+ opTab,
+ SqlStdOperatorTable.ROW_NUMBER.getNameAsId(),
+ ImmutableList.<RelDataType>of(),
+ ImmutableList.<String>of(),
+ SqlStdOperatorTable.ROW_NUMBER.getSyntax(),
+ SqlStdOperatorTable.ROW_NUMBER.getKind(),
+ SqlStdOperatorTable.ROW_NUMBER.getFunctionType());
+
// ROW_NUMBER() expects specific kind of framing.
- if (aggCall.getOperator() == SqlStdOperatorTable.ROW_NUMBER) {
+ if (aggCall.getOperator() == row_number_function) {
window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO));
window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO));
window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO));
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 54e808a..c11571a 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -67,11 +67,14 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;
import java.util.regex.Pattern;
+import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
/**
@@ -297,6 +300,30 @@ public abstract class SqlOperatorBaseTest {
@Test public void testDummy() {
}
+ @Test public void testSqlOperatorOverloading() {
+ final SqlStdOperatorTable operatorTable = SqlStdOperatorTable.instance();
+ for (SqlOperator sqlOperator : operatorTable.getOperatorList()) {
+ String operatorName = sqlOperator.getName();
+ List<SqlOperator> routines = new ArrayList<>();
+ operatorTable.lookupOperatorOverloads(
+ new SqlIdentifier(operatorName, SqlParserPos.ZERO),
+ null,
+ sqlOperator.getSyntax(),
+ routines);
+
+ Iterator<SqlOperator> iter = routines.iterator();
+ while (iter.hasNext()) {
+ SqlOperator operator = iter.next();
+ if (!sqlOperator.getClass().isInstance(operator)) {
+ iter.remove();
+ }
+ }
+ assertThat(routines.size(), equalTo(1));
+ assertThat(sqlOperator, equalTo(routines.get(0)));
+ }
+ }
+
+
@Test public void testBetween() {
tester.setFor(
SqlStdOperatorTable.BETWEEN,
http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index cde2b8c..b3a8699 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -632,7 +632,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
checkExp("'a' between 'b' and 'c'");
checkExp("'' between 2 and 3"); // can implicitly convert CHAR to INTEGER
checkWholeExpFails("date '2012-02-03' between 2 and 3",
- "(?s).*Cannot apply 'BETWEEN' to arguments of type.*");
+ "(?s).*Cannot apply 'BETWEEN ASYMMETRIC' to arguments of type.*");
}
@Test public void testCharsetMismatch() {
[3/3] calcite git commit: Fix up [CALCITE-1062]
Posted by jh...@apache.org.
Fix up [CALCITE-1062]
Add SqlKind for ROW_NUMBER and other rank functions.
Use iterator rather than list when resolving operator overloads.
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/72b2cfb7
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/72b2cfb7
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/72b2cfb7
Branch: refs/heads/master
Commit: 72b2cfb799242e0d1d7e6aed8bfe43cceb554c7c
Parents: c1ceba4
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Feb 9 15:16:11 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Feb 9 16:04:56 2016 -0800
----------------------------------------------------------------------
.../org/apache/calcite/sql/SqlFunction.java | 63 ++--
.../java/org/apache/calcite/sql/SqlKind.java | 15 +
.../org/apache/calcite/sql/SqlOperator.java | 75 ++--
.../org/apache/calcite/sql/SqlRankFunction.java | 13 +-
.../java/org/apache/calcite/sql/SqlUtil.java | 340 +++++++++----------
.../calcite/sql/fun/SqlStdOperatorTable.java | 21 +-
.../sql/util/ReflectiveSqlOperatorTable.java | 81 +++--
.../calcite/sql2rel/SqlToRelConverter.java | 10 +-
8 files changed, 289 insertions(+), 329 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
index 2ed8bda..3bdc91c 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
@@ -19,7 +19,6 @@ package org.apache.calcite.sql;
import org.apache.calcite.linq4j.function.Function1;
import org.apache.calcite.linq4j.function.Functions;
import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlOperandTypeChecker;
import org.apache.calcite.sql.type.SqlOperandTypeInference;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
@@ -141,16 +140,11 @@ public class SqlFunction extends SqlOperator {
return sqlIdentifier;
}
- /**
- * @return fully qualified name of function
- */
- public SqlIdentifier getNameAsId() {
+ @Override public SqlIdentifier getNameAsId() {
if (sqlIdentifier != null) {
return sqlIdentifier;
}
- return new SqlIdentifier(
- getName(),
- SqlParserPos.ZERO);
+ return super.getNameAsId();
}
/**
@@ -239,38 +233,18 @@ public class SqlFunction extends SqlOperator {
// Indicate to the validator that we're validating a new function call
validator.pushFunctionCall();
- List<String> argNames = constructArgNameList(
- call);
-
- List<SqlNode> args = constructOperandList(
- validator,
- call,
- argNames);
-
- List<RelDataType> argTypes = constructArgTypeList(
- validator,
- scope,
- call,
- args,
- convertRowArgToColumnList);
-
- SqlFunction function = (SqlFunction) SqlUtil.lookupRoutine(
- validator.getOperatorTable(),
- getNameAsId(),
- argTypes,
- argNames,
- SqlSyntax.FUNCTION,
- getKind(),
- getFunctionType());
- try {
- boolean containsRowArg = false;
- for (SqlNode operand : args) {
- if (operand.getKind() == SqlKind.ROW && convertRowArgToColumnList) {
- containsRowArg = true;
- break;
- }
- }
+ final List<String> argNames = constructArgNameList(call);
+
+ final List<SqlNode> args = constructOperandList(validator, call, argNames);
+
+ final List<RelDataType> argTypes = constructArgTypeList(validator, scope,
+ call, args, convertRowArgToColumnList);
+ final SqlFunction function =
+ (SqlFunction) SqlUtil.lookupRoutine(validator.getOperatorTable(),
+ getNameAsId(), argTypes, argNames, getFunctionType(), SqlSyntax.FUNCTION, getKind()
+ );
+ try {
// if we have a match on function name and parameter count, but
// couldn't find a function with a COLUMN_LIST type, retry, but
// this time, don't convert the row argument to a COLUMN_LIST type;
@@ -278,7 +252,7 @@ public class SqlFunction extends SqlOperator {
// (corresponding to column references), now that we can set the
// scope to that of the source cursor referenced by that ColumnList
// type
- if (containsRowArg) {
+ if (convertRowArgToColumnList && containsRowArg(args)) {
if (function == null
&& SqlUtil.matchRoutinesByParameterCount(
validator.getOperatorTable(), getNameAsId(), argTypes,
@@ -318,6 +292,15 @@ public class SqlFunction extends SqlOperator {
validator.popFunctionCall();
}
}
+
+ private boolean containsRowArg(List<SqlNode> args) {
+ for (SqlNode operand : args) {
+ if (operand.getKind() == SqlKind.ROW) {
+ return true;
+ }
+ }
+ return false;
+ }
}
// End SqlFunction.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/SqlKind.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
index 270a311..bbc7e7e 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -693,6 +693,21 @@ public enum SqlKind {
/** The {@code SINGLE_VALUE} aggregate function. */
SINGLE_VALUE,
+ /** The {@code ROW_NUMBER} window function. */
+ ROW_NUMBER,
+
+ /** The {@code RANK} window function. */
+ RANK,
+
+ /** The {@code PERCENT_RANK} window function. */
+ PERCENT_RANK,
+
+ /** The {@code DENSE_RANK} window function. */
+ DENSE_RANK,
+
+ /** The {@code ROW_NUMBER} window function. */
+ CUME_DIST,
+
// DDL and session control statements follow. The list is not exhaustive: feel
// free to add more.
http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
index e3d9c27..d3bd645 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
@@ -204,6 +204,13 @@ public abstract class SqlOperator {
return name;
}
+ /**
+ * Returns the fully-qualified name of this operator.
+ */
+ public SqlIdentifier getNameAsId() {
+ return new SqlIdentifier(getName(), SqlParserPos.ZERO);
+ }
+
public SqlKind getKind() {
return kind;
}
@@ -483,29 +490,19 @@ public abstract class SqlOperator {
SqlValidator validator,
SqlValidatorScope scope,
SqlCall call) {
+ for (SqlNode operand : call.getOperandList()) {
+ RelDataType nodeType = validator.deriveType(scope, operand);
+ assert nodeType != null;
+ }
- List<SqlNode> args = constructOperandList(
- validator,
- call,
- null);
-
- List<RelDataType> argTypes = constructArgTypeList(
- validator,
- scope,
- call,
- args,
- false);
-
- SqlOperator sqlOperator = SqlUtil.lookupRoutine(
- validator.getOperatorTable(),
- new SqlIdentifier(
- call.getOperator().getName(),
- call.getParserPosition()),
- argTypes,
- null,
- getSyntax(),
- getKind(),
- null);
+ final List<SqlNode> args = constructOperandList(validator, call, null);
+
+ final List<RelDataType> argTypes = constructArgTypeList(validator, scope,
+ call, args, false);
+
+ final SqlOperator sqlOperator =
+ SqlUtil.lookupRoutine(validator.getOperatorTable(), getNameAsId(),
+ argTypes, null, null, getSyntax(), getKind());
((SqlBasicCall) call).setOperator(sqlOperator);
RelDataType type = call.getOperator().validateOperands(validator, scope, call);
@@ -539,6 +536,18 @@ public abstract class SqlOperator {
SqlValidator validator,
SqlCall call,
List<String> argNames) {
+ if (argNames == null) {
+ return call.getOperandList();
+ }
+ if (argNames.size() < call.getOperandList().size()) {
+ throw validator.newValidationError(call,
+ RESOURCE.someButNotAllArgumentsAreNamed());
+ }
+ final int duplicate = Util.firstDuplicate(argNames);
+ if (duplicate >= 0) {
+ throw validator.newValidationError(call,
+ RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
+ }
final ImmutableList.Builder<SqlNode> argBuilder = ImmutableList.builder();
for (SqlNode operand : call.getOperandList()) {
if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
@@ -546,24 +555,7 @@ public abstract class SqlOperator {
argBuilder.add(operandList.get(0));
}
}
-
- final List<SqlNode> args;
- if (argNames == null) {
- args = call.getOperandList();
- } else {
- if (argNames.size() < call.getOperandList().size()) {
- throw validator.newValidationError(call,
- RESOURCE.someButNotAllArgumentsAreNamed());
- }
- int duplicate = Util.firstDuplicate(argNames);
- if (duplicate >= 0) {
- throw validator.newValidationError(call,
- RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
- }
- args = argBuilder.build();
- }
-
- return args;
+ return argBuilder.build();
}
protected List<RelDataType> constructArgTypeList(
@@ -593,8 +585,7 @@ public abstract class SqlOperator {
argTypeBuilder.add(nodeType);
}
- final List<RelDataType> argTypes = argTypeBuilder.build();
- return argTypes;
+ return argTypeBuilder.build();
}
/**
http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
index 738add1..8bf4721 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
@@ -25,16 +25,9 @@ import org.apache.calcite.sql.type.ReturnTypes;
public class SqlRankFunction extends SqlAggFunction {
//~ Constructors -----------------------------------------------------------
- public SqlRankFunction(String name, boolean requiresOrder) {
- super(
- name,
- null,
- SqlKind.OTHER_FUNCTION,
- ReturnTypes.INTEGER,
- null,
- OperandTypes.NILADIC,
- SqlFunctionCategory.NUMERIC,
- requiresOrder,
+ public SqlRankFunction(boolean requiresOrder, SqlKind kind) {
+ super(kind.name(), null, kind, ReturnTypes.INTEGER, null,
+ OperandTypes.NILADIC, SqlFunctionCategory.NUMERIC, requiresOrder,
true);
}
http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
index 2ba78aa..40e1255 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
@@ -38,7 +38,10 @@ import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import java.nio.charset.Charset;
@@ -325,41 +328,35 @@ public abstract class SqlUtil {
* @return matching routine, or null if none found
* @sql.99 Part 2 Section 10.4
*/
- public static SqlOperator lookupRoutine(
- SqlOperatorTable opTab,
- SqlIdentifier funcName,
- List<RelDataType> argTypes,
- List<String> argNames,
- SqlSyntax sqlSyntax,
- SqlKind sqlKind,
- SqlFunctionCategory category) {
- List<SqlOperator> list =
+ public static SqlOperator lookupRoutine(SqlOperatorTable opTab,
+ SqlIdentifier funcName, List<RelDataType> argTypes,
+ List<String> argNames, SqlFunctionCategory category,
+ SqlSyntax syntax, SqlKind sqlKind) {
+ Iterator<SqlOperator> list =
lookupSubjectRoutines(
opTab,
funcName,
argTypes,
argNames,
- sqlSyntax,
+ syntax,
sqlKind,
category);
- if (list.isEmpty()) {
- return null;
- } else {
+ if (list.hasNext()) {
// return first on schema path
- return list.get(0);
+ return list.next();
}
+ return null;
}
- private static void filterOperatorRoutinesByKind(
- List<SqlOperator> routines,
- SqlKind sqlKind) {
- Iterator<SqlOperator> iter = routines.iterator();
- while (iter.hasNext()) {
- SqlOperator sqlOperator = iter.next();
- if (sqlKind != sqlOperator.getKind()) {
- iter.remove();
- }
- }
+ private static Iterator<SqlOperator>
+ filterOperatorRoutinesByKind(Iterator<SqlOperator> routines,
+ final SqlKind sqlKind) {
+ return Iterators.filter(routines,
+ new Predicate<SqlOperator>() {
+ public boolean apply(SqlOperator input) {
+ return input.getKind() == sqlKind;
+ }
+ });
}
/**
@@ -375,7 +372,7 @@ public abstract class SqlUtil {
* @return list of matching routines
* @sql.99 Part 2 Section 10.4
*/
- public static List<SqlOperator> lookupSubjectRoutines(
+ public static Iterator<SqlOperator> lookupSubjectRoutines(
SqlOperatorTable opTab,
SqlIdentifier funcName,
List<RelDataType> argTypes,
@@ -384,12 +381,12 @@ public abstract class SqlUtil {
SqlKind sqlKind,
SqlFunctionCategory category) {
// start with all routines matching by name
- List<SqlOperator> routines =
+ Iterator<SqlOperator> routines =
lookupSubjectRoutinesByName(opTab, funcName, sqlSyntax, category);
// first pass: eliminate routines which don't accept the given
// number of arguments
- filterRoutinesByParameterCount(routines, argTypes);
+ routines = filterRoutinesByParameterCount(routines, argTypes);
// NOTE: according to SQL99, procedures are NOT overloaded on type,
// only on number of arguments.
@@ -399,28 +396,29 @@ public abstract class SqlUtil {
// second pass: eliminate routines which don't accept the given
// argument types
- filterRoutinesByParameterType(sqlSyntax, routines, argTypes, argNames);
+ routines = filterRoutinesByParameterType(sqlSyntax, routines, argTypes, argNames);
+
// see if we can stop now; this is necessary for the case
// of builtin functions where we don't have param type info
- if (routines.size() < 2) {
+ final List<SqlOperator> list = Lists.newArrayList(routines);
+ routines = list.iterator();
+ if (list.size() < 2) {
return routines;
}
// third pass: for each parameter from left to right, eliminate
// all routines except those with the best precedence match for
// the given arguments
- filterRoutinesByTypePrecedence(sqlSyntax, routines, argTypes);
+ routines = filterRoutinesByTypePrecedence(sqlSyntax, routines, argTypes);
// fourth pass: eliminate routines which do not have the same
// SqlKind as requested
- filterOperatorRoutinesByKind(routines, sqlKind);
- return routines;
+ return filterOperatorRoutinesByKind(routines, sqlKind);
}
/**
- * Determine if there is a routine matching the given name and number of
- * arguments.
- *
+ * Determines whether there is a routine matching the given name and number
+ * of arguments.
*
* @param opTab operator table to search
* @param funcName name of function being invoked
@@ -434,182 +432,172 @@ public abstract class SqlUtil {
List<RelDataType> argTypes,
SqlFunctionCategory category) {
// start with all routines matching by name
- List<SqlOperator> routines =
+ Iterator<SqlOperator> routines =
lookupSubjectRoutinesByName(opTab, funcName, SqlSyntax.FUNCTION, category);
// first pass: eliminate routines which don't accept the given
// number of arguments
- filterRoutinesByParameterCount(routines, argTypes);
+ routines = filterRoutinesByParameterCount(routines, argTypes);
- return routines.size() > 0;
+ return routines.hasNext();
}
- private static List<SqlOperator> lookupSubjectRoutinesByName(
+ private static Iterator<SqlOperator> lookupSubjectRoutinesByName(
SqlOperatorTable opTab,
SqlIdentifier funcName,
- SqlSyntax sqlSyntax,
+ final SqlSyntax syntax,
SqlFunctionCategory category) {
- final List<SqlOperator> sqlOperators = Lists.newArrayList();
- opTab.lookupOperatorOverloads(
- funcName,
- category,
- sqlSyntax,
- sqlOperators);
- List<SqlOperator> routines = Lists.newArrayList();
- for (SqlOperator sqlOperator : sqlOperators) {
- if (sqlSyntax == SqlSyntax.FUNCTION) {
- if (sqlOperator instanceof SqlFunction) {
- routines.add(sqlOperator);
- }
- } else if (sqlSyntax == sqlOperator.getSyntax()) {
- routines.add(sqlOperator);
- }
- }
- return routines;
- }
-
- private static void filterRoutinesByParameterCount(
- List<SqlOperator> routines,
- List<RelDataType> argTypes) {
- Iterator<? extends SqlOperator> iter = routines.iterator();
- while (iter.hasNext()) {
- SqlOperator operator = iter.next();
- SqlOperandCountRange od = operator.getOperandCountRange();
- if (!od.isValidCount(argTypes.size())) {
- iter.remove();
- }
- }
+ final List<SqlOperator> sqlOperators = new ArrayList<>();
+ opTab.lookupOperatorOverloads(funcName, category, syntax, sqlOperators);
+ switch (syntax) {
+ case FUNCTION:
+ return Iterators.filter(sqlOperators.iterator(),
+ Predicates.instanceOf(SqlFunction.class));
+ default:
+ return Iterators.filter(sqlOperators.iterator(),
+ new Predicate<SqlOperator>() {
+ public boolean apply(SqlOperator operator) {
+ return operator.getSyntax() == syntax;
+ }
+ });
+ }
+ }
+
+ private static Iterator<SqlOperator> filterRoutinesByParameterCount(
+ Iterator<SqlOperator> routines,
+ final List<RelDataType> argTypes) {
+ return Iterators.filter(routines,
+ new Predicate<SqlOperator>() {
+ public boolean apply(SqlOperator operator) {
+ SqlOperandCountRange od = operator.getOperandCountRange();
+ return od.isValidCount(argTypes.size());
+ }
+ });
}
/**
* @sql.99 Part 2 Section 10.4 Syntax Rule 6.b.iii.2.B
*/
- private static void filterRoutinesByParameterType(
- SqlSyntax sqlSyntax,
- List<SqlOperator> routines,
- final List<RelDataType> argTypes, List<String> argNames) {
- if (sqlSyntax != SqlSyntax.FUNCTION) {
- return;
- }
-
- List<SqlFunction> sqlFunctions = Lists.newArrayList();
- for (SqlOperator sqlOperator : routines) {
- sqlFunctions.add((SqlFunction) sqlOperator);
+ private static Iterator<SqlOperator> filterRoutinesByParameterType(
+ SqlSyntax syntax,
+ final Iterator<SqlOperator> routines,
+ final List<RelDataType> argTypes, final List<String> argNames) {
+ if (syntax != SqlSyntax.FUNCTION) {
+ return routines;
}
- routines.clear();
- Iterator<SqlFunction> iter = sqlFunctions.iterator();
- loop:
- while (iter.hasNext()) {
- SqlFunction function = iter.next();
- List<RelDataType> paramTypes = function.getParamTypes();
- if (paramTypes == null) {
- // no parameter information for builtins; keep for now
- continue;
- }
- final List<RelDataType> permutedArgTypes;
- if (argNames != null) {
- // Arguments passed by name. Make sure that the function has parameters
- // of all of these names.
- final Map<Integer, Integer> map = new HashMap<>();
- for (Ord<String> argName : Ord.zip(argNames)) {
- final int i = function.getParamNames().indexOf(argName.e);
- if (i < 0) {
- iter.remove();
- continue loop;
- }
- map.put(i, argName.i);
- }
- permutedArgTypes = Functions.generate(paramTypes.size(),
- new Function1<Integer, RelDataType>() {
- public RelDataType apply(Integer a0) {
- if (map.containsKey(a0)) {
- return argTypes.get(map.get(a0));
- } else {
- return null;
+ //noinspection unchecked
+ return (Iterator) Iterators.filter(
+ Iterators.filter(routines, SqlFunction.class),
+ new Predicate<SqlFunction>() {
+ public boolean apply(SqlFunction function) {
+ List<RelDataType> paramTypes = function.getParamTypes();
+ if (paramTypes == null) {
+ // no parameter information for builtins; keep for now
+ return true;
+ }
+ final List<RelDataType> permutedArgTypes;
+ if (argNames != null) {
+ // Arguments passed by name. Make sure that the function has
+ // parameters of all of these names.
+ final Map<Integer, Integer> map = new HashMap<>();
+ for (Ord<String> argName : Ord.zip(argNames)) {
+ final int i = function.getParamNames().indexOf(argName.e);
+ if (i < 0) {
+ return false;
}
+ map.put(i, argName.i);
}
- });
- } else {
- permutedArgTypes = Lists.newArrayList(argTypes);
- while (permutedArgTypes.size() < argTypes.size()) {
- paramTypes.add(null);
- }
- }
- for (Pair<RelDataType, RelDataType> p
- : Pair.zip(paramTypes, permutedArgTypes)) {
- final RelDataType argType = p.right;
- final RelDataType paramType = p.left;
- if (argType != null
- && !SqlTypeUtil.canCastFrom(paramType, argType, false)) {
- iter.remove();
- continue loop;
- }
- }
- }
-
- routines.addAll(sqlFunctions);
+ permutedArgTypes = Functions.generate(paramTypes.size(),
+ new Function1<Integer, RelDataType>() {
+ public RelDataType apply(Integer a0) {
+ if (map.containsKey(a0)) {
+ return argTypes.get(map.get(a0));
+ } else {
+ return null;
+ }
+ }
+ });
+ } else {
+ permutedArgTypes = Lists.newArrayList(argTypes);
+ while (permutedArgTypes.size() < argTypes.size()) {
+ paramTypes.add(null);
+ }
+ }
+ for (Pair<RelDataType, RelDataType> p
+ : Pair.zip(paramTypes, permutedArgTypes)) {
+ final RelDataType argType = p.right;
+ final RelDataType paramType = p.left;
+ if (argType != null
+ && !SqlTypeUtil.canCastFrom(paramType, argType, false)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
}
/**
* @sql.99 Part 2 Section 9.4
*/
- private static void filterRoutinesByTypePrecedence(
+ private static Iterator<SqlOperator> filterRoutinesByTypePrecedence(
SqlSyntax sqlSyntax,
- List<SqlOperator> routines,
+ Iterator<SqlOperator> routines,
List<RelDataType> argTypes) {
if (sqlSyntax != SqlSyntax.FUNCTION) {
- return;
+ return routines;
}
- List<SqlFunction> sqlFunctions = Lists.newArrayList();
- for (SqlOperator sqlOperator : routines) {
- sqlFunctions.add((SqlFunction) sqlOperator);
+ List<SqlFunction> sqlFunctions =
+ Lists.newArrayList(Iterators.filter(routines, SqlFunction.class));
+
+ for (final Ord<RelDataType> argType : Ord.zip(argTypes)) {
+ final RelDataTypePrecedenceList precList =
+ argType.e.getPrecedenceList();
+ final RelDataType bestMatch = bestMatch(sqlFunctions, argType.i, precList);
+ if (bestMatch != null) {
+ sqlFunctions =
+ Lists.newArrayList(
+ Iterables.filter(sqlFunctions,
+ new Predicate<SqlFunction>() {
+ public boolean apply(SqlFunction function) {
+ final List<RelDataType> paramTypes = function.getParamTypes();
+ if (paramTypes == null) {
+ return false;
+ }
+ final RelDataType paramType = paramTypes.get(argType.i);
+ return precList.compareTypePrecedence(paramType, bestMatch) >= 0;
+ }
+ }));
+ }
}
- routines.clear();
+ //noinspection unchecked
+ return (Iterator) sqlFunctions.iterator();
+ }
- for (int i = 0; i < argTypes.size(); ++i) {
- RelDataTypePrecedenceList precList =
- argTypes.get(i).getPrecedenceList();
- RelDataType bestMatch = null;
- for (SqlFunction function : sqlFunctions) {
- List<RelDataType> paramTypes = function.getParamTypes();
- if (paramTypes == null) {
- continue;
- }
- final RelDataType paramType = paramTypes.get(i);
- if (bestMatch == null) {
- bestMatch = paramType;
- } else {
- int c =
- precList.compareTypePrecedence(
- bestMatch,
- paramType);
- if (c < 0) {
- bestMatch = paramType;
- }
- }
+ private static RelDataType bestMatch(List<SqlFunction> sqlFunctions, int i,
+ RelDataTypePrecedenceList precList) {
+ RelDataType bestMatch = null;
+ for (SqlFunction function : sqlFunctions) {
+ List<RelDataType> paramTypes = function.getParamTypes();
+ if (paramTypes == null) {
+ continue;
}
- if (bestMatch != null) {
- Iterator<SqlFunction> iter = sqlFunctions.iterator();
- while (iter.hasNext()) {
- SqlFunction function = iter.next();
- List<RelDataType> paramTypes = function.getParamTypes();
- int c;
- if (paramTypes == null) {
- c = -1;
- } else {
- c = precList.compareTypePrecedence(
- paramTypes.get(i),
- bestMatch);
- }
- if (c < 0) {
- iter.remove();
- }
+ final RelDataType paramType = paramTypes.get(i);
+ if (bestMatch == null) {
+ bestMatch = paramType;
+ } else {
+ int c =
+ precList.compareTypePrecedence(
+ bestMatch,
+ paramType);
+ if (c < 0) {
+ bestMatch = paramType;
}
}
}
- routines.addAll(sqlFunctions);
+ return bestMatch;
}
/**
http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index db755a2..dce373f 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -859,33 +859,34 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
// WINDOW Rank Functions
//-------------------------------------------------------------
/**
- * <code>CUME_DIST</code> Window function.
+ * <code>CUME_DIST</code> window function.
*/
public static final SqlRankFunction CUME_DIST =
- new SqlRankFunction("CUME_DIST", true);
+ new SqlRankFunction(true, SqlKind.CUME_DIST);
/**
- * <code>DENSE_RANK</code> Window function.
+ * <code>DENSE_RANK</code> window function.
*/
public static final SqlRankFunction DENSE_RANK =
- new SqlRankFunction("DENSE_RANK", true);
+ new SqlRankFunction(true, SqlKind.DENSE_RANK);
/**
- * <code>PERCENT_RANK</code> Window function.
+ * <code>PERCENT_RANK</code> window function.
*/
public static final SqlRankFunction PERCENT_RANK =
- new SqlRankFunction("PERCENT_RANK", true);
+ new SqlRankFunction(true, SqlKind.PERCENT_RANK);
/**
- * <code>RANK</code> Window function.
+ * <code>RANK</code> window function.
*/
- public static final SqlRankFunction RANK = new SqlRankFunction("RANK", true);
+ public static final SqlRankFunction RANK =
+ new SqlRankFunction(true, SqlKind.RANK);
/**
- * <code>ROW_NUMBER</code> Window function.
+ * <code>ROW_NUMBER</code> window function.
*/
public static final SqlRankFunction ROW_NUMBER =
- new SqlRankFunction("ROW_NUMBER", false);
+ new SqlRankFunction(false, SqlKind.ROW_NUMBER);
//-------------------------------------------------------------
// SPECIAL OPERATORS
http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
index 3291095..494e600 100644
--- a/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
@@ -16,30 +16,26 @@
*/
package org.apache.calcite.sql.util;
-import org.apache.calcite.sql.SqlBinaryOperator;
import org.apache.calcite.sql.SqlFunction;
import org.apache.calcite.sql.SqlFunctionCategory;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlOperatorTable;
-import org.apache.calcite.sql.SqlPostfixOperator;
-import org.apache.calcite.sql.SqlPrefixOperator;
import org.apache.calcite.sql.SqlSyntax;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
+import com.google.common.base.Throwables;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import java.lang.reflect.Field;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
- * ReflectiveSqlOperatorTable implements the {@link SqlOperatorTable } interface
+ * ReflectiveSqlOperatorTable implements the {@link SqlOperatorTable} interface
* by reflecting the public fields of a subclass.
*/
public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
@@ -47,10 +43,7 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
//~ Instance fields --------------------------------------------------------
- private final Multimap<String, SqlOperator> operators = HashMultimap.create();
-
- private final Map<Pair<String, SqlSyntax>, SqlOperator> mapNameToOp =
- new HashMap<Pair<String, SqlSyntax>, SqlOperator>();
+ private final Multimap<Key, SqlOperator> operators = HashMultimap.create();
//~ Constructors -----------------------------------------------------------
@@ -78,14 +71,8 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
SqlOperator op = (SqlOperator) field.get(this);
register(op);
}
- } catch (IllegalArgumentException e) {
- throw Util.newInternal(
- e,
- "Error while initializing operator table");
- } catch (IllegalAccessException e) {
- throw Util.newInternal(
- e,
- "Error while initializing operator table");
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw Throwables.propagate(e);
}
}
}
@@ -112,7 +99,7 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
// Always look up built-in operators case-insensitively. Even in sessions
// with unquotedCasing=UNCHANGED and caseSensitive=true.
final Collection<SqlOperator> list =
- operators.get(simpleName.toUpperCase());
+ operators.get(new Key(simpleName, syntax));
if (list.isEmpty()) {
return;
}
@@ -133,41 +120,51 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
case BINARY:
case PREFIX:
case POSTFIX:
- SqlOperator extra = mapNameToOp.get(Pair.of(simpleName, syntax));
- // REVIEW: should only search operators added during this method?
- if (extra != null && !operatorList.contains(extra)) {
- operatorList.add(extra);
+ for (SqlOperator extra : operators.get(new Key(simpleName, syntax))) {
+ // REVIEW: should only search operators added during this method?
+ if (extra != null && !operatorList.contains(extra)) {
+ operatorList.add(extra);
+ }
}
break;
}
}
- public void register(SqlOperator op) {
- operators.put(op.getName().toUpperCase(), op);
- if (op instanceof SqlBinaryOperator) {
- mapNameToOp.put(Pair.of(op.getName(), SqlSyntax.BINARY), op);
- } else if (op instanceof SqlPrefixOperator) {
- mapNameToOp.put(Pair.of(op.getName(), SqlSyntax.PREFIX), op);
- } else if (op instanceof SqlPostfixOperator) {
- mapNameToOp.put(Pair.of(op.getName(), SqlSyntax.POSTFIX), op);
- }
- }
-
/**
- * Registers a function in the table.
- *
- * @param function Function to register
+ * Registers a function or operator in the table.
*/
- public void register(SqlFunction function) {
- operators.put(function.getName().toUpperCase(), function);
- SqlFunctionCategory funcType = function.getFunctionType();
- assert funcType != null
- : "Function type for " + function.getName() + " not set";
+ public void register(SqlOperator op) {
+ operators.put(new Key(op.getName(), op.getSyntax()), op);
+ if (op instanceof SqlFunction) {
+ SqlFunction function = (SqlFunction) op;
+ SqlFunctionCategory funcType = function.getFunctionType();
+ assert funcType != null
+ : "Function type for " + function.getName() + " not set";
+ }
}
public List<SqlOperator> getOperatorList() {
return ImmutableList.copyOf(operators.values());
}
+
+ /** Key for looking up operators. The name is stored in upper-case because we
+ * store case-insensitively, even in a case-sensitive session. */
+ private static class Key extends Pair<String, SqlSyntax> {
+ Key(String name, SqlSyntax syntax) {
+ super(name.toUpperCase(), normalize(syntax));
+ }
+
+ private static SqlSyntax normalize(SqlSyntax syntax) {
+ switch (syntax) {
+ case BINARY:
+ case PREFIX:
+ case POSTFIX:
+ return syntax;
+ default:
+ return SqlSyntax.FUNCTION;
+ }
+ }
+ }
}
// End ReflectiveSqlOperatorTable.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 31a2b5c..1fe4177 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1831,17 +1831,9 @@ public class SqlToRelConverter {
SqlNode windowOrRef = call.operand(1);
final SqlWindow window =
validator.resolveWindow(windowOrRef, bb.scope, true);
- final SqlOperator row_number_function = SqlUtil.lookupRoutine(
- opTab,
- SqlStdOperatorTable.ROW_NUMBER.getNameAsId(),
- ImmutableList.<RelDataType>of(),
- ImmutableList.<String>of(),
- SqlStdOperatorTable.ROW_NUMBER.getSyntax(),
- SqlStdOperatorTable.ROW_NUMBER.getKind(),
- SqlStdOperatorTable.ROW_NUMBER.getFunctionType());
// ROW_NUMBER() expects specific kind of framing.
- if (aggCall.getOperator() == row_number_function) {
+ if (aggCall.getKind() == SqlKind.ROW_NUMBER) {
window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO));
window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO));
window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO));