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:31 UTC

[2/2] git commit: TAJO-182: Correct NULL value handling of primitive operators. (hyunsik)

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);