You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2013/12/23 06:18:30 UTC
[1/2] TAJO-182: Correct NULL value handling of primitive operators.
(hyunsik)
Updated Branches:
refs/heads/master 302824a39 -> e8c5c2771
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java
index fbcc9a0..f4172dc 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java
@@ -114,7 +114,7 @@ public class TestJoinQuery {
}
for (int i = 0; i < 3; i++) {
- res.next();
+ assertTrue(res.next());
Object [] resultTuple = resultSet.get(res.getFloat("s_acctbal"));
assertEquals(resultTuple[0], res.getFloat("s_acctbal"));
assertEquals(resultTuple[1], res.getString("s_name"));
@@ -157,7 +157,8 @@ public class TestJoinQuery {
result.put(3, 3);
result.put(4, 0);
result.put(5, 0);
- while(res.next()) {
+ for (int i = 0; i < result.size(); i++) {
+ assertTrue(res.next());
assertTrue(result.get(res.getInt(1)) == res.getInt(2));
}
} finally {
@@ -168,7 +169,7 @@ public class TestJoinQuery {
@Test
public final void testFullOuterJoin1() throws Exception {
ResultSet res = tpch.execute(
- "select c_custkey, orders.o_orderkey, from orders full outer join customer on c_custkey = o_orderkey;");
+ "select c_custkey, orders.o_orderkey from orders full outer join customer on c_custkey = o_orderkey;");
try {
Map<Integer, Integer> result = Maps.newHashMap();
result.put(1, 1);
@@ -176,7 +177,8 @@ public class TestJoinQuery {
result.put(3, 3);
result.put(4, 0);
result.put(5, 0);
- while(res.next()) {
+ for (int i = 0; i < result.size(); i++) {
+ assertTrue(res.next());
assertTrue(result.get(res.getInt(1)) == res.getInt(2));
}
} finally {
@@ -186,7 +188,9 @@ public class TestJoinQuery {
@Test
public void testJoinRefEval() throws Exception {
- ResultSet res = tpch.execute("select r_regionkey, n_regionkey, (r_regionkey + n_regionkey) as plus from region, nation where r_regionkey = n_regionkey");
+ ResultSet res = tpch.execute(
+ "select r_regionkey, n_regionkey, (r_regionkey + n_regionkey) as plus from region, nation " +
+ "where r_regionkey = n_regionkey");
try {
int r, n;
while(res.next()) {
[2/2] git commit: TAJO-182: Correct NULL value handling of primitive
operators. (hyunsik)
Posted by hy...@apache.org.
TAJO-182: Correct NULL value handling of primitive operators. (hyunsik)
Project: http://git-wip-us.apache.org/repos/asf/incubator-tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tajo/commit/e8c5c277
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/e8c5c277
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/e8c5c277
Branch: refs/heads/master
Commit: e8c5c27717e134264a93a0430521a07c45079215
Parents: 302824a
Author: Hyunsik Choi <hy...@apache.org>
Authored: Mon Dec 23 14:14:51 2013 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Mon Dec 23 14:14:51 2013 +0900
----------------------------------------------------------------------
CHANGES.txt | 6 +-
.../java/org/apache/tajo/datum/BitDatum.java | 6 +-
.../java/org/apache/tajo/datum/BlobDatum.java | 6 +-
.../org/apache/tajo/datum/BooleanDatum.java | 195 +++++++--------
.../java/org/apache/tajo/datum/CharDatum.java | 8 +-
.../java/org/apache/tajo/datum/DateDatum.java | 18 ++
.../main/java/org/apache/tajo/datum/Datum.java | 177 ++++++++------
.../org/apache/tajo/datum/DatumFactory.java | 33 ++-
.../java/org/apache/tajo/datum/Float4Datum.java | 4 +-
.../java/org/apache/tajo/datum/Float8Datum.java | 23 +-
.../java/org/apache/tajo/datum/Inet4Datum.java | 8 +-
.../java/org/apache/tajo/datum/Int2Datum.java | 12 +-
.../java/org/apache/tajo/datum/Int4Datum.java | 14 +-
.../java/org/apache/tajo/datum/Int8Datum.java | 5 +-
.../java/org/apache/tajo/datum/NullDatum.java | 79 ++++++-
.../java/org/apache/tajo/datum/TextDatum.java | 14 +-
.../java/org/apache/tajo/datum/TimeDatum.java | 18 ++
.../org/apache/tajo/datum/TimestampDatum.java | 13 +
.../org/apache/tajo/datum/TestBoolDatum.java | 106 +++++----
.../org/apache/tajo/engine/parser/SQLParser.g4 | 5 +-
.../org/apache/tajo/engine/eval/BinaryEval.java | 235 +++++++++----------
.../org/apache/tajo/engine/eval/CastEval.java | 29 ++-
.../org/apache/tajo/engine/eval/InEval.java | 16 +-
.../engine/eval/PatternMatchPredicateEval.java | 16 +-
.../apache/tajo/engine/function/InCountry.java | 3 +-
.../tajo/engine/function/string/SplitPart.java | 15 +-
.../apache/tajo/engine/parser/SQLAnalyzer.java | 27 ++-
.../planner/physical/HashFullOuterJoinExec.java | 2 +-
.../planner/physical/HashLeftOuterJoinExec.java | 2 +-
.../planner/physical/NLLeftOuterJoinExec.java | 2 +-
.../engine/planner/physical/SeqScanExec.java | 2 +-
.../tajo/engine/eval/TestSQLExpression.java | 87 +++++++
.../TestStringOperatorsAndFunctions.java | 42 ++--
.../apache/tajo/engine/query/TestJoinQuery.java | 14 +-
34 files changed, 793 insertions(+), 449 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index c717e9a..24f574a 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -164,7 +164,11 @@ Release 0.8.0 - unreleased
BUG FIXES
- TAJO-431: HCatalogStore can't write any data using INSERT OVERWRITE clause. (jaehwa)
+ TAJO-182: Comparison of primitive values including null value should
+ return NULL. (hyunsik)
+
+ TAJO-431: HCatalogStore can't write any data using INSERT OVERWRITE clause.
+ (jaehwa)
TAJO-442: Cast operator with nested functions causes NPE. (hyunsik)
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java
index 17f9382..9838570 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/BitDatum.java
@@ -108,10 +108,12 @@ public class BitDatum extends Datum {
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case BIT:
return DatumFactory.createBool(this.val == (((BitDatum) datum).val));
+ case NULL_TYPE:
+ return datum;
default:
throw new InvalidOperationException(datum.type());
}
@@ -128,6 +130,8 @@ public class BitDatum extends Datum {
} else {
return 0;
}
+ case NULL_TYPE:
+ return -1;
default:
throw new InvalidOperationException(datum.type());
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java
index 8ec66d9..1ba8a64 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/BlobDatum.java
@@ -139,12 +139,14 @@ public class BlobDatum extends Datum {
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case BLOB:
initFromBytes();
((BlobDatum)datum).initFromBytes();
return DatumFactory.createBool(Arrays.equals(this.val, ((BlobDatum)datum).val));
+ case NULL_TYPE:
+ return datum;
default:
throw new InvalidOperationException(datum.type());
}
@@ -157,6 +159,8 @@ public class BlobDatum extends Datum {
initFromBytes();
((BlobDatum)datum).initFromBytes();
return bb.compareTo(((BlobDatum) datum).bb);
+ case NULL_TYPE:
+ return -1;
default:
throw new InvalidOperationException(datum.type());
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java
index 56fd3b5..d975cd8 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/BooleanDatum.java
@@ -23,137 +23,146 @@ import org.apache.tajo.common.TajoDataTypes;
import org.apache.tajo.datum.exception.InvalidOperationException;
public class BooleanDatum extends Datum {
- @Expose private boolean val;
- public static final String TRUE="t";
- public static final String FALSE="f";
-
- public BooleanDatum() {
+ @Expose private boolean val;
+ public static final String TRUE_STRING ="t";
+ public static final String FALSE_STRING ="f";
+ public static final BooleanDatum TRUE = new BooleanDatum(true);
+ public static final BooleanDatum FALSE = new BooleanDatum(false);
+
+ public static final int UNKNOWN_INT = 0;
+ public static final int TRUE_INT = 1;
+ public static final int FALSE_INT = 2;
+ public static final byte [] TRUE_BYTES = new byte[] {TRUE_INT};
+ public static final byte [] FALSE_BYTES = new byte[] {FALSE_INT};
+
+ /** 0 - UNKNOWN, 1 - TRUE, 2 - FALSE */
+ public static final Datum [] THREE_VALUES = new Datum [] {
+ NullDatum.get(), TRUE, FALSE
+ };
+
+ public static final Datum [][] AND_LOGIC = new Datum [][] {
+ // unknown true false
+ new Datum [] {NullDatum.get(), NullDatum.get(), FALSE}, // unknown
+ new Datum [] {NullDatum.get(), TRUE, FALSE}, // true
+ new Datum [] {FALSE, FALSE, FALSE} // false
+ };
+
+ public static final Datum [][] OR_LOGIC = new Datum [][] {
+ // unknown true false
+ new Datum [] {NullDatum.get(), TRUE, NullDatum.get()}, // unknown
+ new Datum [] {TRUE, TRUE, TRUE }, // true
+ new Datum [] {NullDatum.get(), TRUE, FALSE } // false
+ };
+
+ protected BooleanDatum() {
super(TajoDataTypes.Type.BOOLEAN);
}
- public BooleanDatum(boolean val) {
- this();
- this.val = val;
- }
+ protected BooleanDatum(boolean val) {
+ super(TajoDataTypes.Type.BOOLEAN);
+ this.val = val;
+ }
- public BooleanDatum(byte byteVal) {
- this();
- this.val = byteVal == 1;
+ protected BooleanDatum(byte byteVal) {
+ super(TajoDataTypes.Type.BOOLEAN);
+ this.val = byteVal == TRUE_INT;
}
- public BooleanDatum(int byteVal) {
+ protected BooleanDatum(int byteVal) {
this();
- this.val = byteVal == 1;
+ this.val = byteVal == TRUE_INT;
}
- public BooleanDatum(byte[] bytes) {
- this(bytes[0]);
+ protected BooleanDatum(byte[] bytes) {
+ this(bytes[0]); // get the first byte
}
- public boolean asBool() {
- return val;
- }
-
- public void setValue(boolean val) {
- this.val = val;
+ public boolean asBool() {
+ return val;
}
@Override
public char asChar() {
return val ? 't' : 'f';
}
-
- @Override
- public short asInt2() {
- return (short) (val ? 1 : 0);
- }
-
- /* (non-Javadoc)
- * @see nta.common.datum.Datum#asInt()
- */
- @Override
- public int asInt4() {
- return val ? 1 : 0;
- }
-
- /* (non-Javadoc)
- * @see nta.common.datum.Datum#asLong()
- */
- @Override
- public long asInt8() {
- return val ? 1 : 0;
- }
-
- /* (non-Javadoc)
- * @see nta.common.datum.Datum#asByte()
- */
- @Override
- public byte asByte() {
- return (byte) (val ? 0x01 : 0x00);
- }
-
- /* (non-Javadoc)
- * @see nta.common.datum.Datum#asByteArray()
- */
- @Override
- public byte[] asByteArray() {
- byte [] bytes = new byte[1];
- bytes[0] = asByte();
- return bytes;
- }
-
- /* (non-Javadoc)
- * @see nta.common.datum.Datum#asFloat()
- */
- @Override
- public float asFloat4() {
- return val ? 1 : 0;
- }
-
- /* (non-Javadoc)
- * @see nta.common.datum.Datum#asDouble()
- */
- @Override
- public double asFloat8() {
- return val ? 1 : 0;
- }
-
- /* (non-Javadoc)
- * @see nta.common.datum.Datum#asChars()
- */
- @Override
- public String asChars() {
- return val ? "t" : "f";
- }
+
+ @Override
+ public short asInt2() {
+ return (short) (val ? TRUE_INT : FALSE_INT);
+ }
+
+ @Override
+ public int asInt4() {
+ return val ? TRUE_INT : FALSE_INT;
+ }
+
+ @Override
+ public long asInt8() {
+ return val ? TRUE_INT : FALSE_INT;
+ }
+
+ @Override
+ public byte asByte() {
+ return (byte) (val ? TRUE_INT : FALSE_INT);
+ }
+
+ @Override
+ public byte[] asByteArray() {
+ return val ? TRUE_BYTES : FALSE_BYTES;
+ }
+
+ @Override
+ public float asFloat4() {
+ return val ? TRUE_INT : FALSE_INT;
+ }
+
+ @Override
+ public double asFloat8() {
+ return val ? TRUE_INT : FALSE_INT;
+ }
+
+ @Override
+ public String asChars() {
+ return val ? TRUE_STRING : FALSE_STRING;
+ }
+
+ @Override
+ public Datum and(Datum datum) {
+ return AND_LOGIC[asInt4()][datum.asInt4()];
+ }
+
+ @Override
+ public Datum or(Datum datum) {
+ return OR_LOGIC[asInt4()][datum.asInt4()];
+ }
@Override
public int size() {
return 1;
}
-
+
@Override
public int hashCode() {
return val ? 7907 : 0; // 7907 is one of the prime numbers
}
-
+
@Override
public boolean equals(Object obj) {
if (obj instanceof BooleanDatum) {
BooleanDatum other = (BooleanDatum) obj;
return val == other.val;
}
-
+
return false;
}
-
+
// Datum Comparator
public BooleanDatum equalsTo(Datum datum) {
switch(datum.type()) {
- case BOOLEAN: return DatumFactory.createBool(this.val ==
- ((BooleanDatum)datum).val);
- default:
- throw new InvalidOperationException(datum.type());
+ case BOOLEAN: return DatumFactory.createBool(this.val == ((BooleanDatum)datum).val);
+ default:
+ throw new InvalidOperationException(datum.type());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java
index 94bafb1..3987078 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/CharDatum.java
@@ -134,13 +134,15 @@ public class CharDatum extends Datum {
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case CHAR:
- return DatumFactory.createBool(this.equals(datum));
+ case VARCHAR:
+ case TEXT:
+ return DatumFactory.createBool(TextDatum.COMPARATOR.compare(bytes, datum.asTextBytes()) == 0);
case NULL_TYPE:
- return DatumFactory.createBool(false);
+ return datum;
default:
throw new InvalidOperationException();
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java
index 9998c72..7029b97 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/DateDatum.java
@@ -38,6 +38,11 @@ public class DateDatum extends Datum {
date = decode(value);
}
+ public DateDatum(String dateStr) {
+ super(TajoDataTypes.Type.DATE);
+ this.date = LocalDate.parse(dateStr, DEFAULT_FORMATTER);
+ }
+
public DateDatum(LocalDate date) {
super(TajoDataTypes.Type.DATE);
this.date = date;
@@ -128,9 +133,22 @@ public class DateDatum extends Datum {
}
@Override
+ public Datum equalsTo(Datum datum) {
+ if (datum.type() == TajoDataTypes.Type.TIME) {
+ return DatumFactory.createBool(date.equals(((DateDatum) datum).date));
+ } else if (datum.isNull()) {
+ return datum;
+ } else {
+ throw new InvalidOperationException();
+ }
+ }
+
+ @Override
public int compareTo(Datum datum) {
if (datum.type() == TajoDataTypes.Type.DATE) {
return date.compareTo(((DateDatum)datum).date);
+ } else if (datum.type() == TajoDataTypes.Type.NULL_TYPE) {
+ return -1;
} else {
throw new InvalidOperationException();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java
index 1ae72c7..0b30e87 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Datum.java
@@ -27,25 +27,29 @@ import org.apache.tajo.json.GsonObject;
import static org.apache.tajo.common.TajoDataTypes.Type;
public abstract class Datum implements Comparable<Datum>, GsonObject {
- @Expose private Type type;
-
- @SuppressWarnings("unused")
+ @Expose private Type type;
+
+ @SuppressWarnings("unused")
private Datum() {
- }
-
- public Datum(Type type) {
- this.type = type;
- }
-
- public Type type() {
- return this.type;
- }
+ }
+
+ public Datum(Type type) {
+ this.type = type;
+ }
+
+ public Type type() {
+ return this.type;
+ }
+
+ public boolean isTrue() {
+ return type == Type.BOOLEAN && asBool();
+ }
public boolean isNull() {
return false;
}
-
- public boolean asBool() {
+
+ public boolean asBool() {
throw new InvalidCastException(type + " cannot be casted to BOOL type");
}
@@ -57,10 +61,10 @@ public abstract class Datum implements Comparable<Datum>, GsonObject {
throw new InvalidCastException(type + " cannot be casted to CHAR type");
}
- public short asInt2() {
+ public short asInt2() {
throw new InvalidCastException(type + " cannot be casted to SHORT type");
}
- public int asInt4() {
+ public int asInt4() {
throw new InvalidCastException(type + " cannot be casted to INT type");
}
@@ -68,90 +72,117 @@ public abstract class Datum implements Comparable<Datum>, GsonObject {
throw new InvalidCastException(type + " cannot be casted to LONG type");
}
- public byte [] asByteArray() {
+ public byte [] asByteArray() {
throw new InvalidCastException(type + " cannot be casted to BYTES type");
}
- public float asFloat4() {
+ public float asFloat4() {
throw new InvalidCastException(type + " cannot be casted to FLOAT type");
}
- public double asFloat8() {
+ public double asFloat8() {
throw new InvalidCastException(type + " cannot be casted to DOUBLE type");
}
- public String asChars() {
+ public String asChars() {
throw new InvalidCastException(type + " cannot be casted to STRING type");
}
public byte[] asTextBytes() {
return toString().getBytes();
}
-
- public boolean isNumeric() {
- return isNumber() || isReal();
- }
-
- public boolean isNumber() {
- return
- this.type == Type.INT2 ||
- this.type == Type.INT4 ||
- this.type == Type.INT8;
- }
-
- public boolean isReal() {
- return
+
+ public boolean isNumeric() {
+ return isNumber() || isReal();
+ }
+
+ public boolean isNumber() {
+ return
+ this.type == Type.INT2 ||
+ this.type == Type.INT4 ||
+ this.type == Type.INT8;
+ }
+
+ public boolean isReal() {
+ return
this.type == Type.FLOAT4||
- this.type == Type.FLOAT8;
- }
-
- public abstract int size();
-
- public Datum plus(Datum datum) {
- throw new InvalidOperationException(datum.type);
- }
-
- public Datum minus(Datum datum) {
- throw new InvalidOperationException(datum.type);
- }
-
- public Datum multiply(Datum datum) {
- throw new InvalidOperationException(datum.type);
- }
-
- public Datum divide(Datum datum) {
- throw new InvalidOperationException(datum.type);
- }
+ this.type == Type.FLOAT8;
+ }
+
+ public abstract int size();
+
+ public Datum and(Datum datum) {
+ throw new InvalidOperationException(datum.type);
+ }
+
+ public Datum or(Datum datum) {
+ throw new InvalidOperationException(datum.type);
+ }
+
+ public Datum plus(Datum datum) {
+ throw new InvalidOperationException(datum.type);
+ }
+
+ public Datum minus(Datum datum) {
+ throw new InvalidOperationException(datum.type);
+ }
+
+ public Datum multiply(Datum datum) {
+ throw new InvalidOperationException(datum.type);
+ }
+
+ public Datum divide(Datum datum) {
+ throw new InvalidOperationException(datum.type);
+ }
public Datum modular(Datum datum) {
throw new InvalidOperationException(datum.type);
}
-
- public BooleanDatum equalsTo(Datum datum) {
+
+ public Datum equalsTo(Datum datum) {
+ if (this instanceof NullDatum || datum instanceof NullDatum) {
+ return NullDatum.get();
+ } else {
+ return DatumFactory.createBool(compareTo(datum) == 0);
+ }
+ }
+
+ public Datum notEqualsTo(Datum datum) {
if (this instanceof NullDatum || datum instanceof NullDatum) {
- // TODO - comparing any value against null will be always unknown
- return DatumFactory.createBool(false);
+ return NullDatum.get();
} else {
- return DatumFactory.createBool(compareTo(datum) == 0);
+ return DatumFactory.createBool(compareTo(datum) != 0);
}
- }
+ }
- public BooleanDatum lessThan(Datum datum) {
+ public Datum lessThan(Datum datum) {
+ if (this.type() == Type.NULL_TYPE || datum.type() == Type.NULL_TYPE) {
+ return NullDatum.get();
+ }
return DatumFactory.createBool(compareTo(datum) < 0);
- }
-
- public BooleanDatum lessThanEqual(Datum datum) {
+ }
+
+ public Datum lessThanEqual(Datum datum) {
+ if (this.type() == Type.NULL_TYPE || datum.type() == Type.NULL_TYPE) {
+ return NullDatum.get();
+ }
return DatumFactory.createBool(compareTo(datum) <= 0);
- }
-
- public BooleanDatum greaterThan(Datum datum) {
+ }
+
+ public Datum greaterThan(Datum datum) {
+ if (this.type() == Type.NULL_TYPE || datum.type() == Type.NULL_TYPE) {
+ return NullDatum.get();
+ }
return DatumFactory.createBool(compareTo(datum) > 0);
- }
-
- public BooleanDatum greaterThanEqual(Datum datum) {
+ }
+
+ public Datum greaterThanEqual(Datum datum) {
+ if (this.type() == Type.NULL_TYPE || datum.type() == Type.NULL_TYPE) {
+ return NullDatum.get();
+ }
return DatumFactory.createBool(compareTo(datum) >= 0);
- }
-
+ }
+
public abstract int compareTo(Datum datum);
@Override
@@ -163,4 +194,4 @@ public abstract class Datum implements Comparable<Datum>, GsonObject {
public String toString() {
return asChars();
}
-}
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java b/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java
index 2082225..080d20c 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/DatumFactory.java
@@ -73,7 +73,7 @@ public class DatumFactory {
switch (dataType.getType()) {
case BOOLEAN:
- return createBool(value.equals(BooleanDatum.TRUE));
+ return createBool(value.equals(BooleanDatum.TRUE_STRING));
case INT2:
return createInt2(value);
case INT4:
@@ -175,13 +175,12 @@ public class DatumFactory {
return NullDatum.get();
}
- public static BooleanDatum createBool(byte val) {
- boolean boolVal = val == 0x01;
- return new BooleanDatum(boolVal);
+ public static Datum createBool(byte val) {
+ return BooleanDatum.THREE_VALUES[(int)val];
}
public static BooleanDatum createBool(boolean val) {
- return new BooleanDatum(val);
+ return val ? BooleanDatum.TRUE : BooleanDatum.FALSE;
}
public static BitDatum createBit(byte val) {
@@ -276,6 +275,30 @@ public class DatumFactory {
return new TimestampDatum(timeStamp);
}
+ public static DateDatum createDate(Datum datum) {
+ switch (datum.type()) {
+ case INT4:
+ return new DateDatum(datum.asInt4());
+ case INT8:
+ return new DateDatum(datum.asInt4());
+ case TEXT:
+ return new DateDatum(datum.asChars());
+ default:
+ throw new InvalidCastException(datum.type() + " cannot be casted to TIMESTAMP type");
+ }
+ }
+
+ public static TimeDatum createTime(Datum datum) {
+ switch (datum.type()) {
+ case INT8:
+ return new TimeDatum(datum.asInt8());
+ case TEXT:
+ return new TimeDatum(datum.asChars());
+ default:
+ throw new InvalidCastException(datum.type() + " cannot be casted to TIMESTAMP type");
+ }
+ }
+
public static TimestampDatum createTimestamp(Datum datum) {
switch (datum.type()) {
case INT8:
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java
index 87ff079..9754b0a 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Float4Datum.java
@@ -122,7 +122,7 @@ public class Float4Datum extends NumericDatum {
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case INT2:
return DatumFactory.createBool(val == datum.asInt2());
@@ -135,7 +135,7 @@ public class Float4Datum extends NumericDatum {
case FLOAT8:
return DatumFactory.createBool(val == datum.asFloat8());
case NULL_TYPE:
- return DatumFactory.createBool(false);
+ return datum;
default:
throw new InvalidOperationException();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
index c6535c2..3569d02 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
@@ -17,7 +17,7 @@
*/
/**
- *
+ *
*/
package org.apache.tajo.datum;
@@ -28,9 +28,6 @@ import org.apache.tajo.util.NumberUtil;
import java.nio.ByteBuffer;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
public class Float8Datum extends NumericDatum {
private static final int size = 8;
@@ -39,7 +36,7 @@ public class Float8Datum extends NumericDatum {
public Float8Datum() {
super(TajoDataTypes.Type.FLOAT8);
}
-
+
public Float8Datum(double val) {
this();
this.val = val;
@@ -55,7 +52,7 @@ public class Float8Datum extends NumericDatum {
public char asChar() {
return asChars().charAt(0);
}
-
+
@Override
public short asInt2() {
return (short) val;
@@ -102,23 +99,23 @@ public class Float8Datum extends NumericDatum {
public int size() {
return size;
}
-
+
@Override
public int hashCode() {
return (int) val;
}
-
+
public boolean equals(Object obj) {
if (obj instanceof Float8Datum) {
Float8Datum other = (Float8Datum) obj;
return val == other.val;
}
-
+
return false;
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case INT2:
return DatumFactory.createBool(val == datum.asInt2());
@@ -131,7 +128,7 @@ public class Float8Datum extends NumericDatum {
case FLOAT8:
return DatumFactory.createBool(val == datum.asFloat8());
case NULL_TYPE:
- return DatumFactory.createBool(false);
+ return datum;
default:
throw new InvalidOperationException();
}
@@ -296,9 +293,9 @@ public class Float8Datum extends NumericDatum {
throw new InvalidOperationException(datum.type());
}
}
-
+
@Override
- public void inverseSign() {
+ public void inverseSign() {
this.val = -val;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java
index bab2a7b..10f0785 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Inet4Datum.java
@@ -105,10 +105,12 @@ public class Inet4Datum extends Datum {
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case INET4:
return DatumFactory.createBool(this.address == ((Inet4Datum)datum).address);
+ case NULL_TYPE:
+ return datum;
default:
throw new InvalidOperationException(datum.type());
}
@@ -126,8 +128,12 @@ public class Inet4Datum extends Datum {
return 1;
} else if (bytes[i] < other[i]) {
return -1;
+ } else {
+ return 0;
}
}
+ case NULL_TYPE:
+ return -1;
default:
throw new InvalidOperationException(datum.type());
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java
index 1cb9d1d..a3b4b2f 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Int2Datum.java
@@ -27,7 +27,7 @@ import java.nio.ByteBuffer;
public class Int2Datum extends NumericDatum {
- private static final int size = 2;
+ private static final int size = 2;
@Expose private short val;
public Int2Datum() {
@@ -36,7 +36,7 @@ public class Int2Datum extends NumericDatum {
public Int2Datum(short val) {
this();
- this.val = val;
+ this.val = val;
}
public Int2Datum(byte[] bytes) {
@@ -49,7 +49,7 @@ public class Int2Datum extends NumericDatum {
public char asChar() {
return asChars().charAt(0);
}
-
+
@Override
public short asInt2() {
return val;
@@ -108,12 +108,12 @@ public class Int2Datum extends NumericDatum {
Int2Datum other = (Int2Datum) obj;
return val == other.val;
}
-
+
return false;
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case INT2:
return DatumFactory.createBool(val == datum.asInt2());
@@ -126,7 +126,7 @@ public class Int2Datum extends NumericDatum {
case FLOAT8:
return DatumFactory.createBool(val == datum.asFloat8());
case NULL_TYPE:
- return DatumFactory.createBool(false);
+ return datum;
default:
throw new InvalidOperationException();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java
index fa7f6c5..9eb02e1 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Int4Datum.java
@@ -29,11 +29,11 @@ import java.nio.ByteBuffer;
public class Int4Datum extends NumericDatum {
private static final int size = 4;
@Expose private int val;
-
+
public Int4Datum() {
super(Type.INT4);
}
-
+
public Int4Datum(int val) {
this();
this.val = val;
@@ -101,23 +101,23 @@ public class Int4Datum extends NumericDatum {
public int size() {
return size;
}
-
+
@Override
public int hashCode() {
return val;
}
-
+
public boolean equals(Object obj) {
if (obj instanceof Int4Datum) {
Int4Datum other = (Int4Datum) obj;
return val == other.val;
}
-
+
return false;
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case INT2:
return DatumFactory.createBool(val == datum.asInt2());
@@ -130,7 +130,7 @@ public class Int4Datum extends NumericDatum {
case FLOAT8:
return DatumFactory.createBool(val == datum.asFloat8());
case NULL_TYPE:
- return DatumFactory.createBool(false);
+ return datum;
default:
throw new InvalidOperationException();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java
index ffe9654..c46106f 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Int8Datum.java
@@ -124,7 +124,7 @@ public class Int8Datum extends NumericDatum {
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case INT2:
return DatumFactory.createBool(val == datum.asInt2());
@@ -137,7 +137,7 @@ public class Int8Datum extends NumericDatum {
case FLOAT8:
return DatumFactory.createBool(val == datum.asFloat8());
case NULL_TYPE:
- return DatumFactory.createBool(false);
+ return datum;
default:
throw new InvalidOperationException();
}
@@ -198,6 +198,7 @@ public class Int8Datum extends NumericDatum {
}
case NULL_TYPE:
return -1;
+
default:
throw new InvalidOperationException();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
index 6a18ef3..a2b42c4 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/NullDatum.java
@@ -18,10 +18,13 @@
package org.apache.tajo.datum;
+import org.apache.tajo.datum.exception.InvalidCastException;
+
import static org.apache.tajo.common.TajoDataTypes.Type;
public class NullDatum extends Datum {
private static NullDatum instance;
+ private static final byte [] EMPTY_BYTES = new byte[0];
static {
instance = new NullDatum();
@@ -34,10 +37,15 @@ public class NullDatum extends Datum {
public static NullDatum get() {
return instance;
}
-
+
+ @Override
+ public boolean isNull() {
+ return true;
+ }
+
@Override
public boolean asBool() {
- return false;
+ throw new InvalidCastException("NULL cannot be casted as a bool type value.");
}
@Override
@@ -62,7 +70,7 @@ public class NullDatum extends Datum {
@Override
public byte[] asByteArray() {
- return new byte[0];
+ return EMPTY_BYTES;
}
@Override
@@ -82,7 +90,7 @@ public class NullDatum extends Datum {
@Override
public byte[] asTextBytes() {
- return new byte[0];
+ return EMPTY_BYTES;
}
@Override
@@ -97,11 +105,70 @@ public class NullDatum extends Datum {
@Override
public int compareTo(Datum datum) {
- return 0;
+ if (datum.type() == Type.NULL_TYPE) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ @Override
+ public Datum and(Datum datum) {
+ return BooleanDatum.AND_LOGIC[BooleanDatum.UNKNOWN_INT][datum.asInt4()];
+ }
+
+ @Override
+ public Datum or(Datum datum) {
+ return BooleanDatum.OR_LOGIC[BooleanDatum.UNKNOWN_INT][datum.asInt4()];
+ }
+
+ public NullDatum plus(Datum datum) {
+ return this;
+ }
+
+ public NullDatum minus(Datum datum) {
+ return this;
+ }
+
+ public NullDatum multiply(Datum datum) {
+ return this;
+ }
+
+ public NullDatum divide(Datum datum) {
+ return this;
+ }
+
+ public NullDatum modular(Datum datum) {
+ return this;
+ }
+
+ public NullDatum equalsTo(Datum datum) {
+ return this;
+ }
+
+ public NullDatum lessThan(Datum datum) {
+ return this;
+ }
+
+ public NullDatum lessThanEqual(Datum datum) {
+ return this;
+ }
+
+ public NullDatum greaterThan(Datum datum) {
+ return this;
+ }
+
+ public NullDatum greaterThanEqual(Datum datum) {
+ return this;
}
@Override
public int hashCode() {
- return 0; // one of the prime number
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "NULL";
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
index a7234b7..26f7297 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
@@ -25,12 +25,14 @@ import org.apache.tajo.datum.exception.InvalidCastException;
import org.apache.tajo.datum.exception.InvalidOperationException;
import java.util.Arrays;
+import java.util.Comparator;
public class TextDatum extends Datum {
@Expose private int size;
@Expose private byte [] bytes;
public static final TextDatum EMPTY_TEXT = new TextDatum("");
+ public static final Comparator<byte[]> COMPARATOR = UnsignedBytes.lexicographicalComparator();
public TextDatum() {
super(TajoDataTypes.Type.TEXT);
@@ -106,10 +108,11 @@ public class TextDatum extends Datum {
case TEXT:
case CHAR:
case BLOB:
- return UnsignedBytes.lexicographicalComparator().compare(bytes, datum.asByteArray());
+ return COMPARATOR.compare(bytes, datum.asByteArray());
case NULL_TYPE:
return -1;
+
default:
throw new InvalidOperationException();
}
@@ -119,22 +122,21 @@ public class TextDatum extends Datum {
public boolean equals(Object obj) {
if (obj instanceof TextDatum) {
TextDatum o = (TextDatum) obj;
- return UnsignedBytes.lexicographicalComparator().compare(this.bytes, o.bytes) == 0;
+ return COMPARATOR.compare(this.bytes, o.bytes) == 0;
}
return false;
}
@Override
- public BooleanDatum equalsTo(Datum datum) {
+ public Datum equalsTo(Datum datum) {
switch (datum.type()) {
case TEXT:
case CHAR:
case BLOB:
- return DatumFactory.createBool(UnsignedBytes.lexicographicalComparator()
- .compare(bytes, datum.asByteArray()) == 0);
+ return DatumFactory.createBool(COMPARATOR.compare(bytes, datum.asByteArray()) == 0);
case NULL_TYPE:
- return DatumFactory.createBool(false);
+ return datum;
default:
throw new InvalidOperationException();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java
index 7ea0d47..f6fac63 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/TimeDatum.java
@@ -38,6 +38,11 @@ public class TimeDatum extends Datum {
time = new LocalTime(value);
}
+ public TimeDatum(String timeStr) {
+ super(TajoDataTypes.Type.TIME);
+ time = LocalTime.parse(timeStr, DEFAULT_FORMATTER);
+ }
+
public TimeDatum(LocalTime time) {
super(TajoDataTypes.Type.TIME);
this.time = time;
@@ -111,9 +116,22 @@ public class TimeDatum extends Datum {
}
@Override
+ public Datum equalsTo(Datum datum) {
+ if (datum.type() == TajoDataTypes.Type.TIME) {
+ return DatumFactory.createBool(time.equals(((TimeDatum) datum).time));
+ } else if (datum.isNull()) {
+ return datum;
+ } else {
+ throw new InvalidOperationException();
+ }
+ }
+
+ @Override
public int compareTo(Datum datum) {
if (datum.type() == TajoDataTypes.Type.TIME) {
return time.compareTo(((TimeDatum)datum).time);
+ } else if (datum.isNull()) {
+ return -1;
} else {
throw new InvalidOperationException();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java
index 7f40e5e..83e10b4 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/TimestampDatum.java
@@ -133,9 +133,22 @@ public class TimestampDatum extends Datum {
}
@Override
+ public Datum equalsTo(Datum datum) {
+ if (datum.type() == TajoDataTypes.Type.TIME) {
+ return DatumFactory.createBool(dateTime.equals(((TimestampDatum) datum).dateTime));
+ } else if (datum.isNull()) {
+ return datum;
+ } else {
+ throw new InvalidOperationException();
+ }
+ }
+
+ @Override
public int compareTo(Datum datum) {
if (datum.type() == TajoDataTypes.Type.TIMESTAMP) {
return dateTime.compareTo(((TimestampDatum)datum).dateTime);
+ } else if (datum.isNull()) {
+ return -1;
} else {
throw new InvalidOperationException();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-common/src/test/java/org/apache/tajo/datum/TestBoolDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/test/java/org/apache/tajo/datum/TestBoolDatum.java b/tajo-common/src/test/java/org/apache/tajo/datum/TestBoolDatum.java
index 3175510..2b3fec2 100644
--- a/tajo-common/src/test/java/org/apache/tajo/datum/TestBoolDatum.java
+++ b/tajo-common/src/test/java/org/apache/tajo/datum/TestBoolDatum.java
@@ -25,50 +25,62 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class TestBoolDatum {
-
- @Test
- public final void testType() {
- Datum d = DatumFactory.createBool(true);
- assertEquals(Type.BOOLEAN, d.type());
- }
-
- @Test
- public final void testAsBool() {
- Datum d = DatumFactory.createBool(false);
- assertEquals(false, d.asBool());
- }
-
- @Test
- public final void testAsShort() {
- Datum d = DatumFactory.createBool(true);
- assertEquals(1, d.asInt2());
- }
-
- @Test
- public final void testAsInt() {
- Datum d = DatumFactory.createBool(true);
- assertEquals(1, d.asInt4());
- }
-
- @Test
- public final void testAsLong() {
- Datum d = DatumFactory.createBool(false);
- assertEquals(0, d.asInt8());
- }
-
- @Test
- public final void testAsByte() {
- Datum d = DatumFactory.createBool(true);
- assertEquals(0x01, d.asByte());
- }
-
- @Test
- public final void testAsChars() {
- Datum d = DatumFactory.createBool(true);
- assertEquals("t", d.asChars());
- }
-
- @Test
+
+ @Test
+ public final void testType() {
+ Datum d = DatumFactory.createBool(true);
+ assertEquals(Type.BOOLEAN, d.type());
+ }
+
+ @Test
+ public final void testAsBool() {
+ Datum trueDatum = DatumFactory.createBool(false);
+ assertEquals(false, trueDatum.asBool());
+ Datum falseDatum = DatumFactory.createBool(false);
+ assertEquals(false, falseDatum.asBool());
+ }
+
+ @Test
+ public final void testAsShort() {
+ Datum trueDatum = DatumFactory.createBool(true);
+ assertEquals(1, trueDatum.asInt2());
+ Datum falseDatum = DatumFactory.createBool(false);
+ assertEquals(2, falseDatum.asInt2());
+ }
+
+ @Test
+ public final void testAsInt() {
+ Datum trueDatum = DatumFactory.createBool(true);
+ assertEquals(1, trueDatum.asInt4());
+ Datum falseDatum = DatumFactory.createBool(false);
+ assertEquals(2, falseDatum.asInt4());
+ }
+
+ @Test
+ public final void testAsLong() {
+ Datum trueDatum = DatumFactory.createBool(true);
+ assertEquals(1, trueDatum.asInt8());
+ Datum falseDatum = DatumFactory.createBool(false);
+ assertEquals(2, falseDatum.asInt8());
+ }
+
+ @Test
+ public final void testAsByte() {
+ Datum trueDatum = DatumFactory.createBool(true);
+ assertEquals(0x01, trueDatum.asByte());
+ Datum falseDatum = DatumFactory.createBool(false);
+ assertEquals(0x02, falseDatum.asByte());
+ }
+
+ @Test
+ public final void testAsChars() {
+ Datum trueDatum = DatumFactory.createBool(true);
+ assertEquals("t", trueDatum.asChars());
+ Datum falseDatum = DatumFactory.createBool(false);
+ assertEquals("f", falseDatum.asChars());
+ }
+
+ @Test
public final void testSize() {
Datum d = DatumFactory.createBool(true);
assertEquals(1, d.size());
@@ -76,7 +88,9 @@ public class TestBoolDatum {
@Test
public final void testAsTextBytes() {
- Datum d = DatumFactory.createBool(true);
- assertArrayEquals(d.toString().getBytes(), d.asTextBytes());
+ Datum trueDatum = DatumFactory.createBool(true);
+ assertArrayEquals(trueDatum.toString().getBytes(), trueDatum.asTextBytes());
+ Datum falseDatum = DatumFactory.createBool(false);
+ assertArrayEquals(falseDatum.toString().getBytes(), falseDatum.asTextBytes());
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4 b/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
index 54e43c7..26d2fd9 100644
--- a/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
+++ b/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
@@ -461,6 +461,7 @@ value_expression
common_value_expression
: numeric_value_expression
| string_value_expression
+ | NULL
;
/*
@@ -928,7 +929,7 @@ predicate
===============================================================================
*/
comparison_predicate
- : left=numeric_value_expression c=comp_op right=numeric_value_expression
+ : left=row_value_predicand c=comp_op right=row_value_predicand
;
comp_op
@@ -1015,7 +1016,7 @@ regex_matcher
*/
null_predicate
- : predicand=numeric_value_expression IS (n=NOT)? NULL
+ : predicand=row_value_predicand IS (n=NOT)? NULL
;
/*
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
index bb25909..a67ca7a 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
@@ -23,54 +23,56 @@ import com.google.common.base.Preconditions;
import com.google.gson.annotations.Expose;
import org.apache.tajo.catalog.CatalogUtil;
import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.common.TajoDataTypes;
import org.apache.tajo.common.TajoDataTypes.DataType;
import org.apache.tajo.datum.Datum;
import org.apache.tajo.datum.DatumFactory;
+import org.apache.tajo.datum.NullDatum;
import org.apache.tajo.storage.Tuple;
+import static org.apache.tajo.common.TajoDataTypes.Type;
+
public class BinaryEval extends EvalNode implements Cloneable {
- @Expose private DataType returnType = null;
+ @Expose private DataType returnType = null;
private class BinaryEvalCtx implements EvalContext {
EvalContext left;
EvalContext right;
}
- /**
- * @param type
- */
- public BinaryEval(EvalType type, EvalNode left, EvalNode right) {
- super(type, left, right);
- Preconditions.checkNotNull(type);
- Preconditions.checkNotNull(left);
- Preconditions.checkNotNull(right);
-
- if(
- type == EvalType.AND ||
- type == EvalType.OR ||
- type == EvalType.EQUAL ||
- type == EvalType.LTH ||
- type == EvalType.GTH ||
- type == EvalType.LEQ ||
- type == EvalType.GEQ ) {
- this.returnType = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.BOOLEAN);
- } else if (
- type == EvalType.PLUS ||
- type == EvalType.MINUS ||
- type == EvalType.MULTIPLY ||
- type == EvalType.DIVIDE ||
- type == EvalType.MODULAR ) {
- this.returnType = determineType(left.getValueType(), right.getValueType());
-
- } else if (type == EvalType.CONCATENATE) {
- this.returnType = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.TEXT);
+ /**
+ * @param type
+ */
+ public BinaryEval(EvalType type, EvalNode left, EvalNode right) {
+ super(type, left, right);
+ Preconditions.checkNotNull(type);
+ Preconditions.checkNotNull(left);
+ Preconditions.checkNotNull(right);
+
+ if(
+ type == EvalType.AND ||
+ type == EvalType.OR ||
+ type == EvalType.EQUAL ||
+ type == EvalType.LTH ||
+ type == EvalType.GTH ||
+ type == EvalType.LEQ ||
+ type == EvalType.GEQ ) {
+ this.returnType = CatalogUtil.newSimpleDataType(Type.BOOLEAN);
+ } else if (
+ type == EvalType.PLUS ||
+ type == EvalType.MINUS ||
+ type == EvalType.MULTIPLY ||
+ type == EvalType.DIVIDE ||
+ type == EvalType.MODULAR ) {
+ this.returnType = determineType(left.getValueType(), right.getValueType());
+
+ } else if (type == EvalType.CONCATENATE) {
+ this.returnType = CatalogUtil.newSimpleDataType(Type.TEXT);
}
- }
+ }
public BinaryEval(PartialBinaryExpr expr) {
- this(expr.type, expr.leftExpr, expr.rightExpr);
- }
+ this(expr.type, expr.leftExpr, expr.rightExpr);
+ }
@Override
public EvalContext newContext() {
@@ -86,105 +88,100 @@ public class BinaryEval extends EvalNode implements Cloneable {
*/
private DataType determineType(DataType left, DataType right) throws InvalidEvalException {
switch (left.getType()) {
- case INT4: {
- switch(right.getType()) {
- case INT2:
- case INT4: return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INT4);
- case INT8: return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INT8);
- case FLOAT4: return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.FLOAT4);
- case FLOAT8: return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.FLOAT8);
- }
+ case INT4: {
+ switch(right.getType()) {
+ case INT2:
+ case INT4: return CatalogUtil.newSimpleDataType(Type.INT4);
+ case INT8: return CatalogUtil.newSimpleDataType(Type.INT8);
+ case FLOAT4: return CatalogUtil.newSimpleDataType(Type.FLOAT4);
+ case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
}
+ }
- case INT8: {
- switch(right.getType()) {
- case INT2:
- case INT4:
- case INT8: return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INT8);
- case FLOAT4:
- case FLOAT8: return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.FLOAT8);
- }
+ case INT8: {
+ switch(right.getType()) {
+ case INT2:
+ case INT4:
+ case INT8: return CatalogUtil.newSimpleDataType(Type.INT8);
+ case FLOAT4:
+ case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
}
+ }
- case FLOAT4: {
- switch(right.getType()) {
- case INT2:
- case INT4:
- case INT8:
- case FLOAT4:
- case FLOAT8: return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.FLOAT8);
- }
+ case FLOAT4: {
+ switch(right.getType()) {
+ case INT2:
+ case INT4:
+ case INT8:
+ case FLOAT4:
+ case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
}
+ }
- case FLOAT8: {
- switch(right.getType()) {
- case INT2:
- case INT4:
- case INT8:
- case FLOAT4:
- case FLOAT8: return CatalogUtil.newSimpleDataType(TajoDataTypes.Type.FLOAT8);
- }
+ case FLOAT8: {
+ switch(right.getType()) {
+ case INT2:
+ case INT4:
+ case INT8:
+ case FLOAT4:
+ case FLOAT8: return CatalogUtil.newSimpleDataType(Type.FLOAT8);
}
+ }
- default: return left;
+ default: return left;
}
}
- /* (non-Javadoc)
- * @see nta.query.executor.eval.Expr#evalBool(Tuple)
- */
- @Override
- public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
+ @Override
+ public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
BinaryEvalCtx binCtx = (BinaryEvalCtx) ctx;
- leftExpr.eval(binCtx == null ? null : binCtx.left, schema, tuple);
+ leftExpr.eval(binCtx == null ? null : binCtx.left, schema, tuple);
rightExpr.eval(binCtx == null ? null : binCtx.right, schema, tuple);
- }
+ }
@Override
public Datum terminate(EvalContext ctx) {
BinaryEvalCtx binCtx = (BinaryEvalCtx) ctx;
+ Datum lhs = leftExpr.terminate(binCtx.left);
+ Datum rhs = rightExpr.terminate(binCtx.right);
switch(type) {
- case AND: {
- boolean left = leftExpr.terminate(binCtx.left).asBool();
- boolean right = rightExpr.terminate(binCtx.right).asBool();
- return DatumFactory.createBool(left && right);
+ case AND:
+ return lhs.and(rhs);
+ case OR:
+ return lhs.or(rhs);
+
+ case EQUAL:
+ return lhs.equalsTo(rhs);
+ case NOT_EQUAL:
+ return lhs.notEqualsTo(rhs);
+ case LTH:
+ return lhs.lessThan(rhs);
+ case LEQ:
+ return lhs.lessThanEqual(rhs);
+ case GTH:
+ return lhs.greaterThan(rhs);
+ case GEQ:
+ return lhs.greaterThanEqual(rhs);
+
+ case PLUS:
+ return lhs.plus(rhs);
+ case MINUS:
+ return lhs.minus(rhs);
+ case MULTIPLY:
+ return lhs.multiply(rhs);
+ case DIVIDE:
+ return lhs.divide(rhs);
+ case MODULAR:
+ return lhs.modular(rhs);
+
+ case CONCATENATE:
+ if (lhs.type() == Type.NULL_TYPE || rhs.type() == Type.NULL_TYPE) {
+ return NullDatum.get();
}
- case OR:
- boolean left = leftExpr.terminate(binCtx.left).asBool();
- boolean right = rightExpr.terminate(binCtx.right).asBool();
- return DatumFactory.createBool(left || right);
-
- case EQUAL:
- return leftExpr.terminate(binCtx.left).equalsTo(rightExpr.terminate(binCtx.right));
- case NOT_EQUAL:
- return DatumFactory.createBool(!leftExpr.terminate(binCtx.left).equalsTo(rightExpr.terminate(binCtx.right)).
- asBool());
- case LTH:
- return leftExpr.terminate(binCtx.left).lessThan(rightExpr.terminate(binCtx.right));
- case LEQ:
- return leftExpr.terminate(binCtx.left).lessThanEqual(rightExpr.terminate(binCtx.right));
- case GTH:
- return leftExpr.terminate(binCtx.left).greaterThan(rightExpr.terminate(binCtx.right));
- case GEQ:
- return leftExpr.terminate(binCtx.left).greaterThanEqual(rightExpr.terminate(binCtx.right));
-
- case PLUS:
- return leftExpr.terminate(binCtx.left).plus(rightExpr.terminate(binCtx.right));
- case MINUS:
- return leftExpr.terminate(binCtx.left).minus(rightExpr.terminate(binCtx.right));
- case MULTIPLY:
- return leftExpr.terminate(binCtx.left).multiply(rightExpr.terminate(binCtx.right));
- case DIVIDE:
- return leftExpr.terminate(binCtx.left).divide(rightExpr.terminate(binCtx.right));
- case MODULAR:
- return leftExpr.terminate(binCtx.left).modular(rightExpr.terminate(binCtx.right));
-
- case CONCATENATE:
- return DatumFactory.createText(leftExpr.terminate(binCtx.left).asChars()
- + rightExpr.terminate(binCtx.right).asChars());
- default:
- throw new InvalidEvalException("We does not support " + type + " expression yet");
+ return DatumFactory.createText(lhs.asChars() + rhs.asChars());
+ default:
+ throw new InvalidEvalException("We does not support " + type + " expression yet");
}
}
@@ -192,16 +189,16 @@ public class BinaryEval extends EvalNode implements Cloneable {
public String getName() {
return "?";
}
-
+
@Override
public DataType getValueType() {
return returnType;
}
-
+
public String toString() {
return leftExpr +" " + type.getOperatorName() + " "+rightExpr;
}
-
+
@Override
public boolean equals(Object obj) {
if (obj instanceof BinaryEval) {
@@ -210,20 +207,20 @@ public class BinaryEval extends EvalNode implements Cloneable {
boolean b1 = this.type == other.type;
boolean b2 = leftExpr.equals(other.leftExpr);
boolean b3 = rightExpr.equals(other.rightExpr);
- return b1 && b2 && b3;
+ return b1 && b2 && b3;
}
return false;
}
-
+
public int hashCode() {
return Objects.hashCode(this.type, leftExpr, rightExpr);
}
-
+
@Override
public Object clone() throws CloneNotSupportedException {
BinaryEval eval = (BinaryEval) super.clone();
eval.returnType = returnType;
-
+
return eval;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CastEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CastEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CastEval.java
index 411dd09..033800d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CastEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CastEval.java
@@ -65,28 +65,37 @@ public class CastEval extends EvalNode {
@Override
public Datum terminate(EvalContext ctx) {
CastContext castContext = (CastContext) ctx;
+ Datum operandDatum = operand.terminate(castContext.childCtx);
+ if (operandDatum.isNull()) {
+ return operandDatum;
+ }
+
switch (target.getType()) {
case BOOLEAN:
- return DatumFactory.createBool(operand.terminate(castContext.childCtx).asBool());
+ return DatumFactory.createBool(operandDatum.asBool());
case CHAR:
- return DatumFactory.createChar(operand.terminate(castContext.childCtx).asChar());
+ return DatumFactory.createChar(operandDatum.asChar());
case INT1:
case INT2:
- return DatumFactory.createInt2(operand.terminate(castContext.childCtx).asInt2());
+ return DatumFactory.createInt2(operandDatum.asInt2());
case INT4:
- return DatumFactory.createInt4(operand.terminate(castContext.childCtx).asInt4());
+ return DatumFactory.createInt4(operandDatum.asInt4());
case INT8:
- return DatumFactory.createInt8(operand.terminate(castContext.childCtx).asInt8());
+ return DatumFactory.createInt8(operandDatum.asInt8());
case FLOAT4:
- return DatumFactory.createFloat4(operand.terminate(castContext.childCtx).asFloat4());
+ return DatumFactory.createFloat4(operandDatum.asFloat4());
case FLOAT8:
- return DatumFactory.createFloat8(operand.terminate(castContext.childCtx).asFloat8());
+ return DatumFactory.createFloat8(operandDatum.asFloat8());
case TEXT:
- return DatumFactory.createText(operand.terminate(castContext.childCtx).asTextBytes());
+ return DatumFactory.createText(operandDatum.asTextBytes());
+ case DATE:
+ return DatumFactory.createDate(operandDatum);
+ case TIME:
+ return DatumFactory.createTime(operandDatum);
case TIMESTAMP:
- return DatumFactory.createTimestamp(operand.terminate(castContext.childCtx));
+ return DatumFactory.createTimestamp(operandDatum);
case BLOB:
- return DatumFactory.createBlob(operand.terminate(castContext.childCtx).asByteArray());
+ return DatumFactory.createBlob(operandDatum.asByteArray());
default:
throw new InvalidCastException("Cannot cast " + operand.getValueType().getType() + " to "
+ target.getType());
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
index 59e8b31..1e26e14 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
@@ -23,7 +23,6 @@ import com.google.gson.annotations.Expose;
import org.apache.tajo.catalog.CatalogUtil;
import org.apache.tajo.catalog.Schema;
import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.datum.BooleanDatum;
import org.apache.tajo.datum.Datum;
import org.apache.tajo.datum.DatumFactory;
import org.apache.tajo.storage.Tuple;
@@ -76,17 +75,12 @@ public class InEval extends BinaryEval {
break;
}
}
-
- if (not) {
- isNullCtx.result.setValue(!isIncluded);
- } else {
- isNullCtx.result.setValue(isIncluded);
- }
+ isNullCtx.result = isIncluded;
}
@Override
public Datum terminate(EvalContext ctx) {
- return ((InEvalCtx)ctx).result;
+ return DatumFactory.createBool(not ^ ((InEvalCtx)ctx).result);
}
@Override
@@ -103,10 +97,6 @@ public class InEval extends BinaryEval {
}
private class InEvalCtx implements EvalContext {
- BooleanDatum result;
-
- InEvalCtx() {
- this.result = DatumFactory.createBool(false);
- }
+ boolean result;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/PatternMatchPredicateEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/PatternMatchPredicateEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/PatternMatchPredicateEval.java
index 64a655c..568af0c 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/PatternMatchPredicateEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/PatternMatchPredicateEval.java
@@ -23,7 +23,6 @@ import org.apache.tajo.catalog.CatalogUtil;
import org.apache.tajo.catalog.Schema;
import org.apache.tajo.common.TajoDataTypes;
import org.apache.tajo.common.TajoDataTypes.DataType;
-import org.apache.tajo.datum.BooleanDatum;
import org.apache.tajo.datum.Datum;
import org.apache.tajo.datum.DatumFactory;
import org.apache.tajo.datum.NullDatum;
@@ -42,7 +41,6 @@ public abstract class PatternMatchPredicateEval extends BinaryEval {
// transient variables
private EvalContext leftContext;
private boolean isNullResult = false;
- private BooleanDatum result;
protected Pattern compiled;
public PatternMatchPredicateEval(EvalType evalType, boolean not, EvalNode predicand, ConstEval pattern,
@@ -73,7 +71,6 @@ public abstract class PatternMatchPredicateEval extends BinaryEval {
public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
if (leftContext == null) {
leftContext = leftExpr.newContext();
- result = DatumFactory.createBool(false);
compile(this.pattern);
}
@@ -81,10 +78,19 @@ public abstract class PatternMatchPredicateEval extends BinaryEval {
Datum predicand = leftExpr.terminate(leftContext);
isNullResult = predicand instanceof NullDatum;
boolean matched = compiled.matcher(predicand.asChars()).matches();
- result.setValue(matched ^ not);
+ ((PatternMatchPredicateContext)ctx).result = matched ^ not;
}
public Datum terminate(EvalContext ctx) {
- return !isNullResult ? result : NullDatum.get();
+ return !isNullResult ?
+ DatumFactory.createBool(((PatternMatchPredicateContext)ctx).result) : NullDatum.get();
+ }
+
+ public EvalContext newContext() {
+ return new PatternMatchPredicateContext();
+ }
+
+ private class PatternMatchPredicateContext implements EvalContext {
+ public boolean result = false;
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/InCountry.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/InCountry.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/InCountry.java
index 0043a12..3cc9efa 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/InCountry.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/InCountry.java
@@ -21,6 +21,7 @@ package org.apache.tajo.engine.function;
import org.apache.tajo.catalog.Column;
import org.apache.tajo.common.TajoDataTypes;
import org.apache.tajo.datum.BooleanDatum;
+import org.apache.tajo.datum.DatumFactory;
import org.apache.tajo.storage.Tuple;
import org.apache.tajo.util.GeoUtil;
@@ -37,6 +38,6 @@ public class InCountry extends GeneralFunction {
String otherCode = params.get(1).asChars();
String thisCode = GeoUtil.getCountryCode(addr);
- return new BooleanDatum(thisCode.equals(otherCode));
+ return DatumFactory.createBool(thisCode.equals(otherCode));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/string/SplitPart.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/string/SplitPart.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/string/SplitPart.java
index 505d531..6de485f 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/string/SplitPart.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/function/string/SplitPart.java
@@ -30,27 +30,32 @@ import org.apache.tajo.storage.Tuple;
/**
* Function definition
*
- * text split_part(string text, delimiter text, field int)
+ * text split_part(string text, delimiter text, part int)
*/
public class SplitPart extends GeneralFunction {
public SplitPart() {
super(new Column[] {
new Column("text", TajoDataTypes.Type.TEXT),
new Column("delimiter", TajoDataTypes.Type.TEXT),
- new Column("field", TajoDataTypes.Type.INT4),
+ new Column("part", TajoDataTypes.Type.INT4),
});
}
@Override
public Datum eval(Tuple params) {
- Datum datum = params.get(0);
- if(datum instanceof NullDatum) return NullDatum.get();
+ Datum text = params.get(0);
+ Datum part = params.get(2);
- String [] split = StringUtils.splitByWholeSeparatorPreserveAllTokens(datum.asChars(), params.get(1).asChars(), -1);
+ if (text.isNull() || part.isNull()) {
+ return NullDatum.get();
+ }
+
+ String [] split = StringUtils.splitByWholeSeparatorPreserveAllTokens(text.asChars(), params.get(1).asChars(), -1);
int idx = params.get(2).asInt4() - 1;
if (split.length > idx) {
return DatumFactory.createText(split[idx]);
} else {
+ // If part is larger than the number of string portions, it will returns NULL.
return NullDatum.get();
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
index ad8acf1..d9e7135 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
@@ -462,6 +462,14 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
return caseWhen;
}
+ @Override public Expr visitCommon_value_expression(SQLParser.Common_value_expressionContext ctx) {
+ if (checkIfExist(ctx.NULL())) {
+ return new NullValue();
+ } else {
+ return visitChildren(ctx);
+ }
+ }
+
@Override
public Expr visitParenthesized_value_expression(SQLParser.Parenthesized_value_expressionContext ctx) {
return visitValue_expression(ctx.value_expression());
@@ -559,7 +567,7 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
}
@Override
- public Expr visitRow_value_predicand(@NotNull SQLParser.Row_value_predicandContext ctx) {
+ public Expr visitRow_value_predicand(SQLParser.Row_value_predicandContext ctx) {
if (checkIfExist(ctx.row_value_special_case())) {
return visitRow_value_special_case(ctx.row_value_special_case());
} else {
@@ -568,11 +576,20 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
}
@Override
+ public Expr visitRow_value_constructor_predicand(SQLParser.Row_value_constructor_predicandContext ctx) {
+ if (checkIfExist(ctx.boolean_predicand())) {
+ return visitBoolean_predicand(ctx.boolean_predicand());
+ } else {
+ return visitCommon_value_expression(ctx.common_value_expression());
+ }
+ }
+
+ @Override
public BinaryOperator visitComparison_predicate(SQLParser.Comparison_predicateContext ctx) {
TerminalNode operator = (TerminalNode) ctx.comp_op().getChild(0);
return new BinaryOperator(tokenToExprType(operator.getSymbol().getType()),
- visitNumeric_value_expression(ctx.left),
- visitNumeric_value_expression(ctx.right));
+ visitRow_value_predicand(ctx.left),
+ visitRow_value_predicand(ctx.right));
}
@Override
@@ -734,7 +751,7 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
@Override
public IsNullPredicate visitNull_predicate(SQLParser.Null_predicateContext ctx) {
- Expr predicand = visit(ctx.numeric_value_expression());
+ Expr predicand = visitRow_value_predicand(ctx.row_value_predicand());
return new IsNullPredicate(ctx.NOT() != null, predicand);
}
@@ -761,7 +778,7 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
return new LiteralValue(ctx.getText(), LiteralType.Unsigned_Integer);
} else {
return new LiteralValue(ctx.getText(), LiteralType.Unsigned_Large_Integer);
- }
+ }
} else {
return new LiteralValue(ctx.getText(), LiteralType.Unsigned_Float);
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java
index 4ab2b84..550f0ee 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java
@@ -185,7 +185,7 @@ public class HashFullOuterJoinExec extends BinaryPhysicalExec {
rightTuple = iterator.next();
frameTuple.set(leftTuple, rightTuple); // evaluate a join condition on both tuples
joinQual.eval(qualCtx, inSchema, frameTuple); //?? isn't it always true if hash function is identity function??
- if (joinQual.terminate(qualCtx).asBool()) { // if both tuples are joinable
+ if (joinQual.terminate(qualCtx).isTrue()) { // if both tuples are joinable
projector.eval(evalContexts, frameTuple);
projector.terminate(evalContexts, outTuple);
found = true;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java
index f291750..f0022cb 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java
@@ -149,7 +149,7 @@ public class HashLeftOuterJoinExec extends BinaryPhysicalExec {
rightTuple = iterator.next();
frameTuple.set(leftTuple, rightTuple); // evaluate a join condition on both tuples
joinQual.eval(qualCtx, inSchema, frameTuple);
- if (joinQual.terminate(qualCtx).asBool()) { // if both tuples are joinable
+ if (joinQual.terminate(qualCtx).isTrue()) { // if both tuples are joinable
projector.eval(evalContexts, frameTuple);
projector.terminate(evalContexts, outTuple);
found = true;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java
index eab6dda..ebc78e2 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java
@@ -112,7 +112,7 @@ public class NLLeftOuterJoinExec extends BinaryPhysicalExec {
frameTuple.set(leftTuple, rightTuple);
joinQual.eval(qualCtx, inSchema, frameTuple);
- if (joinQual.terminate(qualCtx).asBool()) {
+ if (joinQual.terminate(qualCtx).isTrue()) {
projector.eval(evalContexts, frameTuple);
projector.terminate(evalContexts, outTuple);
foundAtLeastOneMatch = true;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java
index d17f7ec..1ae6640 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java
@@ -181,7 +181,7 @@ public class SeqScanExec extends PhysicalExec {
} else {
while ((tuple = scanner.next()) != null) {
qual.eval(qualCtx, inSchema, tuple);
- if (qual.terminate(qualCtx).asBool()) {
+ if (qual.terminate(qualCtx).isTrue()) {
projector.eval(evalContexts, tuple);
projector.terminate(evalContexts, outTuple);
return outTuple;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestSQLExpression.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestSQLExpression.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestSQLExpression.java
index c96f7e5..2d76fec 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestSQLExpression.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestSQLExpression.java
@@ -97,4 +97,91 @@ public class TestSQLExpression extends ExprTestBase {
schema.addColumn("col2", TEXT);
testEval(schema, "table1", "123,234", "select col1, col2 from table1 where true", new String[]{"123", "234"});
}
+
+ @Test
+ public void testNullComparisons() throws IOException {
+ testSimpleEval("select null is null", new String[] {"t"});
+ testSimpleEval("select null is not null", new String[] {"f"});
+
+ testSimpleEval("select (1::int2 > null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int2 < null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int2 >= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int2 <= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int2 <> null) is null", new String[] {"t"});
+
+ testSimpleEval("select (1::int4 > null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int4 < null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int4 >= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int4 <= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int4 <> null) is null", new String[] {"t"});
+
+ testSimpleEval("select (1::int8 > null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int8 < null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int8 >= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int8 <= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::int8 <> null) is null", new String[] {"t"});
+
+ testSimpleEval("select (1::float > null) is null", new String[] {"t"});
+ testSimpleEval("select (1::float < null) is null", new String[] {"t"});
+ testSimpleEval("select (1::float >= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::float <= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::float <> null) is null", new String[] {"t"});
+
+ testSimpleEval("select (1::float8 > null) is null", new String[] {"t"});
+ testSimpleEval("select (1::float8 < null) is null", new String[] {"t"});
+ testSimpleEval("select (1::float8 >= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::float8 <= null) is null", new String[] {"t"});
+ testSimpleEval("select (1::float8 <> null) is null", new String[] {"t"});
+
+ testSimpleEval("select ('abc' > null) is null", new String[] {"t"});
+ testSimpleEval("select ('abc' < null) is null", new String[] {"t"});
+ testSimpleEval("select ('abc' >= null) is null", new String[] {"t"});
+ testSimpleEval("select ('abc' <= null) is null", new String[] {"t"});
+ testSimpleEval("select ('abc' <> null) is null", new String[] {"t"});
+
+ testSimpleEval("select ('1980-04-01'::date > null) is null", new String[] {"t"});
+ testSimpleEval("select ('1980-04-01'::date < null) is null", new String[] {"t"});
+ testSimpleEval("select ('1980-04-01'::date >= null) is null", new String[] {"t"});
+ testSimpleEval("select ('1980-04-01'::date <= null) is null", new String[] {"t"});
+ testSimpleEval("select ('1980-04-01'::date <> null) is null", new String[] {"t"});
+
+ testSimpleEval("select ('09:08:50'::time > null) is null", new String[] {"t"});
+ testSimpleEval("select ('09:08:50'::time < null) is null", new String[] {"t"});
+ testSimpleEval("select ('09:08:50'::time >= null) is null", new String[] {"t"});
+ testSimpleEval("select ('09:08:50'::time <= null) is null", new String[] {"t"});
+ testSimpleEval("select ('09:08:50'::time <> null) is null", new String[] {"t"});
+
+ testSimpleEval("select ('1980-04-01 01:50:30'::timestamp > null) is null", new String[] {"t"});
+ testSimpleEval("select ('1980-04-01 01:50:30'::timestamp < null) is null", new String[] {"t"});
+ testSimpleEval("select ('1980-04-01 01:50:30'::timestamp >= null) is null", new String[] {"t"});
+ testSimpleEval("select ('1980-04-01 01:50:30'::timestamp <= null) is null", new String[] {"t"});
+ testSimpleEval("select ('1980-04-01 01:50:30'::timestamp <> null) is null", new String[] {"t"});
+
+
+ // Three Valued Logic - AND
+ testSimpleEval("select (true AND true)", new String[] {"t"}); // true - true -> true
+ testSimpleEval("select (true AND 1 > null) is null", new String[] {"t"}); // true - unknown -> unknown
+ testSimpleEval("select (true AND false)", new String[] {"f"}); // true - false -> true
+
+ testSimpleEval("select (1 > null AND true) is null", new String[] {"t"}); // unknown - true -> true
+ testSimpleEval("select (1 > null AND 1 > null) is null", new String[] {"t"}); // unknown - unknown -> unknown
+ testSimpleEval("select (1 > null AND false)", new String[] {"f"}); // unknown - false -> false
+
+ testSimpleEval("select (false AND true)", new String[] {"f"}); // false - true -> true
+ testSimpleEval("select (false AND 1 > null) is null", new String[] {"f"}); // false - unknown -> unknown
+ testSimpleEval("select (false AND false)", new String[] {"f"}); // false - false -> false
+
+ // Three Valued Logic - OR
+ testSimpleEval("select (true OR true)", new String[] {"t"}); // true - true -> true
+ testSimpleEval("select (true OR 1 > null)", new String[] {"t"}); // true - unknown -> true
+ testSimpleEval("select (true OR false)", new String[] {"t"}); // true - false -> true
+
+ testSimpleEval("select (1 > null OR true)", new String[] {"t"}); // unknown - true -> true
+ testSimpleEval("select (1 > null OR 1 > null) is null", new String[] {"t"}); // unknown - unknown -> unknown
+ testSimpleEval("select (1 > null OR false) is null", new String[] {"t"}); // unknown - false -> false
+
+ testSimpleEval("select (false OR true)", new String[] {"t"}); // false - true -> true
+ testSimpleEval("select (false OR 1 > null) is null", new String[] {"t"}); // false - unknown -> unknown
+ testSimpleEval("select (false OR false)", new String[] {"f"}); // false - false -> false
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/e8c5c277/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java
index c611b83..ac350fc 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/function/TestStringOperatorsAndFunctions.java
@@ -215,7 +215,8 @@ public class TestStringOperatorsAndFunctions extends ExprTestBase {
schema.addColumn("col1", TEXT);
schema.addColumn("col2", TEXT);
schema.addColumn("col3", TEXT);
- testEval(schema, "table1", "abc,efg,3.14", "select reverse(col1) || reverse(col2) from table1", new String[]{"cbagfe"});
+ testEval(schema, "table1", "abc,efg,3.14", "select reverse(col1) || reverse(col2) from table1",
+ new String[]{"cbagfe"});
}
@Test
@@ -291,7 +292,8 @@ public class TestStringOperatorsAndFunctions extends ExprTestBase {
schema.addColumn("col1", TEXT);
schema.addColumn("col2", TEXT);
schema.addColumn("col3", TEXT);
- testEval(schema, "table1", "abc,efg,3.14", "select md5(col1) from table1", new String[]{"900150983cd24fb0d6963f7d28e17f72"});
+ testEval(schema, "table1", "abc,efg,3.14", "select md5(col1) from table1",
+ new String[]{"900150983cd24fb0d6963f7d28e17f72"});
}
@Test
@@ -340,6 +342,20 @@ public class TestStringOperatorsAndFunctions extends ExprTestBase {
@Test
public void testSplitPart() throws IOException {
testSimpleEval("select split_part('1386577650.123', '.', 1) as col1 ", new String[]{"1386577650"});
+ testSimpleEval("select split_part('1386577650.123', '.', 2) as col1 ", new String[]{"123"});
+ // If part is larger than the number of string portions, it will returns NULL.
+ testSimpleEval("select split_part('1386577650.123', '.', 3) is null", new String[]{"t"});
+
+ // null handling tests
+ Schema schema = new Schema();
+ schema.addColumn("col1", TEXT);
+ schema.addColumn("col2", TEXT);
+ schema.addColumn("col3", TEXT);
+ testEval(schema, "t1", ",.,1", "select split_part(col1, col2, col3::int) is null from t1", new String[]{"t"});
+ testEval(schema, "t1", "1386577650.123,,1", "select split_part(col1, col2, col3::int) from t1",
+ new String[]{"1386577650.123"});
+ testEval(schema, "t1", "1386577650.123,.,", "select split_part(col1, col2, col3::int) is null from t1",
+ new String[]{"t"});
}
@Test
@@ -386,24 +402,22 @@ public class TestStringOperatorsAndFunctions extends ExprTestBase {
// empty string
testSimpleEval("select locate('abcdef', '') as col1 ", new String[]{"1"});
testSimpleEval("select locate('abcdef', '', 2) as col1 ", new String[]{"2"});
- testSimpleEval("select locate('abcdef', '', 6) as col1 ", new String[]{"6"}); // pos = last index of string (expected value(6) is tested on mysql)
- testSimpleEval("select locate('abcdef', '', 7) as col1 ", new String[]{"7"}); // pos = last index + 1 (expected value(7) is tested on mysql)
- testSimpleEval("select locate('abcdef', '', 8) as col1 ", new String[]{"0"}); // pos = greater then last index + 1 (expected value(0) is tested on mysql)
- testSimpleEval("select locate('abcdef', '', 9) as col1 ", new String[]{"0"}); // pos = greater then last index + 1 (expected value(0) is tested on mysql)
+ // pos = last index of string (expected value(6) is tested on mysql)
+ testSimpleEval("select locate('abcdef', '', 6) as col1 ", new String[]{"6"});
+ // pos = last index + 1 (expected value(7) is tested on mysql)
+ testSimpleEval("select locate('abcdef', '', 7) as col1 ", new String[]{"7"});
+ // pos = greater then last index + 1 (expected value(0) is tested on mysql)
+ testSimpleEval("select locate('abcdef', '', 8) as col1 ", new String[]{"0"});
+ // pos = greater then last index + 1 (expected value(0) is tested on mysql)
+ testSimpleEval("select locate('abcdef', '', 9) as col1 ", new String[]{"0"});
testSimpleEval("select locate('가나다라', '', 2) as col1 ", new String[]{"2"});
testSimpleEval("select locate('가나다라', '', 4) as col1 ", new String[]{"4"});
testSimpleEval("select locate('가나다라', '', 5) as col1 ", new String[]{"5"});
testSimpleEval("select locate('가나다라', '', 6) as col1 ", new String[]{"0"});
- //TODO If there is a minus value in function argument, next error occurred.
- //org.apache.tajo.engine.parser.SQLSyntaxError: ERROR: syntax error at or near 'locate'
- //LINE 1:7 select locate('abcdef', 'a', -1) as col1
- // ^^^^^^
- //at org.apache.tajo.engine.parser.SQLAnalyzer.parse(SQLAnalyzer.java:64)
-
// negative pos
- //testSimpleEval("select locate('abcdef', 'a', -1) as col1 ", new String[]{"0"});
- //testSimpleEval("select locate('abcdef', 'a', -5) as col1 ", new String[]{"0"});
+ testSimpleEval("select locate('abcdef', 'a', -1) as col1 ", new String[]{"0"});
+ testSimpleEval("select locate('abcdef', 'a', -5) as col1 ", new String[]{"0"});
Schema schema = new Schema();
schema.addColumn("col1", TEXT);